github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/cmd/api-router.go (about)

     1  // Copyright (c) 2015-2021 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package cmd
    19  
    20  import (
    21  	"net"
    22  	"net/http"
    23  
    24  	consoleapi "github.com/minio/console/api"
    25  	xhttp "github.com/minio/minio/internal/http"
    26  	"github.com/minio/mux"
    27  	"github.com/minio/pkg/v2/wildcard"
    28  	"github.com/rs/cors"
    29  )
    30  
    31  func newHTTPServerFn() *xhttp.Server {
    32  	globalObjLayerMutex.RLock()
    33  	defer globalObjLayerMutex.RUnlock()
    34  	return globalHTTPServer
    35  }
    36  
    37  func setHTTPServer(h *xhttp.Server) {
    38  	globalObjLayerMutex.Lock()
    39  	globalHTTPServer = h
    40  	globalObjLayerMutex.Unlock()
    41  }
    42  
    43  func newConsoleServerFn() *consoleapi.Server {
    44  	globalObjLayerMutex.RLock()
    45  	defer globalObjLayerMutex.RUnlock()
    46  	return globalConsoleSrv
    47  }
    48  
    49  func setConsoleSrv(srv *consoleapi.Server) {
    50  	globalObjLayerMutex.Lock()
    51  	globalConsoleSrv = srv
    52  	globalObjLayerMutex.Unlock()
    53  }
    54  
    55  func newObjectLayerFn() ObjectLayer {
    56  	globalObjLayerMutex.RLock()
    57  	defer globalObjLayerMutex.RUnlock()
    58  	return globalObjectAPI
    59  }
    60  
    61  func setObjectLayer(o ObjectLayer) {
    62  	globalObjLayerMutex.Lock()
    63  	globalObjectAPI = o
    64  	globalObjLayerMutex.Unlock()
    65  }
    66  
    67  // objectAPIHandler implements and provides http handlers for S3 API.
    68  type objectAPIHandlers struct {
    69  	ObjectAPI func() ObjectLayer
    70  }
    71  
    72  // getHost tries its best to return the request host.
    73  // According to section 14.23 of RFC 2616 the Host header
    74  // can include the port number if the default value of 80 is not used.
    75  func getHost(r *http.Request) string {
    76  	if r.URL.IsAbs() {
    77  		return r.URL.Host
    78  	}
    79  	return r.Host
    80  }
    81  
    82  func notImplementedHandler(w http.ResponseWriter, r *http.Request) {
    83  	writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
    84  }
    85  
    86  type rejectedAPI struct {
    87  	api     string
    88  	methods []string
    89  	queries []string
    90  	path    string
    91  }
    92  
    93  var rejectedObjAPIs = []rejectedAPI{
    94  	{
    95  		api:     "torrent",
    96  		methods: []string{http.MethodPut, http.MethodDelete, http.MethodGet},
    97  		queries: []string{"torrent", ""},
    98  		path:    "/{object:.+}",
    99  	},
   100  	{
   101  		api:     "acl",
   102  		methods: []string{http.MethodDelete},
   103  		queries: []string{"acl", ""},
   104  		path:    "/{object:.+}",
   105  	},
   106  }
   107  
   108  var rejectedBucketAPIs = []rejectedAPI{
   109  	{
   110  		api:     "inventory",
   111  		methods: []string{http.MethodGet, http.MethodPut, http.MethodDelete},
   112  		queries: []string{"inventory", ""},
   113  	},
   114  	{
   115  		api:     "cors",
   116  		methods: []string{http.MethodPut, http.MethodDelete},
   117  		queries: []string{"cors", ""},
   118  	},
   119  	{
   120  		api:     "metrics",
   121  		methods: []string{http.MethodGet, http.MethodPut, http.MethodDelete},
   122  		queries: []string{"metrics", ""},
   123  	},
   124  	{
   125  		api:     "website",
   126  		methods: []string{http.MethodPut},
   127  		queries: []string{"website", ""},
   128  	},
   129  	{
   130  		api:     "logging",
   131  		methods: []string{http.MethodPut, http.MethodDelete},
   132  		queries: []string{"logging", ""},
   133  	},
   134  	{
   135  		api:     "accelerate",
   136  		methods: []string{http.MethodPut, http.MethodDelete},
   137  		queries: []string{"accelerate", ""},
   138  	},
   139  	{
   140  		api:     "requestPayment",
   141  		methods: []string{http.MethodPut, http.MethodDelete},
   142  		queries: []string{"requestPayment", ""},
   143  	},
   144  	{
   145  		api:     "acl",
   146  		methods: []string{http.MethodDelete, http.MethodPut, http.MethodHead},
   147  		queries: []string{"acl", ""},
   148  	},
   149  	{
   150  		api:     "publicAccessBlock",
   151  		methods: []string{http.MethodDelete, http.MethodPut, http.MethodGet},
   152  		queries: []string{"publicAccessBlock", ""},
   153  	},
   154  	{
   155  		api:     "ownershipControls",
   156  		methods: []string{http.MethodDelete, http.MethodPut, http.MethodGet},
   157  		queries: []string{"ownershipControls", ""},
   158  	},
   159  	{
   160  		api:     "intelligent-tiering",
   161  		methods: []string{http.MethodDelete, http.MethodPut, http.MethodGet},
   162  		queries: []string{"intelligent-tiering", ""},
   163  	},
   164  	{
   165  		api:     "analytics",
   166  		methods: []string{http.MethodDelete, http.MethodPut, http.MethodGet},
   167  		queries: []string{"analytics", ""},
   168  	},
   169  }
   170  
   171  // Set of s3 handler options as bit flags.
   172  type s3HFlag uint8
   173  
   174  const (
   175  	// when provided, disables Gzip compression.
   176  	noGZS3HFlag = 1 << iota
   177  
   178  	// when provided, enables only tracing of headers. Otherwise, both headers
   179  	// and body are traced.
   180  	traceHdrsS3HFlag
   181  
   182  	// when provided, disables throttling via the `maxClients` middleware.
   183  	noThrottleS3HFlag
   184  )
   185  
   186  func (h s3HFlag) has(flag s3HFlag) bool {
   187  	// Use bitwise-AND and check if the result is non-zero.
   188  	return h&flag != 0
   189  }
   190  
   191  // s3APIMiddleware - performs some common handler functionality for S3 API
   192  // handlers.
   193  //
   194  // It is set per-"handler function registration" in the router to allow for
   195  // behavior modification via flags.
   196  //
   197  // This middleware always calls `collectAPIStats` to collect API stats.
   198  //
   199  // The passed in handler function must be a method of `objectAPIHandlers` for
   200  // the name displayed in logs and trace to be accurate. The name is extracted
   201  // via reflection.
   202  //
   203  // When **no** flags are passed, the behavior is to trace both headers and body,
   204  // gzip the response and throttle the handler via `maxClients`. Each of these
   205  // can be disabled via the corresponding `s3HFlag`.
   206  //
   207  // CAUTION: for requests involving large req/resp bodies ensure to pass the
   208  // `traceHdrsS3HFlag`, otherwise both headers and body will be traced, causing
   209  // high memory usage!
   210  func s3APIMiddleware(f http.HandlerFunc, flags ...s3HFlag) http.HandlerFunc {
   211  	// Collect all flags with bitwise-OR and assign operator
   212  	var handlerFlags s3HFlag
   213  	for _, flag := range flags {
   214  		handlerFlags |= flag
   215  	}
   216  
   217  	// Get name of the handler using reflection.
   218  	handlerName := getHandlerName(f, "objectAPIHandlers")
   219  
   220  	var handler http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) {
   221  		// Wrap the actual handler with the appropriate tracing middleware.
   222  		var tracedHandler http.HandlerFunc
   223  		if handlerFlags.has(traceHdrsS3HFlag) {
   224  			tracedHandler = httpTraceHdrs(f)
   225  		} else {
   226  			tracedHandler = httpTraceAll(f)
   227  		}
   228  
   229  		// Skip wrapping with the gzip middleware if specified.
   230  		var gzippedHandler http.HandlerFunc = tracedHandler
   231  		if !handlerFlags.has(noGZS3HFlag) {
   232  			gzippedHandler = gzipHandler(gzippedHandler)
   233  		}
   234  
   235  		// Skip wrapping with throttling middleware if specified.
   236  		var throttledHandler http.HandlerFunc = gzippedHandler
   237  		if !handlerFlags.has(noThrottleS3HFlag) {
   238  			throttledHandler = maxClients(throttledHandler)
   239  		}
   240  
   241  		// Collect API stats using the API name got from reflection in
   242  		// `getHandlerName`.
   243  		statsCollectedHandler := collectAPIStats(handlerName, throttledHandler)
   244  
   245  		// Call the final handler.
   246  		statsCollectedHandler(w, r)
   247  	}
   248  
   249  	return handler
   250  }
   251  
   252  // registerAPIRouter - registers S3 compatible APIs.
   253  func registerAPIRouter(router *mux.Router) {
   254  	// Initialize API.
   255  	api := objectAPIHandlers{
   256  		ObjectAPI: newObjectLayerFn,
   257  	}
   258  
   259  	// API Router
   260  	apiRouter := router.PathPrefix(SlashSeparator).Subrouter()
   261  
   262  	var routers []*mux.Router
   263  	for _, domainName := range globalDomainNames {
   264  		if IsKubernetes() {
   265  			routers = append(routers, apiRouter.MatcherFunc(func(r *http.Request, match *mux.RouteMatch) bool {
   266  				host, _, err := net.SplitHostPort(getHost(r))
   267  				if err != nil {
   268  					host = r.Host
   269  				}
   270  				// Make sure to skip matching minio.<domain>` this is
   271  				// specifically meant for operator/k8s deployment
   272  				// The reason we need to skip this is for a special
   273  				// usecase where we need to make sure that
   274  				// minio.<namespace>.svc.<cluster_domain> is ignored
   275  				// by the bucketDNS style to ensure that path style
   276  				// is available and honored at this domain.
   277  				//
   278  				// All other `<bucket>.<namespace>.svc.<cluster_domain>`
   279  				// makes sure that buckets are routed through this matcher
   280  				// to match for `<bucket>`
   281  				return host != minioReservedBucket+"."+domainName
   282  			}).Host("{bucket:.+}."+domainName).Subrouter())
   283  		} else {
   284  			routers = append(routers, apiRouter.Host("{bucket:.+}."+domainName).Subrouter())
   285  		}
   286  	}
   287  	routers = append(routers, apiRouter.PathPrefix("/{bucket}").Subrouter())
   288  
   289  	for _, router := range routers {
   290  		// Register all rejected object APIs
   291  		for _, r := range rejectedObjAPIs {
   292  			t := router.Methods(r.methods...).
   293  				HandlerFunc(collectAPIStats(r.api, httpTraceAll(notImplementedHandler))).
   294  				Queries(r.queries...)
   295  			t.Path(r.path)
   296  		}
   297  
   298  		// Object operations
   299  		// HeadObject
   300  		router.Methods(http.MethodHead).Path("/{object:.+}").
   301  			HandlerFunc(s3APIMiddleware(api.HeadObjectHandler))
   302  
   303  		// GetObjectAttributes
   304  		router.Methods(http.MethodGet).Path("/{object:.+}").
   305  			HandlerFunc(s3APIMiddleware(api.GetObjectAttributesHandler, traceHdrsS3HFlag)).
   306  			Queries("attributes", "")
   307  
   308  		// CopyObjectPart
   309  		router.Methods(http.MethodPut).Path("/{object:.+}").
   310  			HeadersRegexp(xhttp.AmzCopySource, ".*?(\\/|%2F).*?").
   311  			HandlerFunc(s3APIMiddleware(api.CopyObjectPartHandler)).
   312  			Queries("partNumber", "{partNumber:.*}", "uploadId", "{uploadId:.*}")
   313  		// PutObjectPart
   314  		router.Methods(http.MethodPut).Path("/{object:.+}").
   315  			HandlerFunc(s3APIMiddleware(api.PutObjectPartHandler, traceHdrsS3HFlag)).
   316  			Queries("partNumber", "{partNumber:.*}", "uploadId", "{uploadId:.*}")
   317  		// ListObjectParts
   318  		router.Methods(http.MethodGet).Path("/{object:.+}").
   319  			HandlerFunc(s3APIMiddleware(api.ListObjectPartsHandler)).
   320  			Queries("uploadId", "{uploadId:.*}")
   321  		// CompleteMultipartUpload
   322  		router.Methods(http.MethodPost).Path("/{object:.+}").
   323  			HandlerFunc(s3APIMiddleware(api.CompleteMultipartUploadHandler)).
   324  			Queries("uploadId", "{uploadId:.*}")
   325  		// NewMultipartUpload
   326  		router.Methods(http.MethodPost).Path("/{object:.+}").
   327  			HandlerFunc(s3APIMiddleware(api.NewMultipartUploadHandler)).
   328  			Queries("uploads", "")
   329  		// AbortMultipartUpload
   330  		router.Methods(http.MethodDelete).Path("/{object:.+}").
   331  			HandlerFunc(s3APIMiddleware(api.AbortMultipartUploadHandler)).
   332  			Queries("uploadId", "{uploadId:.*}")
   333  		// GetObjectACL - this is a dummy call.
   334  		router.Methods(http.MethodGet).Path("/{object:.+}").
   335  			HandlerFunc(s3APIMiddleware(api.GetObjectACLHandler, traceHdrsS3HFlag)).
   336  			Queries("acl", "")
   337  		// PutObjectACL - this is a dummy call.
   338  		router.Methods(http.MethodPut).Path("/{object:.+}").
   339  			HandlerFunc(s3APIMiddleware(api.PutObjectACLHandler, traceHdrsS3HFlag)).
   340  			Queries("acl", "")
   341  		// GetObjectTagging
   342  		router.Methods(http.MethodGet).Path("/{object:.+}").
   343  			HandlerFunc(s3APIMiddleware(api.GetObjectTaggingHandler, traceHdrsS3HFlag)).
   344  			Queries("tagging", "")
   345  		// PutObjectTagging
   346  		router.Methods(http.MethodPut).Path("/{object:.+}").
   347  			HandlerFunc(s3APIMiddleware(api.PutObjectTaggingHandler, traceHdrsS3HFlag)).
   348  			Queries("tagging", "")
   349  		// DeleteObjectTagging
   350  		router.Methods(http.MethodDelete).Path("/{object:.+}").
   351  			HandlerFunc(s3APIMiddleware(api.DeleteObjectTaggingHandler, traceHdrsS3HFlag)).
   352  			Queries("tagging", "")
   353  		// SelectObjectContent
   354  		router.Methods(http.MethodPost).Path("/{object:.+}").
   355  			HandlerFunc(s3APIMiddleware(api.SelectObjectContentHandler, traceHdrsS3HFlag)).
   356  			Queries("select", "").Queries("select-type", "2")
   357  		// GetObjectRetention
   358  		router.Methods(http.MethodGet).Path("/{object:.+}").
   359  			HandlerFunc(s3APIMiddleware(api.GetObjectRetentionHandler)).
   360  			Queries("retention", "")
   361  		// GetObjectLegalHold
   362  		router.Methods(http.MethodGet).Path("/{object:.+}").
   363  			HandlerFunc(s3APIMiddleware(api.GetObjectLegalHoldHandler)).
   364  			Queries("legal-hold", "")
   365  		// GetObject with lambda ARNs
   366  		router.Methods(http.MethodGet).Path("/{object:.+}").
   367  			HandlerFunc(s3APIMiddleware(api.GetObjectLambdaHandler, traceHdrsS3HFlag)).
   368  			Queries("lambdaArn", "{lambdaArn:.*}")
   369  		// GetObject
   370  		router.Methods(http.MethodGet).Path("/{object:.+}").
   371  			HandlerFunc(s3APIMiddleware(api.GetObjectHandler, traceHdrsS3HFlag))
   372  		// CopyObject
   373  		router.Methods(http.MethodPut).Path("/{object:.+}").
   374  			HeadersRegexp(xhttp.AmzCopySource, ".*?(\\/|%2F).*?").
   375  			HandlerFunc(s3APIMiddleware(api.CopyObjectHandler))
   376  		// PutObjectRetention
   377  		router.Methods(http.MethodPut).Path("/{object:.+}").
   378  			HandlerFunc(s3APIMiddleware(api.PutObjectRetentionHandler)).
   379  			Queries("retention", "")
   380  		// PutObjectLegalHold
   381  		router.Methods(http.MethodPut).Path("/{object:.+}").
   382  			HandlerFunc(s3APIMiddleware(api.PutObjectLegalHoldHandler)).
   383  			Queries("legal-hold", "")
   384  
   385  		// PutObject with auto-extract support for zip
   386  		router.Methods(http.MethodPut).Path("/{object:.+}").
   387  			HeadersRegexp(xhttp.AmzSnowballExtract, "true").
   388  			HandlerFunc(s3APIMiddleware(api.PutObjectExtractHandler, traceHdrsS3HFlag))
   389  
   390  		// PutObject
   391  		router.Methods(http.MethodPut).Path("/{object:.+}").
   392  			HandlerFunc(s3APIMiddleware(api.PutObjectHandler, traceHdrsS3HFlag))
   393  
   394  		// DeleteObject
   395  		router.Methods(http.MethodDelete).Path("/{object:.+}").
   396  			HandlerFunc(s3APIMiddleware(api.DeleteObjectHandler))
   397  
   398  		// PostRestoreObject
   399  		router.Methods(http.MethodPost).Path("/{object:.+}").
   400  			HandlerFunc(s3APIMiddleware(api.PostRestoreObjectHandler)).
   401  			Queries("restore", "")
   402  
   403  		// Bucket operations
   404  
   405  		// GetBucketLocation
   406  		router.Methods(http.MethodGet).
   407  			HandlerFunc(s3APIMiddleware(api.GetBucketLocationHandler)).
   408  			Queries("location", "")
   409  		// GetBucketPolicy
   410  		router.Methods(http.MethodGet).
   411  			HandlerFunc(s3APIMiddleware(api.GetBucketPolicyHandler)).
   412  			Queries("policy", "")
   413  		// GetBucketLifecycle
   414  		router.Methods(http.MethodGet).
   415  			HandlerFunc(s3APIMiddleware(api.GetBucketLifecycleHandler)).
   416  			Queries("lifecycle", "")
   417  		// GetBucketEncryption
   418  		router.Methods(http.MethodGet).
   419  			HandlerFunc(s3APIMiddleware(api.GetBucketEncryptionHandler)).
   420  			Queries("encryption", "")
   421  		// GetBucketObjectLockConfig
   422  		router.Methods(http.MethodGet).
   423  			HandlerFunc(s3APIMiddleware(api.GetBucketObjectLockConfigHandler)).
   424  			Queries("object-lock", "")
   425  		// GetBucketReplicationConfig
   426  		router.Methods(http.MethodGet).
   427  			HandlerFunc(s3APIMiddleware(api.GetBucketReplicationConfigHandler)).
   428  			Queries("replication", "")
   429  		// GetBucketVersioning
   430  		router.Methods(http.MethodGet).
   431  			HandlerFunc(s3APIMiddleware(api.GetBucketVersioningHandler)).
   432  			Queries("versioning", "")
   433  		// GetBucketNotification
   434  		router.Methods(http.MethodGet).
   435  			HandlerFunc(s3APIMiddleware(api.GetBucketNotificationHandler)).
   436  			Queries("notification", "")
   437  		// ListenNotification
   438  		router.Methods(http.MethodGet).
   439  			HandlerFunc(s3APIMiddleware(api.ListenNotificationHandler, noThrottleS3HFlag)).
   440  			Queries("events", "{events:.*}")
   441  		// ResetBucketReplicationStatus - MinIO extension API
   442  		router.Methods(http.MethodGet).
   443  			HandlerFunc(s3APIMiddleware(api.ResetBucketReplicationStatusHandler)).
   444  			Queries("replication-reset-status", "")
   445  
   446  		// Dummy Bucket Calls
   447  		// GetBucketACL -- this is a dummy call.
   448  		router.Methods(http.MethodGet).
   449  			HandlerFunc(s3APIMiddleware(api.GetBucketACLHandler)).
   450  			Queries("acl", "")
   451  		// PutBucketACL -- this is a dummy call.
   452  		router.Methods(http.MethodPut).
   453  			HandlerFunc(s3APIMiddleware(api.PutBucketACLHandler)).
   454  			Queries("acl", "")
   455  		// GetBucketCors - this is a dummy call.
   456  		router.Methods(http.MethodGet).
   457  			HandlerFunc(s3APIMiddleware(api.GetBucketCorsHandler)).
   458  			Queries("cors", "")
   459  		// GetBucketWebsiteHandler - this is a dummy call.
   460  		router.Methods(http.MethodGet).
   461  			HandlerFunc(s3APIMiddleware(api.GetBucketWebsiteHandler)).
   462  			Queries("website", "")
   463  		// GetBucketAccelerateHandler - this is a dummy call.
   464  		router.Methods(http.MethodGet).
   465  			HandlerFunc(s3APIMiddleware(api.GetBucketAccelerateHandler)).
   466  			Queries("accelerate", "")
   467  		// GetBucketRequestPaymentHandler - this is a dummy call.
   468  		router.Methods(http.MethodGet).
   469  			HandlerFunc(s3APIMiddleware(api.GetBucketRequestPaymentHandler)).
   470  			Queries("requestPayment", "")
   471  		// GetBucketLoggingHandler - this is a dummy call.
   472  		router.Methods(http.MethodGet).
   473  			HandlerFunc(s3APIMiddleware(api.GetBucketLoggingHandler)).
   474  			Queries("logging", "")
   475  		// GetBucketTaggingHandler
   476  		router.Methods(http.MethodGet).
   477  			HandlerFunc(s3APIMiddleware(api.GetBucketTaggingHandler)).
   478  			Queries("tagging", "")
   479  		// DeleteBucketWebsiteHandler
   480  		router.Methods(http.MethodDelete).
   481  			HandlerFunc(s3APIMiddleware(api.DeleteBucketWebsiteHandler)).
   482  			Queries("website", "")
   483  		// DeleteBucketTaggingHandler
   484  		router.Methods(http.MethodDelete).
   485  			HandlerFunc(s3APIMiddleware(api.DeleteBucketTaggingHandler)).
   486  			Queries("tagging", "")
   487  
   488  		// ListMultipartUploads
   489  		router.Methods(http.MethodGet).
   490  			HandlerFunc(s3APIMiddleware(api.ListMultipartUploadsHandler)).
   491  			Queries("uploads", "")
   492  		// ListObjectsV2M
   493  		router.Methods(http.MethodGet).
   494  			HandlerFunc(s3APIMiddleware(api.ListObjectsV2MHandler)).
   495  			Queries("list-type", "2", "metadata", "true")
   496  		// ListObjectsV2
   497  		router.Methods(http.MethodGet).
   498  			HandlerFunc(s3APIMiddleware(api.ListObjectsV2Handler)).
   499  			Queries("list-type", "2")
   500  		// ListObjectVersions
   501  		router.Methods(http.MethodGet).
   502  			HandlerFunc(s3APIMiddleware(api.ListObjectVersionsMHandler)).
   503  			Queries("versions", "", "metadata", "true")
   504  		// ListObjectVersions
   505  		router.Methods(http.MethodGet).
   506  			HandlerFunc(s3APIMiddleware(api.ListObjectVersionsHandler)).
   507  			Queries("versions", "")
   508  		// GetBucketPolicyStatus
   509  		router.Methods(http.MethodGet).
   510  			HandlerFunc(s3APIMiddleware(api.GetBucketPolicyStatusHandler)).
   511  			Queries("policyStatus", "")
   512  		// PutBucketLifecycle
   513  		router.Methods(http.MethodPut).
   514  			HandlerFunc(s3APIMiddleware(api.PutBucketLifecycleHandler)).
   515  			Queries("lifecycle", "")
   516  		// PutBucketReplicationConfig
   517  		router.Methods(http.MethodPut).
   518  			HandlerFunc(s3APIMiddleware(api.PutBucketReplicationConfigHandler)).
   519  			Queries("replication", "")
   520  		// PutBucketEncryption
   521  		router.Methods(http.MethodPut).
   522  			HandlerFunc(s3APIMiddleware(api.PutBucketEncryptionHandler)).
   523  			Queries("encryption", "")
   524  
   525  		// PutBucketPolicy
   526  		router.Methods(http.MethodPut).
   527  			HandlerFunc(s3APIMiddleware(api.PutBucketPolicyHandler)).
   528  			Queries("policy", "")
   529  
   530  		// PutBucketObjectLockConfig
   531  		router.Methods(http.MethodPut).
   532  			HandlerFunc(s3APIMiddleware(api.PutBucketObjectLockConfigHandler)).
   533  			Queries("object-lock", "")
   534  		// PutBucketTaggingHandler
   535  		router.Methods(http.MethodPut).
   536  			HandlerFunc(s3APIMiddleware(api.PutBucketTaggingHandler)).
   537  			Queries("tagging", "")
   538  		// PutBucketVersioning
   539  		router.Methods(http.MethodPut).
   540  			HandlerFunc(s3APIMiddleware(api.PutBucketVersioningHandler)).
   541  			Queries("versioning", "")
   542  		// PutBucketNotification
   543  		router.Methods(http.MethodPut).
   544  			HandlerFunc(s3APIMiddleware(api.PutBucketNotificationHandler)).
   545  			Queries("notification", "")
   546  		// ResetBucketReplicationStart - MinIO extension API
   547  		router.Methods(http.MethodPut).
   548  			HandlerFunc(s3APIMiddleware(api.ResetBucketReplicationStartHandler)).
   549  			Queries("replication-reset", "")
   550  
   551  		// PutBucket
   552  		router.Methods(http.MethodPut).
   553  			HandlerFunc(s3APIMiddleware(api.PutBucketHandler))
   554  		// HeadBucket
   555  		router.Methods(http.MethodHead).
   556  			HandlerFunc(s3APIMiddleware(api.HeadBucketHandler))
   557  		// PostPolicy
   558  		router.Methods(http.MethodPost).
   559  			MatcherFunc(func(r *http.Request, _ *mux.RouteMatch) bool {
   560  				return isRequestPostPolicySignatureV4(r)
   561  			}).
   562  			HandlerFunc(s3APIMiddleware(api.PostPolicyBucketHandler, traceHdrsS3HFlag))
   563  		// DeleteMultipleObjects
   564  		router.Methods(http.MethodPost).
   565  			HandlerFunc(s3APIMiddleware(api.DeleteMultipleObjectsHandler)).
   566  			Queries("delete", "")
   567  		// DeleteBucketPolicy
   568  		router.Methods(http.MethodDelete).
   569  			HandlerFunc(s3APIMiddleware(api.DeleteBucketPolicyHandler)).
   570  			Queries("policy", "")
   571  		// DeleteBucketReplication
   572  		router.Methods(http.MethodDelete).
   573  			HandlerFunc(s3APIMiddleware(api.DeleteBucketReplicationConfigHandler)).
   574  			Queries("replication", "")
   575  		// DeleteBucketLifecycle
   576  		router.Methods(http.MethodDelete).
   577  			HandlerFunc(s3APIMiddleware(api.DeleteBucketLifecycleHandler)).
   578  			Queries("lifecycle", "")
   579  		// DeleteBucketEncryption
   580  		router.Methods(http.MethodDelete).
   581  			HandlerFunc(s3APIMiddleware(api.DeleteBucketEncryptionHandler)).
   582  			Queries("encryption", "")
   583  		// DeleteBucket
   584  		router.Methods(http.MethodDelete).
   585  			HandlerFunc(s3APIMiddleware(api.DeleteBucketHandler))
   586  
   587  		// MinIO extension API for replication.
   588  		//
   589  		router.Methods(http.MethodGet).
   590  			HandlerFunc(s3APIMiddleware(api.GetBucketReplicationMetricsV2Handler)).
   591  			Queries("replication-metrics", "2")
   592  		// deprecated handler
   593  		router.Methods(http.MethodGet).
   594  			HandlerFunc(s3APIMiddleware(api.GetBucketReplicationMetricsHandler)).
   595  			Queries("replication-metrics", "")
   596  
   597  		// ValidateBucketReplicationCreds
   598  		router.Methods(http.MethodGet).
   599  			HandlerFunc(s3APIMiddleware(api.ValidateBucketReplicationCredsHandler)).
   600  			Queries("replication-check", "")
   601  
   602  		// Register rejected bucket APIs
   603  		for _, r := range rejectedBucketAPIs {
   604  			router.Methods(r.methods...).
   605  				HandlerFunc(collectAPIStats(r.api, httpTraceAll(notImplementedHandler))).
   606  				Queries(r.queries...)
   607  		}
   608  
   609  		// S3 ListObjectsV1 (Legacy)
   610  		router.Methods(http.MethodGet).
   611  			HandlerFunc(s3APIMiddleware(api.ListObjectsV1Handler))
   612  	}
   613  
   614  	// Root operation
   615  
   616  	// ListenNotification
   617  	apiRouter.Methods(http.MethodGet).Path(SlashSeparator).
   618  		HandlerFunc(s3APIMiddleware(api.ListenNotificationHandler, noThrottleS3HFlag)).
   619  		Queries("events", "{events:.*}")
   620  
   621  	// ListBuckets
   622  	apiRouter.Methods(http.MethodGet).Path(SlashSeparator).
   623  		HandlerFunc(s3APIMiddleware(api.ListBucketsHandler))
   624  
   625  	// S3 browser with signature v4 adds '//' for ListBuckets request, so rather
   626  	// than failing with UnknownAPIRequest we simply handle it for now.
   627  	apiRouter.Methods(http.MethodGet).Path(SlashSeparator + SlashSeparator).
   628  		HandlerFunc(s3APIMiddleware(api.ListBucketsHandler))
   629  
   630  	// If none of the routes match add default error handler routes
   631  	apiRouter.NotFoundHandler = collectAPIStats("notfound", httpTraceAll(errorResponseHandler))
   632  	apiRouter.MethodNotAllowedHandler = collectAPIStats("methodnotallowed", httpTraceAll(methodNotAllowedHandler("S3")))
   633  }
   634  
   635  // corsHandler handler for CORS (Cross Origin Resource Sharing)
   636  func corsHandler(handler http.Handler) http.Handler {
   637  	commonS3Headers := []string{
   638  		xhttp.Date,
   639  		xhttp.ETag,
   640  		xhttp.ServerInfo,
   641  		xhttp.Connection,
   642  		xhttp.AcceptRanges,
   643  		xhttp.ContentRange,
   644  		xhttp.ContentEncoding,
   645  		xhttp.ContentLength,
   646  		xhttp.ContentType,
   647  		xhttp.ContentDisposition,
   648  		xhttp.LastModified,
   649  		xhttp.ContentLanguage,
   650  		xhttp.CacheControl,
   651  		xhttp.RetryAfter,
   652  		xhttp.AmzBucketRegion,
   653  		xhttp.Expires,
   654  		"X-Amz*",
   655  		"x-amz*",
   656  		"*",
   657  	}
   658  	opts := cors.Options{
   659  		AllowOriginFunc: func(origin string) bool {
   660  			for _, allowedOrigin := range globalAPIConfig.getCorsAllowOrigins() {
   661  				if wildcard.MatchSimple(allowedOrigin, origin) {
   662  					return true
   663  				}
   664  			}
   665  			return false
   666  		},
   667  		AllowedMethods: []string{
   668  			http.MethodGet,
   669  			http.MethodPut,
   670  			http.MethodHead,
   671  			http.MethodPost,
   672  			http.MethodDelete,
   673  			http.MethodOptions,
   674  			http.MethodPatch,
   675  		},
   676  		AllowedHeaders:   commonS3Headers,
   677  		ExposedHeaders:   commonS3Headers,
   678  		AllowCredentials: true,
   679  	}
   680  	return cors.New(opts).Handler(handler)
   681  }