mirror of
https://github.com/minio/minio.git
synced 2024-12-25 06:35:56 -05:00
api: Set appropriate content-type for success/error responses. (#3537)
Golang HTTP client automatically detects content-type but for S3 clients this content-type might be incorrect or might misbehave. For example: ``` Content-Type: text/xml; charset=utf-8 ``` Should be ``` Content-Type: application/xml ``` Allow this to be set properly.
This commit is contained in:
parent
c8f57133a4
commit
926c75d0b5
@ -35,19 +35,19 @@ const (
|
|||||||
func (adminAPI adminAPIHandlers) ServiceStatusHandler(w http.ResponseWriter, r *http.Request) {
|
func (adminAPI adminAPIHandlers) ServiceStatusHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
adminAPIErr := checkRequestAuthType(r, "", "", "")
|
adminAPIErr := checkRequestAuthType(r, "", "", "")
|
||||||
if adminAPIErr != ErrNone {
|
if adminAPIErr != ErrNone {
|
||||||
writeErrorResponse(w, r, adminAPIErr, r.URL.Path)
|
writeErrorResponse(w, adminAPIErr, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
storageInfo := newObjectLayerFn().StorageInfo()
|
storageInfo := newObjectLayerFn().StorageInfo()
|
||||||
jsonBytes, err := json.Marshal(storageInfo)
|
jsonBytes, err := json.Marshal(storageInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponseNoHeader(w, r, ErrInternalError, r.URL.Path)
|
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||||
errorIf(err, "Failed to marshal storage info into json.")
|
errorIf(err, "Failed to marshal storage info into json.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Reply with storage information (across nodes in a
|
// Reply with storage information (across nodes in a
|
||||||
// distributed setup) as json.
|
// distributed setup) as json.
|
||||||
writeSuccessResponse(w, jsonBytes)
|
writeSuccessResponseJSON(w, jsonBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServiceStopHandler - POST /?service
|
// ServiceStopHandler - POST /?service
|
||||||
@ -58,11 +58,13 @@ func (adminAPI adminAPIHandlers) ServiceStatusHandler(w http.ResponseWriter, r *
|
|||||||
func (adminAPI adminAPIHandlers) ServiceStopHandler(w http.ResponseWriter, r *http.Request) {
|
func (adminAPI adminAPIHandlers) ServiceStopHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
adminAPIErr := checkRequestAuthType(r, "", "", "")
|
adminAPIErr := checkRequestAuthType(r, "", "", "")
|
||||||
if adminAPIErr != ErrNone {
|
if adminAPIErr != ErrNone {
|
||||||
writeErrorResponse(w, r, adminAPIErr, r.URL.Path)
|
writeErrorResponse(w, adminAPIErr, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reply to the client before stopping minio server.
|
// Reply to the client before stopping minio server.
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
sendServiceCmd(globalAdminPeers, serviceStop)
|
sendServiceCmd(globalAdminPeers, serviceStop)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,11 +76,13 @@ func (adminAPI adminAPIHandlers) ServiceStopHandler(w http.ResponseWriter, r *ht
|
|||||||
func (adminAPI adminAPIHandlers) ServiceRestartHandler(w http.ResponseWriter, r *http.Request) {
|
func (adminAPI adminAPIHandlers) ServiceRestartHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
adminAPIErr := checkRequestAuthType(r, "", "", "")
|
adminAPIErr := checkRequestAuthType(r, "", "", "")
|
||||||
if adminAPIErr != ErrNone {
|
if adminAPIErr != ErrNone {
|
||||||
writeErrorResponse(w, r, adminAPIErr, r.URL.Path)
|
writeErrorResponse(w, adminAPIErr, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reply to the client before restarting minio server.
|
// Reply to the client before restarting minio server.
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
sendServiceCmd(globalAdminPeers, serviceRestart)
|
sendServiceCmd(globalAdminPeers, serviceRestart)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,14 +135,14 @@ func validateLockQueryParams(vars url.Values) (string, string, time.Duration, AP
|
|||||||
func (adminAPI adminAPIHandlers) ListLocksHandler(w http.ResponseWriter, r *http.Request) {
|
func (adminAPI adminAPIHandlers) ListLocksHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
adminAPIErr := checkRequestAuthType(r, "", "", "")
|
adminAPIErr := checkRequestAuthType(r, "", "", "")
|
||||||
if adminAPIErr != ErrNone {
|
if adminAPIErr != ErrNone {
|
||||||
writeErrorResponse(w, r, adminAPIErr, r.URL.Path)
|
writeErrorResponse(w, adminAPIErr, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
vars := r.URL.Query()
|
vars := r.URL.Query()
|
||||||
bucket, prefix, relTime, adminAPIErr := validateLockQueryParams(vars)
|
bucket, prefix, relTime, adminAPIErr := validateLockQueryParams(vars)
|
||||||
if adminAPIErr != ErrNone {
|
if adminAPIErr != ErrNone {
|
||||||
writeErrorResponse(w, r, adminAPIErr, r.URL.Path)
|
writeErrorResponse(w, adminAPIErr, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,7 +150,7 @@ func (adminAPI adminAPIHandlers) ListLocksHandler(w http.ResponseWriter, r *http
|
|||||||
// are available since relTime.
|
// are available since relTime.
|
||||||
volLocks, err := listPeerLocksInfo(globalAdminPeers, bucket, prefix, relTime)
|
volLocks, err := listPeerLocksInfo(globalAdminPeers, bucket, prefix, relTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
|
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||||
errorIf(err, "Failed to fetch lock information from remote nodes.")
|
errorIf(err, "Failed to fetch lock information from remote nodes.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -154,14 +158,14 @@ func (adminAPI adminAPIHandlers) ListLocksHandler(w http.ResponseWriter, r *http
|
|||||||
// Marshal list of locks as json.
|
// Marshal list of locks as json.
|
||||||
jsonBytes, err := json.Marshal(volLocks)
|
jsonBytes, err := json.Marshal(volLocks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponseNoHeader(w, r, ErrInternalError, r.URL.Path)
|
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||||
errorIf(err, "Failed to marshal lock information into json.")
|
errorIf(err, "Failed to marshal lock information into json.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reply with list of locks held on bucket, matching prefix
|
// Reply with list of locks held on bucket, matching prefix
|
||||||
// older than relTime supplied, as json.
|
// older than relTime supplied, as json.
|
||||||
writeSuccessResponse(w, jsonBytes)
|
writeSuccessResponseJSON(w, jsonBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClearLocksHandler - POST /?lock&bucket=mybucket&prefix=myprefix&older-than=relTime
|
// ClearLocksHandler - POST /?lock&bucket=mybucket&prefix=myprefix&older-than=relTime
|
||||||
@ -173,14 +177,14 @@ func (adminAPI adminAPIHandlers) ListLocksHandler(w http.ResponseWriter, r *http
|
|||||||
func (adminAPI adminAPIHandlers) ClearLocksHandler(w http.ResponseWriter, r *http.Request) {
|
func (adminAPI adminAPIHandlers) ClearLocksHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
adminAPIErr := checkRequestAuthType(r, "", "", "")
|
adminAPIErr := checkRequestAuthType(r, "", "", "")
|
||||||
if adminAPIErr != ErrNone {
|
if adminAPIErr != ErrNone {
|
||||||
writeErrorResponse(w, r, adminAPIErr, r.URL.Path)
|
writeErrorResponse(w, adminAPIErr, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
vars := r.URL.Query()
|
vars := r.URL.Query()
|
||||||
bucket, prefix, relTime, adminAPIErr := validateLockQueryParams(vars)
|
bucket, prefix, relTime, adminAPIErr := validateLockQueryParams(vars)
|
||||||
if adminAPIErr != ErrNone {
|
if adminAPIErr != ErrNone {
|
||||||
writeErrorResponse(w, r, adminAPIErr, r.URL.Path)
|
writeErrorResponse(w, adminAPIErr, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,7 +192,7 @@ func (adminAPI adminAPIHandlers) ClearLocksHandler(w http.ResponseWriter, r *htt
|
|||||||
// are available since relTime.
|
// are available since relTime.
|
||||||
volLocks, err := listPeerLocksInfo(globalAdminPeers, bucket, prefix, relTime)
|
volLocks, err := listPeerLocksInfo(globalAdminPeers, bucket, prefix, relTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponseNoHeader(w, r, ErrInternalError, r.URL.Path)
|
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||||
errorIf(err, "Failed to fetch lock information from remote nodes.")
|
errorIf(err, "Failed to fetch lock information from remote nodes.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -196,14 +200,16 @@ func (adminAPI adminAPIHandlers) ClearLocksHandler(w http.ResponseWriter, r *htt
|
|||||||
// Marshal list of locks as json.
|
// Marshal list of locks as json.
|
||||||
jsonBytes, err := json.Marshal(volLocks)
|
jsonBytes, err := json.Marshal(volLocks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponseNoHeader(w, r, ErrInternalError, r.URL.Path)
|
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||||
errorIf(err, "Failed to marshal lock information into json.")
|
errorIf(err, "Failed to marshal lock information into json.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove lock matching bucket/prefix older than relTime.
|
// Remove lock matching bucket/prefix older than relTime.
|
||||||
for _, volLock := range volLocks {
|
for _, volLock := range volLocks {
|
||||||
globalNSMutex.ForceUnlock(volLock.Bucket, volLock.Object)
|
globalNSMutex.ForceUnlock(volLock.Bucket, volLock.Object)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reply with list of locks cleared, as json.
|
// Reply with list of locks cleared, as json.
|
||||||
writeSuccessResponse(w, jsonBytes)
|
writeSuccessResponseJSON(w, jsonBytes)
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -482,51 +483,67 @@ func generateMultiDeleteResponse(quiet bool, deletedObjects []ObjectIdentifier,
|
|||||||
return deleteResp
|
return deleteResp
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeResponse(w http.ResponseWriter, statusCode int, response []byte) {
|
func writeResponse(w http.ResponseWriter, statusCode int, response []byte, mType mimeType) {
|
||||||
setCommonHeaders(w)
|
setCommonHeaders(w)
|
||||||
w.WriteHeader(statusCode)
|
if mType != mimeNone {
|
||||||
if response == nil {
|
w.Header().Set("Content-Type", string(mType))
|
||||||
return
|
}
|
||||||
|
w.WriteHeader(statusCode)
|
||||||
|
if response != nil {
|
||||||
|
w.Write(response)
|
||||||
|
w.(http.Flusher).Flush()
|
||||||
}
|
}
|
||||||
w.Write(response)
|
|
||||||
w.(http.Flusher).Flush()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeSuccessResponse writes success headers and response if any.
|
// mimeType represents various MIME type used API responses.
|
||||||
func writeSuccessResponse(w http.ResponseWriter, response []byte) {
|
type mimeType string
|
||||||
writeResponse(w, http.StatusOK, response)
|
|
||||||
|
const (
|
||||||
|
// Means no response type.
|
||||||
|
mimeNone mimeType = ""
|
||||||
|
// Means response type is JSON.
|
||||||
|
mimeJSON mimeType = "application/json"
|
||||||
|
// Means response type is XML.
|
||||||
|
mimeXML mimeType = "application/xml"
|
||||||
|
)
|
||||||
|
|
||||||
|
// writeSuccessResponseJSON writes success headers and response if any,
|
||||||
|
// with content-type set to `application/json`.
|
||||||
|
func writeSuccessResponseJSON(w http.ResponseWriter, response []byte) {
|
||||||
|
writeResponse(w, http.StatusOK, response, mimeJSON)
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeSuccessResponseXML writes success headers and response if any,
|
||||||
|
// with content-type set to `application/xml`.
|
||||||
|
func writeSuccessResponseXML(w http.ResponseWriter, response []byte) {
|
||||||
|
writeResponse(w, http.StatusOK, response, mimeXML)
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeSuccessNoContent writes success headers with http status 204
|
// writeSuccessNoContent writes success headers with http status 204
|
||||||
func writeSuccessNoContent(w http.ResponseWriter) {
|
func writeSuccessNoContent(w http.ResponseWriter) {
|
||||||
writeResponse(w, http.StatusNoContent, nil)
|
writeResponse(w, http.StatusNoContent, nil, mimeNone)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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("Location", location)
|
||||||
writeResponse(w, http.StatusSeeOther, nil)
|
writeResponse(w, http.StatusSeeOther, nil, mimeNone)
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeSuccessResponseHeadersOnly(w http.ResponseWriter) {
|
||||||
|
writeResponse(w, http.StatusOK, nil, mimeNone)
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeErrorRespone writes error headers
|
// writeErrorRespone writes error headers
|
||||||
func writeErrorResponse(w http.ResponseWriter, req *http.Request, errorCode APIErrorCode, resource string) {
|
func writeErrorResponse(w http.ResponseWriter, errorCode APIErrorCode, reqURL *url.URL) {
|
||||||
apiError := getAPIError(errorCode)
|
|
||||||
// set common headers
|
|
||||||
setCommonHeaders(w)
|
|
||||||
// write Header
|
|
||||||
w.WriteHeader(apiError.HTTPStatusCode)
|
|
||||||
writeErrorResponseNoHeader(w, req, errorCode, resource)
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeErrorResponseNoHeader(w http.ResponseWriter, req *http.Request, errorCode APIErrorCode, resource string) {
|
|
||||||
apiError := getAPIError(errorCode)
|
apiError := getAPIError(errorCode)
|
||||||
// Generate error response.
|
// Generate error response.
|
||||||
errorResponse := getAPIErrorResponse(apiError, resource)
|
errorResponse := getAPIErrorResponse(apiError, reqURL.Path)
|
||||||
encodedErrorResponse := encodeResponse(errorResponse)
|
encodedErrorResponse := encodeResponse(errorResponse)
|
||||||
// HEAD should have no body, do not attempt to write to it
|
writeResponse(w, apiError.HTTPStatusCode, encodedErrorResponse, mimeXML)
|
||||||
if req.Method != "HEAD" {
|
}
|
||||||
// write error body
|
|
||||||
w.Write(encodedErrorResponse)
|
func writeErrorResponseHeadersOnly(w http.ResponseWriter, errorCode APIErrorCode) {
|
||||||
w.(http.Flusher).Flush()
|
apiError := getAPIError(errorCode)
|
||||||
}
|
writeResponse(w, apiError.HTTPStatusCode, nil, mimeNone)
|
||||||
}
|
}
|
||||||
|
@ -231,5 +231,5 @@ func (a authHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
a.handler.ServeHTTP(w, r)
|
a.handler.ServeHTTP(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
writeErrorResponse(w, r, ErrSignatureVersionNotSupported, r.URL.Path)
|
writeErrorResponse(w, ErrSignatureVersionNotSupported, r.URL)
|
||||||
}
|
}
|
||||||
|
@ -66,12 +66,12 @@ func (api objectAPIHandlers) ListObjectsV2Handler(w http.ResponseWriter, r *http
|
|||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, r, ErrServerNotInitialized, r.URL.Path)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s3Error := checkRequestAuthType(r, bucket, "s3:ListBucket", serverConfig.GetRegion()); s3Error != ErrNone {
|
if s3Error := checkRequestAuthType(r, bucket, "s3:ListBucket", serverConfig.GetRegion()); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ func (api objectAPIHandlers) ListObjectsV2Handler(w http.ResponseWriter, r *http
|
|||||||
// Validate the query params before beginning to serve the request.
|
// Validate the query params before beginning to serve the request.
|
||||||
// fetch-owner is not validated since it is a boolean
|
// fetch-owner is not validated since it is a boolean
|
||||||
if s3Error := validateListObjectsArgs(prefix, marker, delimiter, maxKeys); s3Error != ErrNone {
|
if s3Error := validateListObjectsArgs(prefix, marker, delimiter, maxKeys); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Inititate a list objects operation based on the input params.
|
// Inititate a list objects operation based on the input params.
|
||||||
@ -97,15 +97,14 @@ func (api objectAPIHandlers) ListObjectsV2Handler(w http.ResponseWriter, r *http
|
|||||||
listObjectsInfo, err := objectAPI.ListObjects(bucket, prefix, marker, delimiter, maxKeys)
|
listObjectsInfo, err := objectAPI.ListObjects(bucket, prefix, marker, delimiter, maxKeys)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "Unable to list objects.")
|
errorIf(err, "Unable to list objects.")
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
response := generateListObjectsV2Response(bucket, prefix, token, startAfter, delimiter, fetchOwner, maxKeys, listObjectsInfo)
|
response := generateListObjectsV2Response(bucket, prefix, token, startAfter, delimiter, fetchOwner, maxKeys, listObjectsInfo)
|
||||||
// Write headers
|
|
||||||
setCommonHeaders(w)
|
|
||||||
// Write success response.
|
// Write success response.
|
||||||
writeSuccessResponse(w, encodeResponse(response))
|
writeSuccessResponseXML(w, encodeResponse(response))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListObjectsV1Handler - GET Bucket (List Objects) Version 1.
|
// ListObjectsV1Handler - GET Bucket (List Objects) Version 1.
|
||||||
@ -120,12 +119,12 @@ func (api objectAPIHandlers) ListObjectsV1Handler(w http.ResponseWriter, r *http
|
|||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, r, ErrServerNotInitialized, r.URL.Path)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s3Error := checkRequestAuthType(r, bucket, "s3:ListBucket", serverConfig.GetRegion()); s3Error != ErrNone {
|
if s3Error := checkRequestAuthType(r, bucket, "s3:ListBucket", serverConfig.GetRegion()); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +133,7 @@ func (api objectAPIHandlers) ListObjectsV1Handler(w http.ResponseWriter, r *http
|
|||||||
|
|
||||||
// Validate all the query params before beginning to serve the request.
|
// Validate all the query params before beginning to serve the request.
|
||||||
if s3Error := validateListObjectsArgs(prefix, marker, delimiter, maxKeys); s3Error != ErrNone {
|
if s3Error := validateListObjectsArgs(prefix, marker, delimiter, maxKeys); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,12 +143,11 @@ func (api objectAPIHandlers) ListObjectsV1Handler(w http.ResponseWriter, r *http
|
|||||||
listObjectsInfo, err := objectAPI.ListObjects(bucket, prefix, marker, delimiter, maxKeys)
|
listObjectsInfo, err := objectAPI.ListObjects(bucket, prefix, marker, delimiter, maxKeys)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "Unable to list objects.")
|
errorIf(err, "Unable to list objects.")
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
response := generateListObjectsV1Response(bucket, prefix, marker, delimiter, maxKeys, listObjectsInfo)
|
response := generateListObjectsV1Response(bucket, prefix, marker, delimiter, maxKeys, listObjectsInfo)
|
||||||
// Write headers
|
|
||||||
setCommonHeaders(w)
|
|
||||||
// Write success response.
|
// Write success response.
|
||||||
writeSuccessResponse(w, encodeResponse(response))
|
writeSuccessResponseXML(w, encodeResponse(response))
|
||||||
}
|
}
|
||||||
|
@ -80,18 +80,18 @@ func (api objectAPIHandlers) GetBucketLocationHandler(w http.ResponseWriter, r *
|
|||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, r, ErrServerNotInitialized, r.URL.Path)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s3Error := checkRequestAuthType(r, bucket, "s3:GetBucketLocation", "us-east-1"); s3Error != ErrNone {
|
if s3Error := checkRequestAuthType(r, bucket, "s3:GetBucketLocation", "us-east-1"); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := objectAPI.GetBucketInfo(bucket); err != nil {
|
if _, err := objectAPI.GetBucketInfo(bucket); err != nil {
|
||||||
errorIf(err, "Unable to fetch bucket info.")
|
errorIf(err, "Unable to fetch bucket info.")
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,8 +104,9 @@ func (api objectAPIHandlers) GetBucketLocationHandler(w http.ResponseWriter, r *
|
|||||||
Location: region,
|
Location: region,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
setCommonHeaders(w) // Write headers.
|
|
||||||
writeSuccessResponse(w, encodedSuccessResponse)
|
// Write success response.
|
||||||
|
writeSuccessResponseXML(w, encodedSuccessResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListMultipartUploadsHandler - GET Bucket (List Multipart uploads)
|
// ListMultipartUploadsHandler - GET Bucket (List Multipart uploads)
|
||||||
@ -122,24 +123,24 @@ func (api objectAPIHandlers) ListMultipartUploadsHandler(w http.ResponseWriter,
|
|||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, r, ErrServerNotInitialized, r.URL.Path)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s3Error := checkRequestAuthType(r, bucket, "s3:ListBucketMultipartUploads", serverConfig.GetRegion()); s3Error != ErrNone {
|
if s3Error := checkRequestAuthType(r, bucket, "s3:ListBucketMultipartUploads", serverConfig.GetRegion()); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
prefix, keyMarker, uploadIDMarker, delimiter, maxUploads, _ := getBucketMultipartResources(r.URL.Query())
|
prefix, keyMarker, uploadIDMarker, delimiter, maxUploads, _ := getBucketMultipartResources(r.URL.Query())
|
||||||
if maxUploads < 0 {
|
if maxUploads < 0 {
|
||||||
writeErrorResponse(w, r, ErrInvalidMaxUploads, r.URL.Path)
|
writeErrorResponse(w, ErrInvalidMaxUploads, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if keyMarker != "" {
|
if keyMarker != "" {
|
||||||
// Marker not common with prefix is not implemented.
|
// Marker not common with prefix is not implemented.
|
||||||
if !strings.HasPrefix(keyMarker, prefix) {
|
if !strings.HasPrefix(keyMarker, prefix) {
|
||||||
writeErrorResponse(w, r, ErrNotImplemented, r.URL.Path)
|
writeErrorResponse(w, ErrNotImplemented, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -147,16 +148,15 @@ func (api objectAPIHandlers) ListMultipartUploadsHandler(w http.ResponseWriter,
|
|||||||
listMultipartsInfo, err := objectAPI.ListMultipartUploads(bucket, prefix, keyMarker, uploadIDMarker, delimiter, maxUploads)
|
listMultipartsInfo, err := objectAPI.ListMultipartUploads(bucket, prefix, keyMarker, uploadIDMarker, delimiter, maxUploads)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "Unable to list multipart uploads.")
|
errorIf(err, "Unable to list multipart uploads.")
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// generate response
|
// generate response
|
||||||
response := generateListMultipartUploadsResponse(bucket, listMultipartsInfo)
|
response := generateListMultipartUploadsResponse(bucket, listMultipartsInfo)
|
||||||
encodedSuccessResponse := encodeResponse(response)
|
encodedSuccessResponse := encodeResponse(response)
|
||||||
// write headers.
|
|
||||||
setCommonHeaders(w)
|
|
||||||
// write success response.
|
// write success response.
|
||||||
writeSuccessResponse(w, encodedSuccessResponse)
|
writeSuccessResponseXML(w, encodedSuccessResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListBucketsHandler - GET Service.
|
// ListBucketsHandler - GET Service.
|
||||||
@ -166,7 +166,7 @@ func (api objectAPIHandlers) ListMultipartUploadsHandler(w http.ResponseWriter,
|
|||||||
func (api objectAPIHandlers) ListBucketsHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) ListBucketsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, r, ErrServerNotInitialized, r.URL.Path)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,24 +177,23 @@ func (api objectAPIHandlers) ListBucketsHandler(w http.ResponseWriter, r *http.R
|
|||||||
s3Error = checkRequestAuthType(r, "", "", serverConfig.GetRegion())
|
s3Error = checkRequestAuthType(r, "", "", serverConfig.GetRegion())
|
||||||
}
|
}
|
||||||
if s3Error != ErrNone {
|
if s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Invoke the list buckets.
|
// Invoke the list buckets.
|
||||||
bucketsInfo, err := objectAPI.ListBuckets()
|
bucketsInfo, err := objectAPI.ListBuckets()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "Unable to list buckets.")
|
errorIf(err, "Unable to list buckets.")
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate response.
|
// Generate response.
|
||||||
response := generateListBucketsResponse(bucketsInfo)
|
response := generateListBucketsResponse(bucketsInfo)
|
||||||
encodedSuccessResponse := encodeResponse(response)
|
encodedSuccessResponse := encodeResponse(response)
|
||||||
// Write headers.
|
|
||||||
setCommonHeaders(w)
|
|
||||||
// Write response.
|
// Write response.
|
||||||
writeSuccessResponse(w, encodedSuccessResponse)
|
writeSuccessResponseXML(w, encodedSuccessResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteMultipleObjectsHandler - deletes multiple objects.
|
// DeleteMultipleObjectsHandler - deletes multiple objects.
|
||||||
@ -204,26 +203,26 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter,
|
|||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, r, ErrServerNotInitialized, r.URL.Path)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s3Error := checkRequestAuthType(r, bucket, "s3:DeleteObject", serverConfig.GetRegion()); s3Error != ErrNone {
|
if s3Error := checkRequestAuthType(r, bucket, "s3:DeleteObject", serverConfig.GetRegion()); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Content-Length is required and should be non-zero
|
// Content-Length is required and should be non-zero
|
||||||
// http://docs.aws.amazon.com/AmazonS3/latest/API/multiobjectdeleteapi.html
|
// http://docs.aws.amazon.com/AmazonS3/latest/API/multiobjectdeleteapi.html
|
||||||
if r.ContentLength <= 0 {
|
if r.ContentLength <= 0 {
|
||||||
writeErrorResponse(w, r, ErrMissingContentLength, r.URL.Path)
|
writeErrorResponse(w, ErrMissingContentLength, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Content-Md5 is requied should be set
|
// Content-Md5 is requied should be set
|
||||||
// http://docs.aws.amazon.com/AmazonS3/latest/API/multiobjectdeleteapi.html
|
// http://docs.aws.amazon.com/AmazonS3/latest/API/multiobjectdeleteapi.html
|
||||||
if _, ok := r.Header["Content-Md5"]; !ok {
|
if _, ok := r.Header["Content-Md5"]; !ok {
|
||||||
writeErrorResponse(w, r, ErrMissingContentMD5, r.URL.Path)
|
writeErrorResponse(w, ErrMissingContentMD5, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,7 +232,7 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter,
|
|||||||
// Read incoming body XML bytes.
|
// Read incoming body XML bytes.
|
||||||
if _, err := io.ReadFull(r.Body, deleteXMLBytes); err != nil {
|
if _, err := io.ReadFull(r.Body, deleteXMLBytes); err != nil {
|
||||||
errorIf(err, "Unable to read HTTP body.")
|
errorIf(err, "Unable to read HTTP body.")
|
||||||
writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
|
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,7 +240,7 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter,
|
|||||||
deleteObjects := &DeleteObjectsRequest{}
|
deleteObjects := &DeleteObjectsRequest{}
|
||||||
if err := xml.Unmarshal(deleteXMLBytes, deleteObjects); err != nil {
|
if err := xml.Unmarshal(deleteXMLBytes, deleteObjects); err != nil {
|
||||||
errorIf(err, "Unable to unmarshal delete objects request XML.")
|
errorIf(err, "Unable to unmarshal delete objects request XML.")
|
||||||
writeErrorResponse(w, r, ErrMalformedXML, r.URL.Path)
|
writeErrorResponse(w, ErrMalformedXML, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,10 +288,9 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter,
|
|||||||
// Generate response
|
// Generate response
|
||||||
response := generateMultiDeleteResponse(deleteObjects.Quiet, deletedObjects, deleteErrors)
|
response := generateMultiDeleteResponse(deleteObjects.Quiet, deletedObjects, deleteErrors)
|
||||||
encodedSuccessResponse := encodeResponse(response)
|
encodedSuccessResponse := encodeResponse(response)
|
||||||
// Write headers
|
|
||||||
setCommonHeaders(w)
|
|
||||||
// Write success response.
|
// Write success response.
|
||||||
writeSuccessResponse(w, encodedSuccessResponse)
|
writeSuccessResponseXML(w, encodedSuccessResponse)
|
||||||
|
|
||||||
// Notify deleted event for objects.
|
// Notify deleted event for objects.
|
||||||
for _, dobj := range deletedObjects {
|
for _, dobj := range deletedObjects {
|
||||||
@ -315,13 +313,13 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter,
|
|||||||
func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, r, ErrServerNotInitialized, r.URL.Path)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutBucket does not have any bucket action.
|
// PutBucket does not have any bucket action.
|
||||||
if s3Error := checkRequestAuthType(r, "", "", "us-east-1"); s3Error != ErrNone {
|
if s3Error := checkRequestAuthType(r, "", "", "us-east-1"); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,7 +329,7 @@ func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Req
|
|||||||
// Validate if incoming location constraint is valid, reject
|
// Validate if incoming location constraint is valid, reject
|
||||||
// requests which do not follow valid region requirements.
|
// requests which do not follow valid region requirements.
|
||||||
if s3Error := isValidLocationConstraint(r); s3Error != ErrNone {
|
if s3Error := isValidLocationConstraint(r); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,12 +341,14 @@ func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Req
|
|||||||
err := objectAPI.MakeBucket(bucket)
|
err := objectAPI.MakeBucket(bucket)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "Unable to create a bucket.")
|
errorIf(err, "Unable to create a bucket.")
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure to add Location information here only for bucket
|
// Make sure to add Location information here only for bucket
|
||||||
w.Header().Set("Location", getLocation(r))
|
w.Header().Set("Location", getLocation(r))
|
||||||
writeSuccessResponse(w, nil)
|
|
||||||
|
writeSuccessResponseHeadersOnly(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PostPolicyBucketHandler - POST policy
|
// PostPolicyBucketHandler - POST policy
|
||||||
@ -358,7 +358,7 @@ func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Req
|
|||||||
func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, r, ErrServerNotInitialized, r.URL.Path)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,14 +367,14 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h
|
|||||||
reader, err := r.MultipartReader()
|
reader, err := r.MultipartReader()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "Unable to initialize multipart reader.")
|
errorIf(err, "Unable to initialize multipart reader.")
|
||||||
writeErrorResponse(w, r, ErrMalformedPOSTRequest, r.URL.Path)
|
writeErrorResponse(w, ErrMalformedPOSTRequest, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fileBody, fileName, formValues, err := extractPostPolicyFormValues(reader)
|
fileBody, fileName, formValues, err := extractPostPolicyFormValues(reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "Unable to parse form values.")
|
errorIf(err, "Unable to parse form values.")
|
||||||
writeErrorResponse(w, r, ErrMalformedPOSTRequest, r.URL.Path)
|
writeErrorResponse(w, ErrMalformedPOSTRequest, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
bucket := mux.Vars(r)["bucket"]
|
bucket := mux.Vars(r)["bucket"]
|
||||||
@ -390,25 +390,25 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h
|
|||||||
// Verify policy signature.
|
// Verify policy signature.
|
||||||
apiErr := doesPolicySignatureMatch(formValues)
|
apiErr := doesPolicySignatureMatch(formValues)
|
||||||
if apiErr != ErrNone {
|
if apiErr != ErrNone {
|
||||||
writeErrorResponse(w, r, apiErr, r.URL.Path)
|
writeErrorResponse(w, apiErr, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
policyBytes, err := base64.StdEncoding.DecodeString(formValues["Policy"])
|
policyBytes, err := base64.StdEncoding.DecodeString(formValues["Policy"])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponse(w, r, ErrMalformedPOSTRequest, r.URL.Path)
|
writeErrorResponse(w, ErrMalformedPOSTRequest, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
postPolicyForm, err := parsePostPolicyForm(string(policyBytes))
|
postPolicyForm, err := parsePostPolicyForm(string(policyBytes))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponse(w, r, ErrMalformedPOSTRequest, r.URL.Path)
|
writeErrorResponse(w, ErrMalformedPOSTRequest, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure formValues adhere to policy restrictions.
|
// Make sure formValues adhere to policy restrictions.
|
||||||
if apiErr = checkPostPolicy(formValues, postPolicyForm); apiErr != ErrNone {
|
if apiErr = checkPostPolicy(formValues, postPolicyForm); apiErr != ErrNone {
|
||||||
writeErrorResponse(w, r, apiErr, r.URL.Path)
|
writeErrorResponse(w, apiErr, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -442,7 +442,7 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h
|
|||||||
objInfo, err := objectAPI.PutObject(bucket, object, -1, fileBody, metadata, sha256sum)
|
objInfo, err := objectAPI.PutObject(bucket, object, -1, fileBody, metadata, sha256sum)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "Unable to create object.")
|
errorIf(err, "Unable to create object.")
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Header().Set("ETag", "\""+objInfo.MD5Sum+"\"")
|
w.Header().Set("ETag", "\""+objInfo.MD5Sum+"\"")
|
||||||
@ -471,10 +471,9 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h
|
|||||||
ETag: "\"" + objInfo.MD5Sum + "\"",
|
ETag: "\"" + objInfo.MD5Sum + "\"",
|
||||||
Location: getObjectLocation(bucket, object),
|
Location: getObjectLocation(bucket, object),
|
||||||
})
|
})
|
||||||
writeResponse(w, http.StatusCreated, resp)
|
writeResponse(w, http.StatusCreated, resp, "application/xml")
|
||||||
|
|
||||||
case "200":
|
case "200":
|
||||||
writeSuccessResponse(w, nil)
|
writeSuccessResponseHeadersOnly(w)
|
||||||
default:
|
default:
|
||||||
writeSuccessNoContent(w)
|
writeSuccessNoContent(w)
|
||||||
}
|
}
|
||||||
@ -504,12 +503,12 @@ func (api objectAPIHandlers) HeadBucketHandler(w http.ResponseWriter, r *http.Re
|
|||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, r, ErrServerNotInitialized, r.URL.Path)
|
writeErrorResponseHeadersOnly(w, ErrServerNotInitialized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s3Error := checkRequestAuthType(r, bucket, "s3:ListBucket", serverConfig.GetRegion()); s3Error != ErrNone {
|
if s3Error := checkRequestAuthType(r, bucket, "s3:ListBucket", serverConfig.GetRegion()); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponseHeadersOnly(w, s3Error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -519,23 +518,24 @@ func (api objectAPIHandlers) HeadBucketHandler(w http.ResponseWriter, r *http.Re
|
|||||||
|
|
||||||
if _, err := objectAPI.GetBucketInfo(bucket); err != nil {
|
if _, err := objectAPI.GetBucketInfo(bucket); err != nil {
|
||||||
errorIf(err, "Unable to fetch bucket info.")
|
errorIf(err, "Unable to fetch bucket info.")
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponseHeadersOnly(w, toAPIErrorCode(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
writeSuccessResponse(w, nil)
|
|
||||||
|
writeSuccessResponseHeadersOnly(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteBucketHandler - Delete bucket
|
// DeleteBucketHandler - Delete bucket
|
||||||
func (api objectAPIHandlers) DeleteBucketHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) DeleteBucketHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, r, ErrServerNotInitialized, r.URL.Path)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteBucket does not have any bucket action.
|
// DeleteBucket does not have any bucket action.
|
||||||
if s3Error := checkRequestAuthType(r, "", "", serverConfig.GetRegion()); s3Error != ErrNone {
|
if s3Error := checkRequestAuthType(r, "", "", serverConfig.GetRegion()); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -549,7 +549,7 @@ func (api objectAPIHandlers) DeleteBucketHandler(w http.ResponseWriter, r *http.
|
|||||||
// Attempt to delete bucket.
|
// Attempt to delete bucket.
|
||||||
if err := objectAPI.DeleteBucket(bucket); err != nil {
|
if err := objectAPI.DeleteBucket(bucket); err != nil {
|
||||||
errorIf(err, "Unable to delete a bucket.")
|
errorIf(err, "Unable to delete a bucket.")
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,12 +42,12 @@ const (
|
|||||||
func (api objectAPIHandlers) GetBucketNotificationHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) GetBucketNotificationHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
objAPI := api.ObjectAPI()
|
objAPI := api.ObjectAPI()
|
||||||
if objAPI == nil {
|
if objAPI == nil {
|
||||||
writeErrorResponse(w, r, ErrServerNotInitialized, r.URL.Path)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s3Error := checkRequestAuthType(r, "", "", serverConfig.GetRegion()); s3Error != ErrNone {
|
if s3Error := checkRequestAuthType(r, "", "", serverConfig.GetRegion()); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ func (api objectAPIHandlers) GetBucketNotificationHandler(w http.ResponseWriter,
|
|||||||
_, err := objAPI.GetBucketInfo(bucket)
|
_, err := objAPI.GetBucketInfo(bucket)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "Unable to find bucket info.")
|
errorIf(err, "Unable to find bucket info.")
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ func (api objectAPIHandlers) GetBucketNotificationHandler(w http.ResponseWriter,
|
|||||||
nConfig, err := loadNotificationConfig(bucket, objAPI)
|
nConfig, err := loadNotificationConfig(bucket, objAPI)
|
||||||
if err != nil && err != errNoSuchNotifications {
|
if err != nil && err != errNoSuchNotifications {
|
||||||
errorIf(err, "Unable to read notification configuration.")
|
errorIf(err, "Unable to read notification configuration.")
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// For no notifications we write a dummy XML.
|
// For no notifications we write a dummy XML.
|
||||||
@ -77,11 +77,12 @@ func (api objectAPIHandlers) GetBucketNotificationHandler(w http.ResponseWriter,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
// For any marshalling failure.
|
// For any marshalling failure.
|
||||||
errorIf(err, "Unable to marshal notification configuration into XML.", err)
|
errorIf(err, "Unable to marshal notification configuration into XML.", err)
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Success.
|
// Success.
|
||||||
writeSuccessResponse(w, notificationBytes)
|
writeSuccessResponseXML(w, notificationBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutBucketNotificationHandler - Minio notification feature enables
|
// PutBucketNotificationHandler - Minio notification feature enables
|
||||||
@ -95,12 +96,12 @@ func (api objectAPIHandlers) GetBucketNotificationHandler(w http.ResponseWriter,
|
|||||||
func (api objectAPIHandlers) PutBucketNotificationHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) PutBucketNotificationHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, r, ErrServerNotInitialized, r.URL.Path)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s3Error := checkRequestAuthType(r, "", "", serverConfig.GetRegion()); s3Error != ErrNone {
|
if s3Error := checkRequestAuthType(r, "", "", serverConfig.GetRegion()); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +111,7 @@ func (api objectAPIHandlers) PutBucketNotificationHandler(w http.ResponseWriter,
|
|||||||
_, err := objectAPI.GetBucketInfo(bucket)
|
_, err := objectAPI.GetBucketInfo(bucket)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "Unable to find bucket info.")
|
errorIf(err, "Unable to find bucket info.")
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,7 +119,7 @@ func (api objectAPIHandlers) PutBucketNotificationHandler(w http.ResponseWriter,
|
|||||||
// always needs a Content-Length if incoming request is not chunked.
|
// always needs a Content-Length if incoming request is not chunked.
|
||||||
if !contains(r.TransferEncoding, "chunked") {
|
if !contains(r.TransferEncoding, "chunked") {
|
||||||
if r.ContentLength == -1 {
|
if r.ContentLength == -1 {
|
||||||
writeErrorResponse(w, r, ErrMissingContentLength, r.URL.Path)
|
writeErrorResponse(w, ErrMissingContentLength, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -132,7 +133,7 @@ func (api objectAPIHandlers) PutBucketNotificationHandler(w http.ResponseWriter,
|
|||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "Unable to read incoming body.")
|
errorIf(err, "Unable to read incoming body.")
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,25 +142,25 @@ func (api objectAPIHandlers) PutBucketNotificationHandler(w http.ResponseWriter,
|
|||||||
notificationConfigBytes := buffer.Bytes()
|
notificationConfigBytes := buffer.Bytes()
|
||||||
if err = xml.Unmarshal(notificationConfigBytes, ¬ificationCfg); err != nil {
|
if err = xml.Unmarshal(notificationConfigBytes, ¬ificationCfg); err != nil {
|
||||||
errorIf(err, "Unable to parse notification configuration XML.")
|
errorIf(err, "Unable to parse notification configuration XML.")
|
||||||
writeErrorResponse(w, r, ErrMalformedXML, r.URL.Path)
|
writeErrorResponse(w, ErrMalformedXML, r.URL)
|
||||||
return
|
return
|
||||||
} // Successfully marshalled notification configuration.
|
} // Successfully marshalled notification configuration.
|
||||||
|
|
||||||
// Validate unmarshalled bucket notification configuration.
|
// Validate unmarshalled bucket notification configuration.
|
||||||
if s3Error := validateNotificationConfig(notificationCfg); s3Error != ErrNone {
|
if s3Error := validateNotificationConfig(notificationCfg); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put bucket notification config.
|
// Put bucket notification config.
|
||||||
err = PutBucketNotificationConfig(bucket, ¬ificationCfg, objectAPI)
|
err = PutBucketNotificationConfig(bucket, ¬ificationCfg, objectAPI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Success.
|
// Success.
|
||||||
writeSuccessResponse(w, nil)
|
writeSuccessResponseHeadersOnly(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutBucketNotificationConfig - Put a new notification config for a
|
// PutBucketNotificationConfig - Put a new notification config for a
|
||||||
@ -249,12 +250,12 @@ func (api objectAPIHandlers) ListenBucketNotificationHandler(w http.ResponseWrit
|
|||||||
// Validate if bucket exists.
|
// Validate if bucket exists.
|
||||||
objAPI := api.ObjectAPI()
|
objAPI := api.ObjectAPI()
|
||||||
if objAPI == nil {
|
if objAPI == nil {
|
||||||
writeErrorResponse(w, r, ErrServerNotInitialized, r.URL.Path)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s3Error := checkRequestAuthType(r, "", "", serverConfig.GetRegion()); s3Error != ErrNone {
|
if s3Error := checkRequestAuthType(r, "", "", serverConfig.GetRegion()); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,19 +266,19 @@ func (api objectAPIHandlers) ListenBucketNotificationHandler(w http.ResponseWrit
|
|||||||
prefixes, suffixes, events := getListenBucketNotificationResources(r.URL.Query())
|
prefixes, suffixes, events := getListenBucketNotificationResources(r.URL.Query())
|
||||||
|
|
||||||
if err := validateFilterValues(prefixes); err != ErrNone {
|
if err := validateFilterValues(prefixes); err != ErrNone {
|
||||||
writeErrorResponse(w, r, err, r.URL.Path)
|
writeErrorResponse(w, err, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateFilterValues(suffixes); err != ErrNone {
|
if err := validateFilterValues(suffixes); err != ErrNone {
|
||||||
writeErrorResponse(w, r, err, r.URL.Path)
|
writeErrorResponse(w, err, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate all the resource events.
|
// Validate all the resource events.
|
||||||
for _, event := range events {
|
for _, event := range events {
|
||||||
if errCode := checkEvent(event); errCode != ErrNone {
|
if errCode := checkEvent(event); errCode != ErrNone {
|
||||||
writeErrorResponse(w, r, errCode, r.URL.Path)
|
writeErrorResponse(w, errCode, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -285,7 +286,7 @@ func (api objectAPIHandlers) ListenBucketNotificationHandler(w http.ResponseWrit
|
|||||||
_, err := objAPI.GetBucketInfo(bucket)
|
_, err := objAPI.GetBucketInfo(bucket)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "Unable to get bucket info.")
|
errorIf(err, "Unable to get bucket info.")
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,7 +339,7 @@ func (api objectAPIHandlers) ListenBucketNotificationHandler(w http.ResponseWrit
|
|||||||
// Add channel for listener events
|
// Add channel for listener events
|
||||||
if err = globalEventNotifier.AddListenerChan(accountARN, nEventCh); err != nil {
|
if err = globalEventNotifier.AddListenerChan(accountARN, nEventCh); err != nil {
|
||||||
errorIf(err, "Error adding a listener!")
|
errorIf(err, "Error adding a listener!")
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Remove listener channel after the writer has closed or the
|
// Remove listener channel after the writer has closed or the
|
||||||
@ -355,7 +356,7 @@ func (api objectAPIHandlers) ListenBucketNotificationHandler(w http.ResponseWrit
|
|||||||
|
|
||||||
err = AddBucketListenerConfig(bucket, &lc, objAPI)
|
err = AddBucketListenerConfig(bucket, &lc, objAPI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer RemoveBucketListenerConfig(bucket, &lc, objAPI)
|
defer RemoveBucketListenerConfig(bucket, &lc, objAPI)
|
||||||
|
@ -121,12 +121,12 @@ func bucketPolicyConditionMatch(conditions map[string]set.StringSet, statement p
|
|||||||
func (api objectAPIHandlers) PutBucketPolicyHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) PutBucketPolicyHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
objAPI := api.ObjectAPI()
|
objAPI := api.ObjectAPI()
|
||||||
if objAPI == nil {
|
if objAPI == nil {
|
||||||
writeErrorResponse(w, r, ErrServerNotInitialized, r.URL.Path)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s3Error := checkRequestAuthType(r, "", "", serverConfig.GetRegion()); s3Error != ErrNone {
|
if s3Error := checkRequestAuthType(r, "", "", serverConfig.GetRegion()); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,7 +137,7 @@ func (api objectAPIHandlers) PutBucketPolicyHandler(w http.ResponseWriter, r *ht
|
|||||||
_, err := objAPI.GetBucketInfo(bucket)
|
_, err := objAPI.GetBucketInfo(bucket)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "Unable to find bucket info.")
|
errorIf(err, "Unable to find bucket info.")
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,12 +146,12 @@ func (api objectAPIHandlers) PutBucketPolicyHandler(w http.ResponseWriter, r *ht
|
|||||||
// incoming request is not chunked.
|
// incoming request is not chunked.
|
||||||
if !contains(r.TransferEncoding, "chunked") {
|
if !contains(r.TransferEncoding, "chunked") {
|
||||||
if r.ContentLength == -1 || r.ContentLength == 0 {
|
if r.ContentLength == -1 || r.ContentLength == 0 {
|
||||||
writeErrorResponse(w, r, ErrMissingContentLength, r.URL.Path)
|
writeErrorResponse(w, ErrMissingContentLength, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// If Content-Length is greater than maximum allowed policy size.
|
// If Content-Length is greater than maximum allowed policy size.
|
||||||
if r.ContentLength > maxAccessPolicySize {
|
if r.ContentLength > maxAccessPolicySize {
|
||||||
writeErrorResponse(w, r, ErrEntityTooLarge, r.URL.Path)
|
writeErrorResponse(w, ErrEntityTooLarge, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -162,13 +162,13 @@ func (api objectAPIHandlers) PutBucketPolicyHandler(w http.ResponseWriter, r *ht
|
|||||||
policyBytes, err := ioutil.ReadAll(io.LimitReader(r.Body, maxAccessPolicySize))
|
policyBytes, err := ioutil.ReadAll(io.LimitReader(r.Body, maxAccessPolicySize))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "Unable to read from client.")
|
errorIf(err, "Unable to read from client.")
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse validate and save bucket policy.
|
// Parse validate and save bucket policy.
|
||||||
if s3Error := parseAndPersistBucketPolicy(bucket, policyBytes, objAPI); s3Error != ErrNone {
|
if s3Error := parseAndPersistBucketPolicy(bucket, policyBytes, objAPI); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,12 +183,12 @@ func (api objectAPIHandlers) PutBucketPolicyHandler(w http.ResponseWriter, r *ht
|
|||||||
func (api objectAPIHandlers) DeleteBucketPolicyHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) DeleteBucketPolicyHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
objAPI := api.ObjectAPI()
|
objAPI := api.ObjectAPI()
|
||||||
if objAPI == nil {
|
if objAPI == nil {
|
||||||
writeErrorResponse(w, r, ErrServerNotInitialized, r.URL.Path)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s3Error := checkRequestAuthType(r, "", "", serverConfig.GetRegion()); s3Error != ErrNone {
|
if s3Error := checkRequestAuthType(r, "", "", serverConfig.GetRegion()); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,7 +199,7 @@ func (api objectAPIHandlers) DeleteBucketPolicyHandler(w http.ResponseWriter, r
|
|||||||
_, err := objAPI.GetBucketInfo(bucket)
|
_, err := objAPI.GetBucketInfo(bucket)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "Unable to find bucket info.")
|
errorIf(err, "Unable to find bucket info.")
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,9 +208,9 @@ func (api objectAPIHandlers) DeleteBucketPolicyHandler(w http.ResponseWriter, r
|
|||||||
if err := persistAndNotifyBucketPolicyChange(bucket, policyChange{true, nil}, objAPI); err != nil {
|
if err := persistAndNotifyBucketPolicyChange(bucket, policyChange{true, nil}, objAPI); err != nil {
|
||||||
switch err.(type) {
|
switch err.(type) {
|
||||||
case BucketPolicyNotFound:
|
case BucketPolicyNotFound:
|
||||||
writeErrorResponse(w, r, ErrNoSuchBucketPolicy, r.URL.Path)
|
writeErrorResponse(w, ErrNoSuchBucketPolicy, r.URL)
|
||||||
default:
|
default:
|
||||||
writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
|
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -226,12 +226,12 @@ func (api objectAPIHandlers) DeleteBucketPolicyHandler(w http.ResponseWriter, r
|
|||||||
func (api objectAPIHandlers) GetBucketPolicyHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) GetBucketPolicyHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
objAPI := api.ObjectAPI()
|
objAPI := api.ObjectAPI()
|
||||||
if objAPI == nil {
|
if objAPI == nil {
|
||||||
writeErrorResponse(w, r, ErrServerNotInitialized, r.URL.Path)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s3Error := checkRequestAuthType(r, "", "", serverConfig.GetRegion()); s3Error != ErrNone {
|
if s3Error := checkRequestAuthType(r, "", "", serverConfig.GetRegion()); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,7 +242,7 @@ func (api objectAPIHandlers) GetBucketPolicyHandler(w http.ResponseWriter, r *ht
|
|||||||
_, err := objAPI.GetBucketInfo(bucket)
|
_, err := objAPI.GetBucketInfo(bucket)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "Unable to find bucket info.")
|
errorIf(err, "Unable to find bucket info.")
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,9 +252,9 @@ func (api objectAPIHandlers) GetBucketPolicyHandler(w http.ResponseWriter, r *ht
|
|||||||
errorIf(err, "Unable to read bucket policy.")
|
errorIf(err, "Unable to read bucket policy.")
|
||||||
switch err.(type) {
|
switch err.(type) {
|
||||||
case BucketPolicyNotFound:
|
case BucketPolicyNotFound:
|
||||||
writeErrorResponse(w, r, ErrNoSuchBucketPolicy, r.URL.Path)
|
writeErrorResponse(w, ErrNoSuchBucketPolicy, r.URL)
|
||||||
default:
|
default:
|
||||||
writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
|
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -169,7 +169,7 @@ func setPrivateBucketHandler(h http.Handler) http.Handler {
|
|||||||
func (h minioPrivateBucketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (h minioPrivateBucketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
// For all non browser requests, reject access to 'reservedBucket'.
|
// For all non browser requests, reject access to 'reservedBucket'.
|
||||||
if !guessIsBrowserReq(r) && path.Clean(r.URL.Path) == reservedBucket {
|
if !guessIsBrowserReq(r) && path.Clean(r.URL.Path) == reservedBucket {
|
||||||
writeErrorResponse(w, r, ErrAllAccessDisabled, r.URL.Path)
|
writeErrorResponse(w, ErrAllAccessDisabled, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
h.handler.ServeHTTP(w, r)
|
h.handler.ServeHTTP(w, r)
|
||||||
@ -231,14 +231,14 @@ func (h timeValidityHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
// All our internal APIs are sensitive towards Date
|
// All our internal APIs are sensitive towards Date
|
||||||
// header, for all requests where Date header is not
|
// header, for all requests where Date header is not
|
||||||
// present we will reject such clients.
|
// present we will reject such clients.
|
||||||
writeErrorResponse(w, r, apiErr, r.URL.Path)
|
writeErrorResponse(w, apiErr, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Verify if the request date header is shifted by less than globalMaxSkewTime parameter in the past
|
// Verify if the request date header is shifted by less than globalMaxSkewTime parameter in the past
|
||||||
// or in the future, reject request otherwise.
|
// or in the future, reject request otherwise.
|
||||||
curTime := time.Now().UTC()
|
curTime := time.Now().UTC()
|
||||||
if curTime.Sub(amzDate) > globalMaxSkewTime || amzDate.Sub(curTime) > globalMaxSkewTime {
|
if curTime.Sub(amzDate) > globalMaxSkewTime || amzDate.Sub(curTime) > globalMaxSkewTime {
|
||||||
writeErrorResponse(w, r, ErrRequestTimeTooSkewed, r.URL.Path)
|
writeErrorResponse(w, ErrRequestTimeTooSkewed, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -327,20 +327,20 @@ func (h resourceHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
// If bucketName is present and not objectName check for bucket level resource queries.
|
// If bucketName is present and not objectName check for bucket level resource queries.
|
||||||
if bucketName != "" && objectName == "" {
|
if bucketName != "" && objectName == "" {
|
||||||
if ignoreNotImplementedBucketResources(r) {
|
if ignoreNotImplementedBucketResources(r) {
|
||||||
writeErrorResponse(w, r, ErrNotImplemented, r.URL.Path)
|
writeErrorResponse(w, ErrNotImplemented, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If bucketName and objectName are present check for its resource queries.
|
// If bucketName and objectName are present check for its resource queries.
|
||||||
if bucketName != "" && objectName != "" {
|
if bucketName != "" && objectName != "" {
|
||||||
if ignoreNotImplementedObjectResources(r) {
|
if ignoreNotImplementedObjectResources(r) {
|
||||||
writeErrorResponse(w, r, ErrNotImplemented, r.URL.Path)
|
writeErrorResponse(w, ErrNotImplemented, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// A put method on path "/" doesn't make sense, ignore it.
|
// A put method on path "/" doesn't make sense, ignore it.
|
||||||
if r.Method == "PUT" && r.URL.Path == "/" {
|
if r.Method == "PUT" && r.URL.Path == "/" {
|
||||||
writeErrorResponse(w, r, ErrNotImplemented, r.URL.Path)
|
writeErrorResponse(w, ErrNotImplemented, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ func checkCopyObjectPreconditions(w http.ResponseWriter, r *http.Request, objInf
|
|||||||
if !ifModifiedSince(objInfo.ModTime, ifModifiedSinceHeader) {
|
if !ifModifiedSince(objInfo.ModTime, ifModifiedSinceHeader) {
|
||||||
// If the object is not modified since the specified time.
|
// If the object is not modified since the specified time.
|
||||||
writeHeaders()
|
writeHeaders()
|
||||||
writeErrorResponse(w, r, ErrPreconditionFailed, r.URL.Path)
|
writeErrorResponse(w, ErrPreconditionFailed, r.URL)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -71,7 +71,7 @@ func checkCopyObjectPreconditions(w http.ResponseWriter, r *http.Request, objInf
|
|||||||
if ifModifiedSince(objInfo.ModTime, ifUnmodifiedSinceHeader) {
|
if ifModifiedSince(objInfo.ModTime, ifUnmodifiedSinceHeader) {
|
||||||
// If the object is modified since the specified time.
|
// If the object is modified since the specified time.
|
||||||
writeHeaders()
|
writeHeaders()
|
||||||
writeErrorResponse(w, r, ErrPreconditionFailed, r.URL.Path)
|
writeErrorResponse(w, ErrPreconditionFailed, r.URL)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,7 +83,7 @@ func checkCopyObjectPreconditions(w http.ResponseWriter, r *http.Request, objInf
|
|||||||
if objInfo.MD5Sum != "" && !isETagEqual(objInfo.MD5Sum, ifMatchETagHeader) {
|
if objInfo.MD5Sum != "" && !isETagEqual(objInfo.MD5Sum, ifMatchETagHeader) {
|
||||||
// If the object ETag does not match with the specified ETag.
|
// If the object ETag does not match with the specified ETag.
|
||||||
writeHeaders()
|
writeHeaders()
|
||||||
writeErrorResponse(w, r, ErrPreconditionFailed, r.URL.Path)
|
writeErrorResponse(w, ErrPreconditionFailed, r.URL)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,7 +95,7 @@ func checkCopyObjectPreconditions(w http.ResponseWriter, r *http.Request, objInf
|
|||||||
if objInfo.MD5Sum != "" && isETagEqual(objInfo.MD5Sum, ifNoneMatchETagHeader) {
|
if objInfo.MD5Sum != "" && isETagEqual(objInfo.MD5Sum, ifNoneMatchETagHeader) {
|
||||||
// If the object ETag matches with the specified ETag.
|
// If the object ETag matches with the specified ETag.
|
||||||
writeHeaders()
|
writeHeaders()
|
||||||
writeErrorResponse(w, r, ErrPreconditionFailed, r.URL.Path)
|
writeErrorResponse(w, ErrPreconditionFailed, r.URL)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,7 +152,7 @@ func checkPreconditions(w http.ResponseWriter, r *http.Request, objInfo ObjectIn
|
|||||||
if ifModifiedSince(objInfo.ModTime, ifUnmodifiedSinceHeader) {
|
if ifModifiedSince(objInfo.ModTime, ifUnmodifiedSinceHeader) {
|
||||||
// If the object is modified since the specified time.
|
// If the object is modified since the specified time.
|
||||||
writeHeaders()
|
writeHeaders()
|
||||||
writeErrorResponse(w, r, ErrPreconditionFailed, r.URL.Path)
|
writeErrorResponse(w, ErrPreconditionFailed, r.URL)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -164,7 +164,7 @@ func checkPreconditions(w http.ResponseWriter, r *http.Request, objInfo ObjectIn
|
|||||||
if !isETagEqual(objInfo.MD5Sum, ifMatchETagHeader) {
|
if !isETagEqual(objInfo.MD5Sum, ifMatchETagHeader) {
|
||||||
// If the object ETag does not match with the specified ETag.
|
// If the object ETag does not match with the specified ETag.
|
||||||
writeHeaders()
|
writeHeaders()
|
||||||
writeErrorResponse(w, r, ErrPreconditionFailed, r.URL.Path)
|
writeErrorResponse(w, ErrPreconditionFailed, r.URL)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,12 +86,12 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req
|
|||||||
// Fetch object stat info.
|
// Fetch object stat info.
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, r, ErrServerNotInitialized, r.URL.Path)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s3Error := checkRequestAuthType(r, bucket, "s3:GetObject", serverConfig.GetRegion()); s3Error != ErrNone {
|
if s3Error := checkRequestAuthType(r, bucket, "s3:GetObject", serverConfig.GetRegion()); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req
|
|||||||
if apiErr == ErrNoSuchKey {
|
if apiErr == ErrNoSuchKey {
|
||||||
apiErr = errAllowableObjectNotFound(bucket, r)
|
apiErr = errAllowableObjectNotFound(bucket, r)
|
||||||
}
|
}
|
||||||
writeErrorResponse(w, r, apiErr, r.URL.Path)
|
writeErrorResponse(w, apiErr, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,14 +119,13 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req
|
|||||||
// Handle only errInvalidRange
|
// Handle only errInvalidRange
|
||||||
// Ignore other parse error and treat it as regular Get request like Amazon S3.
|
// Ignore other parse error and treat it as regular Get request like Amazon S3.
|
||||||
if err == errInvalidRange {
|
if err == errInvalidRange {
|
||||||
writeErrorResponse(w, r, ErrInvalidRange, r.URL.Path)
|
writeErrorResponse(w, ErrInvalidRange, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// log the error.
|
// log the error.
|
||||||
errorIf(err, "Invalid request range")
|
errorIf(err, "Invalid request range")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate pre-conditions if any.
|
// Validate pre-conditions if any.
|
||||||
@ -166,8 +165,7 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req
|
|||||||
// partial data has already been written before an error
|
// partial data has already been written before an error
|
||||||
// occurred then no point in setting StatusCode and
|
// occurred then no point in setting StatusCode and
|
||||||
// sending error XML.
|
// sending error XML.
|
||||||
apiErr := toAPIErrorCode(err)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
writeErrorResponse(w, r, apiErr, r.URL.Path)
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -190,12 +188,12 @@ func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Re
|
|||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, r, ErrServerNotInitialized, r.URL.Path)
|
writeErrorResponseHeadersOnly(w, ErrServerNotInitialized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s3Error := checkRequestAuthType(r, bucket, "s3:GetObject", serverConfig.GetRegion()); s3Error != ErrNone {
|
if s3Error := checkRequestAuthType(r, bucket, "s3:GetObject", serverConfig.GetRegion()); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponseHeadersOnly(w, s3Error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,7 +209,7 @@ func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Re
|
|||||||
if apiErr == ErrNoSuchKey {
|
if apiErr == ErrNoSuchKey {
|
||||||
apiErr = errAllowableObjectNotFound(bucket, r)
|
apiErr = errAllowableObjectNotFound(bucket, r)
|
||||||
}
|
}
|
||||||
writeErrorResponse(w, r, apiErr, r.URL.Path)
|
writeErrorResponseHeadersOnly(w, apiErr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,11 +233,13 @@ func getCpObjMetadataFromHeader(header http.Header, defaultMeta map[string]strin
|
|||||||
if isMetadataReplace(header) {
|
if isMetadataReplace(header) {
|
||||||
return extractMetadataFromHeader(header)
|
return extractMetadataFromHeader(header)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if x-amz-metadata-directive says COPY then we
|
// if x-amz-metadata-directive says COPY then we
|
||||||
// return the default metadata.
|
// return the default metadata.
|
||||||
if isMetadataCopy(header) {
|
if isMetadataCopy(header) {
|
||||||
return defaultMeta
|
return defaultMeta
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy is default behavior if not x-amz-metadata-directive is set.
|
// Copy is default behavior if not x-amz-metadata-directive is set.
|
||||||
return defaultMeta
|
return defaultMeta
|
||||||
}
|
}
|
||||||
@ -256,12 +256,12 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
|
|||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, r, ErrServerNotInitialized, r.URL.Path)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s3Error := checkRequestAuthType(r, dstBucket, "s3:PutObject", serverConfig.GetRegion()); s3Error != ErrNone {
|
if s3Error := checkRequestAuthType(r, dstBucket, "s3:PutObject", serverConfig.GetRegion()); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,13 +277,13 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
|
|||||||
srcBucket, srcObject := path2BucketAndObject(cpSrcPath)
|
srcBucket, srcObject := path2BucketAndObject(cpSrcPath)
|
||||||
// If source object is empty or bucket is empty, reply back invalid copy source.
|
// If source object is empty or bucket is empty, reply back invalid copy source.
|
||||||
if srcObject == "" || srcBucket == "" {
|
if srcObject == "" || srcBucket == "" {
|
||||||
writeErrorResponse(w, r, ErrInvalidCopySource, r.URL.Path)
|
writeErrorResponse(w, ErrInvalidCopySource, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if metadata directive is valid.
|
// Check if metadata directive is valid.
|
||||||
if !isMetadataDirectiveValid(r.Header) {
|
if !isMetadataDirectiveValid(r.Header) {
|
||||||
writeErrorResponse(w, r, ErrInvalidMetadataDirective, r.URL.Path)
|
writeErrorResponse(w, ErrInvalidMetadataDirective, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,7 +311,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
|
|||||||
objInfo, err := objectAPI.GetObjectInfo(srcBucket, srcObject)
|
objInfo, err := objectAPI.GetObjectInfo(srcBucket, srcObject)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "Unable to fetch object info.")
|
errorIf(err, "Unable to fetch object info.")
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), cpSrcPath)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,7 +322,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
|
|||||||
|
|
||||||
/// maximum Upload size for object in a single CopyObject operation.
|
/// maximum Upload size for object in a single CopyObject operation.
|
||||||
if isMaxObjectSize(objInfo.Size) {
|
if isMaxObjectSize(objInfo.Size) {
|
||||||
writeErrorResponse(w, r, ErrEntityTooLarge, cpSrcPath)
|
writeErrorResponse(w, ErrEntityTooLarge, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,7 +339,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
|
|||||||
if !isMetadataReplace(r.Header) && cpSrcDstSame {
|
if !isMetadataReplace(r.Header) && cpSrcDstSame {
|
||||||
// If x-amz-metadata-directive is not set to REPLACE then we need
|
// If x-amz-metadata-directive is not set to REPLACE then we need
|
||||||
// to error out if source and destination are same.
|
// to error out if source and destination are same.
|
||||||
writeErrorResponse(w, r, ErrInvalidCopyDest, r.URL.Path)
|
writeErrorResponse(w, ErrInvalidCopyDest, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,17 +347,16 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
|
|||||||
// object is same then only metadata is updated.
|
// object is same then only metadata is updated.
|
||||||
objInfo, err = objectAPI.CopyObject(srcBucket, srcObject, dstBucket, dstObject, newMetadata)
|
objInfo, err = objectAPI.CopyObject(srcBucket, srcObject, dstBucket, dstObject, newMetadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
md5Sum := objInfo.MD5Sum
|
md5Sum := objInfo.MD5Sum
|
||||||
response := generateCopyObjectResponse(md5Sum, objInfo.ModTime)
|
response := generateCopyObjectResponse(md5Sum, objInfo.ModTime)
|
||||||
encodedSuccessResponse := encodeResponse(response)
|
encodedSuccessResponse := encodeResponse(response)
|
||||||
// write headers
|
|
||||||
setCommonHeaders(w)
|
// Write success response.
|
||||||
// write success response.
|
writeSuccessResponseXML(w, encodedSuccessResponse)
|
||||||
writeSuccessResponse(w, encodedSuccessResponse)
|
|
||||||
|
|
||||||
// Notify object created event.
|
// Notify object created event.
|
||||||
eventNotify(eventData{
|
eventNotify(eventData{
|
||||||
@ -376,13 +375,13 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
|
|||||||
func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, r, ErrServerNotInitialized, r.URL.Path)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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["X-Amz-Copy-Source"]; ok {
|
||||||
writeErrorResponse(w, r, ErrInvalidCopySource, r.URL.Path)
|
writeErrorResponse(w, ErrInvalidCopySource, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,7 +393,7 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req
|
|||||||
md5Bytes, err := checkValidMD5(r.Header.Get("Content-Md5"))
|
md5Bytes, err := checkValidMD5(r.Header.Get("Content-Md5"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "Unable to validate content-md5 format.")
|
errorIf(err, "Unable to validate content-md5 format.")
|
||||||
writeErrorResponse(w, r, ErrInvalidDigest, r.URL.Path)
|
writeErrorResponse(w, ErrInvalidDigest, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,18 +405,18 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req
|
|||||||
size, err = strconv.ParseInt(sizeStr, 10, 64)
|
size, err = strconv.ParseInt(sizeStr, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "Unable to parse `x-amz-decoded-content-length` into its integer value", sizeStr)
|
errorIf(err, "Unable to parse `x-amz-decoded-content-length` into its integer value", sizeStr)
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if size == -1 && !contains(r.TransferEncoding, "chunked") {
|
if size == -1 && !contains(r.TransferEncoding, "chunked") {
|
||||||
writeErrorResponse(w, r, ErrMissingContentLength, r.URL.Path)
|
writeErrorResponse(w, ErrMissingContentLength, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
/// maximum Upload size for objects in a single operation
|
/// maximum Upload size for objects in a single operation
|
||||||
if isMaxObjectSize(size) {
|
if isMaxObjectSize(size) {
|
||||||
writeErrorResponse(w, r, ErrEntityTooLarge, r.URL.Path)
|
writeErrorResponse(w, ErrEntityTooLarge, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -437,12 +436,12 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req
|
|||||||
switch rAuthType {
|
switch rAuthType {
|
||||||
default:
|
default:
|
||||||
// For all unknown auth types return error.
|
// For all unknown auth types return error.
|
||||||
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
writeErrorResponse(w, ErrAccessDenied, r.URL)
|
||||||
return
|
return
|
||||||
case authTypeAnonymous:
|
case authTypeAnonymous:
|
||||||
// http://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html
|
// http://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html
|
||||||
if s3Error := enforceBucketPolicy(bucket, "s3:PutObject", r.URL); s3Error != ErrNone {
|
if s3Error := enforceBucketPolicy(bucket, "s3:PutObject", r.URL); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Create anonymous object.
|
// Create anonymous object.
|
||||||
@ -452,7 +451,7 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req
|
|||||||
reader, s3Error := newSignV4ChunkedReader(r)
|
reader, s3Error := newSignV4ChunkedReader(r)
|
||||||
if s3Error != ErrNone {
|
if s3Error != ErrNone {
|
||||||
errorIf(errSignatureMismatch, dumpRequest(r))
|
errorIf(errSignatureMismatch, dumpRequest(r))
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
objInfo, err = objectAPI.PutObject(bucket, object, size, reader, metadata, sha256sum)
|
objInfo, err = objectAPI.PutObject(bucket, object, size, reader, metadata, sha256sum)
|
||||||
@ -460,14 +459,14 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req
|
|||||||
s3Error := isReqAuthenticatedV2(r)
|
s3Error := isReqAuthenticatedV2(r)
|
||||||
if s3Error != ErrNone {
|
if s3Error != ErrNone {
|
||||||
errorIf(errSignatureMismatch, dumpRequest(r))
|
errorIf(errSignatureMismatch, dumpRequest(r))
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
objInfo, err = objectAPI.PutObject(bucket, object, size, r.Body, metadata, sha256sum)
|
objInfo, err = objectAPI.PutObject(bucket, object, size, r.Body, metadata, sha256sum)
|
||||||
case authTypePresigned, authTypeSigned:
|
case authTypePresigned, authTypeSigned:
|
||||||
if s3Error := reqSignatureV4Verify(r); s3Error != ErrNone {
|
if s3Error := reqSignatureV4Verify(r); s3Error != ErrNone {
|
||||||
errorIf(errSignatureMismatch, dumpRequest(r))
|
errorIf(errSignatureMismatch, dumpRequest(r))
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !skipContentSha256Cksum(r) {
|
if !skipContentSha256Cksum(r) {
|
||||||
@ -478,11 +477,11 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req
|
|||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "Unable to create an object.")
|
errorIf(err, "Unable to create an object.")
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Header().Set("ETag", "\""+objInfo.MD5Sum+"\"")
|
w.Header().Set("ETag", "\""+objInfo.MD5Sum+"\"")
|
||||||
writeSuccessResponse(w, nil)
|
writeSuccessResponseHeadersOnly(w)
|
||||||
|
|
||||||
// Notify object created event.
|
// Notify object created event.
|
||||||
eventNotify(eventData{
|
eventNotify(eventData{
|
||||||
@ -506,12 +505,12 @@ func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r
|
|||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, r, ErrServerNotInitialized, r.URL.Path)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s3Error := checkRequestAuthType(r, bucket, "s3:PutObject", serverConfig.GetRegion()); s3Error != ErrNone {
|
if s3Error := checkRequestAuthType(r, bucket, "s3:PutObject", serverConfig.GetRegion()); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -521,16 +520,15 @@ func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r
|
|||||||
uploadID, err := objectAPI.NewMultipartUpload(bucket, object, metadata)
|
uploadID, err := objectAPI.NewMultipartUpload(bucket, object, metadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "Unable to initiate new multipart upload id.")
|
errorIf(err, "Unable to initiate new multipart upload id.")
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
response := generateInitiateMultipartUploadResponse(bucket, object, uploadID)
|
response := generateInitiateMultipartUploadResponse(bucket, object, uploadID)
|
||||||
encodedSuccessResponse := encodeResponse(response)
|
encodedSuccessResponse := encodeResponse(response)
|
||||||
// write headers
|
|
||||||
setCommonHeaders(w)
|
// Write success response.
|
||||||
// write success response.
|
writeSuccessResponseXML(w, encodedSuccessResponse)
|
||||||
writeSuccessResponse(w, encodedSuccessResponse)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutObjectPartHandler - Upload part
|
// PutObjectPartHandler - Upload part
|
||||||
@ -541,14 +539,14 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http
|
|||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, r, ErrServerNotInitialized, r.URL.Path)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// get Content-Md5 sent by client and verify if valid
|
// get Content-Md5 sent by client and verify if valid
|
||||||
md5Bytes, err := checkValidMD5(r.Header.Get("Content-Md5"))
|
md5Bytes, err := checkValidMD5(r.Header.Get("Content-Md5"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponse(w, r, ErrInvalidDigest, r.URL.Path)
|
writeErrorResponse(w, ErrInvalidDigest, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -562,18 +560,18 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http
|
|||||||
size, err = strconv.ParseInt(sizeStr, 10, 64)
|
size, err = strconv.ParseInt(sizeStr, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "Unable to parse `x-amz-decoded-content-length` into its integer value", sizeStr)
|
errorIf(err, "Unable to parse `x-amz-decoded-content-length` into its integer value", sizeStr)
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if size == -1 {
|
if size == -1 {
|
||||||
writeErrorResponse(w, r, ErrMissingContentLength, r.URL.Path)
|
writeErrorResponse(w, ErrMissingContentLength, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
/// maximum Upload size for multipart objects in a single operation
|
/// maximum Upload size for multipart objects in a single operation
|
||||||
if isMaxObjectSize(size) {
|
if isMaxObjectSize(size) {
|
||||||
writeErrorResponse(w, r, ErrEntityTooLarge, r.URL.Path)
|
writeErrorResponse(w, ErrEntityTooLarge, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -582,13 +580,13 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http
|
|||||||
|
|
||||||
partID, err := strconv.Atoi(partIDString)
|
partID, err := strconv.Atoi(partIDString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponse(w, r, ErrInvalidPart, r.URL.Path)
|
writeErrorResponse(w, ErrInvalidPart, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// check partID with maximum part ID for multipart objects
|
// check partID with maximum part ID for multipart objects
|
||||||
if isMaxPartID(partID) {
|
if isMaxPartID(partID) {
|
||||||
writeErrorResponse(w, r, ErrInvalidMaxParts, r.URL.Path)
|
writeErrorResponse(w, ErrInvalidMaxParts, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -598,12 +596,12 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http
|
|||||||
switch rAuthType {
|
switch rAuthType {
|
||||||
default:
|
default:
|
||||||
// For all unknown auth types return error.
|
// For all unknown auth types return error.
|
||||||
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
writeErrorResponse(w, ErrAccessDenied, r.URL)
|
||||||
return
|
return
|
||||||
case authTypeAnonymous:
|
case authTypeAnonymous:
|
||||||
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
|
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
|
||||||
if s3Error := enforceBucketPolicy(bucket, "s3:PutObject", r.URL); s3Error != ErrNone {
|
if s3Error := enforceBucketPolicy(bucket, "s3:PutObject", r.URL); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// No need to verify signature, anonymous request access is already allowed.
|
// No need to verify signature, anonymous request access is already allowed.
|
||||||
@ -613,7 +611,7 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http
|
|||||||
reader, s3Error := newSignV4ChunkedReader(r)
|
reader, s3Error := newSignV4ChunkedReader(r)
|
||||||
if s3Error != ErrNone {
|
if s3Error != ErrNone {
|
||||||
errorIf(errSignatureMismatch, dumpRequest(r))
|
errorIf(errSignatureMismatch, dumpRequest(r))
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
partMD5, err = objectAPI.PutObjectPart(bucket, object, uploadID, partID, size, reader, incomingMD5, sha256sum)
|
partMD5, err = objectAPI.PutObjectPart(bucket, object, uploadID, partID, size, reader, incomingMD5, sha256sum)
|
||||||
@ -621,14 +619,14 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http
|
|||||||
s3Error := isReqAuthenticatedV2(r)
|
s3Error := isReqAuthenticatedV2(r)
|
||||||
if s3Error != ErrNone {
|
if s3Error != ErrNone {
|
||||||
errorIf(errSignatureMismatch, dumpRequest(r))
|
errorIf(errSignatureMismatch, dumpRequest(r))
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
partMD5, err = objectAPI.PutObjectPart(bucket, object, uploadID, partID, size, r.Body, incomingMD5, sha256sum)
|
partMD5, err = objectAPI.PutObjectPart(bucket, object, uploadID, partID, size, r.Body, incomingMD5, sha256sum)
|
||||||
case authTypePresigned, authTypeSigned:
|
case authTypePresigned, authTypeSigned:
|
||||||
if s3Error := reqSignatureV4Verify(r); s3Error != ErrNone {
|
if s3Error := reqSignatureV4Verify(r); s3Error != ErrNone {
|
||||||
errorIf(errSignatureMismatch, dumpRequest(r))
|
errorIf(errSignatureMismatch, dumpRequest(r))
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -640,13 +638,14 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "Unable to create object part.")
|
errorIf(err, "Unable to create object part.")
|
||||||
// Verify if the underlying error is signature mismatch.
|
// Verify if the underlying error is signature mismatch.
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if partMD5 != "" {
|
if partMD5 != "" {
|
||||||
w.Header().Set("ETag", "\""+partMD5+"\"")
|
w.Header().Set("ETag", "\""+partMD5+"\"")
|
||||||
}
|
}
|
||||||
writeSuccessResponse(w, nil)
|
|
||||||
|
writeSuccessResponseHeadersOnly(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AbortMultipartUploadHandler - Abort multipart upload
|
// AbortMultipartUploadHandler - Abort multipart upload
|
||||||
@ -657,19 +656,19 @@ func (api objectAPIHandlers) AbortMultipartUploadHandler(w http.ResponseWriter,
|
|||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, r, ErrServerNotInitialized, r.URL.Path)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s3Error := checkRequestAuthType(r, bucket, "s3:AbortMultipartUpload", serverConfig.GetRegion()); s3Error != ErrNone {
|
if s3Error := checkRequestAuthType(r, bucket, "s3:AbortMultipartUpload", serverConfig.GetRegion()); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadID, _, _, _ := getObjectResources(r.URL.Query())
|
uploadID, _, _, _ := getObjectResources(r.URL.Query())
|
||||||
if err := objectAPI.AbortMultipartUpload(bucket, object, uploadID); err != nil {
|
if err := objectAPI.AbortMultipartUpload(bucket, object, uploadID); err != nil {
|
||||||
errorIf(err, "Unable to abort multipart upload.")
|
errorIf(err, "Unable to abort multipart upload.")
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
writeSuccessNoContent(w)
|
writeSuccessNoContent(w)
|
||||||
@ -683,36 +682,35 @@ func (api objectAPIHandlers) ListObjectPartsHandler(w http.ResponseWriter, r *ht
|
|||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, r, ErrServerNotInitialized, r.URL.Path)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s3Error := checkRequestAuthType(r, bucket, "s3:ListMultipartUploadParts", serverConfig.GetRegion()); s3Error != ErrNone {
|
if s3Error := checkRequestAuthType(r, bucket, "s3:ListMultipartUploadParts", serverConfig.GetRegion()); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadID, partNumberMarker, maxParts, _ := getObjectResources(r.URL.Query())
|
uploadID, partNumberMarker, maxParts, _ := getObjectResources(r.URL.Query())
|
||||||
if partNumberMarker < 0 {
|
if partNumberMarker < 0 {
|
||||||
writeErrorResponse(w, r, ErrInvalidPartNumberMarker, r.URL.Path)
|
writeErrorResponse(w, ErrInvalidPartNumberMarker, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if maxParts < 0 {
|
if maxParts < 0 {
|
||||||
writeErrorResponse(w, r, ErrInvalidMaxParts, r.URL.Path)
|
writeErrorResponse(w, ErrInvalidMaxParts, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
listPartsInfo, err := objectAPI.ListObjectParts(bucket, object, uploadID, partNumberMarker, maxParts)
|
listPartsInfo, err := objectAPI.ListObjectParts(bucket, object, uploadID, partNumberMarker, maxParts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "Unable to list uploaded parts.")
|
errorIf(err, "Unable to list uploaded parts.")
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
response := generateListPartsResponse(listPartsInfo)
|
response := generateListPartsResponse(listPartsInfo)
|
||||||
encodedSuccessResponse := encodeResponse(response)
|
encodedSuccessResponse := encodeResponse(response)
|
||||||
// Write headers.
|
|
||||||
setCommonHeaders(w)
|
|
||||||
// Write success response.
|
// Write success response.
|
||||||
writeSuccessResponse(w, encodedSuccessResponse)
|
writeSuccessResponseXML(w, encodedSuccessResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompleteMultipartUploadHandler - Complete multipart upload.
|
// CompleteMultipartUploadHandler - Complete multipart upload.
|
||||||
@ -723,12 +721,12 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite
|
|||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, r, ErrServerNotInitialized, r.URL.Path)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s3Error := checkRequestAuthType(r, bucket, "s3:PutObject", serverConfig.GetRegion()); s3Error != ErrNone {
|
if s3Error := checkRequestAuthType(r, bucket, "s3:PutObject", serverConfig.GetRegion()); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -739,23 +737,24 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite
|
|||||||
completeMultipartBytes, err := ioutil.ReadAll(r.Body)
|
completeMultipartBytes, err := ioutil.ReadAll(r.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "Unable to complete multipart upload.")
|
errorIf(err, "Unable to complete multipart upload.")
|
||||||
writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
|
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
complMultipartUpload := &completeMultipartUpload{}
|
complMultipartUpload := &completeMultipartUpload{}
|
||||||
if err = xml.Unmarshal(completeMultipartBytes, complMultipartUpload); err != nil {
|
if err = xml.Unmarshal(completeMultipartBytes, complMultipartUpload); err != nil {
|
||||||
errorIf(err, "Unable to parse complete multipart upload XML.")
|
errorIf(err, "Unable to parse complete multipart upload XML.")
|
||||||
writeErrorResponse(w, r, ErrMalformedXML, r.URL.Path)
|
writeErrorResponse(w, ErrMalformedXML, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(complMultipartUpload.Parts) == 0 {
|
if len(complMultipartUpload.Parts) == 0 {
|
||||||
writeErrorResponse(w, r, ErrMalformedXML, r.URL.Path)
|
writeErrorResponse(w, ErrMalformedXML, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !sort.IsSorted(completedParts(complMultipartUpload.Parts)) {
|
if !sort.IsSorted(completedParts(complMultipartUpload.Parts)) {
|
||||||
writeErrorResponse(w, r, ErrInvalidPartOrder, r.URL.Path)
|
writeErrorResponse(w, ErrInvalidPartOrder, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Complete parts.
|
// Complete parts.
|
||||||
var completeParts []completePart
|
var completeParts []completePart
|
||||||
for _, part := range complMultipartUpload.Parts {
|
for _, part := range complMultipartUpload.Parts {
|
||||||
@ -779,7 +778,7 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite
|
|||||||
writePartSmallErrorResponse(w, r, oErr)
|
writePartSmallErrorResponse(w, r, oErr)
|
||||||
default:
|
default:
|
||||||
// Handle all other generic issues.
|
// Handle all other generic issues.
|
||||||
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -791,7 +790,7 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite
|
|||||||
encodedSuccessResponse := encodeResponse(response)
|
encodedSuccessResponse := encodeResponse(response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "Unable to parse CompleteMultipartUpload response")
|
errorIf(err, "Unable to parse CompleteMultipartUpload response")
|
||||||
writeErrorResponseNoHeader(w, r, ErrInternalError, r.URL.Path)
|
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -799,8 +798,7 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite
|
|||||||
w.Header().Set("ETag", "\""+md5Sum+"\"")
|
w.Header().Set("ETag", "\""+md5Sum+"\"")
|
||||||
|
|
||||||
// Write success response.
|
// Write success response.
|
||||||
w.Write(encodedSuccessResponse)
|
writeSuccessResponseXML(w, encodedSuccessResponse)
|
||||||
w.(http.Flusher).Flush()
|
|
||||||
|
|
||||||
// Fetch object info for notifications.
|
// Fetch object info for notifications.
|
||||||
objInfo, err := objectAPI.GetObjectInfo(bucket, object)
|
objInfo, err := objectAPI.GetObjectInfo(bucket, object)
|
||||||
@ -830,12 +828,12 @@ func (api objectAPIHandlers) DeleteObjectHandler(w http.ResponseWriter, r *http.
|
|||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, r, ErrServerNotInitialized, r.URL.Path)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s3Error := checkRequestAuthType(r, bucket, "s3:DeleteObject", serverConfig.GetRegion()); s3Error != ErrNone {
|
if s3Error := checkRequestAuthType(r, bucket, "s3:DeleteObject", serverConfig.GetRegion()); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user