[#184] Unify error handling

Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
Denis Kirillov 2021-08-05 12:18:52 +03:00
parent 6674e350cc
commit f4c29cd300
17 changed files with 196 additions and 541 deletions

View file

@ -1,7 +1,6 @@
package api
import (
"context"
"fmt"
"net/http"
)
@ -118,6 +117,7 @@ const (
ErrObjectLockInvalidHeaders
ErrInvalidTagDirective
// Add new error codes here.
ErrNotSupported
// SSE-S3 related API errors.
ErrInvalidEncryptionMethod
@ -967,6 +967,12 @@ var errorCodes = errorCodeMap{
Description: "Unknown tag directive.",
HTTPStatusCode: http.StatusBadRequest,
},
ErrNotSupported: {
ErrCode: ErrNotSupported,
Code: "BadRequest",
Description: "Not supported by NeoFS S3 Gate",
HTTPStatusCode: http.StatusNotImplemented,
},
ErrInvalidEncryptionMethod: {
ErrCode: ErrInvalidEncryptionMethod,
Code: "InvalidRequest",
@ -1898,15 +1904,10 @@ func GetAPIError(code ErrorCode) Error {
// getErrorResponse gets in standard error and resource value and
// provides a encodable populated response values.
func getAPIErrorResponse(ctx context.Context, err error, resource, requestID, hostID string) ErrorResponse {
func getAPIErrorResponse(info *ReqInfo, err error) ErrorResponse {
code := "InternalError"
desc := err.Error()
info := GetReqInfo(ctx)
if info == nil {
info = &ReqInfo{}
}
if e, ok := err.(Error); ok {
code = e.Code
desc = e.Description
@ -1917,9 +1918,9 @@ func getAPIErrorResponse(ctx context.Context, err error, resource, requestID, ho
Message: desc,
BucketName: info.BucketName,
Key: info.ObjectName,
Resource: resource,
RequestID: requestID,
HostID: hostID,
Resource: info.URL.Path,
RequestID: info.RequestID,
HostID: info.DeploymentID,
}
}

View file

@ -21,8 +21,6 @@ type (
}
)
const notSupported = "Not supported by NeoFS S3 Gate: "
var _ api.Handler = (*handler)(nil)
// New creates new api.Handler using given logger and client.

View file

@ -6,7 +6,6 @@ import (
"strings"
"time"
"github.com/gorilla/mux"
"github.com/nspcc-dev/neofs-s3-gw/api"
"github.com/nspcc-dev/neofs-s3-gw/api/layer"
"go.uber.org/zap"
@ -31,10 +30,7 @@ func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
err error
inf *layer.ObjectInfo
req = mux.Vars(r)
bkt = req["bucket"]
obj = req["object"]
rid = api.GetRequestID(r.Context())
reqInfo = api.GetReqInfo(r.Context())
)
src := r.Header.Get("X-Amz-Copy-Source")
@ -48,12 +44,7 @@ func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
// its non "null" value, we should error out since we do not support
// any versions other than "null".
if vid := u.Query().Get("versionId"); vid != "" && vid != "null" {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: api.GetAPIError(api.ErrNoSuchVersion).Code,
Description: "",
HTTPStatusCode: http.StatusBadRequest,
}, r.URL)
h.logAndSendError(w, "no such version", reqInfo, api.GetAPIError(api.ErrNoSuchVersion))
return
}
@ -64,34 +55,34 @@ func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
args, err := parseCopyObjectArgs(r.Header)
if err != nil {
writeError(w, r, h.log, "could not parse request params ", rid, bkt, obj, err)
h.logAndSendError(w, "could not parse request params", reqInfo, err)
return
}
if inf, err = h.obj.GetObjectInfo(r.Context(), srcBucket, srcObject); err != nil {
writeError(w, r, h.log, "could not find object", rid, bkt, obj, err)
h.logAndSendError(w, "could not find object", reqInfo, err)
return
}
if err = checkPreconditions(inf, args.Conditional); err != nil {
api.WriteErrorResponse(r.Context(), w, api.GetAPIError(api.ErrPreconditionFailed), r.URL)
h.logAndSendError(w, "precondition failed", reqInfo, api.GetAPIError(api.ErrPreconditionFailed))
return
}
params := &layer.CopyObjectParams{
SrcBucket: srcBucket,
DstBucket: bkt,
DstBucket: reqInfo.BucketName,
SrcObject: srcObject,
DstObject: obj,
DstObject: reqInfo.ObjectName,
SrcSize: inf.Size,
Header: inf.Headers,
}
if inf, err = h.obj.CopyObject(r.Context(), params); err != nil {
writeErrorCopy(w, r, h.log, "could not copy object", rid, bkt, obj, srcBucket, srcObject, err)
writeErrorCopy(w, reqInfo, h.log, "could not copy object", srcBucket, srcObject, err)
return
} else if err = api.EncodeToResponse(w, &CopyObjectResponse{LastModified: inf.Created.Format(time.RFC3339), ETag: inf.HashSum}); err != nil {
writeErrorCopy(w, r, h.log, "something went wrong", rid, bkt, obj, srcBucket, srcObject, err)
writeErrorCopy(w, reqInfo, h.log, "something went wrong", srcBucket, srcObject, err)
return
}
@ -101,20 +92,16 @@ func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
zap.Stringer("object_id", inf.ID()))
}
func writeErrorCopy(w http.ResponseWriter, r *http.Request, log *zap.Logger, msg, rid, bkt, obj, srcBucket, srcObject string, err error) {
func writeErrorCopy(w http.ResponseWriter, reqInfo *api.ReqInfo, log *zap.Logger, msg, srcBucket, srcObject string, err error) {
log.Error(msg,
zap.String("request_id", rid),
zap.String("dst_bucket_name", bkt),
zap.String("dst_object_name", obj),
zap.String("request_id", reqInfo.RequestID),
zap.String("dst_bucket_name", reqInfo.BucketName),
zap.String("dst_object_name", reqInfo.ObjectName),
zap.String("src_bucket_name", srcBucket),
zap.String("src_object_name", srcObject),
zap.Error(err))
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: api.GetAPIError(api.ErrInternalError).Code,
Description: err.Error(),
HTTPStatusCode: http.StatusInternalServerError,
}, r.URL)
api.WriteErrorResponse(w, reqInfo, err)
}
func parseCopyObjectArgs(headers http.Header) (*copyObjectArgs, error) {

View file

@ -4,7 +4,6 @@ import (
"encoding/xml"
"net/http"
"github.com/gorilla/mux"
"github.com/nspcc-dev/neofs-s3-gw/api"
"github.com/nspcc-dev/neofs-s3-gw/api/layer"
"go.uber.org/zap"
@ -42,18 +41,13 @@ type DeleteObjectsResponse struct {
}
func (h *handler) DeleteObjectHandler(w http.ResponseWriter, r *http.Request) {
var (
req = mux.Vars(r)
bkt = req["bucket"]
obj = req["object"]
rid = api.GetRequestID(r.Context())
)
reqInfo := api.GetReqInfo(r.Context())
if err := h.obj.DeleteObject(r.Context(), bkt, obj); err != nil {
if err := h.obj.DeleteObject(r.Context(), reqInfo.BucketName, reqInfo.ObjectName); err != nil {
h.log.Error("could not delete object",
zap.String("request_id", rid),
zap.String("bucket_name", bkt),
zap.String("object_name", obj),
zap.String("request_id", reqInfo.RequestID),
zap.String("bucket_name", reqInfo.BucketName),
zap.String("object_name", reqInfo.ObjectName),
zap.Error(err))
// Ignore delete errors:
@ -70,30 +64,26 @@ func (h *handler) DeleteObjectHandler(w http.ResponseWriter, r *http.Request) {
// DeleteMultipleObjectsHandler handles multiple delete requests.
func (h *handler) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *http.Request) {
var (
req = mux.Vars(r)
bkt = req["bucket"]
rid = api.GetRequestID(r.Context())
)
reqInfo := api.GetReqInfo(r.Context())
// Content-Md5 is requied should be set
// http://docs.aws.amazon.com/AmazonS3/latest/API/multiobjectdeleteapi.html
if _, ok := r.Header[api.ContentMD5]; !ok {
api.WriteErrorResponse(r.Context(), w, api.GetAPIError(api.ErrMissingContentMD5), r.URL)
h.logAndSendError(w, "missing Content-MD5", reqInfo, api.GetAPIError(api.ErrMissingContentMD5))
return
}
// Content-Length is required and should be non-zero
// http://docs.aws.amazon.com/AmazonS3/latest/API/multiobjectdeleteapi.html
if r.ContentLength <= 0 {
api.WriteErrorResponse(r.Context(), w, api.GetAPIError(api.ErrMissingContentLength), r.URL)
h.logAndSendError(w, "missing Content-Length", reqInfo, api.GetAPIError(api.ErrMissingContentLength))
return
}
// Unmarshal list of keys to be deleted.
requested := &DeleteObjectsRequest{}
if err := xml.NewDecoder(r.Body).Decode(requested); err != nil {
api.WriteErrorResponse(r.Context(), w, err, r.URL)
h.logAndSendError(w, "couldn't decode body", reqInfo, err)
return
}
@ -109,12 +99,12 @@ func (h *handler) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *http.Re
DeletedObjects: make([]ObjectIdentifier, 0, len(toRemove)),
}
if errs := h.obj.DeleteObjects(r.Context(), bkt, toRemove); errs != nil && !requested.Quiet {
h.log.Error("could not delete objects",
zap.String("request_id", rid),
zap.String("bucket_name", bkt),
zap.Strings("object_name", toRemove),
zap.Errors("errors", errs))
if errs := h.obj.DeleteObjects(r.Context(), reqInfo.BucketName, toRemove); errs != nil && !requested.Quiet {
additional := []zap.Field{
zap.Strings("objects_name", toRemove),
zap.Errors("errors", errs),
}
h.logAndSendError(w, "could not delete objects", reqInfo, nil, additional...)
for _, e := range errs {
if err, ok := e.(*api.DeleteError); ok {
@ -137,40 +127,14 @@ func (h *handler) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *http.Re
}
if err := api.EncodeToResponse(w, response); err != nil {
h.log.Error("could not write response",
zap.String("request_id", rid),
zap.String("bucket_name", bkt),
zap.Strings("object_name", toRemove),
zap.Error(err))
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: api.GetAPIError(api.ErrInternalError).Code,
Description: err.Error(),
HTTPStatusCode: http.StatusInternalServerError,
}, r.URL)
h.logAndSendError(w, "could not write response", reqInfo, err, zap.Strings("objects_name", toRemove))
return
}
}
func (h *handler) DeleteBucketHandler(w http.ResponseWriter, r *http.Request) {
var (
rid = api.GetRequestID(r.Context())
p = layer.DeleteBucketParams{}
req = mux.Vars(r)
)
p.Name = req["bucket"]
err := h.obj.DeleteBucket(r.Context(), &p)
if err != nil {
h.log.Error("couldn't delete bucket",
zap.String("request_id", rid),
zap.String("bucket_name", p.Name),
zap.Error(err))
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: api.GetAPIError(api.ErrInternalError).Code,
Description: err.Error(),
HTTPStatusCode: http.StatusInternalServerError,
}, r.URL)
reqInfo := api.GetReqInfo(r.Context())
if err := h.obj.DeleteBucket(r.Context(), &layer.DeleteBucketParams{Name: reqInfo.BucketName}); err != nil {
h.logAndSendError(w, "couldn't delete bucket", reqInfo, err)
}
}

View file

@ -7,10 +7,8 @@ import (
"strings"
"time"
"github.com/gorilla/mux"
"github.com/nspcc-dev/neofs-s3-gw/api"
"github.com/nspcc-dev/neofs-s3-gw/api/layer"
"go.uber.org/zap"
)
type conditionalArgs struct {
@ -79,30 +77,27 @@ func (h *handler) GetObjectHandler(w http.ResponseWriter, r *http.Request) {
inf *layer.ObjectInfo
params *layer.RangeParams
req = mux.Vars(r)
bkt = req["bucket"]
obj = req["object"]
rid = api.GetRequestID(r.Context())
reqInfo = api.GetReqInfo(r.Context())
)
args, err := parseGetObjectArgs(r.Header)
if err != nil {
writeError(w, r, h.log, "could not parse request params", rid, bkt, obj, err)
h.logAndSendError(w, "could not parse request params", reqInfo, err)
return
}
if inf, err = h.obj.GetObjectInfo(r.Context(), bkt, obj); err != nil {
writeError(w, r, h.log, "could not find object", rid, bkt, obj, err)
if inf, err = h.obj.GetObjectInfo(r.Context(), reqInfo.BucketName, reqInfo.ObjectName); err != nil {
h.logAndSendError(w, "could not find object", reqInfo, err)
return
}
if err = checkPreconditions(inf, args.Conditional); err != nil {
api.WriteErrorResponse(r.Context(), w, err, r.URL)
h.logAndSendError(w, "precondition failed", reqInfo, err)
return
}
if params, err = fetchRangeHeader(r.Header, uint64(inf.Size)); err != nil {
writeError(w, r, h.log, "could not parse range header", rid, bkt, obj, err)
h.logAndSendError(w, "could not parse range header", reqInfo, err)
return
}
writeHeaders(w.Header(), inf)
@ -117,7 +112,7 @@ func (h *handler) GetObjectHandler(w http.ResponseWriter, r *http.Request) {
Range: params,
}
if err = h.obj.GetObject(r.Context(), getParams); err != nil {
writeError(w, r, h.log, "could not get object", rid, bkt, obj, err)
h.logAndSendError(w, "could not get object", reqInfo, err)
}
}
@ -174,13 +169,3 @@ func writeRangeHeaders(w http.ResponseWriter, params *layer.RangeParams, size in
w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", params.Start, params.End, size))
w.WriteHeader(http.StatusPartialContent)
}
func writeError(w http.ResponseWriter, r *http.Request, log *zap.Logger, msg, rid, bkt, obj string, err error) {
log.Error(msg,
zap.String("request_id", rid),
zap.String("bucket_name", bkt),
zap.String("object_name", obj),
zap.Error(err))
api.WriteErrorResponse(r.Context(), w, err, r.URL)
}

View file

@ -4,7 +4,6 @@ import (
"bytes"
"net/http"
"github.com/gorilla/mux"
"github.com/nspcc-dev/neofs-s3-gw/api"
"github.com/nspcc-dev/neofs-s3-gw/api/layer"
"go.uber.org/zap"
@ -29,20 +28,11 @@ func (h *handler) HeadObjectHandler(w http.ResponseWriter, r *http.Request) {
err error
inf *layer.ObjectInfo
req = mux.Vars(r)
bkt = req["bucket"]
obj = req["object"]
rid = api.GetRequestID(r.Context())
reqInfo = api.GetReqInfo(r.Context())
)
if inf, err = h.obj.GetObjectInfo(r.Context(), bkt, obj); err != nil {
h.log.Error("could not fetch object info",
zap.String("request_id", rid),
zap.String("bucket_name", bkt),
zap.String("object_name", obj),
zap.Error(err))
api.WriteErrorResponse(r.Context(), w, err, r.URL)
if inf, err = h.obj.GetObjectInfo(r.Context(), reqInfo.BucketName, reqInfo.ObjectName); err != nil {
h.logAndSendError(w, "could not fetch object info", reqInfo, err)
return
}
buffer := bytes.NewBuffer(make([]byte, 0, sizeToDetectType))
@ -53,15 +43,7 @@ func (h *handler) HeadObjectHandler(w http.ResponseWriter, r *http.Request) {
Range: getRangeToDetectContentType(inf.Size),
}
if err = h.obj.GetObject(r.Context(), getParams); err != nil {
h.log.Error("could not get object",
zap.String("request_id", rid),
zap.String("bucket_name", bkt),
zap.String("object_name", obj),
zap.Stringer("oid", inf.ID()),
zap.Error(err))
api.WriteErrorResponse(r.Context(), w, err, r.URL)
h.logAndSendError(w, "could not get object", reqInfo, err, zap.Stringer("oid", inf.ID()))
return
}
inf.ContentType = http.DetectContentType(buffer.Bytes())
@ -70,19 +52,10 @@ func (h *handler) HeadObjectHandler(w http.ResponseWriter, r *http.Request) {
}
func (h *handler) HeadBucketHandler(w http.ResponseWriter, r *http.Request) {
var (
req = mux.Vars(r)
bkt = req["bucket"]
rid = api.GetRequestID(r.Context())
)
reqInfo := api.GetReqInfo(r.Context())
if _, err := h.obj.GetBucketInfo(r.Context(), bkt); err != nil {
h.log.Error("could not fetch object info",
zap.String("request_id", rid),
zap.String("bucket_name", bkt),
zap.Error(err))
api.WriteErrorResponse(r.Context(), w, err, r.URL)
if _, err := h.obj.GetBucketInfo(r.Context(), reqInfo.BucketName); err != nil {
h.logAndSendError(w, "could not fetch object info", reqInfo, err)
return
}

View file

@ -3,40 +3,18 @@ package handler
import (
"net/http"
"github.com/gorilla/mux"
"github.com/nspcc-dev/neofs-s3-gw/api"
"go.uber.org/zap"
)
func (h *handler) GetBucketLocationHandler(w http.ResponseWriter, r *http.Request) {
var (
bkt = mux.Vars(r)["bucket"]
rid = api.GetRequestID(r.Context())
)
if _, err := h.obj.GetBucketInfo(r.Context(), bkt); err != nil {
h.log.Error("something went wrong",
zap.String("request_id", rid),
zap.Error(err))
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: api.GetAPIError(api.ErrInternalError).Code,
Description: err.Error(),
HTTPStatusCode: http.StatusInternalServerError,
}, r.URL)
return
} else if err = api.EncodeToResponse(w, LocationResponse{Location: ""}); err != nil {
h.log.Error("could not write response",
zap.String("request_id", rid),
zap.Error(err))
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: api.GetAPIError(api.ErrInternalError).Code,
Description: err.Error(),
HTTPStatusCode: http.StatusInternalServerError,
}, r.URL)
reqInfo := api.GetReqInfo(r.Context())
if _, err := h.obj.GetBucketInfo(r.Context(), reqInfo.BucketName); err != nil {
h.logAndSendError(w, "something went wrong", reqInfo, err)
return
}
if err := api.EncodeToResponse(w, LocationResponse{Location: ""}); err != nil {
h.logAndSendError(w, "something went wrong", reqInfo, err)
}
}

View file

@ -7,7 +7,6 @@ import (
"github.com/nspcc-dev/neofs-api-go/pkg/owner"
"github.com/nspcc-dev/neofs-s3-gw/api"
"go.uber.org/zap"
)
// VersioningConfiguration contains VersioningConfiguration XML representation.
@ -26,36 +25,17 @@ type ListMultipartUploadsResult struct {
const maxObjectList = 1000 // Limit number of objects in a listObjectsResponse/listObjectsVersionsResponse.
func (h *handler) registerAndSendError(w http.ResponseWriter, r *http.Request, err error, logText string) {
rid := api.GetRequestID(r.Context())
h.log.Error(logText,
zap.String("request_id", rid),
zap.Error(err))
api.WriteErrorResponse(r.Context(), w, err, r.URL)
}
// ListBucketsHandler handles bucket listing requests.
func (h *handler) ListBucketsHandler(w http.ResponseWriter, r *http.Request) {
var (
err error
own = owner.NewID()
res *ListBucketsResponse
rid = api.GetRequestID(r.Context())
own = owner.NewID()
res *ListBucketsResponse
reqInfo = api.GetReqInfo(r.Context())
)
list, err := h.obj.ListBuckets(r.Context())
if err != nil {
h.log.Error("something went wrong",
zap.String("request_id", rid),
zap.Error(err))
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: api.GetAPIError(api.ErrInternalError).Code,
Description: err.Error(),
HTTPStatusCode: http.StatusInternalServerError,
}, r.URL)
h.logAndSendError(w, "something went wrong", reqInfo, err)
return
}
@ -78,58 +58,34 @@ func (h *handler) ListBucketsHandler(w http.ResponseWriter, r *http.Request) {
}
if err = api.EncodeToResponse(w, res); err != nil {
h.log.Error("something went wrong",
zap.String("request_id", rid),
zap.Error(err))
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: api.GetAPIError(api.ErrInternalError).Code,
Description: err.Error(),
HTTPStatusCode: http.StatusInternalServerError,
}, r.URL)
h.logAndSendError(w, "something went wrong", reqInfo, err)
}
}
// GetBucketVersioningHandler implements bucket versioning getter handler.
func (h *handler) GetBucketVersioningHandler(w http.ResponseWriter, r *http.Request) {
var (
rid = api.GetRequestID(r.Context())
res = new(VersioningConfiguration)
reqInfo = api.GetReqInfo(r.Context())
res = new(VersioningConfiguration)
)
res.Xmlns = "http://s3.amazonaws.com/doc/2006-03-01/"
if err := api.EncodeToResponse(w, res); err != nil {
h.log.Error("something went wrong",
zap.String("request_id", rid),
zap.Error(err))
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: api.GetAPIError(api.ErrInternalError).Code,
Description: err.Error(),
HTTPStatusCode: http.StatusInternalServerError,
}, r.URL)
h.logAndSendError(w, "something went wrong", reqInfo, err)
}
}
// ListMultipartUploadsHandler implements multipart uploads listing handler.
func (h *handler) ListMultipartUploadsHandler(w http.ResponseWriter, r *http.Request) {
var (
rid = api.GetRequestID(r.Context())
res = new(ListMultipartUploadsResult)
reqInfo = api.GetReqInfo(r.Context())
res = new(ListMultipartUploadsResult)
)
res.Xmlns = "http://s3.amazonaws.com/doc/2006-03-01/"
if err := api.EncodeToResponse(w, res); err != nil {
h.log.Error("something went wrong",
zap.String("request_id", rid),
zap.Error(err))
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: api.GetAPIError(api.ErrInternalError).Code,
Description: err.Error(),
HTTPStatusCode: http.StatusInternalServerError,
}, r.URL)
h.logAndSendError(w, "something went wrong", reqInfo, err)
}
}

View file

@ -3,54 +3,29 @@ package handler
import (
"net/http"
"github.com/gorilla/mux"
"github.com/nspcc-dev/neofs-s3-gw/api"
)
func (h *handler) DeleteBucketPolicyHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: api.GetAPIError(api.ErrBadRequest).Code,
Description: notSupported + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not supported", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotSupported))
}
func (h *handler) DeleteBucketLifecycleHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: api.GetAPIError(api.ErrBadRequest).Code,
Description: notSupported + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not supported", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotSupported))
}
func (h *handler) DeleteBucketEncryptionHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: api.GetAPIError(api.ErrBadRequest).Code,
Description: notSupported + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not supported", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotSupported))
}
func (h *handler) PutBucketTaggingHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: api.GetAPIError(api.ErrBadRequest).Code,
Description: notSupported + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not supported", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotSupported))
}
func (h *handler) PutBucketVersioningHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: api.GetAPIError(api.ErrBadRequest).Code,
Description: notSupported + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not supported", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotSupported))
}
func (h *handler) PutBucketNotificationHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: api.GetAPIError(api.ErrBadRequest).Code,
Description: notSupported + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not supported", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotSupported))
}

View file

@ -13,21 +13,21 @@ import (
// ListObjectsV1Handler handles objects listing requests for API version 1.
func (h *handler) ListObjectsV1Handler(w http.ResponseWriter, r *http.Request) {
params, err := parseListObjectsArgsV1(r)
reqInfo := api.GetReqInfo(r.Context())
params, err := parseListObjectsArgsV1(reqInfo)
if err != nil {
h.registerAndSendError(w, r, err, "failed to parse arguments")
h.logAndSendError(w, "failed to parse arguments", reqInfo, err)
return
}
list, err := h.obj.ListObjectsV1(r.Context(), params)
if err != nil {
h.registerAndSendError(w, r, err, "something went wrong")
h.logAndSendError(w, "something went wrong", reqInfo, err)
return
}
err = api.EncodeToResponse(w, encodeV1(params, list))
if err != nil {
h.registerAndSendError(w, r, err, "something went wrong")
if err = api.EncodeToResponse(w, encodeV1(params, list)); err != nil {
h.logAndSendError(w, "something went wrong", reqInfo, err)
}
}
@ -52,21 +52,21 @@ func encodeV1(p *layer.ListObjectsParamsV1, list *layer.ListObjectsInfoV1) *List
// ListObjectsV2Handler handles objects listing requests for API version 2.
func (h *handler) ListObjectsV2Handler(w http.ResponseWriter, r *http.Request) {
params, err := parseListObjectsArgsV2(r)
reqInfo := api.GetReqInfo(r.Context())
params, err := parseListObjectsArgsV2(reqInfo)
if err != nil {
h.registerAndSendError(w, r, err, "failed to parse arguments")
h.logAndSendError(w, "failed to parse arguments", reqInfo, err)
return
}
list, err := h.obj.ListObjectsV2(r.Context(), params)
if err != nil {
h.registerAndSendError(w, r, err, "something went wrong")
h.logAndSendError(w, "something went wrong", reqInfo, err)
return
}
err = api.EncodeToResponse(w, encodeV2(params, list))
if err != nil {
h.registerAndSendError(w, r, err, "something went wrong")
if err = api.EncodeToResponse(w, encodeV2(params, list)); err != nil {
h.logAndSendError(w, "something went wrong", reqInfo, err)
}
}
@ -91,14 +91,13 @@ func encodeV2(p *layer.ListObjectsParamsV2, list *layer.ListObjectsInfoV2) *List
return res
}
func parseListObjectsArgsV1(r *http.Request) (*layer.ListObjectsParamsV1, error) {
func parseListObjectsArgsV1(reqInfo *api.ReqInfo) (*layer.ListObjectsParamsV1, error) {
var (
err error
res layer.ListObjectsParamsV1
queryValues = r.URL.Query()
queryValues = reqInfo.URL.Query()
)
common, err := parseListObjectArgs(r)
common, err := parseListObjectArgs(reqInfo)
if err != nil {
return nil, err
}
@ -109,14 +108,13 @@ func parseListObjectsArgsV1(r *http.Request) (*layer.ListObjectsParamsV1, error)
return &res, nil
}
func parseListObjectsArgsV2(r *http.Request) (*layer.ListObjectsParamsV2, error) {
func parseListObjectsArgsV2(reqInfo *api.ReqInfo) (*layer.ListObjectsParamsV2, error) {
var (
err error
res layer.ListObjectsParamsV2
queryValues = r.URL.Query()
queryValues = reqInfo.URL.Query()
)
common, err := parseListObjectArgs(r)
common, err := parseListObjectArgs(reqInfo)
if err != nil {
return nil, err
}
@ -132,17 +130,14 @@ func parseListObjectsArgsV2(r *http.Request) (*layer.ListObjectsParamsV2, error)
return &res, nil
}
func parseListObjectArgs(r *http.Request) (*layer.ListObjectsParamsCommon, error) {
func parseListObjectArgs(reqInfo *api.ReqInfo) (*layer.ListObjectsParamsCommon, error) {
var (
err error
res layer.ListObjectsParamsCommon
queryValues = r.URL.Query()
queryValues = reqInfo.URL.Query()
)
if info := api.GetReqInfo(r.Context()); info != nil {
res.Bucket = info.BucketName
}
res.Bucket = reqInfo.BucketName
res.Delimiter = queryValues.Get("delimiter")
res.Encode = queryValues.Get("encoding-type")
@ -204,29 +199,30 @@ func fillContents(src []*layer.ObjectInfo, encode string, fetchOwner bool) []Obj
}
func (h *handler) ListBucketObjectVersionsHandler(w http.ResponseWriter, r *http.Request) {
p, err := parseListObjectVersionsRequest(r)
reqInfo := api.GetReqInfo(r.Context())
p, err := parseListObjectVersionsRequest(reqInfo)
if err != nil {
h.registerAndSendError(w, r, err, "failed to parse request ")
h.logAndSendError(w, "failed to parse request", reqInfo, err)
return
}
info, err := h.obj.ListObjectVersions(r.Context(), p)
if err != nil {
h.registerAndSendError(w, r, err, "something went wrong")
h.logAndSendError(w, "something went wrong", reqInfo, err)
return
}
response := encodeListObjectVersionsToResponse(info, p.Bucket)
if err := api.EncodeToResponse(w, response); err != nil {
h.registerAndSendError(w, r, err, "something went wrong")
if err = api.EncodeToResponse(w, response); err != nil {
h.logAndSendError(w, "something went wrong", reqInfo, err)
}
}
func parseListObjectVersionsRequest(r *http.Request) (*layer.ListObjectVersionsParams, error) {
func parseListObjectVersionsRequest(reqInfo *api.ReqInfo) (*layer.ListObjectVersionsParams, error) {
var (
err error
res layer.ListObjectVersionsParams
queryValues = r.URL.Query()
queryValues = reqInfo.URL.Query()
)
if queryValues.Get("max-keys") == "" {
@ -240,10 +236,7 @@ func parseListObjectVersionsRequest(r *http.Request) (*layer.ListObjectVersionsP
res.Delimiter = queryValues.Get("delimiter")
res.Encode = queryValues.Get("encoding-type")
res.VersionIDMarker = queryValues.Get("version-id-marker")
if info := api.GetReqInfo(r.Context()); info != nil {
res.Bucket = info.BucketName
}
res.Bucket = reqInfo.BucketName
return &res, nil
}

View file

@ -7,7 +7,6 @@ import (
"strconv"
"strings"
"github.com/gorilla/mux"
"github.com/nspcc-dev/neofs-api-go/pkg/acl"
"github.com/nspcc-dev/neofs-node/pkg/policy"
"github.com/nspcc-dev/neofs-s3-gw/api"
@ -32,37 +31,23 @@ type createBucketParams struct {
func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
var (
err error
info *layer.ObjectInfo
req = mux.Vars(r)
bkt = req["bucket"]
obj = req["object"]
rid = api.GetRequestID(r.Context())
err error
info *layer.ObjectInfo
reqInfo = api.GetReqInfo(r.Context())
)
metadata := parseMetadata(r)
params := &layer.PutObjectParams{
Bucket: bkt,
Object: obj,
Bucket: reqInfo.BucketName,
Object: reqInfo.ObjectName,
Reader: r.Body,
Size: r.ContentLength,
Header: metadata,
}
if info, err = h.obj.PutObject(r.Context(), params); err != nil {
h.log.Error("could not upload object",
zap.String("request_id", rid),
zap.String("bucket_name", bkt),
zap.String("object_name", obj),
zap.Error(err))
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: api.GetAPIError(api.ErrInternalError).Code,
Description: err.Error(),
HTTPStatusCode: http.StatusInternalServerError,
}, r.URL)
h.logAndSendError(w, "could not upload object", reqInfo, err)
return
}
@ -83,11 +68,11 @@ func parseMetadata(r *http.Request) map[string]string {
func (h *handler) CreateBucketHandler(w http.ResponseWriter, r *http.Request) {
var (
err error
p = layer.CreateBucketParams{}
req = mux.Vars(r)
err error
reqInfo = api.GetReqInfo(r.Context())
p = layer.CreateBucketParams{Name: reqInfo.BucketName}
)
p.Name = req["bucket"]
if val, ok := r.Header["X-Amz-Acl"]; ok {
p.ACL, err = parseBasicACL(val[0])
} else {
@ -95,19 +80,19 @@ func (h *handler) CreateBucketHandler(w http.ResponseWriter, r *http.Request) {
}
if err != nil {
h.registerAndSendError(w, r, err, "could not parse basic ACL")
h.logAndSendError(w, "could not parse basic ACL", reqInfo, err)
return
}
createParams, err := parseLocationConstraint(r)
if err != nil {
h.registerAndSendError(w, r, err, "could not parse body")
h.logAndSendError(w, "could not parse body", reqInfo, err)
return
}
p.BoxData, err = layer.GetBoxData(r.Context())
if err != nil {
h.registerAndSendError(w, r, err, "could not get boxData")
h.logAndSendError(w, "could not get boxData", reqInfo, err)
return
}
@ -122,14 +107,14 @@ func (h *handler) CreateBucketHandler(w http.ResponseWriter, r *http.Request) {
if p.Policy == nil {
p.Policy, err = policy.Parse(defaultPolicy)
if err != nil {
h.registerAndSendError(w, r, err, "could not parse policy")
h.logAndSendError(w, "could not parse policy", reqInfo, err)
return
}
}
cid, err := h.obj.CreateBucket(r.Context(), &p)
if err != nil {
h.registerAndSendError(w, r, err, "could not create bucket")
h.logAndSendError(w, "could not create bucket", reqInfo, err)
return
}

View file

@ -3,318 +3,161 @@ package handler
import (
"net/http"
"github.com/gorilla/mux"
"github.com/nspcc-dev/neofs-s3-gw/api"
)
func (h *handler) CopyObjectPartHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) PutObjectPartHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) ListObjectPartsHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) CompleteMultipartUploadHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) NewMultipartUploadHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) AbortMultipartUploadHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) GetObjectACLHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) PutObjectACLHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) GetObjectTaggingHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) PutObjectTaggingHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) DeleteObjectTaggingHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) SelectObjectContentHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) GetObjectRetentionHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) GetObjectLegalHoldHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) PutObjectRetentionHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) PutObjectLegalHoldHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) GetBucketPolicyHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) GetBucketLifecycleHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) GetBucketEncryptionHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) GetBucketACLHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) PutBucketACLHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) GetBucketCorsHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) GetBucketWebsiteHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) GetBucketAccelerateHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) GetBucketRequestPaymentHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) GetBucketLoggingHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) GetBucketReplicationHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) GetBucketTaggingHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) DeleteBucketWebsiteHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) DeleteBucketTaggingHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) GetBucketObjectLockConfigHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) GetBucketNotificationHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) ListenBucketNotificationHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) ListObjectsV2MHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) PutBucketLifecycleHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) PutBucketEncryptionHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) PutBucketPolicyHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) PutBucketObjectLockConfigHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}
func (h *handler) PostPolicyBucketHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me " + mux.CurrentRoute(r).GetName(),
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
h.logAndSendError(w, "not implemented", api.GetReqInfo(r.Context()), api.GetAPIError(api.ErrNotImplemented))
}

20
api/handler/util.go Normal file
View file

@ -0,0 +1,20 @@
package handler
import (
"net/http"
"github.com/nspcc-dev/neofs-s3-gw/api"
"go.uber.org/zap"
)
func (h *handler) logAndSendError(w http.ResponseWriter, logText string, reqInfo *api.ReqInfo, err error, additional ...zap.Field) {
fields := []zap.Field{zap.String("request_id", reqInfo.RequestID),
zap.String("method", reqInfo.API),
zap.String("bucket_name", reqInfo.BucketName),
zap.String("object_name", reqInfo.ObjectName),
zap.Error(err)}
fields = append(fields, additional...)
h.log.Error(logText, fields...)
api.WriteErrorResponse(w, reqInfo, err)
}

View file

@ -49,9 +49,7 @@ func (m *maxClients) Handle(f http.HandlerFunc) http.HandlerFunc {
f.ServeHTTP(w, r)
case <-deadline.C:
// Send a http timeout message
WriteErrorResponse(r.Context(), w,
errorCodes.ToAPIErr(ErrOperationMaxedOut),
r.URL)
WriteErrorResponse(w, GetReqInfo(r.Context()), errorCodes.ToAPIErr(ErrOperationMaxedOut))
return
case <-r.Context().Done():
return

View file

@ -30,6 +30,7 @@ type (
API string // API name - GetObject PutObject NewMultipartUpload etc.
BucketName string // Bucket name
ObjectName string // Object name
URL *url.URL // Request url
tags []KeyVal // Any additional info not accommodated by above fields
}
@ -136,6 +137,7 @@ func NewReqInfo(w http.ResponseWriter, r *http.Request, req ObjectRequest) *ReqI
RemoteHost: GetSourceIP(r),
RequestID: GetRequestID(w),
DeploymentID: deploymentID.String(),
URL: r.URL,
}
}
@ -194,9 +196,9 @@ func SetReqInfo(ctx context.Context, req *ReqInfo) context.Context {
// GetReqInfo returns ReqInfo if set.
func GetReqInfo(ctx context.Context) *ReqInfo {
if ctx == nil {
return nil
return &ReqInfo{}
} else if r, ok := ctx.Value(ctxRequestInfo).(*ReqInfo); ok {
return r
}
return nil
return &ReqInfo{}
}

View file

@ -2,11 +2,9 @@ package api
import (
"bytes"
"context"
"encoding/xml"
"fmt"
"net/http"
"net/url"
"strconv"
"github.com/google/uuid"
@ -119,7 +117,7 @@ var s3ErrorResponseMap = map[string]string{
}
// WriteErrorResponse writes error headers.
func WriteErrorResponse(ctx context.Context, w http.ResponseWriter, err error, reqURL *url.URL) {
func WriteErrorResponse(w http.ResponseWriter, reqInfo *ReqInfo, err error) {
code := http.StatusInternalServerError
if e, ok := err.(Error); ok {
@ -136,8 +134,7 @@ func WriteErrorResponse(ctx context.Context, w http.ResponseWriter, err error, r
}
// Generate error response.
errorResponse := getAPIErrorResponse(ctx, err, reqURL.Path,
w.Header().Get(hdrAmzRequestID), deploymentID.String())
errorResponse := getAPIErrorResponse(reqInfo, err)
encodedErrorResponse := EncodeResponse(errorResponse)
WriteResponse(w, code, encodedErrorResponse, MimeXML)
}
@ -145,11 +142,11 @@ func WriteErrorResponse(ctx context.Context, w http.ResponseWriter, err error, r
// If none of the http routes match respond with appropriate errors.
func errorResponseHandler(w http.ResponseWriter, r *http.Request) {
desc := fmt.Sprintf("Unknown API request at %s", r.URL.Path)
WriteErrorResponse(r.Context(), w, Error{
WriteErrorResponse(w, GetReqInfo(r.Context()), Error{
Code: "XMinioUnknownAPIRequest",
Description: desc,
HTTPStatusCode: http.StatusBadRequest,
}, r.URL)
})
}
// Write http common headers.

View file

@ -27,7 +27,7 @@ func AttachUserAuth(router *mux.Router, center auth.Center, log *zap.Logger) {
ctx = r.Context()
} else {
log.Error("failed to pass authentication", zap.Error(err))
WriteErrorResponse(r.Context(), w, GetAPIError(ErrAccessDenied), r.URL)
WriteErrorResponse(w, GetReqInfo(r.Context()), GetAPIError(ErrAccessDenied))
return
}
} else {