Ensure that we use constants everywhere (#7845)

This allows for canonicalization of the strings
throughout our code and provides a common space
for all these constants to reside.

This list is rather non-exhaustive but captures
all the headers used in AWS S3 API operations
This commit is contained in:
Harshavardhana 2019-07-02 22:34:32 -07:00 committed by GitHub
parent 9610a74c19
commit c43f745449
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 319 additions and 214 deletions

View File

@ -34,6 +34,7 @@ import (
"github.com/tidwall/gjson" "github.com/tidwall/gjson"
"github.com/tidwall/sjson" "github.com/tidwall/sjson"
xhttp "github.com/minio/minio/cmd/http"
"github.com/minio/minio/cmd/logger" "github.com/minio/minio/cmd/logger"
"github.com/minio/minio/pkg/cpu" "github.com/minio/minio/pkg/cpu"
"github.com/minio/minio/pkg/disk" "github.com/minio/minio/pkg/disk"
@ -682,7 +683,7 @@ func (a adminAPIHandlers) HealHandler(w http.ResponseWriter, r *http.Request) {
// Start writing response to client // Start writing response to client
started = true started = true
setCommonHeaders(w) setCommonHeaders(w)
w.Header().Set("Content-Type", string(mimeJSON)) w.Header().Set(xhttp.ContentType, string(mimeJSON))
// Set 200 OK status // Set 200 OK status
w.WriteHeader(200) w.WriteHeader(200)
} }
@ -702,20 +703,20 @@ func (a adminAPIHandlers) HealHandler(w http.ResponseWriter, r *http.Request) {
var errorRespJSON []byte var errorRespJSON []byte
if hr.errBody == "" { if hr.errBody == "" {
errorRespJSON = encodeResponseJSON(getAPIErrorResponse(ctx, hr.apiErr, errorRespJSON = encodeResponseJSON(getAPIErrorResponse(ctx, hr.apiErr,
r.URL.Path, w.Header().Get(responseRequestIDKey), r.URL.Path, w.Header().Get(xhttp.AmzRequestID),
globalDeploymentID)) globalDeploymentID))
} else { } else {
errorRespJSON = encodeResponseJSON(APIErrorResponse{ errorRespJSON = encodeResponseJSON(APIErrorResponse{
Code: hr.apiErr.Code, Code: hr.apiErr.Code,
Message: hr.errBody, Message: hr.errBody,
Resource: r.URL.Path, Resource: r.URL.Path,
RequestID: w.Header().Get(responseRequestIDKey), RequestID: w.Header().Get(xhttp.AmzRequestID),
HostID: globalDeploymentID, HostID: globalDeploymentID,
}) })
} }
if !started { if !started {
setCommonHeaders(w) setCommonHeaders(w)
w.Header().Set("Content-Type", string(mimeJSON)) w.Header().Set(xhttp.ContentType, string(mimeJSON))
w.WriteHeader(hr.apiErr.HTTPStatusCode) w.WriteHeader(hr.apiErr.HTTPStatusCode)
} }
w.Write(errorRespJSON) w.Write(errorRespJSON)
@ -1487,7 +1488,7 @@ func (a adminAPIHandlers) TraceHandler(w http.ResponseWriter, r *http.Request) {
// Avoid reusing tcp connection if read timeout is hit // Avoid reusing tcp connection if read timeout is hit
// This is needed to make r.Context().Done() work as // This is needed to make r.Context().Done() work as
// expected in case of read timeout // expected in case of read timeout
w.Header().Add("Connection", "close") w.Header().Add(xhttp.Connection, "close")
doneCh := make(chan struct{}) doneCh := make(chan struct{})
defer close(doneCh) defer close(doneCh)

View File

@ -20,11 +20,6 @@ import (
"encoding/xml" "encoding/xml"
) )
const (
// Response request id.
responseRequestIDKey = "x-amz-request-id"
)
// ObjectIdentifier carries key name for the object to delete. // ObjectIdentifier carries key name for the object to delete.
type ObjectIdentifier struct { type ObjectIdentifier struct {
ObjectName string `xml:"Key"` ObjectName string `xml:"Key"`

View File

@ -26,6 +26,7 @@ import (
"time" "time"
"github.com/minio/minio/cmd/crypto" "github.com/minio/minio/cmd/crypto"
xhttp "github.com/minio/minio/cmd/http"
) )
// Returns a hexadecimal representation of time at the // Returns a hexadecimal representation of time at the
@ -36,13 +37,13 @@ func mustGetRequestID(t time.Time) string {
// Write http common headers // Write http common headers
func setCommonHeaders(w http.ResponseWriter) { func setCommonHeaders(w http.ResponseWriter) {
w.Header().Set("Server", "MinIO/"+ReleaseTag) w.Header().Set(xhttp.ServerInfo, "MinIO/"+ReleaseTag)
// Set `x-amz-bucket-region` only if region is set on the server // Set `x-amz-bucket-region` only if region is set on the server
// by default minio uses an empty region. // by default minio uses an empty region.
if region := globalServerConfig.GetRegion(); region != "" { if region := globalServerConfig.GetRegion(); region != "" {
w.Header().Set("X-Amz-Bucket-Region", region) w.Header().Set(xhttp.AmzBucketRegion, region)
} }
w.Header().Set("Accept-Ranges", "bytes") w.Header().Set(xhttp.AcceptRanges, "bytes")
// Remove sensitive information // Remove sensitive information
crypto.RemoveSensitiveHeaders(w.Header()) crypto.RemoveSensitiveHeaders(w.Header())
@ -72,23 +73,23 @@ func setObjectHeaders(w http.ResponseWriter, objInfo ObjectInfo, rs *HTTPRangeSp
// Set last modified time. // Set last modified time.
lastModified := objInfo.ModTime.UTC().Format(http.TimeFormat) lastModified := objInfo.ModTime.UTC().Format(http.TimeFormat)
w.Header().Set("Last-Modified", lastModified) w.Header().Set(xhttp.LastModified, lastModified)
// Set Etag if available. // Set Etag if available.
if objInfo.ETag != "" { if objInfo.ETag != "" {
w.Header()["ETag"] = []string{"\"" + objInfo.ETag + "\""} w.Header()[xhttp.ETag] = []string{"\"" + objInfo.ETag + "\""}
} }
if objInfo.ContentType != "" { if objInfo.ContentType != "" {
w.Header().Set("Content-Type", objInfo.ContentType) w.Header().Set(xhttp.ContentType, objInfo.ContentType)
} }
if objInfo.ContentEncoding != "" { if objInfo.ContentEncoding != "" {
w.Header().Set("Content-Encoding", objInfo.ContentEncoding) w.Header().Set(xhttp.ContentEncoding, objInfo.ContentEncoding)
} }
if !objInfo.Expires.IsZero() { if !objInfo.Expires.IsZero() {
w.Header().Set("Expires", objInfo.Expires.UTC().Format(http.TimeFormat)) w.Header().Set(xhttp.Expires, objInfo.Expires.UTC().Format(http.TimeFormat))
} }
// Set all other user defined metadata. // Set all other user defined metadata.
@ -124,10 +125,10 @@ func setObjectHeaders(w http.ResponseWriter, objInfo ObjectInfo, rs *HTTPRangeSp
} }
// Set content length. // Set content length.
w.Header().Set("Content-Length", strconv.FormatInt(rangeLen, 10)) w.Header().Set(xhttp.ContentLength, strconv.FormatInt(rangeLen, 10))
if rs != nil { if rs != nil {
contentRange := fmt.Sprintf("bytes %d-%d/%d", start, start+rangeLen-1, totalObjectSize) contentRange := fmt.Sprintf("bytes %d-%d/%d", start, start+rangeLen-1, totalObjectSize)
w.Header().Set("Content-Range", contentRange) w.Header().Set(xhttp.ContentRange, contentRange)
} }
return nil return nil

View File

@ -26,6 +26,7 @@ import (
"strings" "strings"
"time" "time"
xhttp "github.com/minio/minio/cmd/http"
"github.com/minio/minio/cmd/logger" "github.com/minio/minio/cmd/logger"
"github.com/minio/minio/pkg/handlers" "github.com/minio/minio/pkg/handlers"
) )
@ -522,9 +523,9 @@ func generateMultiDeleteResponse(quiet bool, deletedObjects []ObjectIdentifier,
func writeResponse(w http.ResponseWriter, statusCode int, response []byte, mType mimeType) { func writeResponse(w http.ResponseWriter, statusCode int, response []byte, mType mimeType) {
setCommonHeaders(w) setCommonHeaders(w)
if mType != mimeNone { if mType != mimeNone {
w.Header().Set("Content-Type", string(mType)) w.Header().Set(xhttp.ContentType, string(mType))
} }
w.Header().Set("Content-Length", strconv.Itoa(len(response))) w.Header().Set(xhttp.ContentLength, strconv.Itoa(len(response)))
w.WriteHeader(statusCode) w.WriteHeader(statusCode)
if response != nil { if response != nil {
w.Write(response) w.Write(response)
@ -563,7 +564,7 @@ func writeSuccessNoContent(w http.ResponseWriter) {
// writeRedirectSeeOther writes Location header with http status 303 // writeRedirectSeeOther writes Location header with http status 303
func writeRedirectSeeOther(w http.ResponseWriter, location string) { func writeRedirectSeeOther(w http.ResponseWriter, location string) {
w.Header().Set("Location", location) w.Header().Set(xhttp.Location, location)
writeResponse(w, http.StatusSeeOther, nil, mimeNone) writeResponse(w, http.StatusSeeOther, nil, mimeNone)
} }
@ -577,12 +578,12 @@ func writeErrorResponse(ctx context.Context, w http.ResponseWriter, err APIError
case "SlowDown", "XMinioServerNotInitialized", "XMinioReadQuorum", "XMinioWriteQuorum": case "SlowDown", "XMinioServerNotInitialized", "XMinioReadQuorum", "XMinioWriteQuorum":
// Set retry-after header to indicate user-agents to retry request after 120secs. // Set retry-after header to indicate user-agents to retry request after 120secs.
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
w.Header().Set("Retry-After", "120") w.Header().Set(xhttp.RetryAfter, "120")
case "AccessDenied": case "AccessDenied":
// The request is from browser and also if browser // The request is from browser and also if browser
// is enabled we need to redirect. // is enabled we need to redirect.
if browser { if browser {
w.Header().Set("Location", minioReservedBucketPath+reqURL.Path) w.Header().Set(xhttp.Location, minioReservedBucketPath+reqURL.Path)
w.WriteHeader(http.StatusTemporaryRedirect) w.WriteHeader(http.StatusTemporaryRedirect)
return return
} }
@ -590,7 +591,7 @@ func writeErrorResponse(ctx context.Context, w http.ResponseWriter, err APIError
// Generate error response. // Generate error response.
errorResponse := getAPIErrorResponse(ctx, err, reqURL.Path, errorResponse := getAPIErrorResponse(ctx, err, reqURL.Path,
w.Header().Get(responseRequestIDKey), globalDeploymentID) w.Header().Get(xhttp.AmzRequestID), globalDeploymentID)
encodedErrorResponse := encodeResponse(errorResponse) encodedErrorResponse := encodeResponse(errorResponse)
writeResponse(w, err.HTTPStatusCode, encodedErrorResponse, mimeXML) writeResponse(w, err.HTTPStatusCode, encodedErrorResponse, mimeXML)
} }
@ -603,7 +604,7 @@ func writeErrorResponseHeadersOnly(w http.ResponseWriter, err APIError) {
// useful for admin APIs. // useful for admin APIs.
func writeErrorResponseJSON(ctx context.Context, w http.ResponseWriter, err APIError, reqURL *url.URL) { func writeErrorResponseJSON(ctx context.Context, w http.ResponseWriter, err APIError, reqURL *url.URL) {
// Generate error response. // Generate error response.
errorResponse := getAPIErrorResponse(ctx, err, reqURL.Path, w.Header().Get(responseRequestIDKey), globalDeploymentID) errorResponse := getAPIErrorResponse(ctx, err, reqURL.Path, w.Header().Get(xhttp.AmzRequestID), globalDeploymentID)
encodedErrorResponse := encodeResponseJSON(errorResponse) encodedErrorResponse := encodeResponseJSON(errorResponse)
writeResponse(w, err.HTTPStatusCode, encodedErrorResponse, mimeJSON) writeResponse(w, err.HTTPStatusCode, encodedErrorResponse, mimeJSON)
} }
@ -621,7 +622,7 @@ func writeCustomErrorResponseJSON(ctx context.Context, w http.ResponseWriter, er
Resource: reqURL.Path, Resource: reqURL.Path,
BucketName: reqInfo.BucketName, BucketName: reqInfo.BucketName,
Key: reqInfo.ObjectName, Key: reqInfo.ObjectName,
RequestID: w.Header().Get(responseRequestIDKey), RequestID: w.Header().Get(xhttp.AmzRequestID),
HostID: globalDeploymentID, HostID: globalDeploymentID,
} }
encodedErrorResponse := encodeResponseJSON(errorResponse) encodedErrorResponse := encodeResponseJSON(errorResponse)
@ -637,12 +638,12 @@ func writeCustomErrorResponseXML(ctx context.Context, w http.ResponseWriter, err
case "SlowDown", "XMinioServerNotInitialized", "XMinioReadQuorum", "XMinioWriteQuorum": case "SlowDown", "XMinioServerNotInitialized", "XMinioReadQuorum", "XMinioWriteQuorum":
// Set retry-after header to indicate user-agents to retry request after 120secs. // Set retry-after header to indicate user-agents to retry request after 120secs.
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
w.Header().Set("Retry-After", "120") w.Header().Set(xhttp.RetryAfter, "120")
case "AccessDenied": case "AccessDenied":
// The request is from browser and also if browser // The request is from browser and also if browser
// is enabled we need to redirect. // is enabled we need to redirect.
if browser && globalIsBrowserEnabled { if browser && globalIsBrowserEnabled {
w.Header().Set("Location", minioReservedBucketPath+reqURL.Path) w.Header().Set(xhttp.Location, minioReservedBucketPath+reqURL.Path)
w.WriteHeader(http.StatusTemporaryRedirect) w.WriteHeader(http.StatusTemporaryRedirect)
return return
} }
@ -655,7 +656,7 @@ func writeCustomErrorResponseXML(ctx context.Context, w http.ResponseWriter, err
Resource: reqURL.Path, Resource: reqURL.Path,
BucketName: reqInfo.BucketName, BucketName: reqInfo.BucketName,
Key: reqInfo.ObjectName, Key: reqInfo.ObjectName,
RequestID: w.Header().Get(responseRequestIDKey), RequestID: w.Header().Get(xhttp.AmzRequestID),
HostID: globalDeploymentID, HostID: globalDeploymentID,
} }

View File

@ -20,6 +20,7 @@ import (
"net/http" "net/http"
"github.com/gorilla/mux" "github.com/gorilla/mux"
xhttp "github.com/minio/minio/cmd/http"
) )
// objectAPIHandler implements and provides http handlers for S3 API. // objectAPIHandler implements and provides http handlers for S3 API.
@ -58,98 +59,98 @@ func registerAPIRouter(router *mux.Router, encryptionEnabled, allowSSEKMS bool)
for _, bucket := range routers { for _, bucket := range routers {
// Object operations // Object operations
// HeadObject // HeadObject
bucket.Methods("HEAD").Path("/{object:.+}").HandlerFunc(httpTraceAll(api.HeadObjectHandler)) bucket.Methods(http.MethodHead).Path("/{object:.+}").HandlerFunc(httpTraceAll(api.HeadObjectHandler))
// CopyObjectPart // CopyObjectPart
bucket.Methods("PUT").Path("/{object:.+}").HeadersRegexp("X-Amz-Copy-Source", ".*?(\\/|%2F).*?").HandlerFunc(httpTraceAll(api.CopyObjectPartHandler)).Queries("partNumber", "{partNumber:[0-9]+}", "uploadId", "{uploadId:.*}") bucket.Methods(http.MethodPut).Path("/{object:.+}").HeadersRegexp(xhttp.AmzCopySource, ".*?(\\/|%2F).*?").HandlerFunc(httpTraceAll(api.CopyObjectPartHandler)).Queries("partNumber", "{partNumber:[0-9]+}", "uploadId", "{uploadId:.*}")
// PutObjectPart // PutObjectPart
bucket.Methods("PUT").Path("/{object:.+}").HandlerFunc(httpTraceHdrs(api.PutObjectPartHandler)).Queries("partNumber", "{partNumber:[0-9]+}", "uploadId", "{uploadId:.*}") bucket.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc(httpTraceHdrs(api.PutObjectPartHandler)).Queries("partNumber", "{partNumber:[0-9]+}", "uploadId", "{uploadId:.*}")
// ListObjectPxarts // ListObjectPxarts
bucket.Methods("GET").Path("/{object:.+}").HandlerFunc(httpTraceAll(api.ListObjectPartsHandler)).Queries("uploadId", "{uploadId:.*}") bucket.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc(httpTraceAll(api.ListObjectPartsHandler)).Queries("uploadId", "{uploadId:.*}")
// CompleteMultipartUpload // CompleteMultipartUpload
bucket.Methods("POST").Path("/{object:.+}").HandlerFunc(httpTraceAll(api.CompleteMultipartUploadHandler)).Queries("uploadId", "{uploadId:.*}") bucket.Methods(http.MethodPost).Path("/{object:.+}").HandlerFunc(httpTraceAll(api.CompleteMultipartUploadHandler)).Queries("uploadId", "{uploadId:.*}")
// NewMultipartUpload // NewMultipartUpload
bucket.Methods("POST").Path("/{object:.+}").HandlerFunc(httpTraceAll(api.NewMultipartUploadHandler)).Queries("uploads", "") bucket.Methods(http.MethodPost).Path("/{object:.+}").HandlerFunc(httpTraceAll(api.NewMultipartUploadHandler)).Queries("uploads", "")
// AbortMultipartUpload // AbortMultipartUpload
bucket.Methods("DELETE").Path("/{object:.+}").HandlerFunc(httpTraceAll(api.AbortMultipartUploadHandler)).Queries("uploadId", "{uploadId:.*}") bucket.Methods(http.MethodDelete).Path("/{object:.+}").HandlerFunc(httpTraceAll(api.AbortMultipartUploadHandler)).Queries("uploadId", "{uploadId:.*}")
// GetObjectACL - this is a dummy call. // GetObjectACL - this is a dummy call.
bucket.Methods("GET").Path("/{object:.+}").HandlerFunc(httpTraceHdrs(api.GetObjectACLHandler)).Queries("acl", "") bucket.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc(httpTraceHdrs(api.GetObjectACLHandler)).Queries("acl", "")
// GetObjectTagging - this is a dummy call. // GetObjectTagging - this is a dummy call.
bucket.Methods("GET").Path("/{object:.+}").HandlerFunc(httpTraceHdrs(api.GetObjectTaggingHandler)).Queries("tagging", "") bucket.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc(httpTraceHdrs(api.GetObjectTaggingHandler)).Queries("tagging", "")
// SelectObjectContent // SelectObjectContent
bucket.Methods("POST").Path("/{object:.+}").HandlerFunc(httpTraceHdrs(api.SelectObjectContentHandler)).Queries("select", "").Queries("select-type", "2") bucket.Methods(http.MethodPost).Path("/{object:.+}").HandlerFunc(httpTraceHdrs(api.SelectObjectContentHandler)).Queries("select", "").Queries("select-type", "2")
// GetObject // GetObject
bucket.Methods("GET").Path("/{object:.+}").HandlerFunc(httpTraceHdrs(api.GetObjectHandler)) bucket.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc(httpTraceHdrs(api.GetObjectHandler))
// CopyObject // CopyObject
bucket.Methods("PUT").Path("/{object:.+}").HeadersRegexp("X-Amz-Copy-Source", ".*?(\\/|%2F).*?").HandlerFunc(httpTraceAll(api.CopyObjectHandler)) bucket.Methods(http.MethodPut).Path("/{object:.+}").HeadersRegexp(xhttp.AmzCopySource, ".*?(\\/|%2F).*?").HandlerFunc(httpTraceAll(api.CopyObjectHandler))
// PutObject // PutObject
bucket.Methods("PUT").Path("/{object:.+}").HandlerFunc(httpTraceHdrs(api.PutObjectHandler)) bucket.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc(httpTraceHdrs(api.PutObjectHandler))
// DeleteObject // DeleteObject
bucket.Methods("DELETE").Path("/{object:.+}").HandlerFunc(httpTraceAll(api.DeleteObjectHandler)) bucket.Methods(http.MethodDelete).Path("/{object:.+}").HandlerFunc(httpTraceAll(api.DeleteObjectHandler))
/// Bucket operations /// Bucket operations
// GetBucketLocation // GetBucketLocation
bucket.Methods("GET").HandlerFunc(httpTraceAll(api.GetBucketLocationHandler)).Queries("location", "") bucket.Methods(http.MethodGet).HandlerFunc(httpTraceAll(api.GetBucketLocationHandler)).Queries("location", "")
// GetBucketPolicy // GetBucketPolicy
bucket.Methods("GET").HandlerFunc(httpTraceAll(api.GetBucketPolicyHandler)).Queries("policy", "") bucket.Methods(http.MethodGet).HandlerFunc(httpTraceAll(api.GetBucketPolicyHandler)).Queries("policy", "")
// Dummy Bucket Calls // Dummy Bucket Calls
// GetBucketACL -- this is a dummy call. // GetBucketACL -- this is a dummy call.
bucket.Methods("GET").HandlerFunc(httpTraceAll(api.GetBucketACLHandler)).Queries("acl", "") bucket.Methods(http.MethodGet).HandlerFunc(httpTraceAll(api.GetBucketACLHandler)).Queries("acl", "")
// GetBucketCors - this is a dummy call. // GetBucketCors - this is a dummy call.
bucket.Methods("GET").HandlerFunc(httpTraceAll(api.GetBucketCorsHandler)).Queries("cors", "") bucket.Methods(http.MethodGet).HandlerFunc(httpTraceAll(api.GetBucketCorsHandler)).Queries("cors", "")
// GetBucketWebsiteHandler - this is a dummy call. // GetBucketWebsiteHandler - this is a dummy call.
bucket.Methods("GET").HandlerFunc(httpTraceAll(api.GetBucketWebsiteHandler)).Queries("website", "") bucket.Methods(http.MethodGet).HandlerFunc(httpTraceAll(api.GetBucketWebsiteHandler)).Queries("website", "")
// GetBucketVersioningHandler - this is a dummy call. // GetBucketVersioningHandler - this is a dummy call.
bucket.Methods("GET").HandlerFunc(httpTraceAll(api.GetBucketVersioningHandler)).Queries("versioning", "") bucket.Methods(http.MethodGet).HandlerFunc(httpTraceAll(api.GetBucketVersioningHandler)).Queries("versioning", "")
// GetBucketAccelerateHandler - this is a dummy call. // GetBucketAccelerateHandler - this is a dummy call.
bucket.Methods("GET").HandlerFunc(httpTraceAll(api.GetBucketAccelerateHandler)).Queries("accelerate", "") bucket.Methods(http.MethodGet).HandlerFunc(httpTraceAll(api.GetBucketAccelerateHandler)).Queries("accelerate", "")
// GetBucketRequestPaymentHandler - this is a dummy call. // GetBucketRequestPaymentHandler - this is a dummy call.
bucket.Methods("GET").HandlerFunc(httpTraceAll(api.GetBucketRequestPaymentHandler)).Queries("requestPayment", "") bucket.Methods(http.MethodGet).HandlerFunc(httpTraceAll(api.GetBucketRequestPaymentHandler)).Queries("requestPayment", "")
// GetBucketLoggingHandler - this is a dummy call. // GetBucketLoggingHandler - this is a dummy call.
bucket.Methods("GET").HandlerFunc(httpTraceAll(api.GetBucketLoggingHandler)).Queries("logging", "") bucket.Methods(http.MethodGet).HandlerFunc(httpTraceAll(api.GetBucketLoggingHandler)).Queries("logging", "")
// GetBucketLifecycleHandler - this is a dummy call. // GetBucketLifecycleHandler - this is a dummy call.
bucket.Methods("GET").HandlerFunc(httpTraceAll(api.GetBucketLifecycleHandler)).Queries("lifecycle", "") bucket.Methods(http.MethodGet).HandlerFunc(httpTraceAll(api.GetBucketLifecycleHandler)).Queries("lifecycle", "")
// GetBucketReplicationHandler - this is a dummy call. // GetBucketReplicationHandler - this is a dummy call.
bucket.Methods("GET").HandlerFunc(httpTraceAll(api.GetBucketReplicationHandler)).Queries("replication", "") bucket.Methods(http.MethodGet).HandlerFunc(httpTraceAll(api.GetBucketReplicationHandler)).Queries("replication", "")
// GetBucketTaggingHandler - this is a dummy call. // GetBucketTaggingHandler - this is a dummy call.
bucket.Methods("GET").HandlerFunc(httpTraceAll(api.GetBucketTaggingHandler)).Queries("tagging", "") bucket.Methods(http.MethodGet).HandlerFunc(httpTraceAll(api.GetBucketTaggingHandler)).Queries("tagging", "")
//DeleteBucketWebsiteHandler //DeleteBucketWebsiteHandler
bucket.Methods("DELETE").HandlerFunc(httpTraceAll(api.DeleteBucketWebsiteHandler)).Queries("website", "") bucket.Methods(http.MethodDelete).HandlerFunc(httpTraceAll(api.DeleteBucketWebsiteHandler)).Queries("website", "")
// DeleteBucketTaggingHandler // DeleteBucketTaggingHandler
bucket.Methods("DELETE").HandlerFunc(httpTraceAll(api.DeleteBucketTaggingHandler)).Queries("tagging", "") bucket.Methods(http.MethodDelete).HandlerFunc(httpTraceAll(api.DeleteBucketTaggingHandler)).Queries("tagging", "")
// GetBucketNotification // GetBucketNotification
bucket.Methods("GET").HandlerFunc(httpTraceAll(api.GetBucketNotificationHandler)).Queries("notification", "") bucket.Methods(http.MethodGet).HandlerFunc(httpTraceAll(api.GetBucketNotificationHandler)).Queries("notification", "")
// ListenBucketNotification // ListenBucketNotification
bucket.Methods("GET").HandlerFunc(httpTraceAll(api.ListenBucketNotificationHandler)).Queries("events", "{events:.*}") bucket.Methods(http.MethodGet).HandlerFunc(httpTraceAll(api.ListenBucketNotificationHandler)).Queries("events", "{events:.*}")
// ListMultipartUploads // ListMultipartUploads
bucket.Methods("GET").HandlerFunc(httpTraceAll(api.ListMultipartUploadsHandler)).Queries("uploads", "") bucket.Methods(http.MethodGet).HandlerFunc(httpTraceAll(api.ListMultipartUploadsHandler)).Queries("uploads", "")
// ListObjectsV2 // ListObjectsV2
bucket.Methods("GET").HandlerFunc(httpTraceAll(api.ListObjectsV2Handler)).Queries("list-type", "2") bucket.Methods(http.MethodGet).HandlerFunc(httpTraceAll(api.ListObjectsV2Handler)).Queries("list-type", "2")
// ListObjectsV1 (Legacy) // ListObjectsV1 (Legacy)
bucket.Methods("GET").HandlerFunc(httpTraceAll(api.ListObjectsV1Handler)) bucket.Methods(http.MethodGet).HandlerFunc(httpTraceAll(api.ListObjectsV1Handler))
// PutBucketPolicy // PutBucketPolicy
bucket.Methods("PUT").HandlerFunc(httpTraceAll(api.PutBucketPolicyHandler)).Queries("policy", "") bucket.Methods(http.MethodPut).HandlerFunc(httpTraceAll(api.PutBucketPolicyHandler)).Queries("policy", "")
// PutBucketNotification // PutBucketNotification
bucket.Methods("PUT").HandlerFunc(httpTraceAll(api.PutBucketNotificationHandler)).Queries("notification", "") bucket.Methods(http.MethodPut).HandlerFunc(httpTraceAll(api.PutBucketNotificationHandler)).Queries("notification", "")
// PutBucket // PutBucket
bucket.Methods("PUT").HandlerFunc(httpTraceAll(api.PutBucketHandler)) bucket.Methods(http.MethodPut).HandlerFunc(httpTraceAll(api.PutBucketHandler))
// HeadBucket // HeadBucket
bucket.Methods("HEAD").HandlerFunc(httpTraceAll(api.HeadBucketHandler)) bucket.Methods(http.MethodHead).HandlerFunc(httpTraceAll(api.HeadBucketHandler))
// PostPolicy // PostPolicy
bucket.Methods("POST").HeadersRegexp("Content-Type", "multipart/form-data*").HandlerFunc(httpTraceHdrs(api.PostPolicyBucketHandler)) bucket.Methods(http.MethodPost).HeadersRegexp(xhttp.ContentType, "multipart/form-data*").HandlerFunc(httpTraceHdrs(api.PostPolicyBucketHandler))
// DeleteMultipleObjects // DeleteMultipleObjects
bucket.Methods("POST").HandlerFunc(httpTraceAll(api.DeleteMultipleObjectsHandler)).Queries("delete", "") bucket.Methods(http.MethodPost).HandlerFunc(httpTraceAll(api.DeleteMultipleObjectsHandler)).Queries("delete", "")
// DeleteBucketPolicy // DeleteBucketPolicy
bucket.Methods("DELETE").HandlerFunc(httpTraceAll(api.DeleteBucketPolicyHandler)).Queries("policy", "") bucket.Methods(http.MethodDelete).HandlerFunc(httpTraceAll(api.DeleteBucketPolicyHandler)).Queries("policy", "")
// DeleteBucket // DeleteBucket
bucket.Methods("DELETE").HandlerFunc(httpTraceAll(api.DeleteBucketHandler)) bucket.Methods(http.MethodDelete).HandlerFunc(httpTraceAll(api.DeleteBucketHandler))
} }
/// Root operation /// Root operation
// ListBuckets // ListBuckets
apiRouter.Methods("GET").Path("/").HandlerFunc(httpTraceAll(api.ListBucketsHandler)) apiRouter.Methods(http.MethodGet).Path("/").HandlerFunc(httpTraceAll(api.ListBucketsHandler))
// If none of the routes match. // If none of the routes match.
apiRouter.NotFoundHandler = http.HandlerFunc(httpTraceAll(notFoundHandler)) apiRouter.NotFoundHandler = http.HandlerFunc(httpTraceAll(notFoundHandler))

View File

@ -29,6 +29,7 @@ import (
"strings" "strings"
jwtgo "github.com/dgrijalva/jwt-go" jwtgo "github.com/dgrijalva/jwt-go"
xhttp "github.com/minio/minio/cmd/http"
"github.com/minio/minio/cmd/logger" "github.com/minio/minio/cmd/logger"
"github.com/minio/minio/pkg/auth" "github.com/minio/minio/pkg/auth"
"github.com/minio/minio/pkg/hash" "github.com/minio/minio/pkg/hash"
@ -38,41 +39,41 @@ import (
// Verify if request has JWT. // Verify if request has JWT.
func isRequestJWT(r *http.Request) bool { func isRequestJWT(r *http.Request) bool {
return strings.HasPrefix(r.Header.Get("Authorization"), jwtAlgorithm) return strings.HasPrefix(r.Header.Get(xhttp.Authorization), jwtAlgorithm)
} }
// Verify if request has AWS Signature Version '4'. // Verify if request has AWS Signature Version '4'.
func isRequestSignatureV4(r *http.Request) bool { func isRequestSignatureV4(r *http.Request) bool {
return strings.HasPrefix(r.Header.Get("Authorization"), signV4Algorithm) return strings.HasPrefix(r.Header.Get(xhttp.Authorization), signV4Algorithm)
} }
// Verify if request has AWS Signature Version '2'. // Verify if request has AWS Signature Version '2'.
func isRequestSignatureV2(r *http.Request) bool { func isRequestSignatureV2(r *http.Request) bool {
return (!strings.HasPrefix(r.Header.Get("Authorization"), signV4Algorithm) && return (!strings.HasPrefix(r.Header.Get(xhttp.Authorization), signV4Algorithm) &&
strings.HasPrefix(r.Header.Get("Authorization"), signV2Algorithm)) strings.HasPrefix(r.Header.Get(xhttp.Authorization), signV2Algorithm))
} }
// Verify if request has AWS PreSign Version '4'. // Verify if request has AWS PreSign Version '4'.
func isRequestPresignedSignatureV4(r *http.Request) bool { func isRequestPresignedSignatureV4(r *http.Request) bool {
_, ok := r.URL.Query()["X-Amz-Credential"] _, ok := r.URL.Query()[xhttp.AmzCredential]
return ok return ok
} }
// Verify request has AWS PreSign Version '2'. // Verify request has AWS PreSign Version '2'.
func isRequestPresignedSignatureV2(r *http.Request) bool { func isRequestPresignedSignatureV2(r *http.Request) bool {
_, ok := r.URL.Query()["AWSAccessKeyId"] _, ok := r.URL.Query()[xhttp.AmzAccessKeyID]
return ok return ok
} }
// Verify if request has AWS Post policy Signature Version '4'. // Verify if request has AWS Post policy Signature Version '4'.
func isRequestPostPolicySignatureV4(r *http.Request) bool { func isRequestPostPolicySignatureV4(r *http.Request) bool {
return strings.Contains(r.Header.Get("Content-Type"), "multipart/form-data") && return strings.Contains(r.Header.Get(xhttp.ContentType), "multipart/form-data") &&
r.Method == http.MethodPost r.Method == http.MethodPost
} }
// Verify if the request has AWS Streaming Signature Version '4'. This is only valid for 'PUT' operation. // Verify if the request has AWS Streaming Signature Version '4'. This is only valid for 'PUT' operation.
func isRequestSignStreamingV4(r *http.Request) bool { func isRequestSignStreamingV4(r *http.Request) bool {
return r.Header.Get("x-amz-content-sha256") == streamingContentSHA256 && return r.Header.Get(xhttp.AmzContentSha256) == streamingContentSHA256 &&
r.Method == http.MethodPut r.Method == http.MethodPut
} }
@ -109,9 +110,9 @@ func getRequestAuthType(r *http.Request) authType {
return authTypeJWT return authTypeJWT
} else if isRequestPostPolicySignatureV4(r) { } else if isRequestPostPolicySignatureV4(r) {
return authTypePostPolicy return authTypePostPolicy
} else if _, ok := r.URL.Query()["Action"]; ok { } else if _, ok := r.URL.Query()[xhttp.Action]; ok {
return authTypeSTS return authTypeSTS
} else if _, ok := r.Header["Authorization"]; !ok { } else if _, ok := r.Header[xhttp.Authorization]; !ok {
return authTypeAnonymous return authTypeAnonymous
} }
return authTypeUnknown return authTypeUnknown
@ -121,7 +122,7 @@ func getRequestAuthType(r *http.Request) authType {
// It does not accept presigned or JWT or anonymous requests. // It does not accept presigned or JWT or anonymous requests.
func checkAdminRequestAuthType(ctx context.Context, r *http.Request, region string) APIErrorCode { func checkAdminRequestAuthType(ctx context.Context, r *http.Request, region string) APIErrorCode {
s3Err := ErrAccessDenied s3Err := ErrAccessDenied
if _, ok := r.Header["X-Amz-Content-Sha256"]; ok && if _, ok := r.Header[xhttp.AmzContentSha256]; ok &&
getRequestAuthType(r) == authTypeSigned && !skipContentSha256Cksum(r) { getRequestAuthType(r) == authTypeSigned && !skipContentSha256Cksum(r) {
// We only support admin credentials to access admin APIs. // We only support admin credentials to access admin APIs.
@ -148,11 +149,11 @@ func checkAdminRequestAuthType(ctx context.Context, r *http.Request, region stri
// Fetch the security token set by the client. // Fetch the security token set by the client.
func getSessionToken(r *http.Request) (token string) { func getSessionToken(r *http.Request) (token string) {
token = r.Header.Get("X-Amz-Security-Token") token = r.Header.Get(xhttp.AmzSecurityToken)
if token != "" { if token != "" {
return token return token
} }
return r.URL.Query().Get("X-Amz-Security-Token") return r.URL.Query().Get(xhttp.AmzSecurityToken)
} }
// Fetch claims in the security token returned by the client, doesn't return // Fetch claims in the security token returned by the client, doesn't return
@ -370,8 +371,8 @@ func isReqAuthenticated(ctx context.Context, r *http.Request, region string, sty
contentMD5, contentSHA256 []byte contentMD5, contentSHA256 []byte
) )
// Extract 'Content-Md5' if present. // Extract 'Content-Md5' if present.
if _, ok := r.Header["Content-Md5"]; ok { if _, ok := r.Header[xhttp.ContentMD5]; ok {
contentMD5, err = base64.StdEncoding.Strict().DecodeString(r.Header.Get("Content-Md5")) contentMD5, err = base64.StdEncoding.Strict().DecodeString(r.Header.Get(xhttp.ContentMD5))
if err != nil || len(contentMD5) == 0 { if err != nil || len(contentMD5) == 0 {
return ErrInvalidDigest return ErrInvalidDigest
} }
@ -380,14 +381,14 @@ func isReqAuthenticated(ctx context.Context, r *http.Request, region string, sty
// Extract either 'X-Amz-Content-Sha256' header or 'X-Amz-Content-Sha256' query parameter (if V4 presigned) // Extract either 'X-Amz-Content-Sha256' header or 'X-Amz-Content-Sha256' query parameter (if V4 presigned)
// Do not verify 'X-Amz-Content-Sha256' if skipSHA256. // Do not verify 'X-Amz-Content-Sha256' if skipSHA256.
if skipSHA256 := skipContentSha256Cksum(r); !skipSHA256 && isRequestPresignedSignatureV4(r) { if skipSHA256 := skipContentSha256Cksum(r); !skipSHA256 && isRequestPresignedSignatureV4(r) {
if sha256Sum, ok := r.URL.Query()["X-Amz-Content-Sha256"]; ok && len(sha256Sum) > 0 { if sha256Sum, ok := r.URL.Query()[xhttp.AmzContentSha256]; ok && len(sha256Sum) > 0 {
contentSHA256, err = hex.DecodeString(sha256Sum[0]) contentSHA256, err = hex.DecodeString(sha256Sum[0])
if err != nil { if err != nil {
return ErrContentSHA256Mismatch return ErrContentSHA256Mismatch
} }
} }
} else if _, ok := r.Header["X-Amz-Content-Sha256"]; !skipSHA256 && ok { } else if _, ok := r.Header[xhttp.AmzContentSha256]; !skipSHA256 && ok {
contentSHA256, err = hex.DecodeString(r.Header.Get("X-Amz-Content-Sha256")) contentSHA256, err = hex.DecodeString(r.Header.Get(xhttp.AmzContentSha256))
if err != nil || len(contentSHA256) == 0 { if err != nil || len(contentSHA256) == 0 {
return ErrContentSHA256Mismatch return ErrContentSHA256Mismatch
} }
@ -395,7 +396,8 @@ func isReqAuthenticated(ctx context.Context, r *http.Request, region string, sty
// Verify 'Content-Md5' and/or 'X-Amz-Content-Sha256' if present. // Verify 'Content-Md5' and/or 'X-Amz-Content-Sha256' if present.
// The verification happens implicit during reading. // The verification happens implicit during reading.
reader, err := hash.NewReader(r.Body, -1, hex.EncodeToString(contentMD5), hex.EncodeToString(contentSHA256), -1, globalCLIContext.StrictS3Compat) reader, err := hash.NewReader(r.Body, -1, hex.EncodeToString(contentMD5),
hex.EncodeToString(contentSHA256), -1, globalCLIContext.StrictS3Compat)
if err != nil { if err != nil {
return toAPIErrorCode(ctx, err) return toAPIErrorCode(ctx, err)
} }

View File

@ -32,6 +32,7 @@ import (
"github.com/minio/minio-go/v6/pkg/set" "github.com/minio/minio-go/v6/pkg/set"
"github.com/minio/minio/cmd/crypto" "github.com/minio/minio/cmd/crypto"
xhttp "github.com/minio/minio/cmd/http"
"github.com/minio/minio/cmd/logger" "github.com/minio/minio/cmd/logger"
"github.com/minio/minio/pkg/dns" "github.com/minio/minio/pkg/dns"
"github.com/minio/minio/pkg/event" "github.com/minio/minio/pkg/event"
@ -445,7 +446,8 @@ func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Req
} }
// Make sure to add Location information here only for bucket // Make sure to add Location information here only for bucket
w.Header().Set("Location", getObjectLocation(r, globalDomainNames, bucket, "")) w.Header().Set(xhttp.Location,
getObjectLocation(r, globalDomainNames, bucket, ""))
writeSuccessResponseHeadersOnly(w) writeSuccessResponseHeadersOnly(w)
return return
@ -466,7 +468,7 @@ func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Req
} }
// Make sure to add Location information here only for bucket // Make sure to add Location information here only for bucket
w.Header().Set("Location", path.Clean(r.URL.Path)) // Clean any trailing slashes. w.Header().Set(xhttp.Location, path.Clean(r.URL.Path)) // Clean any trailing slashes.
writeSuccessResponseHeadersOnly(w) writeSuccessResponseHeadersOnly(w)
} }
@ -681,8 +683,8 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h
} }
location := getObjectLocation(r, globalDomainNames, bucket, object) location := getObjectLocation(r, globalDomainNames, bucket, object)
w.Header()["ETag"] = []string{`"` + objInfo.ETag + `"`} w.Header()[xhttp.ETag] = []string{`"` + objInfo.ETag + `"`}
w.Header().Set("Location", location) w.Header().Set(xhttp.Location, location)
// Notify object created event. // Notify object created event.
defer sendEvent(eventArgs{ defer sendEvent(eventArgs{

View File

@ -21,6 +21,7 @@ import (
"os" "os"
"strings" "strings"
xhttp "github.com/minio/minio/cmd/http"
"github.com/minio/minio/cmd/logger" "github.com/minio/minio/cmd/logger"
"github.com/minio/minio/pkg/hash" "github.com/minio/minio/pkg/hash"
@ -166,7 +167,7 @@ func FromMinioClientListMultipartsInfo(lmur minio.ListMultipartUploadsResult) Li
// FromMinioClientObjectInfo converts minio ObjectInfo to gateway ObjectInfo // FromMinioClientObjectInfo converts minio ObjectInfo to gateway ObjectInfo
func FromMinioClientObjectInfo(bucket string, oi minio.ObjectInfo) ObjectInfo { func FromMinioClientObjectInfo(bucket string, oi minio.ObjectInfo) ObjectInfo {
userDefined := FromMinioClientMetadata(oi.Metadata) userDefined := FromMinioClientMetadata(oi.Metadata)
userDefined["Content-Type"] = oi.ContentType userDefined[xhttp.ContentType] = oi.ContentType
return ObjectInfo{ return ObjectInfo{
Bucket: bucket, Bucket: bucket,
@ -176,7 +177,7 @@ func FromMinioClientObjectInfo(bucket string, oi minio.ObjectInfo) ObjectInfo {
ETag: canonicalizeETag(oi.ETag), ETag: canonicalizeETag(oi.ETag),
UserDefined: userDefined, UserDefined: userDefined,
ContentType: oi.ContentType, ContentType: oi.ContentType,
ContentEncoding: oi.Metadata.Get("Content-Encoding"), ContentEncoding: oi.Metadata.Get(xhttp.ContentEncoding),
StorageClass: oi.StorageClass, StorageClass: oi.StorageClass,
Expires: oi.Expires, Expires: oi.Expires,
} }

View File

@ -28,6 +28,7 @@ import (
humanize "github.com/dustin/go-humanize" humanize "github.com/dustin/go-humanize"
"github.com/minio/minio/cmd/crypto" "github.com/minio/minio/cmd/crypto"
xhttp "github.com/minio/minio/cmd/http"
"github.com/minio/minio/cmd/logger" "github.com/minio/minio/cmd/logger"
"github.com/minio/minio/pkg/dns" "github.com/minio/minio/pkg/dns"
"github.com/minio/minio/pkg/handlers" "github.com/minio/minio/pkg/handlers"
@ -261,10 +262,10 @@ func (h cacheControlHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if hasSuffix(r.URL.Path, ".js") || r.URL.Path == minioReservedBucketPath+"/favicon.ico" { if hasSuffix(r.URL.Path, ".js") || r.URL.Path == minioReservedBucketPath+"/favicon.ico" {
// For assets set cache expiry of one year. For each release, the name // For assets set cache expiry of one year. For each release, the name
// of the asset name will change and hence it can not be served from cache. // of the asset name will change and hence it can not be served from cache.
w.Header().Set("Cache-Control", "max-age=31536000") w.Header().Set(xhttp.CacheControl, "max-age=31536000")
} else { } else {
// For non asset requests we serve index.html which will never be cached. // For non asset requests we serve index.html which will never be cached.
w.Header().Set("Cache-Control", "no-store") w.Header().Set(xhttp.CacheControl, "no-store")
} }
} }
} }
@ -380,15 +381,15 @@ type resourceHandler struct {
// setCorsHandler handler for CORS (Cross Origin Resource Sharing) // setCorsHandler handler for CORS (Cross Origin Resource Sharing)
func setCorsHandler(h http.Handler) http.Handler { func setCorsHandler(h http.Handler) http.Handler {
commonS3Headers := []string{ commonS3Headers := []string{
"Date", xhttp.Date,
"ETag", xhttp.ETag,
"Server", xhttp.ServerInfo,
"Connection", xhttp.Connection,
"Accept-Ranges", xhttp.AcceptRanges,
"Content-Range", xhttp.ContentRange,
"Content-Encoding", xhttp.ContentEncoding,
"Content-Length", xhttp.ContentLength,
"Content-Type", xhttp.ContentType,
"X-Amz*", "X-Amz*",
"x-amz*", "x-amz*",
"*", "*",
@ -765,7 +766,7 @@ func addCustomHeaders(h http.Handler) http.Handler {
func (s customHeaderHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (s customHeaderHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Set custom headers such as x-amz-request-id for each request. // Set custom headers such as x-amz-request-id for each request.
w.Header().Set(responseRequestIDKey, mustGetRequestID(UTCNow())) w.Header().Set(xhttp.AmzRequestID, mustGetRequestID(UTCNow()))
s.handler.ServeHTTP(logger.NewResponseWriter(w), r) s.handler.ServeHTTP(logger.NewResponseWriter(w), r)
} }

View File

@ -27,6 +27,7 @@ import (
"net/url" "net/url"
"strings" "strings"
xhttp "github.com/minio/minio/cmd/http"
"github.com/minio/minio/cmd/logger" "github.com/minio/minio/cmd/logger"
"github.com/minio/minio/pkg/auth" "github.com/minio/minio/pkg/auth"
"github.com/minio/minio/pkg/handlers" "github.com/minio/minio/pkg/handlers"
@ -219,8 +220,8 @@ func extractReqParams(r *http.Request) map[string]string {
func extractRespElements(w http.ResponseWriter) map[string]string { func extractRespElements(w http.ResponseWriter) map[string]string {
return map[string]string{ return map[string]string{
"requestId": w.Header().Get(responseRequestIDKey), "requestId": w.Header().Get(xhttp.AmzRequestID),
"content-length": w.Header().Get("Content-Length"), "content-length": w.Header().Get(xhttp.ContentLength),
// Add more fields here. // Add more fields here.
} }
} }

81
cmd/http/headers.go Normal file
View File

@ -0,0 +1,81 @@
/*
* MinIO Cloud Storage, (C) 2019 MinIO, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package http
// Standard S3 HTTP response constants
const (
LastModified = "Last-Modified"
Date = "Date"
ETag = "ETag"
ContentType = "Content-Type"
ContentMD5 = "Content-Md5"
ContentEncoding = "Content-Encoding"
Expires = "Expires"
ContentLength = "Content-Length"
ContentLanguage = "Content-Language"
ContentRange = "Content-Range"
Connection = "Connection"
AcceptRanges = "Accept-Ranges"
AmzBucketRegion = "X-Amz-Bucket-Region"
ServerInfo = "Server"
RetryAfter = "Retry-After"
Location = "Location"
CacheControl = "Cache-Control"
ContentDisposition = "Content-Disposition"
Authorization = "Authorization"
Action = "Action"
)
// Standard S3 HTTP request constants
const (
IfModifiedSince = "If-Modified-Since"
IfUnmodifiedSince = "If-Unmodified-Since"
IfMatch = "If-Match"
IfNoneMatch = "If-None-Match"
// S3 extensions
AmzCopySourceIfModifiedSince = "x-amz-copy-source-if-modified-since"
AmzCopySourceIfUnmodifiedSince = "x-amz-copy-source-if-unmodified-since"
AmzCopySourceIfNoneMatch = "x-amz-copy-source-if-none-match"
AmzCopySourceIfMatch = "x-amz-copy-source-if-match"
AmzCopySource = "X-Amz-Copy-Source"
AmzCopySourceVersionID = "X-Amz-Copy-Source-Version-Id"
AmzCopySourceRange = "X-Amz-Copy-Source-Range"
// Signature V4 related contants.
AmzContentSha256 = "X-Amz-Content-Sha256"
AmzDate = "X-Amz-Date"
AmzAlgorithm = "X-Amz-Algorithm"
AmzExpires = "X-Amz-Expires"
AmzSignedHeaders = "X-Amz-SignedHeaders"
AmzSignature = "X-Amz-Signature"
AmzCredential = "X-Amz-Credential"
AmzSecurityToken = "X-Amz-Security-Token"
AmzDecodedContentLength = "X-Amz-Decoded-Content-Length"
// Signature v2 related constants
AmzSignatureV2 = "Signature"
AmzAccessKeyID = "AWSAccessKeyId"
// Response request id.
AmzRequestID = "x-amz-request-id"
// Deployment id.
MinioDeploymentID = "x-minio-deployment-id"
)

View File

@ -22,6 +22,7 @@ import (
"time" "time"
"github.com/gorilla/mux" "github.com/gorilla/mux"
xhttp "github.com/minio/minio/cmd/http"
"github.com/minio/minio/pkg/handlers" "github.com/minio/minio/pkg/handlers"
) )
@ -67,13 +68,13 @@ func ToEntry(w http.ResponseWriter, r *http.Request, api string, statusCode int,
for k, v := range w.Header() { for k, v := range w.Header() {
respHeader[k] = strings.Join(v, ",") respHeader[k] = strings.Join(v, ",")
} }
respHeader["Etag"] = strings.Trim(respHeader["Etag"], `"`) respHeader[xhttp.ETag] = strings.Trim(respHeader[xhttp.ETag], `"`)
entry := Entry{ entry := Entry{
Version: Version, Version: Version,
DeploymentID: deploymentID, DeploymentID: deploymentID,
RemoteHost: handlers.GetSourceIP(r), RemoteHost: handlers.GetSourceIP(r),
RequestID: w.Header().Get("x-amz-request-id"), RequestID: w.Header().Get(xhttp.AmzRequestID),
UserAgent: r.UserAgent(), UserAgent: r.UserAgent(),
Time: time.Now().UTC().Format(time.RFC3339Nano), Time: time.Now().UTC().Format(time.RFC3339Nano),
ReqQuery: reqQuery, ReqQuery: reqQuery,

View File

@ -20,6 +20,7 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"errors" "errors"
"net/http"
gohttp "net/http" gohttp "net/http"
xhttp "github.com/minio/minio/cmd/http" xhttp "github.com/minio/minio/cmd/http"
@ -49,11 +50,11 @@ func (h *Target) startHTTPLogger() {
continue continue
} }
req, err := gohttp.NewRequest("POST", h.endpoint, bytes.NewBuffer(logJSON)) req, err := gohttp.NewRequest(http.MethodPost, h.endpoint, bytes.NewBuffer(logJSON))
if err != nil { if err != nil {
continue continue
} }
req.Header.Set("Content-Type", "application/json") req.Header.Set(xhttp.ContentType, "application/json")
resp, err := h.client.Do(req) resp, err := h.client.Do(req)
if err != nil { if err != nil {

View File

@ -36,6 +36,7 @@ import (
snappy "github.com/golang/snappy" snappy "github.com/golang/snappy"
"github.com/minio/minio-go/v6/pkg/s3utils" "github.com/minio/minio-go/v6/pkg/s3utils"
"github.com/minio/minio/cmd/crypto" "github.com/minio/minio/cmd/crypto"
xhttp "github.com/minio/minio/cmd/http"
"github.com/minio/minio/cmd/logger" "github.com/minio/minio/cmd/logger"
"github.com/minio/minio/pkg/dns" "github.com/minio/minio/pkg/dns"
"github.com/minio/minio/pkg/hash" "github.com/minio/minio/pkg/hash"
@ -346,7 +347,7 @@ func isCompressible(header http.Header, object string) bool {
// Eliminate the non-compressible objects. // Eliminate the non-compressible objects.
func excludeForCompression(header http.Header, object string) bool { func excludeForCompression(header http.Header, object string) bool {
objStr := object objStr := object
contentType := header.Get("Content-Type") contentType := header.Get(xhttp.ContentType)
if globalIsCompressionEnabled { if globalIsCompressionEnabled {
// We strictly disable compression for standard extensions/content-types (`compressed`). // We strictly disable compression for standard extensions/content-types (`compressed`).
if hasStringSuffixInSlice(objStr, standardExcludeCompressExtensions) || hasPattern(standardExcludeCompressContentTypes, contentType) { if hasStringSuffixInSlice(objStr, standardExcludeCompressExtensions) || hasPattern(standardExcludeCompressContentTypes, contentType) {

View File

@ -23,6 +23,7 @@ import (
"time" "time"
"github.com/minio/minio/cmd/crypto" "github.com/minio/minio/cmd/crypto"
xhttp "github.com/minio/minio/cmd/http"
"github.com/minio/minio/pkg/event" "github.com/minio/minio/pkg/event"
"github.com/minio/minio/pkg/handlers" "github.com/minio/minio/pkg/handlers"
) )
@ -49,7 +50,7 @@ func checkCopyObjectPartPreconditions(ctx context.Context, w http.ResponseWriter
// x-amz-copy-source-if-none-match // x-amz-copy-source-if-none-match
func checkCopyObjectPreconditions(ctx context.Context, w http.ResponseWriter, r *http.Request, objInfo ObjectInfo, encETag string) bool { func checkCopyObjectPreconditions(ctx context.Context, w http.ResponseWriter, r *http.Request, objInfo ObjectInfo, encETag string) bool {
// Return false for methods other than GET and HEAD. // Return false for methods other than GET and HEAD.
if r.Method != "PUT" { if r.Method != http.MethodPut {
return false return false
} }
if encETag == "" { if encETag == "" {
@ -68,15 +69,15 @@ func checkCopyObjectPreconditions(ctx context.Context, w http.ResponseWriter, r
setCommonHeaders(w) setCommonHeaders(w)
// set object-related metadata headers // set object-related metadata headers
w.Header().Set("Last-Modified", objInfo.ModTime.UTC().Format(http.TimeFormat)) w.Header().Set(xhttp.LastModified, objInfo.ModTime.UTC().Format(http.TimeFormat))
if objInfo.ETag != "" { if objInfo.ETag != "" {
w.Header()["ETag"] = []string{"\"" + objInfo.ETag + "\""} w.Header()[xhttp.ETag] = []string{"\"" + objInfo.ETag + "\""}
} }
} }
// x-amz-copy-source-if-modified-since: Return the object only if it has been modified // x-amz-copy-source-if-modified-since: Return the object only if it has been modified
// since the specified time otherwise return 412 (precondition failed). // since the specified time otherwise return 412 (precondition failed).
ifModifiedSinceHeader := r.Header.Get("x-amz-copy-source-if-modified-since") ifModifiedSinceHeader := r.Header.Get(xhttp.AmzCopySourceIfModifiedSince)
if ifModifiedSinceHeader != "" { if ifModifiedSinceHeader != "" {
if givenTime, err := time.Parse(http.TimeFormat, ifModifiedSinceHeader); err == nil { if givenTime, err := time.Parse(http.TimeFormat, ifModifiedSinceHeader); err == nil {
if !ifModifiedSince(objInfo.ModTime, givenTime) { if !ifModifiedSince(objInfo.ModTime, givenTime) {
@ -90,7 +91,7 @@ func checkCopyObjectPreconditions(ctx context.Context, w http.ResponseWriter, r
// x-amz-copy-source-if-unmodified-since : Return the object only if it has not been // x-amz-copy-source-if-unmodified-since : Return the object only if it has not been
// modified since the specified time, otherwise return a 412 (precondition failed). // modified since the specified time, otherwise return a 412 (precondition failed).
ifUnmodifiedSinceHeader := r.Header.Get("x-amz-copy-source-if-unmodified-since") ifUnmodifiedSinceHeader := r.Header.Get(xhttp.AmzCopySourceIfUnmodifiedSince)
if ifUnmodifiedSinceHeader != "" { if ifUnmodifiedSinceHeader != "" {
if givenTime, err := time.Parse(http.TimeFormat, ifUnmodifiedSinceHeader); err == nil { if givenTime, err := time.Parse(http.TimeFormat, ifUnmodifiedSinceHeader); err == nil {
if ifModifiedSince(objInfo.ModTime, givenTime) { if ifModifiedSince(objInfo.ModTime, givenTime) {
@ -106,7 +107,7 @@ func checkCopyObjectPreconditions(ctx context.Context, w http.ResponseWriter, r
// x-amz-copy-source-if-match : Return the object only if its entity tag (ETag) is the // x-amz-copy-source-if-match : Return the object only if its entity tag (ETag) is the
// same as the one specified; otherwise return a 412 (precondition failed). // same as the one specified; otherwise return a 412 (precondition failed).
ifMatchETagHeader := r.Header.Get("x-amz-copy-source-if-match") ifMatchETagHeader := r.Header.Get(xhttp.AmzCopySourceIfMatch)
if ifMatchETagHeader != "" { if ifMatchETagHeader != "" {
etag := objInfo.ETag etag := objInfo.ETag
if shouldDecryptEtag { if shouldDecryptEtag {
@ -122,7 +123,7 @@ func checkCopyObjectPreconditions(ctx context.Context, w http.ResponseWriter, r
// If-None-Match : Return the object only if its entity tag (ETag) is different from the // If-None-Match : Return the object only if its entity tag (ETag) is different from the
// one specified otherwise, return a 304 (not modified). // one specified otherwise, return a 304 (not modified).
ifNoneMatchETagHeader := r.Header.Get("x-amz-copy-source-if-none-match") ifNoneMatchETagHeader := r.Header.Get(xhttp.AmzCopySourceIfNoneMatch)
if ifNoneMatchETagHeader != "" { if ifNoneMatchETagHeader != "" {
etag := objInfo.ETag etag := objInfo.ETag
if shouldDecryptEtag { if shouldDecryptEtag {
@ -147,7 +148,7 @@ func checkCopyObjectPreconditions(ctx context.Context, w http.ResponseWriter, r
// If-None-Match // If-None-Match
func checkPreconditions(ctx context.Context, w http.ResponseWriter, r *http.Request, objInfo ObjectInfo) bool { func checkPreconditions(ctx context.Context, w http.ResponseWriter, r *http.Request, objInfo ObjectInfo) bool {
// Return false for methods other than GET and HEAD. // Return false for methods other than GET and HEAD.
if r.Method != "GET" && r.Method != "HEAD" { if r.Method != http.MethodGet && r.Method != http.MethodHead {
return false return false
} }
// If the object doesn't have a modtime (IsZero), or the modtime // If the object doesn't have a modtime (IsZero), or the modtime
@ -163,15 +164,15 @@ func checkPreconditions(ctx context.Context, w http.ResponseWriter, r *http.Requ
setCommonHeaders(w) setCommonHeaders(w)
// set object-related metadata headers // set object-related metadata headers
w.Header().Set("Last-Modified", objInfo.ModTime.UTC().Format(http.TimeFormat)) w.Header().Set(xhttp.LastModified, objInfo.ModTime.UTC().Format(http.TimeFormat))
if objInfo.ETag != "" { if objInfo.ETag != "" {
w.Header()["ETag"] = []string{"\"" + objInfo.ETag + "\""} w.Header()[xhttp.ETag] = []string{"\"" + objInfo.ETag + "\""}
} }
} }
// If-Modified-Since : Return the object only if it has been modified since the specified time, // If-Modified-Since : Return the object only if it has been modified since the specified time,
// otherwise return a 304 (not modified). // otherwise return a 304 (not modified).
ifModifiedSinceHeader := r.Header.Get("If-Modified-Since") ifModifiedSinceHeader := r.Header.Get(xhttp.IfModifiedSince)
if ifModifiedSinceHeader != "" { if ifModifiedSinceHeader != "" {
if givenTime, err := time.Parse(http.TimeFormat, ifModifiedSinceHeader); err == nil { if givenTime, err := time.Parse(http.TimeFormat, ifModifiedSinceHeader); err == nil {
if !ifModifiedSince(objInfo.ModTime, givenTime) { if !ifModifiedSince(objInfo.ModTime, givenTime) {
@ -185,7 +186,7 @@ func checkPreconditions(ctx context.Context, w http.ResponseWriter, r *http.Requ
// If-Unmodified-Since : Return the object only if it has not been modified since the specified // If-Unmodified-Since : Return the object only if it has not been modified since the specified
// time, otherwise return a 412 (precondition failed). // time, otherwise return a 412 (precondition failed).
ifUnmodifiedSinceHeader := r.Header.Get("If-Unmodified-Since") ifUnmodifiedSinceHeader := r.Header.Get(xhttp.IfUnmodifiedSince)
if ifUnmodifiedSinceHeader != "" { if ifUnmodifiedSinceHeader != "" {
if givenTime, err := time.Parse(http.TimeFormat, ifUnmodifiedSinceHeader); err == nil { if givenTime, err := time.Parse(http.TimeFormat, ifUnmodifiedSinceHeader); err == nil {
if ifModifiedSince(objInfo.ModTime, givenTime) { if ifModifiedSince(objInfo.ModTime, givenTime) {
@ -199,7 +200,7 @@ func checkPreconditions(ctx context.Context, w http.ResponseWriter, r *http.Requ
// If-Match : Return the object only if its entity tag (ETag) is the same as the one specified; // If-Match : Return the object only if its entity tag (ETag) is the same as the one specified;
// otherwise return a 412 (precondition failed). // otherwise return a 412 (precondition failed).
ifMatchETagHeader := r.Header.Get("If-Match") ifMatchETagHeader := r.Header.Get(xhttp.IfMatch)
if ifMatchETagHeader != "" { if ifMatchETagHeader != "" {
if !isETagEqual(objInfo.ETag, ifMatchETagHeader) { if !isETagEqual(objInfo.ETag, ifMatchETagHeader) {
// If the object ETag does not match with the specified ETag. // If the object ETag does not match with the specified ETag.
@ -211,7 +212,7 @@ func checkPreconditions(ctx context.Context, w http.ResponseWriter, r *http.Requ
// If-None-Match : Return the object only if its entity tag (ETag) is different from the // If-None-Match : Return the object only if its entity tag (ETag) is different from the
// one specified otherwise, return a 304 (not modified). // one specified otherwise, return a 304 (not modified).
ifNoneMatchETagHeader := r.Header.Get("If-None-Match") ifNoneMatchETagHeader := r.Header.Get(xhttp.IfNoneMatch)
if ifNoneMatchETagHeader != "" { if ifNoneMatchETagHeader != "" {
if isETagEqual(objInfo.ETag, ifNoneMatchETagHeader) { if isETagEqual(objInfo.ETag, ifNoneMatchETagHeader) {
// If the object ETag matches with the specified ETag. // If the object ETag matches with the specified ETag.

View File

@ -36,6 +36,7 @@ import (
miniogo "github.com/minio/minio-go/v6" miniogo "github.com/minio/minio-go/v6"
"github.com/minio/minio-go/v6/pkg/encrypt" "github.com/minio/minio-go/v6/pkg/encrypt"
"github.com/minio/minio/cmd/crypto" "github.com/minio/minio/cmd/crypto"
xhttp "github.com/minio/minio/cmd/http"
"github.com/minio/minio/cmd/logger" "github.com/minio/minio/cmd/logger"
"github.com/minio/minio/pkg/dns" "github.com/minio/minio/pkg/dns"
"github.com/minio/minio/pkg/event" "github.com/minio/minio/pkg/event"
@ -50,12 +51,12 @@ import (
// supportedHeadGetReqParams - supported request parameters for GET and HEAD presigned request. // supportedHeadGetReqParams - supported request parameters for GET and HEAD presigned request.
var supportedHeadGetReqParams = map[string]string{ var supportedHeadGetReqParams = map[string]string{
"response-expires": "Expires", "response-expires": xhttp.Expires,
"response-content-type": "Content-Type", "response-content-type": xhttp.ContentType,
"response-cache-control": "Cache-Control", "response-cache-control": xhttp.CacheControl,
"response-content-encoding": "Content-Encoding", "response-content-encoding": xhttp.ContentEncoding,
"response-content-language": "Content-Language", "response-content-language": xhttp.ContentLanguage,
"response-content-disposition": "Content-Disposition", "response-content-disposition": xhttp.ContentDisposition,
} }
const ( const (
@ -165,7 +166,7 @@ func (api objectAPIHandlers) SelectObjectContentHandler(w http.ResponseWriter, r
BucketName: bucket, BucketName: bucket,
Key: object, Key: object,
Resource: r.URL.Path, Resource: r.URL.Path,
RequestID: w.Header().Get(responseRequestIDKey), RequestID: w.Header().Get(xhttp.AmzRequestID),
HostID: globalDeploymentID, HostID: globalDeploymentID,
}) })
writeResponse(w, serr.HTTPStatusCode(), encodedErrorResponse, mimeXML) writeResponse(w, serr.HTTPStatusCode(), encodedErrorResponse, mimeXML)
@ -207,7 +208,7 @@ func (api objectAPIHandlers) SelectObjectContentHandler(w http.ResponseWriter, r
BucketName: bucket, BucketName: bucket,
Key: object, Key: object,
Resource: r.URL.Path, Resource: r.URL.Path,
RequestID: w.Header().Get(responseRequestIDKey), RequestID: w.Header().Get(xhttp.AmzRequestID),
HostID: globalDeploymentID, HostID: globalDeploymentID,
}) })
writeResponse(w, serr.HTTPStatusCode(), encodedErrorResponse, mimeXML) writeResponse(w, serr.HTTPStatusCode(), encodedErrorResponse, mimeXML)
@ -650,7 +651,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
// TODO: Reject requests where body/payload is present, for now we don't even read it. // TODO: Reject requests where body/payload is present, for now we don't even read it.
// Read escaped copy source path to check for parameters. // Read escaped copy source path to check for parameters.
cpSrcPath := r.Header.Get("X-Amz-Copy-Source") cpSrcPath := r.Header.Get(xhttp.AmzCopySource)
// Check https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectVersioning.html // Check https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectVersioning.html
// Regardless of whether you have enabled versioning, each object in your bucket // Regardless of whether you have enabled versioning, each object in your bucket
@ -668,7 +669,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
// Note that url.Parse does the unescaping // Note that url.Parse does the unescaping
cpSrcPath = u.Path cpSrcPath = u.Path
} }
if vid := r.Header.Get("X-Amz-Copy-Source-Version-Id"); vid != "" { if vid := r.Header.Get(xhttp.AmzCopySourceVersionID); vid != "" {
// Check if versionId header was added, if yes then check if // Check if versionId header was added, if yes then check if
// its non "null" value, we should error out since we do not support // its non "null" value, we should error out since we do not support
// any versions other than "null". // any versions other than "null".
@ -1271,7 +1272,7 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req
} else if hasServerSideEncryptionHeader(r.Header) { } else if hasServerSideEncryptionHeader(r.Header) {
etag = getDecryptedETag(r.Header, objInfo, false) etag = getDecryptedETag(r.Header, objInfo, false)
} }
w.Header()["ETag"] = []string{"\"" + etag + "\""} w.Header()[xhttp.ETag] = []string{"\"" + etag + "\""}
if objectAPI.IsEncryptionSupported() { if objectAPI.IsEncryptionSupported() {
if crypto.IsEncrypted(objInfo.UserDefined) { if crypto.IsEncrypted(objInfo.UserDefined) {
@ -1453,7 +1454,7 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt
} }
// Read escaped copy source path to check for parameters. // Read escaped copy source path to check for parameters.
cpSrcPath := r.Header.Get("X-Amz-Copy-Source") cpSrcPath := r.Header.Get(xhttp.AmzCopySource)
// Check https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectVersioning.html // Check https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectVersioning.html
// Regardless of whether you have enabled versioning, each object in your bucket // Regardless of whether you have enabled versioning, each object in your bucket
@ -1471,7 +1472,7 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt
// Note that url.Parse does the unescaping // Note that url.Parse does the unescaping
cpSrcPath = u.Path cpSrcPath = u.Path
} }
if vid := r.Header.Get("X-Amz-Copy-Source-Version-Id"); vid != "" { if vid := r.Header.Get(xhttp.AmzCopySourceVersionID); vid != "" {
// Check if X-Amz-Copy-Source-Version-Id header was added, if yes then check if // Check if X-Amz-Copy-Source-Version-Id header was added, if yes then check if
// its non "null" value, we should error out since we do not support // its non "null" value, we should error out since we do not support
// any versions other than "null". // any versions other than "null".
@ -1540,7 +1541,7 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt
// Get request range. // Get request range.
var rs *HTTPRangeSpec var rs *HTTPRangeSpec
rangeHeader := r.Header.Get("x-amz-copy-source-range") rangeHeader := r.Header.Get(xhttp.AmzCopySourceRange)
if rangeHeader != "" { if rangeHeader != "" {
var parseRangeErr error var parseRangeErr error
if rs, parseRangeErr = parseCopyPartRangeSpec(rangeHeader); parseRangeErr != nil { if rs, parseRangeErr = parseCopyPartRangeSpec(rangeHeader); parseRangeErr != nil {
@ -1732,7 +1733,7 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http
object := vars["object"] object := vars["object"]
// X-Amz-Copy-Source shouldn't be set for this call. // X-Amz-Copy-Source shouldn't be set for this call.
if _, ok := r.Header["X-Amz-Copy-Source"]; ok { if _, ok := r.Header[xhttp.AmzCopySource]; ok {
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrInvalidCopySource), r.URL, guessIsBrowserReq(r)) writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrInvalidCopySource), r.URL, guessIsBrowserReq(r))
return return
} }
@ -1750,7 +1751,7 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http
rAuthType := getRequestAuthType(r) rAuthType := getRequestAuthType(r)
// For auth type streaming signature, we need to gather a different content length. // For auth type streaming signature, we need to gather a different content length.
if rAuthType == authTypeStreamingSigned { if rAuthType == authTypeStreamingSigned {
if sizeStr, ok := r.Header["X-Amz-Decoded-Content-Length"]; ok { if sizeStr, ok := r.Header[xhttp.AmzDecodedContentLength]; ok {
if sizeStr[0] == "" { if sizeStr[0] == "" {
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrMissingContentLength), r.URL, guessIsBrowserReq(r)) writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrMissingContentLength), r.URL, guessIsBrowserReq(r))
return return
@ -1952,7 +1953,7 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http
if isEncrypted { if isEncrypted {
etag = tryDecryptETag(objectEncryptionKey, partInfo.ETag, crypto.SSEC.IsRequested(r.Header)) etag = tryDecryptETag(objectEncryptionKey, partInfo.ETag, crypto.SSEC.IsRequested(r.Header))
} }
w.Header()["ETag"] = []string{"\"" + etag + "\""} w.Header()[xhttp.ETag] = []string{"\"" + etag + "\""}
writeSuccessResponseHeadersOnly(w) writeSuccessResponseHeadersOnly(w)
} }
@ -2267,15 +2268,15 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite
case "SlowDown", "XMinioServerNotInitialized", "XMinioReadQuorum", "XMinioWriteQuorum": case "SlowDown", "XMinioServerNotInitialized", "XMinioReadQuorum", "XMinioWriteQuorum":
// Set retry-after header to indicate user-agents to retry request after 120secs. // Set retry-after header to indicate user-agents to retry request after 120secs.
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
w.Header().Set("Retry-After", "120") w.Header().Set(xhttp.RetryAfter, "120")
} }
// Generate error response. // Generate error response.
errorResponse := getAPIErrorResponse(ctx, err, reqURL.Path, errorResponse := getAPIErrorResponse(ctx, err, reqURL.Path,
w.Header().Get(responseRequestIDKey), globalDeploymentID) w.Header().Get(xhttp.AmzRequestID), globalDeploymentID)
encodedErrorResponse, _ := xml.Marshal(errorResponse) encodedErrorResponse, _ := xml.Marshal(errorResponse)
setCommonHeaders(w) setCommonHeaders(w)
w.Header().Set("Content-Type", string(mimeXML)) w.Header().Set(xhttp.ContentType, string(mimeXML))
w.Write(encodedErrorResponse) w.Write(encodedErrorResponse)
w.(http.Flusher).Flush() w.(http.Flusher).Flush()
} }
@ -2310,7 +2311,7 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite
} }
// Set etag. // Set etag.
w.Header()["ETag"] = []string{"\"" + objInfo.ETag + "\""} w.Header()[xhttp.ETag] = []string{"\"" + objInfo.ETag + "\""}
// Write success response. // Write success response.
writeSuccessResponseXML(w, encodedSuccessResponse) writeSuccessResponseXML(w, encodedSuccessResponse)

View File

@ -28,6 +28,7 @@ import (
"time" "time"
"github.com/gorilla/mux" "github.com/gorilla/mux"
xhttp "github.com/minio/minio/cmd/http"
"github.com/minio/minio/cmd/logger" "github.com/minio/minio/cmd/logger"
"github.com/minio/minio/pkg/event" "github.com/minio/minio/pkg/event"
xnet "github.com/minio/minio/pkg/net" xnet "github.com/minio/minio/pkg/net"
@ -675,7 +676,7 @@ func (s *peerRESTServer) TraceHandler(w http.ResponseWriter, r *http.Request) {
} }
trcAll := r.URL.Query().Get(peerRESTTraceAll) == "true" trcAll := r.URL.Query().Get(peerRESTTraceAll) == "true"
w.Header().Set("Connection", "close") w.Header().Set(xhttp.Connection, "close")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
w.(http.Flusher).Flush() w.(http.Flusher).Flush()

View File

@ -34,6 +34,7 @@ import (
"time" "time"
humanize "github.com/dustin/go-humanize" humanize "github.com/dustin/go-humanize"
xhttp "github.com/minio/minio/cmd/http"
"github.com/minio/minio/pkg/policy" "github.com/minio/minio/pkg/policy"
) )
@ -1202,7 +1203,7 @@ func (s *TestSuiteCommon) TestPutObject(c *check) {
c.Assert(err, nil) c.Assert(err, nil)
c.Assert(response.StatusCode, http.StatusOK) c.Assert(response.StatusCode, http.StatusOK)
// The response Etag header should contain Md5sum of an empty string. // The response Etag header should contain Md5sum of an empty string.
c.Assert(response.Header.Get("Etag"), "\""+emptyETag+"\"") c.Assert(response.Header.Get(xhttp.ETag), "\""+emptyETag+"\"")
} }
// TestListBuckets - Make request for listing of all buckets. // TestListBuckets - Make request for listing of all buckets.
@ -2728,5 +2729,5 @@ func (s *TestSuiteCommon) TestObjectMultipart(c *check) {
parts = append(parts, part) parts = append(parts, part)
} }
etag := getCompleteMultipartMD5(parts) etag := getCompleteMultipartMD5(parts)
c.Assert(canonicalizeETag(response.Header.Get("Etag")), etag) c.Assert(canonicalizeETag(response.Header.Get(xhttp.ETag)), etag)
} }

View File

@ -28,6 +28,8 @@ import (
"strconv" "strconv"
"strings" "strings"
xhttp "github.com/minio/minio/cmd/http"
"github.com/minio/minio/pkg/auth" "github.com/minio/minio/pkg/auth"
) )
@ -68,13 +70,13 @@ var resourceList = []string{
func doesPolicySignatureV2Match(formValues http.Header) APIErrorCode { func doesPolicySignatureV2Match(formValues http.Header) APIErrorCode {
cred := globalServerConfig.GetCredential() cred := globalServerConfig.GetCredential()
accessKey := formValues.Get("AWSAccessKeyId") accessKey := formValues.Get(xhttp.AmzAccessKeyID)
cred, _, s3Err := checkKeyValid(accessKey) cred, _, s3Err := checkKeyValid(accessKey)
if s3Err != ErrNone { if s3Err != ErrNone {
return s3Err return s3Err
} }
policy := formValues.Get("Policy") policy := formValues.Get("Policy")
signature := formValues.Get("Signature") signature := formValues.Get(xhttp.AmzSignatureV2)
if !compareSignatureV2(signature, calculateSignatureV2(policy, cred.SecretKey)) { if !compareSignatureV2(signature, calculateSignatureV2(policy, cred.SecretKey)) {
return ErrSignatureDoesNotMatch return ErrSignatureDoesNotMatch
} }
@ -131,11 +133,11 @@ func doesPresignV2SignatureMatch(r *http.Request) APIErrorCode {
return ErrInvalidQueryParams return ErrInvalidQueryParams
} }
switch keyval[0] { switch keyval[0] {
case "AWSAccessKeyId": case xhttp.AmzAccessKeyID:
accessKey = keyval[1] accessKey = keyval[1]
case "Signature": case xhttp.AmzSignatureV2:
gotSignature = keyval[1] gotSignature = keyval[1]
case "Expires": case xhttp.Expires:
expires = keyval[1] expires = keyval[1]
default: default:
filteredQueries = append(filteredQueries, query) filteredQueries = append(filteredQueries, query)
@ -177,13 +179,13 @@ func doesPresignV2SignatureMatch(r *http.Request) APIErrorCode {
} }
func getReqAccessKeyV2(r *http.Request) (auth.Credentials, bool, APIErrorCode) { func getReqAccessKeyV2(r *http.Request) (auth.Credentials, bool, APIErrorCode) {
if accessKey := r.URL.Query().Get("AWSAccessKeyId"); accessKey != "" { if accessKey := r.URL.Query().Get(xhttp.AmzAccessKeyID); accessKey != "" {
return checkKeyValid(accessKey) return checkKeyValid(accessKey)
} }
// below is V2 Signed Auth header format, splitting on `space` (after the `AWS` string). // below is V2 Signed Auth header format, splitting on `space` (after the `AWS` string).
// Authorization = "AWS" + " " + AWSAccessKeyId + ":" + Signature // Authorization = "AWS" + " " + AWSAccessKeyId + ":" + Signature
authFields := strings.Split(r.Header.Get("Authorization"), " ") authFields := strings.Split(r.Header.Get(xhttp.Authorization), " ")
if len(authFields) != 2 { if len(authFields) != 2 {
return auth.Credentials{}, false, ErrMissingFields return auth.Credentials{}, false, ErrMissingFields
} }
@ -219,7 +221,7 @@ func getReqAccessKeyV2(r *http.Request) (auth.Credentials, bool, APIErrorCode) {
func validateV2AuthHeader(r *http.Request) (auth.Credentials, APIErrorCode) { func validateV2AuthHeader(r *http.Request) (auth.Credentials, APIErrorCode) {
var cred auth.Credentials var cred auth.Credentials
v2Auth := r.Header.Get("Authorization") v2Auth := r.Header.Get(xhttp.Authorization)
if v2Auth == "" { if v2Auth == "" {
return cred, ErrAuthHeaderEmpty return cred, ErrAuthHeaderEmpty
} }
@ -238,7 +240,7 @@ func validateV2AuthHeader(r *http.Request) (auth.Credentials, APIErrorCode) {
} }
func doesSignV2Match(r *http.Request) APIErrorCode { func doesSignV2Match(r *http.Request) APIErrorCode {
v2Auth := r.Header.Get("Authorization") v2Auth := r.Header.Get(xhttp.Authorization)
cred, apiError := validateV2AuthHeader(r) cred, apiError := validateV2AuthHeader(r)
if apiError != ErrNone { if apiError != ErrNone {
return apiError return apiError
@ -380,7 +382,7 @@ func getStringToSignV2(method string, encodedResource, encodedQuery string, head
date := expires // Date is set to expires date for presign operations. date := expires // Date is set to expires date for presign operations.
if date == "" { if date == "" {
// If expires date is empty then request header Date is used. // If expires date is empty then request header Date is used.
date = headers.Get("Date") date = headers.Get(xhttp.Date)
} }
// From the Amazon docs: // From the Amazon docs:
@ -393,8 +395,8 @@ func getStringToSignV2(method string, encodedResource, encodedQuery string, head
// CanonicalizedResource; // CanonicalizedResource;
stringToSign := strings.Join([]string{ stringToSign := strings.Join([]string{
method, method,
headers.Get("Content-MD5"), headers.Get(xhttp.ContentMD5),
headers.Get("Content-Type"), headers.Get(xhttp.ContentType),
date, date,
canonicalHeaders, canonicalHeaders,
}, "\n") }, "\n")

View File

@ -26,6 +26,7 @@ import (
"strconv" "strconv"
"strings" "strings"
xhttp "github.com/minio/minio/cmd/http"
"github.com/minio/minio/cmd/logger" "github.com/minio/minio/cmd/logger"
"github.com/minio/minio/pkg/auth" "github.com/minio/minio/pkg/auth"
"github.com/minio/sha256-simd" "github.com/minio/sha256-simd"
@ -44,12 +45,12 @@ func skipContentSha256Cksum(r *http.Request) bool {
) )
if isRequestPresignedSignatureV4(r) { if isRequestPresignedSignatureV4(r) {
v, ok = r.URL.Query()["X-Amz-Content-Sha256"] v, ok = r.URL.Query()[xhttp.AmzContentSha256]
if !ok { if !ok {
v, ok = r.Header["X-Amz-Content-Sha256"] v, ok = r.Header[xhttp.AmzContentSha256]
} }
} else { } else {
v, ok = r.Header["X-Amz-Content-Sha256"] v, ok = r.Header[xhttp.AmzContentSha256]
} }
// If x-amz-content-sha256 is set and the value is not // If x-amz-content-sha256 is set and the value is not
@ -81,15 +82,15 @@ func getContentSha256Cksum(r *http.Request, stype serviceType) string {
// X-Amz-Content-Sha256, if not set in presigned requests, checksum // X-Amz-Content-Sha256, if not set in presigned requests, checksum
// will default to 'UNSIGNED-PAYLOAD'. // will default to 'UNSIGNED-PAYLOAD'.
defaultSha256Cksum = unsignedPayload defaultSha256Cksum = unsignedPayload
v, ok = r.URL.Query()["X-Amz-Content-Sha256"] v, ok = r.URL.Query()[xhttp.AmzContentSha256]
if !ok { if !ok {
v, ok = r.Header["X-Amz-Content-Sha256"] v, ok = r.Header[xhttp.AmzContentSha256]
} }
} else { } else {
// X-Amz-Content-Sha256, if not set in signed requests, checksum // X-Amz-Content-Sha256, if not set in signed requests, checksum
// will default to sha256([]byte("")). // will default to sha256([]byte("")).
defaultSha256Cksum = emptySHA256 defaultSha256Cksum = emptySHA256
v, ok = r.Header["X-Amz-Content-Sha256"] v, ok = r.Header[xhttp.AmzContentSha256]
} }
// We found 'X-Amz-Content-Sha256' return the captured value. // We found 'X-Amz-Content-Sha256' return the captured value.

View File

@ -36,6 +36,7 @@ import (
"time" "time"
"github.com/minio/minio-go/v6/pkg/s3utils" "github.com/minio/minio-go/v6/pkg/s3utils"
xhttp "github.com/minio/minio/cmd/http"
sha256 "github.com/minio/sha256-simd" sha256 "github.com/minio/sha256-simd"
) )
@ -172,7 +173,7 @@ func doesPolicySignatureV4Match(formValues http.Header) APIErrorCode {
region := globalServerConfig.GetRegion() region := globalServerConfig.GetRegion()
// Parse credential tag. // Parse credential tag.
credHeader, err := parseCredentialHeader("Credential="+formValues.Get("X-Amz-Credential"), region, serviceS3) credHeader, err := parseCredentialHeader("Credential="+formValues.Get(xhttp.AmzCredential), region, serviceS3)
if err != ErrNone { if err != ErrNone {
return ErrMissingFields return ErrMissingFields
} }
@ -189,7 +190,7 @@ func doesPolicySignatureV4Match(formValues http.Header) APIErrorCode {
newSignature := getSignature(signingKey, formValues.Get("Policy")) newSignature := getSignature(signingKey, formValues.Get("Policy"))
// Verify signature. // Verify signature.
if !compareSignatureV4(newSignature, formValues.Get("X-Amz-Signature")) { if !compareSignatureV4(newSignature, formValues.Get(xhttp.AmzSignature)) {
return ErrSignatureDoesNotMatch return ErrSignatureDoesNotMatch
} }
@ -223,11 +224,11 @@ func doesPresignedSignatureMatch(hashedPayload string, r *http.Request, region s
// Construct new query. // Construct new query.
query := make(url.Values) query := make(url.Values)
if req.URL.Query().Get("X-Amz-Content-Sha256") != "" { if req.URL.Query().Get(xhttp.AmzContentSha256) != "" {
query.Set("X-Amz-Content-Sha256", hashedPayload) query.Set(xhttp.AmzContentSha256, hashedPayload)
} }
query.Set("X-Amz-Algorithm", signV4Algorithm) query.Set(xhttp.AmzAlgorithm, signV4Algorithm)
// If the host which signed the request is slightly ahead in time (by less than globalMaxSkewTime) the // If the host which signed the request is slightly ahead in time (by less than globalMaxSkewTime) the
// request should still be allowed. // request should still be allowed.
@ -244,10 +245,10 @@ func doesPresignedSignatureMatch(hashedPayload string, r *http.Request, region s
expireSeconds := int(pSignValues.Expires / time.Second) expireSeconds := int(pSignValues.Expires / time.Second)
// Construct the query. // Construct the query.
query.Set("X-Amz-Date", t.Format(iso8601Format)) query.Set(xhttp.AmzDate, t.Format(iso8601Format))
query.Set("X-Amz-Expires", strconv.Itoa(expireSeconds)) query.Set(xhttp.AmzExpires, strconv.Itoa(expireSeconds))
query.Set("X-Amz-SignedHeaders", getSignedHeaders(extractedSignedHeaders)) query.Set(xhttp.AmzSignedHeaders, getSignedHeaders(extractedSignedHeaders))
query.Set("X-Amz-Credential", cred.AccessKey+"/"+pSignValues.Credential.getScope()) query.Set(xhttp.AmzCredential, cred.AccessKey+"/"+pSignValues.Credential.getScope())
// Save other headers available in the request parameters. // Save other headers available in the request parameters.
for k, v := range req.URL.Query() { for k, v := range req.URL.Query() {
@ -273,24 +274,24 @@ func doesPresignedSignatureMatch(hashedPayload string, r *http.Request, region s
encodedQuery := query.Encode() encodedQuery := query.Encode()
// Verify if date query is same. // Verify if date query is same.
if req.URL.Query().Get("X-Amz-Date") != query.Get("X-Amz-Date") { if req.URL.Query().Get(xhttp.AmzDate) != query.Get(xhttp.AmzDate) {
return ErrSignatureDoesNotMatch return ErrSignatureDoesNotMatch
} }
// Verify if expires query is same. // Verify if expires query is same.
if req.URL.Query().Get("X-Amz-Expires") != query.Get("X-Amz-Expires") { if req.URL.Query().Get(xhttp.AmzExpires) != query.Get(xhttp.AmzExpires) {
return ErrSignatureDoesNotMatch return ErrSignatureDoesNotMatch
} }
// Verify if signed headers query is same. // Verify if signed headers query is same.
if req.URL.Query().Get("X-Amz-SignedHeaders") != query.Get("X-Amz-SignedHeaders") { if req.URL.Query().Get(xhttp.AmzSignedHeaders) != query.Get(xhttp.AmzSignedHeaders) {
return ErrSignatureDoesNotMatch return ErrSignatureDoesNotMatch
} }
// Verify if credential query is same. // Verify if credential query is same.
if req.URL.Query().Get("X-Amz-Credential") != query.Get("X-Amz-Credential") { if req.URL.Query().Get(xhttp.AmzCredential) != query.Get(xhttp.AmzCredential) {
return ErrSignatureDoesNotMatch return ErrSignatureDoesNotMatch
} }
// Verify if sha256 payload query is same. // Verify if sha256 payload query is same.
if req.URL.Query().Get("X-Amz-Content-Sha256") != "" { if req.URL.Query().Get(xhttp.AmzContentSha256) != "" {
if req.URL.Query().Get("X-Amz-Content-Sha256") != query.Get("X-Amz-Content-Sha256") { if req.URL.Query().Get(xhttp.AmzContentSha256) != query.Get(xhttp.AmzContentSha256) {
return ErrContentSHA256Mismatch return ErrContentSHA256Mismatch
} }
} }
@ -311,7 +312,7 @@ func doesPresignedSignatureMatch(hashedPayload string, r *http.Request, region s
newSignature := getSignature(presignedSigningKey, presignedStringToSign) newSignature := getSignature(presignedSigningKey, presignedStringToSign)
// Verify signature. // Verify signature.
if !compareSignatureV4(req.URL.Query().Get("X-Amz-Signature"), newSignature) { if !compareSignatureV4(req.URL.Query().Get(xhttp.AmzSignature), newSignature) {
return ErrSignatureDoesNotMatch return ErrSignatureDoesNotMatch
} }
return ErrNone return ErrNone
@ -325,7 +326,7 @@ func doesSignatureMatch(hashedPayload string, r *http.Request, region string, st
req := *r req := *r
// Save authorization header. // Save authorization header.
v4Auth := req.Header.Get("Authorization") v4Auth := req.Header.Get(xhttp.Authorization)
// Parse signature version '4' header. // Parse signature version '4' header.
signV4Values, err := parseSignV4(v4Auth, region, stype) signV4Values, err := parseSignV4(v4Auth, region, stype)
@ -346,8 +347,8 @@ func doesSignatureMatch(hashedPayload string, r *http.Request, region string, st
// Extract date, if not present throw error. // Extract date, if not present throw error.
var date string var date string
if date = req.Header.Get(http.CanonicalHeaderKey("x-amz-date")); date == "" { if date = req.Header.Get(xhttp.AmzDate); date == "" {
if date = r.Header.Get("Date"); date == "" { if date = r.Header.Get(xhttp.Date); date == "" {
return ErrMissingDateHeader return ErrMissingDateHeader
} }
} }

View File

@ -29,6 +29,7 @@ import (
"time" "time"
"github.com/gorilla/mux" "github.com/gorilla/mux"
xhttp "github.com/minio/minio/cmd/http"
"github.com/minio/minio/cmd/logger" "github.com/minio/minio/cmd/logger"
) )
@ -114,7 +115,7 @@ func (s *storageRESTServer) GetInstanceID(w http.ResponseWriter, r *http.Request
s.writeErrorResponse(w, err) s.writeErrorResponse(w, err)
return return
} }
w.Header().Set("Content-Length", strconv.Itoa(len(s.instanceID))) w.Header().Set(xhttp.ContentLength, strconv.Itoa(len(s.instanceID)))
w.Write([]byte(s.instanceID)) w.Write([]byte(s.instanceID))
w.(http.Flusher).Flush() w.(http.Flusher).Flush()
} }
@ -283,7 +284,7 @@ func (s *storageRESTServer) ReadAllHandler(w http.ResponseWriter, r *http.Reques
s.writeErrorResponse(w, err) s.writeErrorResponse(w, err)
return return
} }
w.Header().Set("Content-Length", strconv.Itoa(len(buf))) w.Header().Set(xhttp.ContentLength, strconv.Itoa(len(buf)))
w.Write(buf) w.Write(buf)
w.(http.Flusher).Flush() w.(http.Flusher).Flush()
} }
@ -327,7 +328,7 @@ func (s *storageRESTServer) ReadFileHandler(w http.ResponseWriter, r *http.Reque
s.writeErrorResponse(w, err) s.writeErrorResponse(w, err)
return return
} }
w.Header().Set("Content-Length", strconv.Itoa(len(buf))) w.Header().Set(xhttp.ContentLength, strconv.Itoa(len(buf)))
w.Write(buf) w.Write(buf)
w.(http.Flusher).Flush() w.(http.Flusher).Flush()
} }
@ -357,7 +358,7 @@ func (s *storageRESTServer) ReadFileStreamHandler(w http.ResponseWriter, r *http
return return
} }
defer rc.Close() defer rc.Close()
w.Header().Set("Content-Length", strconv.Itoa(length)) w.Header().Set(xhttp.ContentLength, strconv.Itoa(length))
io.Copy(w, rc) io.Copy(w, rc)
w.(http.Flusher).Flush() w.(http.Flusher).Flush()

View File

@ -29,6 +29,7 @@ import (
"time" "time"
humanize "github.com/dustin/go-humanize" humanize "github.com/dustin/go-humanize"
xhttp "github.com/minio/minio/cmd/http"
"github.com/minio/minio/pkg/auth" "github.com/minio/minio/pkg/auth"
sha256 "github.com/minio/sha256-simd" sha256 "github.com/minio/sha256-simd"
) )
@ -69,7 +70,7 @@ func calculateSeedSignature(r *http.Request) (cred auth.Credentials, signature s
req := *r req := *r
// Save authorization header. // Save authorization header.
v4Auth := req.Header.Get("Authorization") v4Auth := req.Header.Get(xhttp.Authorization)
// Parse signature version '4' header. // Parse signature version '4' header.
signV4Values, errCode := parseSignV4(v4Auth, globalServerConfig.GetRegion(), serviceS3) signV4Values, errCode := parseSignV4(v4Auth, globalServerConfig.GetRegion(), serviceS3)
@ -81,7 +82,7 @@ func calculateSeedSignature(r *http.Request) (cred auth.Credentials, signature s
payload := streamingContentSHA256 payload := streamingContentSHA256
// Payload for STREAMING signature should be 'STREAMING-AWS4-HMAC-SHA256-PAYLOAD' // Payload for STREAMING signature should be 'STREAMING-AWS4-HMAC-SHA256-PAYLOAD'
if payload != req.Header.Get("X-Amz-Content-Sha256") { if payload != req.Header.Get(xhttp.AmzContentSha256) {
return cred, "", "", time.Time{}, ErrContentSHA256Mismatch return cred, "", "", time.Time{}, ErrContentSHA256Mismatch
} }

View File

@ -19,12 +19,14 @@ package cmd
import ( import (
"encoding/xml" "encoding/xml"
"net/http" "net/http"
xhttp "github.com/minio/minio/cmd/http"
) )
// writeSTSErrorRespone writes error headers // writeSTSErrorRespone writes error headers
func writeSTSErrorResponse(w http.ResponseWriter, err STSError) { func writeSTSErrorResponse(w http.ResponseWriter, err STSError) {
// Generate error response. // Generate error response.
stsErrorResponse := getSTSErrorResponse(err, w.Header().Get(responseRequestIDKey)) stsErrorResponse := getSTSErrorResponse(err, w.Header().Get(xhttp.AmzRequestID))
encodedErrorResponse := encodeResponse(stsErrorResponse) encodedErrorResponse := encodeResponse(stsErrorResponse)
writeResponse(w, err.HTTPStatusCode, encodedErrorResponse, mimeXML) writeResponse(w, err.HTTPStatusCode, encodedErrorResponse, mimeXML)
} }

View File

@ -24,6 +24,7 @@ import (
"net/http" "net/http"
"github.com/gorilla/mux" "github.com/gorilla/mux"
xhttp "github.com/minio/minio/cmd/http"
"github.com/minio/minio/cmd/logger" "github.com/minio/minio/cmd/logger"
"github.com/minio/minio/pkg/auth" "github.com/minio/minio/pkg/auth"
iampolicy "github.com/minio/minio/pkg/iam/policy" iampolicy "github.com/minio/minio/pkg/iam/policy"
@ -53,16 +54,16 @@ func registerSTSRouter(router *mux.Router) {
stsRouter := router.NewRoute().PathPrefix("/").Subrouter() stsRouter := router.NewRoute().PathPrefix("/").Subrouter()
// Assume roles with no JWT, handles AssumeRole. // Assume roles with no JWT, handles AssumeRole.
stsRouter.Methods("POST").MatcherFunc(func(r *http.Request, rm *mux.RouteMatch) bool { stsRouter.Methods(http.MethodPost).MatcherFunc(func(r *http.Request, rm *mux.RouteMatch) bool {
ctypeOk := wildcard.MatchSimple("application/x-www-form-urlencoded*", r.Header.Get("Content-Type")) ctypeOk := wildcard.MatchSimple("application/x-www-form-urlencoded*", r.Header.Get(xhttp.ContentType))
authOk := wildcard.MatchSimple("AWS4-HMAC-SHA256*", r.Header.Get("Authorization")) authOk := wildcard.MatchSimple(signV4Algorithm+"*", r.Header.Get(xhttp.Authorization))
noQueries := len(r.URL.Query()) == 0 noQueries := len(r.URL.Query()) == 0
return ctypeOk && authOk && noQueries return ctypeOk && authOk && noQueries
}).HandlerFunc(httpTraceAll(sts.AssumeRole)) }).HandlerFunc(httpTraceAll(sts.AssumeRole))
// Assume roles with JWT handler, handles both ClientGrants and WebIdentity. // Assume roles with JWT handler, handles both ClientGrants and WebIdentity.
stsRouter.Methods("POST").MatcherFunc(func(r *http.Request, rm *mux.RouteMatch) bool { stsRouter.Methods("POST").MatcherFunc(func(r *http.Request, rm *mux.RouteMatch) bool {
ctypeOk := wildcard.MatchSimple("application/x-www-form-urlencoded*", r.Header.Get("Content-Type")) ctypeOk := wildcard.MatchSimple("application/x-www-form-urlencoded*", r.Header.Get(xhttp.ContentType))
noQueries := len(r.URL.Query()) == 0 noQueries := len(r.URL.Query()) == 0
return ctypeOk && noQueries return ctypeOk && noQueries
}).HandlerFunc(httpTraceAll(sts.AssumeRoleWithJWT)) }).HandlerFunc(httpTraceAll(sts.AssumeRoleWithJWT))
@ -227,7 +228,7 @@ func (sts *stsAPIHandlers) AssumeRole(w http.ResponseWriter, r *http.Request) {
}, },
} }
assumeRoleResponse.ResponseMetadata.RequestID = w.Header().Get(responseRequestIDKey) assumeRoleResponse.ResponseMetadata.RequestID = w.Header().Get(xhttp.AmzRequestID)
writeSuccessResponseXML(w, encodeResponse(assumeRoleResponse)) writeSuccessResponseXML(w, encodeResponse(assumeRoleResponse))
} }
@ -369,7 +370,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithJWT(w http.ResponseWriter, r *http.Requ
SubjectFromToken: subFromToken, SubjectFromToken: subFromToken,
}, },
} }
clientGrantsResponse.ResponseMetadata.RequestID = w.Header().Get(responseRequestIDKey) clientGrantsResponse.ResponseMetadata.RequestID = w.Header().Get(xhttp.AmzRequestID)
encodedSuccessResponse = encodeResponse(clientGrantsResponse) encodedSuccessResponse = encodeResponse(clientGrantsResponse)
case webIdentity: case webIdentity:
webIdentityResponse := &AssumeRoleWithWebIdentityResponse{ webIdentityResponse := &AssumeRoleWithWebIdentityResponse{
@ -378,7 +379,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithJWT(w http.ResponseWriter, r *http.Requ
SubjectFromWebIdentityToken: subFromToken, SubjectFromWebIdentityToken: subFromToken,
}, },
} }
webIdentityResponse.ResponseMetadata.RequestID = w.Header().Get(responseRequestIDKey) webIdentityResponse.ResponseMetadata.RequestID = w.Header().Get(xhttp.AmzRequestID)
encodedSuccessResponse = encodeResponse(webIdentityResponse) encodedSuccessResponse = encodeResponse(webIdentityResponse)
} }

View File

@ -36,6 +36,7 @@ import (
"strings" "strings"
"time" "time"
xhttp "github.com/minio/minio/cmd/http"
"github.com/minio/minio/cmd/logger" "github.com/minio/minio/cmd/logger"
"github.com/minio/minio/pkg/handlers" "github.com/minio/minio/pkg/handlers"
@ -426,7 +427,7 @@ func newContext(r *http.Request, w http.ResponseWriter, api string) context.Cont
} }
reqInfo := &logger.ReqInfo{ reqInfo := &logger.ReqInfo{
DeploymentID: globalDeploymentID, DeploymentID: globalDeploymentID,
RequestID: w.Header().Get(responseRequestIDKey), RequestID: w.Header().Get(xhttp.AmzRequestID),
RemoteHost: handlers.GetSourceIP(r), RemoteHost: handlers.GetSourceIP(r),
UserAgent: r.UserAgent(), UserAgent: r.UserAgent(),
API: api, API: api,

View File

@ -41,6 +41,7 @@ import (
"github.com/minio/minio-go/v6/pkg/set" "github.com/minio/minio-go/v6/pkg/set"
"github.com/minio/minio/browser" "github.com/minio/minio/browser"
"github.com/minio/minio/cmd/crypto" "github.com/minio/minio/cmd/crypto"
xhttp "github.com/minio/minio/cmd/http"
"github.com/minio/minio/cmd/logger" "github.com/minio/minio/cmd/logger"
"github.com/minio/minio/pkg/auth" "github.com/minio/minio/pkg/auth"
"github.com/minio/minio/pkg/dns" "github.com/minio/minio/pkg/dns"
@ -1217,7 +1218,7 @@ func (web *webAPIHandlers) Download(w http.ResponseWriter, r *http.Request) {
} }
// Add content disposition. // Add content disposition.
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", path.Base(objInfo.Name))) w.Header().Set(xhttp.ContentDisposition, fmt.Sprintf("attachment; filename=\"%s\"", path.Base(objInfo.Name)))
setHeadGetRespHeaders(w, r.URL.Query()) setHeadGetRespHeaders(w, r.URL.Query())
@ -1879,11 +1880,11 @@ func presignedGet(host, bucket, object string, expiry int64, creds auth.Credenti
} }
query := url.Values{} query := url.Values{}
query.Set("X-Amz-Algorithm", signV4Algorithm) query.Set(xhttp.AmzAlgorithm, signV4Algorithm)
query.Set("X-Amz-Credential", credential) query.Set(xhttp.AmzCredential, credential)
query.Set("X-Amz-Date", dateStr) query.Set(xhttp.AmzDate, dateStr)
query.Set("X-Amz-Expires", expiryStr) query.Set(xhttp.AmzExpires, expiryStr)
query.Set("X-Amz-SignedHeaders", "host") query.Set(xhttp.AmzSignedHeaders, "host")
queryStr := s3utils.QueryEncode(query) queryStr := s3utils.QueryEncode(query)
path := "/" + path.Join(bucket, object) path := "/" + path.Join(bucket, object)
@ -1897,7 +1898,7 @@ func presignedGet(host, bucket, object string, expiry int64, creds auth.Credenti
signature := getSignature(signingKey, stringToSign) signature := getSignature(signingKey, stringToSign)
// Construct the final presigned URL. // Construct the final presigned URL.
return host + s3utils.EncodePath(path) + "?" + queryStr + "&" + "X-Amz-Signature=" + signature return host + s3utils.EncodePath(path) + "?" + queryStr + "&" + xhttp.AmzSignature + "=" + signature
} }
// toJSONError converts regular errors into more user friendly // toJSONError converts regular errors into more user friendly