Merge pull request #16 from nspcc-dev/api-refactoring-for-request-id

Refactoring API package
This commit is contained in:
Evgeniy Kulikov 2020-08-11 15:06:38 +03:00 committed by GitHub
commit 4d4e52fea7
5 changed files with 295 additions and 87 deletions

View file

@ -1623,12 +1623,15 @@ func GetAPIError(code ErrorCode) Error {
// getErrorResponse gets in standard error and resource value and // getErrorResponse gets in standard error and resource value and
// provides a encodable populated response values // provides a encodable populated response values
func getAPIErrorResponse(ctx context.Context, err Error, resource, requestID, hostID string) ErrorResponse { func getAPIErrorResponse(ctx context.Context, err Error, resource, requestID, hostID string) ErrorResponse {
reqInfo := GetReqInfo(ctx) info := GetReqInfo(ctx)
if info == nil {
info = &ReqInfo{}
}
return ErrorResponse{ return ErrorResponse{
Code: err.Code, Code: err.Code,
Message: err.Description, Message: err.Description,
BucketName: reqInfo.BucketName, BucketName: info.BucketName,
Key: reqInfo.ObjectName, Key: info.ObjectName,
Resource: resource, Resource: resource,
RequestID: requestID, RequestID: requestID,
HostID: hostID, HostID: hostID,

View file

@ -7,6 +7,7 @@ import (
"github.com/nspcc-dev/neofs-api-go/container" "github.com/nspcc-dev/neofs-api-go/container"
"github.com/nspcc-dev/neofs-api-go/refs" "github.com/nspcc-dev/neofs-api-go/refs"
"github.com/nspcc-dev/neofs-api-go/service" "github.com/nspcc-dev/neofs-api-go/service"
"github.com/nspcc-dev/neofs-s3-gate/api"
"github.com/nspcc-dev/neofs-s3-gate/auth" "github.com/nspcc-dev/neofs-s3-gate/auth"
"go.uber.org/zap" "go.uber.org/zap"
) )
@ -28,9 +29,11 @@ type (
) )
func (n *layer) containerInfo(ctx context.Context, cid refs.CID) (*BucketInfo, error) { func (n *layer) containerInfo(ctx context.Context, cid refs.CID) (*BucketInfo, error) {
rid := api.GetRequestID(ctx)
bearer, err := auth.GetBearerToken(ctx) bearer, err := auth.GetBearerToken(ctx)
if err != nil { if err != nil {
n.log.Error("could not receive bearer token", n.log.Error("could not receive bearer token",
zap.String("request_id", rid),
zap.Error(err)) zap.Error(err))
return nil, err return nil, err
} }
@ -44,6 +47,7 @@ func (n *layer) containerInfo(ctx context.Context, cid refs.CID) (*BucketInfo, e
if err = service.SignRequestData(n.key, req); err != nil { if err = service.SignRequestData(n.key, req); err != nil {
n.log.Error("could not prepare request", n.log.Error("could not prepare request",
zap.String("request_id", rid),
zap.Error(err)) zap.Error(err))
return nil, err return nil, err
} }
@ -51,6 +55,7 @@ func (n *layer) containerInfo(ctx context.Context, cid refs.CID) (*BucketInfo, e
conn, err := n.cli.GetConnection(ctx) conn, err := n.cli.GetConnection(ctx)
if err != nil { if err != nil {
n.log.Error("could not prepare client", n.log.Error("could not prepare client",
zap.String("request_id", rid),
zap.Error(err)) zap.Error(err))
return nil, err return nil, err
} }
@ -62,6 +67,7 @@ func (n *layer) containerInfo(ctx context.Context, cid refs.CID) (*BucketInfo, e
res, err := container.NewServiceClient(conn).Get(ctx, req) res, err := container.NewServiceClient(conn).Get(ctx, req)
if err != nil { if err != nil {
n.log.Error("could not list buckets", n.log.Error("could not list buckets",
zap.String("request_id", rid),
zap.Error(err)) zap.Error(err))
return nil, err return nil, err
} }
@ -76,9 +82,11 @@ func (n *layer) containerInfo(ctx context.Context, cid refs.CID) (*BucketInfo, e
} }
func (n *layer) containerList(ctx context.Context) ([]BucketInfo, error) { func (n *layer) containerList(ctx context.Context) ([]BucketInfo, error) {
rid := api.GetRequestID(ctx)
bearer, err := auth.GetBearerToken(ctx) bearer, err := auth.GetBearerToken(ctx)
if err != nil { if err != nil {
n.log.Error("could not receive bearer token", n.log.Error("could not receive bearer token",
zap.String("request_id", rid),
zap.Error(err)) zap.Error(err))
return nil, err return nil, err
} }
@ -92,6 +100,7 @@ func (n *layer) containerList(ctx context.Context) ([]BucketInfo, error) {
if err := service.SignRequestData(n.key, req); err != nil { if err := service.SignRequestData(n.key, req); err != nil {
n.log.Error("could not prepare request", n.log.Error("could not prepare request",
zap.String("request_id", rid),
zap.Error(err)) zap.Error(err))
return nil, err return nil, err
} }
@ -99,6 +108,7 @@ func (n *layer) containerList(ctx context.Context) ([]BucketInfo, error) {
conn, err := n.cli.GetConnection(ctx) conn, err := n.cli.GetConnection(ctx)
if err != nil { if err != nil {
n.log.Error("could not prepare client", n.log.Error("could not prepare client",
zap.String("request_id", rid),
zap.Error(err)) zap.Error(err))
return nil, err return nil, err
} }
@ -110,6 +120,7 @@ func (n *layer) containerList(ctx context.Context) ([]BucketInfo, error) {
res, err := container.NewServiceClient(conn).List(ctx, req) res, err := container.NewServiceClient(conn).List(ctx, req)
if err != nil { if err != nil {
n.log.Error("could not list buckets", n.log.Error("could not list buckets",
zap.String("request_id", rid),
zap.Error(err)) zap.Error(err))
return nil, err return nil, err
} }
@ -119,6 +130,7 @@ func (n *layer) containerList(ctx context.Context) ([]BucketInfo, error) {
info, err := n.containerInfo(ctx, cid) info, err := n.containerInfo(ctx, cid)
if err != nil { if err != nil {
n.log.Error("could not fetch container info", n.log.Error("could not fetch container info",
zap.String("request_id", rid),
zap.Error(err)) zap.Error(err))
continue continue
} }

View file

@ -278,8 +278,9 @@ func receiveObject(cli object.Service_GetClient) (*object.Object, error) {
switch o := resp.R.(type) { switch o := resp.R.(type) {
case *object.GetResponse_Object: case *object.GetResponse_Object:
if obj != nil {
if _, hdr := o.Object.LastHeader(object.HeaderType(object.TombstoneHdr)); hdr != nil { return nil, errors.New("object headers already received")
} else if _, hdr := o.Object.LastHeader(object.HeaderType(object.TombstoneHdr)); hdr != nil {
return nil, errors.New("object already removed") return nil, errors.New("object already removed")
} }
@ -480,9 +481,11 @@ func (n *layer) storageGroupPut(ctx context.Context, p sgParams) (*object.Object
return nil, err return nil, err
} }
client := object.NewServiceClient(conn)
// todo: think about timeout // todo: think about timeout
putClient, err := client.Put(ctx) ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
putClient, err := object.NewServiceClient(conn).Put(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -2,7 +2,14 @@ package api
import ( import (
"context" "context"
"net"
"net/http"
"net/url"
"regexp"
"strings"
"sync" "sync"
"github.com/gorilla/mux"
) )
type ( type (
@ -25,6 +32,12 @@ type (
ObjectName string // Object name ObjectName string // Object name
tags []KeyVal // Any additional info not accommodated by above fields tags []KeyVal // Any additional info not accommodated by above fields
} }
ObjectRequest struct {
Bucket string
Object string
Method string
}
) )
// Key used for Get/SetReqInfo // Key used for Get/SetReqInfo
@ -32,17 +45,97 @@ type contextKeyType string
const ctxRequestInfo = contextKeyType("NeoFS-S3-Gate") const ctxRequestInfo = contextKeyType("NeoFS-S3-Gate")
var (
// De-facto standard header keys.
xForwardedFor = http.CanonicalHeaderKey("X-Forwarded-For")
xRealIP = http.CanonicalHeaderKey("X-Real-IP")
)
var (
// RFC7239 defines a new "Forwarded: " header designed to replace the
// existing use of X-Forwarded-* headers.
// e.g. Forwarded: for=192.0.2.60;proto=https;by=203.0.113.43
forwarded = http.CanonicalHeaderKey("Forwarded")
// Allows for a sub-match of the first value after 'for=' to the next
// comma, semi-colon or space. The match is case-insensitive.
forRegex = regexp.MustCompile(`(?i)(?:for=)([^(;|, )]+)(.*)`)
)
// GetSourceIP retrieves the IP from the X-Forwarded-For, X-Real-IP and RFC7239
// Forwarded headers (in that order), falls back to r.RemoteAddr when all
// else fails.
func GetSourceIP(r *http.Request) string {
var addr string
if fwd := r.Header.Get(xForwardedFor); fwd != "" {
// Only grab the first (client) address. Note that '192.168.0.1,
// 10.1.1.1' is a valid key for X-Forwarded-For where addresses after
// the first may represent forwarding proxies earlier in the chain.
s := strings.Index(fwd, ", ")
if s == -1 {
s = len(fwd)
}
addr = fwd[:s]
} else if fwd := r.Header.Get(xRealIP); fwd != "" {
// X-Real-IP should only contain one IP address (the client making the
// request).
addr = fwd
} else if fwd := r.Header.Get(forwarded); fwd != "" {
// match should contain at least two elements if the protocol was
// specified in the Forwarded header. The first element will always be
// the 'for=' capture, which we ignore. In the case of multiple IP
// addresses (for=8.8.8.8, 8.8.4.4, 172.16.1.20 is valid) we only
// extract the first, which should be the client IP.
if match := forRegex.FindStringSubmatch(fwd); len(match) > 1 {
// IPv6 addresses in Forwarded headers are quoted-strings. We strip
// these quotes.
addr = strings.Trim(match[1], `"`)
}
}
if addr != "" {
return addr
}
// Default to remote address if headers not set.
addr, _, _ = net.SplitHostPort(r.RemoteAddr)
return addr
}
func prepareContext(w http.ResponseWriter, r *http.Request) context.Context {
vars := mux.Vars(r)
bucket := vars["bucket"]
object, err := url.PathUnescape(vars["object"])
if err != nil {
object = vars["object"]
}
prefix, err := url.QueryUnescape(vars["prefix"])
if err != nil {
prefix = vars["prefix"]
}
if prefix != "" {
object = prefix
}
return SetReqInfo(r.Context(),
// prepare request info
NewReqInfo(w, r, ObjectRequest{
Bucket: bucket,
Object: object,
Method: mux.CurrentRoute(r).GetName(),
}))
}
// NewReqInfo : // NewReqInfo :
func NewReqInfo(remoteHost, userAgent, deploymentID, requestID, api, bucket, object string) *ReqInfo { func NewReqInfo(w http.ResponseWriter, r *http.Request, req ObjectRequest) *ReqInfo {
req := ReqInfo{} return &ReqInfo{
req.RemoteHost = remoteHost API: req.Method,
req.UserAgent = userAgent BucketName: req.Bucket,
req.API = api ObjectName: req.Object,
req.DeploymentID = deploymentID UserAgent: r.UserAgent(),
req.RequestID = requestID RemoteHost: GetSourceIP(r),
req.BucketName = bucket RequestID: GetRequestID(w),
req.ObjectName = object DeploymentID: deploymentID.String(),
return &req }
} }
// AppendTags - appends key/val to ReqInfo.tags // AppendTags - appends key/val to ReqInfo.tags
@ -99,13 +192,9 @@ func SetReqInfo(ctx context.Context, req *ReqInfo) context.Context {
// GetReqInfo returns ReqInfo if set. // GetReqInfo returns ReqInfo if set.
func GetReqInfo(ctx context.Context) *ReqInfo { func GetReqInfo(ctx context.Context) *ReqInfo {
if ctx != nil { if ctx == nil {
r, ok := ctx.Value(ctxRequestInfo).(*ReqInfo) return nil
if ok { } else if r, ok := ctx.Value(ctxRequestInfo).(*ReqInfo); ok {
return r
}
r = &ReqInfo{}
SetReqInfo(ctx, r)
return r return r
} }
return nil return nil

View file

@ -1,12 +1,15 @@
package api package api
import ( import (
"context"
"net/http" "net/http"
"github.com/google/uuid"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/nspcc-dev/neofs-s3-gate/api/metrics" "github.com/nspcc-dev/neofs-s3-gate/api/metrics"
"github.com/nspcc-dev/neofs-s3-gate/auth" "github.com/nspcc-dev/neofs-s3-gate/auth"
"go.uber.org/zap" "go.uber.org/zap"
"google.golang.org/grpc/metadata"
) )
type ( type (
@ -90,8 +93,44 @@ const (
mimeXML mimeType = "application/xml" mimeXML mimeType = "application/xml"
) )
func setRequestID(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// generate random UUIDv4
id, _ := uuid.NewRandom()
// set request id into response header
w.Header().Set(hdrAmzRequestID, id.String())
// set request id into gRPC meta header
r = r.WithContext(metadata.AppendToOutgoingContext(
r.Context(), hdrAmzRequestID, id.String(),
))
// set request info into context
r = r.WithContext(prepareContext(w, r))
// continue execution
h.ServeHTTP(w, r)
})
}
func GetRequestID(v interface{}) string {
switch t := v.(type) {
case context.Context:
return GetReqInfo(t).RequestID
case http.ResponseWriter:
return t.Header().Get(hdrAmzRequestID)
default:
panic("unknown type")
}
}
func Attach(r *mux.Router, m MaxClients, h Handler, center *auth.Center, log *zap.Logger) { func Attach(r *mux.Router, m MaxClients, h Handler, center *auth.Center, log *zap.Logger) {
api := r.PathPrefix(SlashSeparator).Subrouter() api := r.PathPrefix(SlashSeparator).Subrouter()
// Attach behaviors: RequestID, ...
api.Use(setRequestID)
// Attach user authentication for all S3 routes. // Attach user authentication for all S3 routes.
AttachUserAuth(api, center, log) AttachUserAuth(api, center, log)
@ -100,203 +139,265 @@ func Attach(r *mux.Router, m MaxClients, h Handler, center *auth.Center, log *za
// Object operations // Object operations
// HeadObject // HeadObject
bucket.Methods(http.MethodHead).Path("/{object:.+}").HandlerFunc( bucket.Methods(http.MethodHead).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("headobject", h.HeadObjectHandler))) m.Handle(metrics.APIStats("headobject", h.HeadObjectHandler))).Name("HeadObject")
// CopyObjectPart // CopyObjectPart
bucket.Methods(http.MethodPut).Path("/{object:.+}").HeadersRegexp(hdrAmzCopySource, ".*?(\\/|%2F).*?").HandlerFunc(m.Handle(metrics.APIStats("copyobjectpart", h.CopyObjectPartHandler))).Queries("partNumber", "{partNumber:[0-9]+}", "uploadId", "{uploadId:.*}") bucket.Methods(http.MethodPut).Path("/{object:.+}").HeadersRegexp(hdrAmzCopySource, ".*?(\\/|%2F).*?").HandlerFunc(m.Handle(metrics.APIStats("copyobjectpart", h.CopyObjectPartHandler))).Queries("partNumber", "{partNumber:[0-9]+}", "uploadId", "{uploadId:.*}").
Name("CopyObjectPart")
// PutObjectPart // PutObjectPart
bucket.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc( bucket.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("putobjectpart", h.PutObjectPartHandler))).Queries("partNumber", "{partNumber:[0-9]+}", "uploadId", "{uploadId:.*}") m.Handle(metrics.APIStats("putobjectpart", h.PutObjectPartHandler))).Queries("partNumber", "{partNumber:[0-9]+}", "uploadId", "{uploadId:.*}").
Name("PutObjectObject")
// ListObjectParts // ListObjectParts
bucket.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc( bucket.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("listobjectparts", h.ListObjectPartsHandler))).Queries("uploadId", "{uploadId:.*}") m.Handle(metrics.APIStats("listobjectparts", h.ListObjectPartsHandler))).Queries("uploadId", "{uploadId:.*}").
Name("ListObjectParts")
// CompleteMultipartUpload // CompleteMultipartUpload
bucket.Methods(http.MethodPost).Path("/{object:.+}").HandlerFunc( bucket.Methods(http.MethodPost).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("completemutipartupload", h.CompleteMultipartUploadHandler))).Queries("uploadId", "{uploadId:.*}") m.Handle(metrics.APIStats("completemutipartupload", h.CompleteMultipartUploadHandler))).Queries("uploadId", "{uploadId:.*}").
Name("CompleteMultipartUpload")
// NewMultipartUpload // NewMultipartUpload
bucket.Methods(http.MethodPost).Path("/{object:.+}").HandlerFunc( bucket.Methods(http.MethodPost).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("newmultipartupload", h.NewMultipartUploadHandler))).Queries("uploads", "") m.Handle(metrics.APIStats("newmultipartupload", h.NewMultipartUploadHandler))).Queries("uploads", "").
Name("NewMultipartUpload")
// AbortMultipartUpload // AbortMultipartUpload
bucket.Methods(http.MethodDelete).Path("/{object:.+}").HandlerFunc( bucket.Methods(http.MethodDelete).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("abortmultipartupload", h.AbortMultipartUploadHandler))).Queries("uploadId", "{uploadId:.*}") m.Handle(metrics.APIStats("abortmultipartupload", h.AbortMultipartUploadHandler))).Queries("uploadId", "{uploadId:.*}").
Name("AbortMultipartUpload")
// GetObjectACL - this is a dummy call. // GetObjectACL - this is a dummy call.
bucket.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc( bucket.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("getobjectacl", h.GetObjectACLHandler))).Queries("acl", "") m.Handle(metrics.APIStats("getobjectacl", h.GetObjectACLHandler))).Queries("acl", "").
Name("GetObjectACL")
// PutObjectACL - this is a dummy call. // PutObjectACL - this is a dummy call.
bucket.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc( bucket.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("putobjectacl", h.PutObjectACLHandler))).Queries("acl", "") m.Handle(metrics.APIStats("putobjectacl", h.PutObjectACLHandler))).Queries("acl", "").
Name("PutObjectACL")
// GetObjectTagging // GetObjectTagging
bucket.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc( bucket.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("getobjecttagging", h.GetObjectTaggingHandler))).Queries("tagging", "") m.Handle(metrics.APIStats("getobjecttagging", h.GetObjectTaggingHandler))).Queries("tagging", "").
Name("GetObjectTagging")
// PutObjectTagging // PutObjectTagging
bucket.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc( bucket.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("putobjecttagging", h.PutObjectTaggingHandler))).Queries("tagging", "") m.Handle(metrics.APIStats("putobjecttagging", h.PutObjectTaggingHandler))).Queries("tagging", "").
Name("PutObjectTagging")
// DeleteObjectTagging // DeleteObjectTagging
bucket.Methods(http.MethodDelete).Path("/{object:.+}").HandlerFunc( bucket.Methods(http.MethodDelete).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("deleteobjecttagging", h.DeleteObjectTaggingHandler))).Queries("tagging", "") m.Handle(metrics.APIStats("deleteobjecttagging", h.DeleteObjectTaggingHandler))).Queries("tagging", "").
Name("DeleteObjectTagging")
// SelectObjectContent // SelectObjectContent
bucket.Methods(http.MethodPost).Path("/{object:.+}").HandlerFunc( bucket.Methods(http.MethodPost).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("selectobjectcontent", h.SelectObjectContentHandler))).Queries("select", "").Queries("select-type", "2") m.Handle(metrics.APIStats("selectobjectcontent", h.SelectObjectContentHandler))).Queries("select", "").Queries("select-type", "2").
Name("SelectObjectContent")
// GetObjectRetention // GetObjectRetention
bucket.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc( bucket.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("getobjectretention", h.GetObjectRetentionHandler))).Queries("retention", "") m.Handle(metrics.APIStats("getobjectretention", h.GetObjectRetentionHandler))).Queries("retention", "").
Name("GetObjectRetention")
// GetObjectLegalHold // GetObjectLegalHold
bucket.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc( bucket.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("getobjectlegalhold", h.GetObjectLegalHoldHandler))).Queries("legal-hold", "") m.Handle(metrics.APIStats("getobjectlegalhold", h.GetObjectLegalHoldHandler))).Queries("legal-hold", "").
Name("GetObjectLegalHold")
// GetObject // GetObject
bucket.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc( bucket.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("getobject", h.GetObjectHandler))) m.Handle(metrics.APIStats("getobject", h.GetObjectHandler))).
Name("GetObject")
// CopyObject // CopyObject
bucket.Methods(http.MethodPut).Path("/{object:.+}").HeadersRegexp(hdrAmzCopySource, ".*?(\\/|%2F).*?").HandlerFunc(m.Handle(metrics.APIStats("copyobject", h.CopyObjectHandler))) bucket.Methods(http.MethodPut).Path("/{object:.+}").HeadersRegexp(hdrAmzCopySource, ".*?(\\/|%2F).*?").HandlerFunc(m.Handle(metrics.APIStats("copyobject", h.CopyObjectHandler))).
Name("CopyObject")
// PutObjectRetention // PutObjectRetention
bucket.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc( bucket.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("putobjectretention", h.PutObjectRetentionHandler))).Queries("retention", "") m.Handle(metrics.APIStats("putobjectretention", h.PutObjectRetentionHandler))).Queries("retention", "").
Name("PutObjectRetention")
// PutObjectLegalHold // PutObjectLegalHold
bucket.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc( bucket.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("putobjectlegalhold", h.PutObjectLegalHoldHandler))).Queries("legal-hold", "") m.Handle(metrics.APIStats("putobjectlegalhold", h.PutObjectLegalHoldHandler))).Queries("legal-hold", "").
Name("PutObjectLegalHold")
// PutObject // PutObject
bucket.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc( bucket.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("putobject", h.PutObjectHandler))) m.Handle(metrics.APIStats("putobject", h.PutObjectHandler))).
Name("PutObject")
// DeleteObject // DeleteObject
bucket.Methods(http.MethodDelete).Path("/{object:.+}").HandlerFunc( bucket.Methods(http.MethodDelete).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("deleteobject", h.DeleteObjectHandler))) m.Handle(metrics.APIStats("deleteobject", h.DeleteObjectHandler))).
Name("DeleteObject")
// Bucket operations // Bucket operations
// GetBucketLocation // GetBucketLocation
bucket.Methods(http.MethodGet).HandlerFunc( bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketlocation", h.GetBucketLocationHandler))).Queries("location", "") m.Handle(metrics.APIStats("getbucketlocation", h.GetBucketLocationHandler))).Queries("location", "").
Name("GetBucketLocation")
// GetBucketPolicy // GetBucketPolicy
bucket.Methods(http.MethodGet).HandlerFunc( bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketpolicy", h.GetBucketPolicyHandler))).Queries("policy", "") m.Handle(metrics.APIStats("getbucketpolicy", h.GetBucketPolicyHandler))).Queries("policy", "").
Name("GetBucketPolicy")
// GetBucketLifecycle // GetBucketLifecycle
bucket.Methods(http.MethodGet).HandlerFunc( bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketlifecycle", h.GetBucketLifecycleHandler))).Queries("lifecycle", "") m.Handle(metrics.APIStats("getbucketlifecycle", h.GetBucketLifecycleHandler))).Queries("lifecycle", "").
Name("GetBucketLifecycle")
// GetBucketEncryption // GetBucketEncryption
bucket.Methods(http.MethodGet).HandlerFunc( bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketencryption", h.GetBucketEncryptionHandler))).Queries("encryption", "") m.Handle(metrics.APIStats("getbucketencryption", h.GetBucketEncryptionHandler))).Queries("encryption", "").
Name("GetBucketEncryption")
// Dummy Bucket Calls // Dummy Bucket Calls
// GetBucketACL -- this is a dummy call. // GetBucketACL -- this is a dummy call.
bucket.Methods(http.MethodGet).HandlerFunc( bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketacl", h.GetBucketACLHandler))).Queries("acl", "") m.Handle(metrics.APIStats("getbucketacl", h.GetBucketACLHandler))).Queries("acl", "").
Name("GetBucketACL")
// PutBucketACL -- this is a dummy call. // PutBucketACL -- this is a dummy call.
bucket.Methods(http.MethodPut).HandlerFunc( bucket.Methods(http.MethodPut).HandlerFunc(
m.Handle(metrics.APIStats("putbucketacl", h.PutBucketACLHandler))).Queries("acl", "") m.Handle(metrics.APIStats("putbucketacl", h.PutBucketACLHandler))).Queries("acl", "").
Name("PutBucketACL")
// GetBucketCors - this is a dummy call. // GetBucketCors - this is a dummy call.
bucket.Methods(http.MethodGet).HandlerFunc( bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketcors", h.GetBucketCorsHandler))).Queries("cors", "") m.Handle(metrics.APIStats("getbucketcors", h.GetBucketCorsHandler))).Queries("cors", "").
Name("GetBucketCors")
// GetBucketWebsiteHandler - this is a dummy call. // GetBucketWebsiteHandler - this is a dummy call.
bucket.Methods(http.MethodGet).HandlerFunc( bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketwebsite", h.GetBucketWebsiteHandler))).Queries("website", "") m.Handle(metrics.APIStats("getbucketwebsite", h.GetBucketWebsiteHandler))).Queries("website", "").
Name("GetBucketWebsite")
// GetBucketAccelerateHandler - this is a dummy call. // GetBucketAccelerateHandler - this is a dummy call.
bucket.Methods(http.MethodGet).HandlerFunc( bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketaccelerate", h.GetBucketAccelerateHandler))).Queries("accelerate", "") m.Handle(metrics.APIStats("getbucketaccelerate", h.GetBucketAccelerateHandler))).Queries("accelerate", "").
Name("GetBucketAccelerate")
// GetBucketRequestPaymentHandler - this is a dummy call. // GetBucketRequestPaymentHandler - this is a dummy call.
bucket.Methods(http.MethodGet).HandlerFunc( bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketrequestpayment", h.GetBucketRequestPaymentHandler))).Queries("requestPayment", "") m.Handle(metrics.APIStats("getbucketrequestpayment", h.GetBucketRequestPaymentHandler))).Queries("requestPayment", "").
Name("GetBucketRequestPayment")
// GetBucketLoggingHandler - this is a dummy call. // GetBucketLoggingHandler - this is a dummy call.
bucket.Methods(http.MethodGet).HandlerFunc( bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketlogging", h.GetBucketLoggingHandler))).Queries("logging", "") m.Handle(metrics.APIStats("getbucketlogging", h.GetBucketLoggingHandler))).Queries("logging", "").
Name("GetBucketLogging")
// GetBucketLifecycleHandler - this is a dummy call. // GetBucketLifecycleHandler - this is a dummy call.
bucket.Methods(http.MethodGet).HandlerFunc( bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketlifecycle", h.GetBucketLifecycleHandler))).Queries("lifecycle", "") m.Handle(metrics.APIStats("getbucketlifecycle", h.GetBucketLifecycleHandler))).Queries("lifecycle", "").
Name("GetBucketLifecycle")
// GetBucketReplicationHandler - this is a dummy call. // GetBucketReplicationHandler - this is a dummy call.
bucket.Methods(http.MethodGet).HandlerFunc( bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketreplication", h.GetBucketReplicationHandler))).Queries("replication", "") m.Handle(metrics.APIStats("getbucketreplication", h.GetBucketReplicationHandler))).Queries("replication", "").
Name("GetBucketReplication")
// GetBucketTaggingHandler // GetBucketTaggingHandler
bucket.Methods(http.MethodGet).HandlerFunc( bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbuckettagging", h.GetBucketTaggingHandler))).Queries("tagging", "") m.Handle(metrics.APIStats("getbuckettagging", h.GetBucketTaggingHandler))).Queries("tagging", "").
Name("GetBucketTagging")
// DeleteBucketWebsiteHandler // DeleteBucketWebsiteHandler
bucket.Methods(http.MethodDelete).HandlerFunc( bucket.Methods(http.MethodDelete).HandlerFunc(
m.Handle(metrics.APIStats("deletebucketwebsite", h.DeleteBucketWebsiteHandler))).Queries("website", "") m.Handle(metrics.APIStats("deletebucketwebsite", h.DeleteBucketWebsiteHandler))).Queries("website", "").
Name("DeleteBucketWebsite")
// DeleteBucketTaggingHandler // DeleteBucketTaggingHandler
bucket.Methods(http.MethodDelete).HandlerFunc( bucket.Methods(http.MethodDelete).HandlerFunc(
m.Handle(metrics.APIStats("deletebuckettagging", h.DeleteBucketTaggingHandler))).Queries("tagging", "") m.Handle(metrics.APIStats("deletebuckettagging", h.DeleteBucketTaggingHandler))).Queries("tagging", "").
Name("DeleteBucketTagging")
// GetBucketObjectLockConfig // GetBucketObjectLockConfig
bucket.Methods(http.MethodGet).HandlerFunc( bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketobjectlockconfiguration", h.GetBucketObjectLockConfigHandler))).Queries("object-lock", "") m.Handle(metrics.APIStats("getbucketobjectlockconfiguration", h.GetBucketObjectLockConfigHandler))).Queries("object-lock", "").
Name("GetBucketObjectLockConfig")
// GetBucketVersioning // GetBucketVersioning
bucket.Methods(http.MethodGet).HandlerFunc( bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketversioning", h.GetBucketVersioningHandler))).Queries("versioning", "") m.Handle(metrics.APIStats("getbucketversioning", h.GetBucketVersioningHandler))).Queries("versioning", "").
Name("GetBucketVersioning")
// GetBucketNotification // GetBucketNotification
bucket.Methods(http.MethodGet).HandlerFunc( bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketnotification", h.GetBucketNotificationHandler))).Queries("notification", "") m.Handle(metrics.APIStats("getbucketnotification", h.GetBucketNotificationHandler))).Queries("notification", "").
Name("GetBucketNotification")
// ListenBucketNotification // ListenBucketNotification
bucket.Methods(http.MethodGet).HandlerFunc(metrics.APIStats("listenbucketnotification", h.ListenBucketNotificationHandler)).Queries("events", "{events:.*}") bucket.Methods(http.MethodGet).HandlerFunc(metrics.APIStats("listenbucketnotification", h.ListenBucketNotificationHandler)).Queries("events", "{events:.*}").
Name("ListenBucketNotification")
// ListMultipartUploads // ListMultipartUploads
bucket.Methods(http.MethodGet).HandlerFunc( bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("listmultipartuploads", h.ListMultipartUploadsHandler))).Queries("uploads", "") m.Handle(metrics.APIStats("listmultipartuploads", h.ListMultipartUploadsHandler))).Queries("uploads", "").
Name("ListMultipartUploads")
// ListObjectsV2M // ListObjectsV2M
bucket.Methods(http.MethodGet).HandlerFunc( bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("listobjectsv2M", h.ListObjectsV2MHandler))).Queries("list-type", "2", "metadata", "true") m.Handle(metrics.APIStats("listobjectsv2M", h.ListObjectsV2MHandler))).Queries("list-type", "2", "metadata", "true").
Name("ListObjectsV2M")
// ListObjectsV2 // ListObjectsV2
bucket.Methods(http.MethodGet).HandlerFunc( bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("listobjectsv2", h.ListObjectsV2Handler))).Queries("list-type", "2") m.Handle(metrics.APIStats("listobjectsv2", h.ListObjectsV2Handler))).Queries("list-type", "2").
Name("ListObjectsV2")
// ListBucketVersions // ListBucketVersions
bucket.Methods(http.MethodGet).HandlerFunc( bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("listbucketversions", h.ListBucketObjectVersionsHandler))).Queries("versions", "") m.Handle(metrics.APIStats("listbucketversions", h.ListBucketObjectVersionsHandler))).Queries("versions", "").
Name("ListBucketVersions")
// ListObjectsV1 (Legacy) // ListObjectsV1 (Legacy)
bucket.Methods(http.MethodGet).HandlerFunc( bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("listobjectsv1", h.ListObjectsV1Handler))) m.Handle(metrics.APIStats("listobjectsv1", h.ListObjectsV1Handler))).
Name("ListObjectsV1")
// PutBucketLifecycle // PutBucketLifecycle
bucket.Methods(http.MethodPut).HandlerFunc( bucket.Methods(http.MethodPut).HandlerFunc(
m.Handle(metrics.APIStats("putbucketlifecycle", h.PutBucketLifecycleHandler))).Queries("lifecycle", "") m.Handle(metrics.APIStats("putbucketlifecycle", h.PutBucketLifecycleHandler))).Queries("lifecycle", "").
Name("PutBucketLifecycle")
// PutBucketEncryption // PutBucketEncryption
bucket.Methods(http.MethodPut).HandlerFunc( bucket.Methods(http.MethodPut).HandlerFunc(
m.Handle(metrics.APIStats("putbucketencryption", h.PutBucketEncryptionHandler))).Queries("encryption", "") m.Handle(metrics.APIStats("putbucketencryption", h.PutBucketEncryptionHandler))).Queries("encryption", "").
Name("PutBucketEncryption")
// PutBucketPolicy // PutBucketPolicy
bucket.Methods(http.MethodPut).HandlerFunc( bucket.Methods(http.MethodPut).HandlerFunc(
m.Handle(metrics.APIStats("putbucketpolicy", h.PutBucketPolicyHandler))).Queries("policy", "") m.Handle(metrics.APIStats("putbucketpolicy", h.PutBucketPolicyHandler))).Queries("policy", "").
Name("PutBucketPolicy")
// PutBucketObjectLockConfig // PutBucketObjectLockConfig
bucket.Methods(http.MethodPut).HandlerFunc( bucket.Methods(http.MethodPut).HandlerFunc(
m.Handle(metrics.APIStats("putbucketobjectlockconfig", h.PutBucketObjectLockConfigHandler))).Queries("object-lock", "") m.Handle(metrics.APIStats("putbucketobjectlockconfig", h.PutBucketObjectLockConfigHandler))).Queries("object-lock", "").
Name("PutBucketObjectLockConfig")
// PutBucketTaggingHandler // PutBucketTaggingHandler
bucket.Methods(http.MethodPut).HandlerFunc( bucket.Methods(http.MethodPut).HandlerFunc(
m.Handle(metrics.APIStats("putbuckettagging", h.PutBucketTaggingHandler))).Queries("tagging", "") m.Handle(metrics.APIStats("putbuckettagging", h.PutBucketTaggingHandler))).Queries("tagging", "").
Name("PutBucketTagging")
// PutBucketVersioning // PutBucketVersioning
bucket.Methods(http.MethodPut).HandlerFunc( bucket.Methods(http.MethodPut).HandlerFunc(
m.Handle(metrics.APIStats("putbucketversioning", h.PutBucketVersioningHandler))).Queries("versioning", "") m.Handle(metrics.APIStats("putbucketversioning", h.PutBucketVersioningHandler))).Queries("versioning", "").
Name("PutBucketVersioning")
// PutBucketNotification // PutBucketNotification
bucket.Methods(http.MethodPut).HandlerFunc( bucket.Methods(http.MethodPut).HandlerFunc(
m.Handle(metrics.APIStats("putbucketnotification", h.PutBucketNotificationHandler))).Queries("notification", "") m.Handle(metrics.APIStats("putbucketnotification", h.PutBucketNotificationHandler))).Queries("notification", "").
Name("PutBucketNotification")
// PutBucket // PutBucket
bucket.Methods(http.MethodPut).HandlerFunc( bucket.Methods(http.MethodPut).HandlerFunc(
m.Handle(metrics.APIStats("putbucket", h.PutBucketHandler))) m.Handle(metrics.APIStats("putbucket", h.PutBucketHandler))).
Name("PutBucket")
// HeadBucket // HeadBucket
bucket.Methods(http.MethodHead).HandlerFunc( bucket.Methods(http.MethodHead).HandlerFunc(
m.Handle(metrics.APIStats("headbucket", h.HeadBucketHandler))) m.Handle(metrics.APIStats("headbucket", h.HeadBucketHandler))).
Name("HeadBucket")
// PostPolicy // PostPolicy
bucket.Methods(http.MethodPost).HeadersRegexp(hdrContentType, "multipart/form-data*").HandlerFunc( bucket.Methods(http.MethodPost).HeadersRegexp(hdrContentType, "multipart/form-data*").HandlerFunc(
m.Handle(metrics.APIStats("postpolicybucket", h.PostPolicyBucketHandler))) m.Handle(metrics.APIStats("postpolicybucket", h.PostPolicyBucketHandler))).
Name("PostPolicyBucket")
// DeleteMultipleObjects // DeleteMultipleObjects
bucket.Methods(http.MethodPost).HandlerFunc( bucket.Methods(http.MethodPost).HandlerFunc(
m.Handle(metrics.APIStats("deletemultipleobjects", h.DeleteMultipleObjectsHandler))).Queries("delete", "") m.Handle(metrics.APIStats("deletemultipleobjects", h.DeleteMultipleObjectsHandler))).Queries("delete", "").
Name("DeleteMultipleObjects")
// DeleteBucketPolicy // DeleteBucketPolicy
bucket.Methods(http.MethodDelete).HandlerFunc( bucket.Methods(http.MethodDelete).HandlerFunc(
m.Handle(metrics.APIStats("deletebucketpolicy", h.DeleteBucketPolicyHandler))).Queries("policy", "") m.Handle(metrics.APIStats("deletebucketpolicy", h.DeleteBucketPolicyHandler))).Queries("policy", "").
Name("DeleteBucketPolicy")
// DeleteBucketLifecycle // DeleteBucketLifecycle
bucket.Methods(http.MethodDelete).HandlerFunc( bucket.Methods(http.MethodDelete).HandlerFunc(
m.Handle(metrics.APIStats("deletebucketlifecycle", h.DeleteBucketLifecycleHandler))).Queries("lifecycle", "") m.Handle(metrics.APIStats("deletebucketlifecycle", h.DeleteBucketLifecycleHandler))).Queries("lifecycle", "").
Name("DeleteBucketLifecycle")
// DeleteBucketEncryption // DeleteBucketEncryption
bucket.Methods(http.MethodDelete).HandlerFunc( bucket.Methods(http.MethodDelete).HandlerFunc(
m.Handle(metrics.APIStats("deletebucketencryption", h.DeleteBucketEncryptionHandler))).Queries("encryption", "") m.Handle(metrics.APIStats("deletebucketencryption", h.DeleteBucketEncryptionHandler))).Queries("encryption", "").
Name("DeleteBucketEncryption")
// DeleteBucket // DeleteBucket
bucket.Methods(http.MethodDelete).HandlerFunc( bucket.Methods(http.MethodDelete).HandlerFunc(
m.Handle(metrics.APIStats("deletebucket", h.DeleteBucketHandler))) m.Handle(metrics.APIStats("deletebucket", h.DeleteBucketHandler))).
Name("DeleteBucket")
// Root operation // Root operation
// ListBuckets // ListBuckets
api.Methods(http.MethodGet).Path(SlashSeparator).HandlerFunc( api.Methods(http.MethodGet).Path(SlashSeparator).HandlerFunc(
m.Handle(metrics.APIStats("listbuckets", h.ListBucketsHandler))) m.Handle(metrics.APIStats("listbuckets", h.ListBucketsHandler))).
Name("ListBuckets")
// S3 browser with signature v4 adds '//' for ListBuckets request, so rather // S3 browser with signature v4 adds '//' for ListBuckets request, so rather
// than failing with UnknownAPIRequest we simply handle it for now. // than failing with UnknownAPIRequest we simply handle it for now.
api.Methods(http.MethodGet).Path(SlashSeparator + SlashSeparator).HandlerFunc( api.Methods(http.MethodGet).Path(SlashSeparator + SlashSeparator).HandlerFunc(
m.Handle(metrics.APIStats("listbuckets", h.ListBucketsHandler))) m.Handle(metrics.APIStats("listbuckets", h.ListBucketsHandler))).
Name("ListBuckets")
// If none of the routes match add default error handler routes // If none of the routes match add default error handler routes
api.NotFoundHandler = metrics.APIStats("notfound", errorResponseHandler) api.NotFoundHandler = metrics.APIStats("notfound", errorResponseHandler)