From f4c29cd300e4e09468b0df027e2f31e05fc64538 Mon Sep 17 00:00:00 2001 From: Denis Kirillov Date: Thu, 5 Aug 2021 12:18:52 +0300 Subject: [PATCH] [#184] Unify error handling Signed-off-by: Denis Kirillov --- api/errors.go | 21 ++-- api/handler/api.go | 2 - api/handler/copy.go | 41 +++--- api/handler/delete.go | 74 +++-------- api/handler/get.go | 29 ++--- api/handler/head.go | 41 ++---- api/handler/info.go | 36 ++---- api/handler/list.go | 66 ++-------- api/handler/not-support.go | 37 +----- api/handler/object_list.go | 67 +++++----- api/handler/put.go | 45 +++---- api/handler/unimplemented.go | 235 ++++++----------------------------- api/handler/util.go | 20 +++ api/max-clients.go | 4 +- api/reqinfo.go | 6 +- api/response.go | 11 +- api/user-auth.go | 2 +- 17 files changed, 196 insertions(+), 541 deletions(-) create mode 100644 api/handler/util.go diff --git a/api/errors.go b/api/errors.go index 9d40d704..84aa740f 100644 --- a/api/errors.go +++ b/api/errors.go @@ -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, } } diff --git a/api/handler/api.go b/api/handler/api.go index f6eb02ed..3710aa4f 100644 --- a/api/handler/api.go +++ b/api/handler/api.go @@ -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. diff --git a/api/handler/copy.go b/api/handler/copy.go index c9fea7ea..af4dbd27 100644 --- a/api/handler/copy.go +++ b/api/handler/copy.go @@ -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) { diff --git a/api/handler/delete.go b/api/handler/delete.go index 1898949c..66cd8d0a 100644 --- a/api/handler/delete.go +++ b/api/handler/delete.go @@ -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) } } diff --git a/api/handler/get.go b/api/handler/get.go index 26ea3304..b7c3792a 100644 --- a/api/handler/get.go +++ b/api/handler/get.go @@ -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) -} diff --git a/api/handler/head.go b/api/handler/head.go index d64a21cf..410e0516 100644 --- a/api/handler/head.go +++ b/api/handler/head.go @@ -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 } diff --git a/api/handler/info.go b/api/handler/info.go index ee12a066..0becc387 100644 --- a/api/handler/info.go +++ b/api/handler/info.go @@ -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) + } } diff --git a/api/handler/list.go b/api/handler/list.go index 3711c4f2..f226d5dd 100644 --- a/api/handler/list.go +++ b/api/handler/list.go @@ -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) } } diff --git a/api/handler/not-support.go b/api/handler/not-support.go index 05ef70e5..532ac5db 100644 --- a/api/handler/not-support.go +++ b/api/handler/not-support.go @@ -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)) } diff --git a/api/handler/object_list.go b/api/handler/object_list.go index a4b58ce4..1a97c3dd 100644 --- a/api/handler/object_list.go +++ b/api/handler/object_list.go @@ -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 } diff --git a/api/handler/put.go b/api/handler/put.go index a0e7ff31..311a206c 100644 --- a/api/handler/put.go +++ b/api/handler/put.go @@ -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 } diff --git a/api/handler/unimplemented.go b/api/handler/unimplemented.go index 34bf13da..69c8e623 100644 --- a/api/handler/unimplemented.go +++ b/api/handler/unimplemented.go @@ -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)) } diff --git a/api/handler/util.go b/api/handler/util.go new file mode 100644 index 00000000..e87432b3 --- /dev/null +++ b/api/handler/util.go @@ -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) +} diff --git a/api/max-clients.go b/api/max-clients.go index f2eb2570..d578ef47 100644 --- a/api/max-clients.go +++ b/api/max-clients.go @@ -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 diff --git a/api/reqinfo.go b/api/reqinfo.go index 65d05cc3..100a12dd 100644 --- a/api/reqinfo.go +++ b/api/reqinfo.go @@ -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{} } diff --git a/api/response.go b/api/response.go index dbfd26b2..6e823468 100644 --- a/api/response.go +++ b/api/response.go @@ -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. diff --git a/api/user-auth.go b/api/user-auth.go index d41d272f..6762ea9b 100644 --- a/api/user-auth.go +++ b/api/user-auth.go @@ -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 {