storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/api-router.go (about) 1 /* 2 * MinIO Cloud Storage, (C) 2016-2020 MinIO, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package cmd 18 19 import ( 20 "net" 21 "net/http" 22 23 "github.com/gorilla/mux" 24 "github.com/rs/cors" 25 26 xhttp "storj.io/minio/cmd/http" 27 "storj.io/minio/pkg/wildcard" 28 ) 29 30 func newHTTPServerFn() *xhttp.Server { 31 globalObjLayerMutex.RLock() 32 defer globalObjLayerMutex.RUnlock() 33 return globalHTTPServer 34 } 35 36 func setHTTPServer(h *xhttp.Server) { 37 globalObjLayerMutex.Lock() 38 globalHTTPServer = h 39 globalObjLayerMutex.Unlock() 40 } 41 42 func newObjectLayerFn() ObjectLayer { 43 globalObjLayerMutex.RLock() 44 defer globalObjLayerMutex.RUnlock() 45 return globalObjectAPI 46 } 47 48 func newCachedObjectLayerFn() CacheObjectLayer { 49 globalObjLayerMutex.RLock() 50 defer globalObjLayerMutex.RUnlock() 51 return globalCacheObjectAPI 52 } 53 54 func setCacheObjectLayer(c CacheObjectLayer) { 55 globalObjLayerMutex.Lock() 56 globalCacheObjectAPI = c 57 globalObjLayerMutex.Unlock() 58 } 59 60 func SetObjectLayer(o ObjectLayer) { 61 globalObjLayerMutex.Lock() 62 globalObjectAPI = o 63 globalObjLayerMutex.Unlock() 64 } 65 66 // ObjectAPIHandler implements and provides http handlers for S3 API. 67 type ObjectAPIHandlers struct { 68 ObjectAPI func() ObjectLayer 69 CacheAPI func() CacheObjectLayer 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, guessIsBrowserReq(r)) 84 } 85 86 type rejectedAPI struct { 87 api string 88 methods []string 89 queries []string 90 path string 91 } 92 93 var rejectedAPIs = []rejectedAPI{ 94 { 95 api: "inventory", 96 methods: []string{http.MethodGet, http.MethodPut, http.MethodDelete}, 97 queries: []string{"inventory", ""}, 98 }, 99 { 100 api: "cors", 101 methods: []string{http.MethodPut, http.MethodDelete}, 102 queries: []string{"cors", ""}, 103 }, 104 { 105 api: "metrics", 106 methods: []string{http.MethodGet, http.MethodPut, http.MethodDelete}, 107 queries: []string{"metrics", ""}, 108 }, 109 { 110 api: "website", 111 methods: []string{http.MethodPut}, 112 queries: []string{"website", ""}, 113 }, 114 { 115 api: "logging", 116 methods: []string{http.MethodPut, http.MethodDelete}, 117 queries: []string{"logging", ""}, 118 }, 119 { 120 api: "accelerate", 121 methods: []string{http.MethodPut, http.MethodDelete}, 122 queries: []string{"accelerate", ""}, 123 }, 124 { 125 api: "requestPayment", 126 methods: []string{http.MethodPut, http.MethodDelete}, 127 queries: []string{"requestPayment", ""}, 128 }, 129 { 130 api: "torrent", 131 methods: []string{http.MethodPut, http.MethodDelete, http.MethodGet}, 132 queries: []string{"torrent", ""}, 133 path: "/{object:.+}", 134 }, 135 { 136 api: "acl", 137 methods: []string{http.MethodDelete}, 138 queries: []string{"acl", ""}, 139 path: "/{object:.+}", 140 }, 141 { 142 api: "acl", 143 methods: []string{http.MethodDelete, http.MethodPut, http.MethodHead}, 144 queries: []string{"acl", ""}, 145 }, 146 { 147 api: "publicAccessBlock", 148 methods: []string{http.MethodDelete, http.MethodPut, http.MethodGet}, 149 queries: []string{"publicAccessBlock", ""}, 150 }, 151 { 152 api: "ownershipControls", 153 methods: []string{http.MethodDelete, http.MethodPut, http.MethodGet}, 154 queries: []string{"ownershipControls", ""}, 155 }, 156 { 157 api: "intelligent-tiering", 158 methods: []string{http.MethodDelete, http.MethodPut, http.MethodGet}, 159 queries: []string{"intelligent-tiering", ""}, 160 }, 161 { 162 api: "analytics", 163 methods: []string{http.MethodDelete, http.MethodPut, http.MethodGet}, 164 queries: []string{"analytics", ""}, 165 }, 166 } 167 168 func rejectUnsupportedAPIs(router *mux.Router) { 169 for _, r := range rejectedAPIs { 170 t := router.Methods(r.methods...). 171 HandlerFunc(CollectAPIStats(r.api, HTTPTraceAll(notImplementedHandler))). 172 Queries(r.queries...) 173 if r.path != "" { 174 t.Path(r.path) 175 } 176 } 177 } 178 179 // registerAPIRouter - registers S3 compatible APIs. 180 func registerAPIRouter(router *mux.Router) { 181 // Initialize API. 182 api := ObjectAPIHandlers{ 183 ObjectAPI: newObjectLayerFn, 184 CacheAPI: newCachedObjectLayerFn, 185 } 186 187 // API Router 188 apiRouter := router.PathPrefix(SlashSeparator).Subrouter() 189 190 var routers []*mux.Router 191 for _, domainName := range globalDomainNames { 192 if IsKubernetes() { 193 routers = append(routers, apiRouter.MatcherFunc(func(r *http.Request, match *mux.RouteMatch) bool { 194 host, _, err := net.SplitHostPort(getHost(r)) 195 if err != nil { 196 host = r.Host 197 } 198 // Make sure to skip matching minio.<domain>` this is 199 // specifically meant for operator/k8s deployment 200 // The reason we need to skip this is for a special 201 // usecase where we need to make sure that 202 // minio.<namespace>.svc.<cluster_domain> is ignored 203 // by the bucketDNS style to ensure that path style 204 // is available and honored at this domain. 205 // 206 // All other `<bucket>.<namespace>.svc.<cluster_domain>` 207 // makes sure that buckets are routed through this matcher 208 // to match for `<bucket>` 209 return host != minioReservedBucket+"."+domainName 210 }).Host("{bucket:.+}."+domainName).Subrouter()) 211 } else { 212 routers = append(routers, apiRouter.Host("{bucket:.+}."+domainName).Subrouter()) 213 } 214 } 215 routers = append(routers, apiRouter.PathPrefix("/{bucket}").Subrouter()) 216 217 for _, router := range routers { 218 rejectUnsupportedAPIs(router) 219 // Object operations 220 // HeadObject 221 router.Methods(http.MethodHead).Path("/{object:.+}").HandlerFunc( 222 CollectAPIStats("headobject", MaxClients(HTTPTraceAll(api.HeadObjectHandler)))) 223 // CopyObjectPart 224 router.Methods(http.MethodPut).Path("/{object:.+}"). 225 HeadersRegexp(xhttp.AmzCopySource, ".*?(\\/|%2F).*?"). 226 HandlerFunc(CollectAPIStats("copyobjectpart", MaxClients(HTTPTraceAll(api.CopyObjectPartHandler)))). 227 Queries("partNumber", "{partNumber:[0-9]+}", "uploadId", "{uploadId:.*}") 228 // PutObjectPart 229 router.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc( 230 CollectAPIStats("putobjectpart", MaxClients(HTTPTraceHdrs(api.PutObjectPartHandler)))).Queries("partNumber", "{partNumber:[0-9]+}", "uploadId", "{uploadId:.*}") 231 // ListObjectParts 232 router.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc( 233 CollectAPIStats("listobjectparts", MaxClients(HTTPTraceAll(api.ListObjectPartsHandler)))).Queries("uploadId", "{uploadId:.*}") 234 // CompleteMultipartUpload 235 router.Methods(http.MethodPost).Path("/{object:.+}").HandlerFunc( 236 CollectAPIStats("completemutipartupload", MaxClients(HTTPTraceAll(api.CompleteMultipartUploadHandler)))).Queries("uploadId", "{uploadId:.*}") 237 // NewMultipartUpload 238 router.Methods(http.MethodPost).Path("/{object:.+}").HandlerFunc( 239 CollectAPIStats("newmultipartupload", MaxClients(HTTPTraceAll(api.NewMultipartUploadHandler)))).Queries("uploads", "") 240 // AbortMultipartUpload 241 router.Methods(http.MethodDelete).Path("/{object:.+}").HandlerFunc( 242 CollectAPIStats("abortmultipartupload", MaxClients(HTTPTraceAll(api.AbortMultipartUploadHandler)))).Queries("uploadId", "{uploadId:.*}") 243 // GetObjectACL - this is a dummy call. 244 router.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc( 245 CollectAPIStats("getobjectacl", MaxClients(HTTPTraceHdrs(api.GetObjectACLHandler)))).Queries("acl", "") 246 // PutObjectACL - this is a dummy call. 247 router.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc( 248 CollectAPIStats("putobjectacl", MaxClients(HTTPTraceHdrs(api.PutObjectACLHandler)))).Queries("acl", "") 249 // GetObjectTagging 250 router.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc( 251 CollectAPIStats("getobjecttagging", MaxClients(HTTPTraceHdrs(api.GetObjectTaggingHandler)))).Queries("tagging", "") 252 // PutObjectTagging 253 router.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc( 254 CollectAPIStats("putobjecttagging", MaxClients(HTTPTraceHdrs(api.PutObjectTaggingHandler)))).Queries("tagging", "") 255 // DeleteObjectTagging 256 router.Methods(http.MethodDelete).Path("/{object:.+}").HandlerFunc( 257 CollectAPIStats("deleteobjecttagging", MaxClients(HTTPTraceHdrs(api.DeleteObjectTaggingHandler)))).Queries("tagging", "") 258 // SelectObjectContent 259 router.Methods(http.MethodPost).Path("/{object:.+}").HandlerFunc( 260 CollectAPIStats("selectobjectcontent", MaxClients(HTTPTraceHdrs(api.SelectObjectContentHandler)))).Queries("select", "").Queries("select-type", "2") 261 // GetObjectRetention 262 router.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc( 263 CollectAPIStats("getobjectretention", MaxClients(HTTPTraceAll(api.GetObjectRetentionHandler)))).Queries("retention", "") 264 // GetObjectLegalHold 265 router.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc( 266 CollectAPIStats("getobjectlegalhold", MaxClients(HTTPTraceAll(api.GetObjectLegalHoldHandler)))).Queries("legal-hold", "") 267 // GetObject 268 router.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc( 269 CollectAPIStats("getobject", MaxClients(HTTPTraceHdrs(api.GetObjectHandler)))) 270 // CopyObject 271 router.Methods(http.MethodPut).Path("/{object:.+}").HeadersRegexp(xhttp.AmzCopySource, ".*?(\\/|%2F).*?").HandlerFunc( 272 CollectAPIStats("copyobject", MaxClients(HTTPTraceAll(api.CopyObjectHandler)))) 273 // PutObjectRetention 274 router.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc( 275 CollectAPIStats("putobjectretention", MaxClients(HTTPTraceAll(api.PutObjectRetentionHandler)))).Queries("retention", "") 276 // PutObjectLegalHold 277 router.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc( 278 CollectAPIStats("putobjectlegalhold", MaxClients(HTTPTraceAll(api.PutObjectLegalHoldHandler)))).Queries("legal-hold", "") 279 280 // PutObject with auto-extract support for zip 281 router.Methods(http.MethodPut).Path("/{object:.+}").HeadersRegexp(xhttp.AmzSnowballExtract, "true").HandlerFunc( 282 CollectAPIStats("putobject", MaxClients(HTTPTraceHdrs(api.PutObjectExtractHandler)))) 283 284 // PutObject 285 router.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc( 286 CollectAPIStats("putobject", MaxClients(HTTPTraceHdrs(api.PutObjectHandler)))) 287 288 // DeleteObject 289 router.Methods(http.MethodDelete).Path("/{object:.+}").HandlerFunc( 290 CollectAPIStats("deleteobject", MaxClients(HTTPTraceAll(api.DeleteObjectHandler)))) 291 292 // PostRestoreObject 293 router.Methods(http.MethodPost).Path("/{object:.+}").HandlerFunc( 294 CollectAPIStats("restoreobject", MaxClients(HTTPTraceAll(api.PostRestoreObjectHandler)))).Queries("restore", "") 295 296 /// Bucket operations 297 // GetBucketLocation 298 router.Methods(http.MethodGet).HandlerFunc( 299 CollectAPIStats("getbucketlocation", MaxClients(HTTPTraceAll(api.GetBucketLocationHandler)))).Queries("location", "") 300 // GetBucketPolicy 301 router.Methods(http.MethodGet).HandlerFunc( 302 CollectAPIStats("getbucketpolicy", MaxClients(HTTPTraceAll(api.GetBucketPolicyHandler)))).Queries("policy", "") 303 // GetBucketLifecycle 304 router.Methods(http.MethodGet).HandlerFunc( 305 CollectAPIStats("getbucketlifecycle", MaxClients(HTTPTraceAll(api.GetBucketLifecycleHandler)))).Queries("lifecycle", "") 306 // GetBucketEncryption 307 router.Methods(http.MethodGet).HandlerFunc( 308 CollectAPIStats("getbucketencryption", MaxClients(HTTPTraceAll(api.GetBucketEncryptionHandler)))).Queries("encryption", "") 309 // GetBucketObjectLockConfig 310 router.Methods(http.MethodGet).HandlerFunc( 311 CollectAPIStats("getbucketobjectlockconfiguration", MaxClients(HTTPTraceAll(api.GetBucketObjectLockConfigHandler)))).Queries("object-lock", "") 312 // GetBucketReplicationConfig 313 router.Methods(http.MethodGet).HandlerFunc( 314 CollectAPIStats("getbucketreplicationconfiguration", MaxClients(HTTPTraceAll(api.GetBucketReplicationConfigHandler)))).Queries("replication", "") 315 // GetBucketVersioning 316 router.Methods(http.MethodGet).HandlerFunc( 317 CollectAPIStats("getbucketversioning", MaxClients(HTTPTraceAll(api.GetBucketVersioningHandler)))).Queries("versioning", "") 318 // GetBucketNotification 319 router.Methods(http.MethodGet).HandlerFunc( 320 CollectAPIStats("getbucketnotification", MaxClients(HTTPTraceAll(api.GetBucketNotificationHandler)))).Queries("notification", "") 321 // ListenNotification 322 router.Methods(http.MethodGet).HandlerFunc( 323 CollectAPIStats("listennotification", MaxClients(HTTPTraceAll(api.ListenNotificationHandler)))).Queries("events", "{events:.*}") 324 325 // Dummy Bucket Calls 326 // GetBucketACL -- this is a dummy call. 327 router.Methods(http.MethodGet).HandlerFunc( 328 CollectAPIStats("getbucketacl", MaxClients(HTTPTraceAll(api.GetBucketACLHandler)))).Queries("acl", "") 329 // PutBucketACL -- this is a dummy call. 330 router.Methods(http.MethodPut).HandlerFunc( 331 CollectAPIStats("putbucketacl", MaxClients(HTTPTraceAll(api.PutBucketACLHandler)))).Queries("acl", "") 332 // GetBucketCors - this is a dummy call. 333 router.Methods(http.MethodGet).HandlerFunc( 334 CollectAPIStats("getbucketcors", MaxClients(HTTPTraceAll(api.GetBucketCorsHandler)))).Queries("cors", "") 335 // GetBucketWebsiteHandler - this is a dummy call. 336 router.Methods(http.MethodGet).HandlerFunc( 337 CollectAPIStats("getbucketwebsite", MaxClients(HTTPTraceAll(api.GetBucketWebsiteHandler)))).Queries("website", "") 338 // GetBucketAccelerateHandler - this is a dummy call. 339 router.Methods(http.MethodGet).HandlerFunc( 340 CollectAPIStats("getbucketaccelerate", MaxClients(HTTPTraceAll(api.GetBucketAccelerateHandler)))).Queries("accelerate", "") 341 // GetBucketRequestPaymentHandler - this is a dummy call. 342 router.Methods(http.MethodGet).HandlerFunc( 343 CollectAPIStats("getbucketrequestpayment", MaxClients(HTTPTraceAll(api.GetBucketRequestPaymentHandler)))).Queries("requestPayment", "") 344 // GetBucketLoggingHandler - this is a dummy call. 345 router.Methods(http.MethodGet).HandlerFunc( 346 CollectAPIStats("getbucketlogging", MaxClients(HTTPTraceAll(api.GetBucketLoggingHandler)))).Queries("logging", "") 347 // GetBucketTaggingHandler 348 router.Methods(http.MethodGet).HandlerFunc( 349 CollectAPIStats("getbuckettagging", MaxClients(HTTPTraceAll(api.GetBucketTaggingHandler)))).Queries("tagging", "") 350 //DeleteBucketWebsiteHandler 351 router.Methods(http.MethodDelete).HandlerFunc( 352 CollectAPIStats("deletebucketwebsite", MaxClients(HTTPTraceAll(api.DeleteBucketWebsiteHandler)))).Queries("website", "") 353 // DeleteBucketTaggingHandler 354 router.Methods(http.MethodDelete).HandlerFunc( 355 CollectAPIStats("deletebuckettagging", MaxClients(HTTPTraceAll(api.DeleteBucketTaggingHandler)))).Queries("tagging", "") 356 357 // ListMultipartUploads 358 router.Methods(http.MethodGet).HandlerFunc( 359 CollectAPIStats("listmultipartuploads", MaxClients(HTTPTraceAll(api.ListMultipartUploadsHandler)))).Queries("uploads", "") 360 // ListObjectsV2M 361 router.Methods(http.MethodGet).HandlerFunc( 362 CollectAPIStats("listobjectsv2M", MaxClients(HTTPTraceAll(api.ListObjectsV2MHandler)))).Queries("list-type", "2", "metadata", "true") 363 // ListObjectsV2 364 router.Methods(http.MethodGet).HandlerFunc( 365 CollectAPIStats("listobjectsv2", MaxClients(HTTPTraceAll(api.ListObjectsV2Handler)))).Queries("list-type", "2") 366 // ListObjectVersions 367 router.Methods(http.MethodGet).HandlerFunc( 368 CollectAPIStats("listobjectversions", MaxClients(HTTPTraceAll(api.ListObjectVersionsHandler)))).Queries("versions", "") 369 // GetBucketPolicyStatus 370 router.Methods(http.MethodGet).HandlerFunc( 371 CollectAPIStats("getpolicystatus", MaxClients(HTTPTraceAll(api.GetBucketPolicyStatusHandler)))).Queries("policyStatus", "") 372 // PutBucketLifecycle 373 router.Methods(http.MethodPut).HandlerFunc( 374 CollectAPIStats("putbucketlifecycle", MaxClients(HTTPTraceAll(api.PutBucketLifecycleHandler)))).Queries("lifecycle", "") 375 // PutBucketReplicationConfig 376 router.Methods(http.MethodPut).HandlerFunc( 377 CollectAPIStats("putbucketreplicationconfiguration", MaxClients(HTTPTraceAll(api.PutBucketReplicationConfigHandler)))).Queries("replication", "") 378 // PutBucketEncryption 379 router.Methods(http.MethodPut).HandlerFunc( 380 CollectAPIStats("putbucketencryption", MaxClients(HTTPTraceAll(api.PutBucketEncryptionHandler)))).Queries("encryption", "") 381 382 // PutBucketPolicy 383 router.Methods(http.MethodPut).HandlerFunc( 384 CollectAPIStats("putbucketpolicy", MaxClients(HTTPTraceAll(api.PutBucketPolicyHandler)))).Queries("policy", "") 385 386 // PutBucketObjectLockConfig 387 router.Methods(http.MethodPut).HandlerFunc( 388 CollectAPIStats("putbucketobjectlockconfig", MaxClients(HTTPTraceAll(api.PutBucketObjectLockConfigHandler)))).Queries("object-lock", "") 389 // PutBucketTaggingHandler 390 router.Methods(http.MethodPut).HandlerFunc( 391 CollectAPIStats("putbuckettagging", MaxClients(HTTPTraceAll(api.PutBucketTaggingHandler)))).Queries("tagging", "") 392 // PutBucketVersioning 393 router.Methods(http.MethodPut).HandlerFunc( 394 CollectAPIStats("putbucketversioning", MaxClients(HTTPTraceAll(api.PutBucketVersioningHandler)))).Queries("versioning", "") 395 // PutBucketNotification 396 router.Methods(http.MethodPut).HandlerFunc( 397 CollectAPIStats("putbucketnotification", MaxClients(HTTPTraceAll(api.PutBucketNotificationHandler)))).Queries("notification", "") 398 // PutBucket 399 router.Methods(http.MethodPut).HandlerFunc( 400 CollectAPIStats("putbucket", MaxClients(HTTPTraceAll(api.PutBucketHandler)))) 401 // HeadBucket 402 router.Methods(http.MethodHead).HandlerFunc( 403 CollectAPIStats("headbucket", MaxClients(HTTPTraceAll(api.HeadBucketHandler)))) 404 // PostPolicy 405 router.Methods(http.MethodPost).HeadersRegexp(xhttp.ContentType, "multipart/form-data*").HandlerFunc( 406 CollectAPIStats("postpolicybucket", MaxClients(HTTPTraceHdrs(api.PostPolicyBucketHandler)))) 407 // DeleteMultipleObjects 408 router.Methods(http.MethodPost).HandlerFunc( 409 CollectAPIStats("deletemultipleobjects", MaxClients(HTTPTraceAll(api.DeleteMultipleObjectsHandler)))).Queries("delete", "") 410 // DeleteBucketPolicy 411 router.Methods(http.MethodDelete).HandlerFunc( 412 CollectAPIStats("deletebucketpolicy", MaxClients(HTTPTraceAll(api.DeleteBucketPolicyHandler)))).Queries("policy", "") 413 // DeleteBucketReplication 414 router.Methods(http.MethodDelete).HandlerFunc( 415 CollectAPIStats("deletebucketreplicationconfiguration", MaxClients(HTTPTraceAll(api.DeleteBucketReplicationConfigHandler)))).Queries("replication", "") 416 // DeleteBucketLifecycle 417 router.Methods(http.MethodDelete).HandlerFunc( 418 CollectAPIStats("deletebucketlifecycle", MaxClients(HTTPTraceAll(api.DeleteBucketLifecycleHandler)))).Queries("lifecycle", "") 419 // DeleteBucketEncryption 420 router.Methods(http.MethodDelete).HandlerFunc( 421 CollectAPIStats("deletebucketencryption", MaxClients(HTTPTraceAll(api.DeleteBucketEncryptionHandler)))).Queries("encryption", "") 422 // DeleteBucket 423 router.Methods(http.MethodDelete).HandlerFunc( 424 CollectAPIStats("deletebucket", MaxClients(HTTPTraceAll(api.DeleteBucketHandler)))) 425 // MinIO extension API for replication. 426 // 427 // GetBucketReplicationMetrics 428 router.Methods(http.MethodGet).HandlerFunc( 429 CollectAPIStats("getbucketreplicationmetrics", MaxClients(HTTPTraceAll(api.GetBucketReplicationMetricsHandler)))).Queries("replication-metrics", "") 430 431 // S3 ListObjectsV1 (Legacy) 432 router.Methods(http.MethodGet).HandlerFunc( 433 CollectAPIStats("listobjectsv1", MaxClients(HTTPTraceAll(api.ListObjectsV1Handler)))) 434 435 } 436 437 /// Root operation 438 439 // ListenNotification 440 apiRouter.Methods(http.MethodGet).Path(SlashSeparator).HandlerFunc( 441 CollectAPIStats("listennotification", MaxClients(HTTPTraceAll(api.ListenNotificationHandler)))).Queries("events", "{events:.*}") 442 443 // ListBuckets 444 apiRouter.Methods(http.MethodGet).Path(SlashSeparator).HandlerFunc( 445 CollectAPIStats("listbuckets", MaxClients(HTTPTraceAll(api.ListBucketsHandler)))) 446 447 // S3 browser with signature v4 adds '//' for ListBuckets request, so rather 448 // than failing with UnknownAPIRequest we simply handle it for now. 449 apiRouter.Methods(http.MethodGet).Path(SlashSeparator + SlashSeparator).HandlerFunc( 450 CollectAPIStats("listbuckets", MaxClients(HTTPTraceAll(api.ListBucketsHandler)))) 451 452 // If none of the routes match add default error handler routes 453 apiRouter.NotFoundHandler = CollectAPIStats("notfound", HTTPTraceAll(ErrorResponseHandler)) 454 apiRouter.MethodNotAllowedHandler = CollectAPIStats("methodnotallowed", HTTPTraceAll(MethodNotAllowedHandler("S3"))) 455 456 } 457 458 // corsHandler handler for CORS (Cross Origin Resource Sharing) 459 func corsHandler(handler http.Handler) http.Handler { 460 commonS3Headers := []string{ 461 xhttp.Date, 462 xhttp.ETag, 463 xhttp.ServerInfo, 464 xhttp.Connection, 465 xhttp.AcceptRanges, 466 xhttp.ContentRange, 467 xhttp.ContentEncoding, 468 xhttp.ContentLength, 469 xhttp.ContentType, 470 xhttp.ContentDisposition, 471 xhttp.LastModified, 472 xhttp.ContentLanguage, 473 xhttp.CacheControl, 474 xhttp.RetryAfter, 475 xhttp.AmzBucketRegion, 476 xhttp.Expires, 477 "X-Amz*", 478 "x-amz*", 479 "*", 480 } 481 482 return cors.New(cors.Options{ 483 AllowOriginFunc: func(origin string) bool { 484 for _, allowedOrigin := range globalAPIConfig.getCorsAllowOrigins() { 485 if wildcard.MatchSimple(allowedOrigin, origin) { 486 return true 487 } 488 } 489 return false 490 }, 491 AllowedMethods: []string{ 492 http.MethodGet, 493 http.MethodPut, 494 http.MethodHead, 495 http.MethodPost, 496 http.MethodDelete, 497 http.MethodOptions, 498 http.MethodPatch, 499 }, 500 AllowedHeaders: commonS3Headers, 501 ExposedHeaders: commonS3Headers, 502 AllowCredentials: true, 503 }).Handler(handler) 504 }