mirror of
https://github.com/minio/minio.git
synced 2024-12-24 22:25:54 -05:00
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:
parent
9610a74c19
commit
c43f745449
@ -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)
|
||||||
|
@ -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"`
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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))
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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{
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
81
cmd/http/headers.go
Normal 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"
|
||||||
|
)
|
@ -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,
|
||||||
|
@ -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 {
|
||||||
|
@ -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) {
|
||||||
|
@ -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.
|
||||||
|
@ -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)
|
||||||
|
@ -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()
|
||||||
|
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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")
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user