Browse Source

refactor

pull/2128/head
Chris Lu 4 years ago
parent
commit
8b382a8209
  1. 83
      weed/iamapi/iamapi_handlers.go
  2. 12
      weed/iamapi/iamapi_management_handlers.go
  3. 3
      weed/iamapi/iamapi_server.go
  4. 2
      weed/s3api/auth_credentials.go
  5. 5
      weed/s3api/filer_multipart_test.go
  6. 20
      weed/s3api/s3api_bucket_handlers.go
  7. 3
      weed/s3api/s3api_bucket_handlers_test.go
  8. 77
      weed/s3api/s3api_handlers.go
  9. 30
      weed/s3api/s3api_object_copy_handlers.go
  10. 30
      weed/s3api/s3api_object_handlers.go
  11. 32
      weed/s3api/s3api_object_handlers_postpolicy.go
  12. 48
      weed/s3api/s3api_object_multipart_handlers.go
  13. 24
      weed/s3api/s3api_object_tagging_handlers.go
  14. 20
      weed/s3api/s3api_objects_list_handlers.go
  15. 3
      weed/s3api/s3api_objects_list_handlers_test.go
  16. 3
      weed/s3api/s3api_server.go
  17. 5
      weed/s3api/s3api_test.go
  18. 81
      weed/s3api/s3err/error_handler.go
  19. 3
      weed/s3api/tags_test.go

83
weed/iamapi/iamapi_handlers.go

@ -1,54 +1,13 @@
package iamapi package iamapi
import ( import (
"bytes"
"encoding/xml"
"fmt" "fmt"
"strconv"
"net/http"
"time"
"github.com/aws/aws-sdk-go/service/iam"
"github.com/chrislusf/seaweedfs/weed/glog" "github.com/chrislusf/seaweedfs/weed/glog"
"github.com/chrislusf/seaweedfs/weed/s3api/s3err" "github.com/chrislusf/seaweedfs/weed/s3api/s3err"
"github.com/aws/aws-sdk-go/service/iam"
)
type mimeType string
const (
mimeNone mimeType = ""
mimeXML mimeType = "application/xml"
"net/http"
) )
func setCommonHeaders(w http.ResponseWriter) {
w.Header().Set("x-amz-request-id", fmt.Sprintf("%d", time.Now().UnixNano()))
w.Header().Set("Accept-Ranges", "bytes")
}
// Encodes the response headers into XML format.
func encodeResponse(response interface{}) []byte {
var bytesBuffer bytes.Buffer
bytesBuffer.WriteString(xml.Header)
e := xml.NewEncoder(&bytesBuffer)
e.Encode(response)
return bytesBuffer.Bytes()
}
// If none of the http routes match respond with MethodNotAllowed
func notFoundHandler(w http.ResponseWriter, r *http.Request) {
glog.V(0).Infof("unsupported %s %s", r.Method, r.RequestURI)
writeErrorResponse(w, s3err.ErrMethodNotAllowed, r)
}
func writeErrorResponse(w http.ResponseWriter, errorCode s3err.ErrorCode, r *http.Request) {
apiError := s3err.GetAPIError(errorCode)
errorResponse := getRESTErrorResponse(apiError, r.URL.Path)
encodedErrorResponse := encodeResponse(errorResponse)
writeResponse(w, apiError.HTTPStatusCode, encodedErrorResponse, mimeXML)
}
func writeIamErrorResponse(w http.ResponseWriter, err error, object string, value string, msg error) { func writeIamErrorResponse(w http.ResponseWriter, err error, object string, value string, msg error) {
errCode := err.Error() errCode := err.Error()
errorResp := ErrorResponse{} errorResp := ErrorResponse{}
@ -63,42 +22,10 @@ func writeIamErrorResponse(w http.ResponseWriter, err error, object string, valu
case iam.ErrCodeNoSuchEntityException: case iam.ErrCodeNoSuchEntityException:
msg := fmt.Sprintf("The %s with name %s cannot be found.", object, value) msg := fmt.Sprintf("The %s with name %s cannot be found.", object, value)
errorResp.Error.Message = &msg errorResp.Error.Message = &msg
writeResponse(w, http.StatusNotFound, encodeResponse(errorResp), mimeXML)
s3err.WriteXMLResponse(w, http.StatusNotFound, errorResp)
case iam.ErrCodeServiceFailureException: case iam.ErrCodeServiceFailureException:
writeResponse(w, http.StatusInternalServerError, encodeResponse(errorResp), mimeXML)
s3err.WriteXMLResponse(w, http.StatusInternalServerError, errorResp)
default: default:
writeResponse(w, http.StatusInternalServerError, encodeResponse(errorResp), mimeXML)
}
}
func getRESTErrorResponse(err s3err.APIError, resource string) s3err.RESTErrorResponse {
return s3err.RESTErrorResponse{
Code: err.Code,
Message: err.Description,
Resource: resource,
RequestID: fmt.Sprintf("%d", time.Now().UnixNano()),
}
}
func writeResponse(w http.ResponseWriter, statusCode int, response []byte, mType mimeType) {
setCommonHeaders(w)
if response != nil {
w.Header().Set("Content-Length", strconv.Itoa(len(response)))
}
if mType != mimeNone {
w.Header().Set("Content-Type", string(mType))
}
w.WriteHeader(statusCode)
if response != nil {
glog.V(4).Infof("status %d %s: %s", statusCode, mType, string(response))
_, err := w.Write(response)
if err != nil {
glog.V(0).Infof("write err: %v", err)
s3err.WriteXMLResponse(w, http.StatusInternalServerError, errorResp)
} }
w.(http.Flusher).Flush()
}
}
func writeSuccessResponseXML(w http.ResponseWriter, response []byte) {
writeResponse(w, http.StatusOK, response, mimeXML)
} }

12
weed/iamapi/iamapi_management_handlers.go

@ -362,7 +362,7 @@ func (iama *IamApiServer) DeleteAccessKey(s3cfg *iam_pb.S3ApiConfiguration, valu
func (iama *IamApiServer) DoActions(w http.ResponseWriter, r *http.Request) { func (iama *IamApiServer) DoActions(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil { if err := r.ParseForm(); err != nil {
writeErrorResponse(w, s3err.ErrInvalidRequest, r)
s3err.WriteErrorResponse(w, s3err.ErrInvalidRequest, r)
return return
} }
values := r.PostForm values := r.PostForm
@ -370,7 +370,7 @@ func (iama *IamApiServer) DoActions(w http.ResponseWriter, r *http.Request) {
s3cfgLock.RLock() s3cfgLock.RLock()
s3cfg := &iam_pb.S3ApiConfiguration{} s3cfg := &iam_pb.S3ApiConfiguration{}
if err := iama.s3ApiConfig.GetS3ApiConfiguration(s3cfg); err != nil { if err := iama.s3ApiConfig.GetS3ApiConfiguration(s3cfg); err != nil {
writeErrorResponse(w, s3err.ErrInternalError, r)
s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
return return
} }
s3cfgLock.RUnlock() s3cfgLock.RUnlock()
@ -411,14 +411,14 @@ func (iama *IamApiServer) DoActions(w http.ResponseWriter, r *http.Request) {
response, err = iama.CreatePolicy(s3cfg, values) response, err = iama.CreatePolicy(s3cfg, values)
if err != nil { if err != nil {
glog.Errorf("CreatePolicy: %+v", err) glog.Errorf("CreatePolicy: %+v", err)
writeErrorResponse(w, s3err.ErrInvalidRequest, r)
s3err.WriteErrorResponse(w, s3err.ErrInvalidRequest, r)
return return
} }
case "PutUserPolicy": case "PutUserPolicy":
response, err = iama.PutUserPolicy(s3cfg, values) response, err = iama.PutUserPolicy(s3cfg, values)
if err != nil { if err != nil {
glog.Errorf("PutUserPolicy: %+v", err) glog.Errorf("PutUserPolicy: %+v", err)
writeErrorResponse(w, s3err.ErrInvalidRequest, r)
s3err.WriteErrorResponse(w, s3err.ErrInvalidRequest, r)
return return
} }
case "GetUserPolicy": case "GetUserPolicy":
@ -437,7 +437,7 @@ func (iama *IamApiServer) DoActions(w http.ResponseWriter, r *http.Request) {
errorResponse := ErrorResponse{} errorResponse := ErrorResponse{}
errorResponse.Error.Code = &errNotImplemented.Code errorResponse.Error.Code = &errNotImplemented.Code
errorResponse.Error.Message = &errNotImplemented.Description errorResponse.Error.Message = &errNotImplemented.Description
writeResponse(w, errNotImplemented.HTTPStatusCode, encodeResponse(errorResponse), mimeXML)
s3err.WriteXMLResponse(w, errNotImplemented.HTTPStatusCode, errorResponse)
return return
} }
if changed { if changed {
@ -449,5 +449,5 @@ func (iama *IamApiServer) DoActions(w http.ResponseWriter, r *http.Request) {
return return
} }
} }
writeSuccessResponseXML(w, encodeResponse(response))
s3err.WriteXMLResponse(w, http.StatusOK, response)
} }

3
weed/iamapi/iamapi_server.go

@ -12,6 +12,7 @@ import (
"github.com/chrislusf/seaweedfs/weed/pb/iam_pb" "github.com/chrislusf/seaweedfs/weed/pb/iam_pb"
"github.com/chrislusf/seaweedfs/weed/s3api" "github.com/chrislusf/seaweedfs/weed/s3api"
. "github.com/chrislusf/seaweedfs/weed/s3api/s3_constants" . "github.com/chrislusf/seaweedfs/weed/s3api/s3_constants"
"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
"github.com/chrislusf/seaweedfs/weed/wdclient" "github.com/chrislusf/seaweedfs/weed/wdclient"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"google.golang.org/grpc" "google.golang.org/grpc"
@ -71,7 +72,7 @@ func (iama *IamApiServer) registerRouter(router *mux.Router) {
apiRouter.Methods("POST").Path("/").HandlerFunc(iama.iam.Auth(iama.DoActions, ACTION_ADMIN)) apiRouter.Methods("POST").Path("/").HandlerFunc(iama.iam.Auth(iama.DoActions, ACTION_ADMIN))
// //
// NotFound // NotFound
apiRouter.NotFoundHandler = http.HandlerFunc(notFoundHandler)
apiRouter.NotFoundHandler = http.HandlerFunc(s3err.NotFoundHandler)
} }
func (iam IamS3ApiConfigure) GetS3ApiConfiguration(s3cfg *iam_pb.S3ApiConfiguration) (err error) { func (iam IamS3ApiConfigure) GetS3ApiConfiguration(s3cfg *iam_pb.S3ApiConfiguration) (err error) {

2
weed/s3api/auth_credentials.go

@ -150,7 +150,7 @@ func (iam *IdentityAccessManagement) Auth(f http.HandlerFunc, action Action) htt
f(w, r) f(w, r)
return return
} }
writeErrorResponse(w, errCode, r)
s3err.WriteErrorResponse(w, errCode, r)
} }
} }

5
weed/s3api/filer_multipart_test.go

@ -3,6 +3,7 @@ package s3api
import ( import (
"github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/s3" "github.com/aws/aws-sdk-go/service/s3"
"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
"testing" "testing"
"time" "time"
) )
@ -19,7 +20,7 @@ func TestInitiateMultipartUploadResult(t *testing.T) {
}, },
} }
encoded := string(encodeResponse(response))
encoded := string(s3err.EncodeXMLResponse(response))
if encoded != expected { if encoded != expected {
t.Errorf("unexpected output: %s\nexpecting:%s", encoded, expected) t.Errorf("unexpected output: %s\nexpecting:%s", encoded, expected)
} }
@ -41,7 +42,7 @@ func TestListPartsResult(t *testing.T) {
}, },
} }
encoded := string(encodeResponse(response))
encoded := string(s3err.EncodeXMLResponse(response))
if encoded != expected { if encoded != expected {
t.Errorf("unexpected output: %s\nexpecting:%s", encoded, expected) t.Errorf("unexpected output: %s\nexpecting:%s", encoded, expected)
} }

20
weed/s3api/s3api_bucket_handlers.go

@ -32,7 +32,7 @@ func (s3a *S3ApiServer) ListBucketsHandler(w http.ResponseWriter, r *http.Reques
if s3a.iam.isEnabled() { if s3a.iam.isEnabled() {
identity, s3Err = s3a.iam.authUser(r) identity, s3Err = s3a.iam.authUser(r)
if s3Err != s3err.ErrNone { if s3Err != s3err.ErrNone {
writeErrorResponse(w, s3Err, r)
s3err.WriteErrorResponse(w, s3Err, r)
return return
} }
} }
@ -42,7 +42,7 @@ func (s3a *S3ApiServer) ListBucketsHandler(w http.ResponseWriter, r *http.Reques
entries, _, err := s3a.list(s3a.option.BucketsPath, "", "", false, math.MaxInt32) entries, _, err := s3a.list(s3a.option.BucketsPath, "", "", false, math.MaxInt32)
if err != nil { if err != nil {
writeErrorResponse(w, s3err.ErrInternalError, r)
s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
return return
} }
@ -69,7 +69,7 @@ func (s3a *S3ApiServer) ListBucketsHandler(w http.ResponseWriter, r *http.Reques
Buckets: buckets, Buckets: buckets,
} }
writeSuccessResponseXML(w, encodeResponse(response))
writeSuccessResponseXML(w, response)
} }
func (s3a *S3ApiServer) PutBucketHandler(w http.ResponseWriter, r *http.Request) { func (s3a *S3ApiServer) PutBucketHandler(w http.ResponseWriter, r *http.Request) {
@ -95,14 +95,14 @@ func (s3a *S3ApiServer) PutBucketHandler(w http.ResponseWriter, r *http.Request)
} }
return nil return nil
}); err != nil { }); err != nil {
writeErrorResponse(w, s3err.ErrInternalError, r)
s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
return return
} }
if exist, err := s3a.exists(s3a.option.BucketsPath, bucket, true); err == nil && exist { if exist, err := s3a.exists(s3a.option.BucketsPath, bucket, true); err == nil && exist {
errCode = s3err.ErrBucketAlreadyExists errCode = s3err.ErrBucketAlreadyExists
} }
if errCode != s3err.ErrNone { if errCode != s3err.ErrNone {
writeErrorResponse(w, errCode, r)
s3err.WriteErrorResponse(w, errCode, r)
return return
} }
@ -118,7 +118,7 @@ func (s3a *S3ApiServer) PutBucketHandler(w http.ResponseWriter, r *http.Request)
// create the folder for bucket, but lazily create actual collection // create the folder for bucket, but lazily create actual collection
if err := s3a.mkdir(s3a.option.BucketsPath, bucket, fn); err != nil { if err := s3a.mkdir(s3a.option.BucketsPath, bucket, fn); err != nil {
glog.Errorf("PutBucketHandler mkdir: %v", err) glog.Errorf("PutBucketHandler mkdir: %v", err)
writeErrorResponse(w, s3err.ErrInternalError, r)
s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
return return
} }
@ -130,7 +130,7 @@ func (s3a *S3ApiServer) DeleteBucketHandler(w http.ResponseWriter, r *http.Reque
bucket, _ := getBucketAndObject(r) bucket, _ := getBucketAndObject(r)
if err := s3a.checkBucket(r, bucket); err != s3err.ErrNone { if err := s3a.checkBucket(r, bucket); err != s3err.ErrNone {
writeErrorResponse(w, err, r)
s3err.WriteErrorResponse(w, err, r)
return return
} }
@ -152,11 +152,11 @@ func (s3a *S3ApiServer) DeleteBucketHandler(w http.ResponseWriter, r *http.Reque
err = s3a.rm(s3a.option.BucketsPath, bucket, false, true) err = s3a.rm(s3a.option.BucketsPath, bucket, false, true)
if err != nil { if err != nil {
writeErrorResponse(w, s3err.ErrInternalError, r)
s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
return return
} }
writeResponse(w, http.StatusNoContent, nil, mimeNone)
s3err.WriteEmptyResponse(w, http.StatusNoContent)
} }
func (s3a *S3ApiServer) HeadBucketHandler(w http.ResponseWriter, r *http.Request) { func (s3a *S3ApiServer) HeadBucketHandler(w http.ResponseWriter, r *http.Request) {
@ -164,7 +164,7 @@ func (s3a *S3ApiServer) HeadBucketHandler(w http.ResponseWriter, r *http.Request
bucket, _ := getBucketAndObject(r) bucket, _ := getBucketAndObject(r)
if err := s3a.checkBucket(r, bucket); err != s3err.ErrNone { if err := s3a.checkBucket(r, bucket); err != s3err.ErrNone {
writeErrorResponse(w, err, r)
s3err.WriteErrorResponse(w, err, r)
return return
} }

3
weed/s3api/s3api_bucket_handlers_test.go

@ -1,6 +1,7 @@
package s3api package s3api
import ( import (
"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
"testing" "testing"
"time" "time"
@ -32,7 +33,7 @@ func TestListBucketsHandler(t *testing.T) {
Buckets: buckets, Buckets: buckets,
} }
encoded := string(encodeResponse(response))
encoded := string(s3err.EncodeXMLResponse(response))
if encoded != expected { if encoded != expected {
t.Errorf("unexpected output: %s\nexpecting:%s", encoded, expected) t.Errorf("unexpected output: %s\nexpecting:%s", encoded, expected)
} }

77
weed/s3api/s3api_handlers.go

@ -1,44 +1,16 @@
package s3api package s3api
import ( import (
"bytes"
"encoding/base64" "encoding/base64"
"encoding/xml"
"fmt" "fmt"
"github.com/chrislusf/seaweedfs/weed/s3api/s3err" "github.com/chrislusf/seaweedfs/weed/s3api/s3err"
"net/http"
"strconv"
"time"
"google.golang.org/grpc" "google.golang.org/grpc"
"net/http"
"github.com/chrislusf/seaweedfs/weed/glog"
"github.com/chrislusf/seaweedfs/weed/pb" "github.com/chrislusf/seaweedfs/weed/pb"
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb" "github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
) )
type mimeType string
const (
mimeNone mimeType = ""
mimeJSON mimeType = "application/json"
mimeXML mimeType = "application/xml"
)
func setCommonHeaders(w http.ResponseWriter) {
w.Header().Set("x-amz-request-id", fmt.Sprintf("%d", time.Now().UnixNano()))
w.Header().Set("Accept-Ranges", "bytes")
}
// Encodes the response headers into XML format.
func encodeResponse(response interface{}) []byte {
var bytesBuffer bytes.Buffer
bytesBuffer.WriteString(xml.Header)
e := xml.NewEncoder(&bytesBuffer)
e.Encode(response)
return bytesBuffer.Bytes()
}
var _ = filer_pb.FilerClient(&S3ApiServer{}) var _ = filer_pb.FilerClient(&S3ApiServer{})
func (s3a *S3ApiServer) WithFilerClient(fn func(filer_pb.SeaweedFilerClient) error) error { func (s3a *S3ApiServer) WithFilerClient(fn func(filer_pb.SeaweedFilerClient) error) error {
@ -53,53 +25,12 @@ func (s3a *S3ApiServer) AdjustedUrl(location *filer_pb.Location) string {
return location.Url return location.Url
} }
// If none of the http routes match respond with MethodNotAllowed
func notFoundHandler(w http.ResponseWriter, r *http.Request) {
glog.V(0).Infof("unsupported %s %s", r.Method, r.RequestURI)
writeErrorResponse(w, s3err.ErrMethodNotAllowed, r)
}
func writeErrorResponse(w http.ResponseWriter, errorCode s3err.ErrorCode, r *http.Request) {
apiError := s3err.GetAPIError(errorCode)
errorResponse := getRESTErrorResponse(apiError, r.URL.Path)
encodedErrorResponse := encodeResponse(errorResponse)
writeResponse(w, apiError.HTTPStatusCode, encodedErrorResponse, mimeXML)
}
func getRESTErrorResponse(err s3err.APIError, resource string) s3err.RESTErrorResponse {
return s3err.RESTErrorResponse{
Code: err.Code,
Message: err.Description,
Resource: resource,
RequestID: fmt.Sprintf("%d", time.Now().UnixNano()),
}
}
func writeResponse(w http.ResponseWriter, statusCode int, response []byte, mType mimeType) {
setCommonHeaders(w)
if response != nil {
w.Header().Set("Content-Length", strconv.Itoa(len(response)))
}
if mType != mimeNone {
w.Header().Set("Content-Type", string(mType))
}
w.WriteHeader(statusCode)
if response != nil {
glog.V(4).Infof("status %d %s: %s", statusCode, mType, string(response))
_, err := w.Write(response)
if err != nil {
glog.V(0).Infof("write err: %v", err)
}
w.(http.Flusher).Flush()
}
}
func writeSuccessResponseXML(w http.ResponseWriter, response []byte) {
writeResponse(w, http.StatusOK, response, mimeXML)
func writeSuccessResponseXML(w http.ResponseWriter, response interface{}) {
s3err.WriteXMLResponse(w, http.StatusOK, response)
} }
func writeSuccessResponseEmpty(w http.ResponseWriter) { func writeSuccessResponseEmpty(w http.ResponseWriter) {
writeResponse(w, http.StatusOK, nil, mimeNone)
s3err.WriteEmptyResponse(w, http.StatusOK)
} }
func validateContentMd5(h http.Header) ([]byte, error) { func validateContentMd5(h http.Header) ([]byte, error) {

30
weed/s3api/s3api_object_copy_handlers.go

@ -32,28 +32,28 @@ func (s3a *S3ApiServer) CopyObjectHandler(w http.ResponseWriter, r *http.Request
dir, name := fullPath.DirAndName() dir, name := fullPath.DirAndName()
entry, err := s3a.getEntry(dir, name) entry, err := s3a.getEntry(dir, name)
if err != nil { if err != nil {
writeErrorResponse(w, s3err.ErrInvalidCopySource, r)
s3err.WriteErrorResponse(w, s3err.ErrInvalidCopySource, r)
} }
entry.Extended = weed_server.SaveAmzMetaData(r, entry.Extended, isReplace(r)) entry.Extended = weed_server.SaveAmzMetaData(r, entry.Extended, isReplace(r))
err = s3a.touch(dir, name, entry) err = s3a.touch(dir, name, entry)
if err != nil { if err != nil {
writeErrorResponse(w, s3err.ErrInvalidCopySource, r)
s3err.WriteErrorResponse(w, s3err.ErrInvalidCopySource, r)
} }
writeSuccessResponseXML(w, encodeResponse(CopyObjectResult{
writeSuccessResponseXML(w, CopyObjectResult{
ETag: fmt.Sprintf("%x", entry.Attributes.Md5), ETag: fmt.Sprintf("%x", entry.Attributes.Md5),
LastModified: time.Now().UTC(), LastModified: time.Now().UTC(),
}))
})
return return
} }
// 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, s3err.ErrInvalidCopySource, r)
s3err.WriteErrorResponse(w, s3err.ErrInvalidCopySource, r)
return return
} }
if srcBucket == dstBucket && srcObject == dstObject { if srcBucket == dstBucket && srcObject == dstObject {
writeErrorResponse(w, s3err.ErrInvalidCopyDest, r)
s3err.WriteErrorResponse(w, s3err.ErrInvalidCopyDest, r)
return return
} }
@ -64,7 +64,7 @@ func (s3a *S3ApiServer) CopyObjectHandler(w http.ResponseWriter, r *http.Request
_, _, resp, err := util.DownloadFile(srcUrl) _, _, resp, err := util.DownloadFile(srcUrl)
if err != nil { if err != nil {
writeErrorResponse(w, s3err.ErrInvalidCopySource, r)
s3err.WriteErrorResponse(w, s3err.ErrInvalidCopySource, r)
return return
} }
defer util.CloseResponse(resp) defer util.CloseResponse(resp)
@ -73,7 +73,7 @@ func (s3a *S3ApiServer) CopyObjectHandler(w http.ResponseWriter, r *http.Request
etag, errCode := s3a.putToFiler(r, dstUrl, resp.Body) etag, errCode := s3a.putToFiler(r, dstUrl, resp.Body)
if errCode != s3err.ErrNone { if errCode != s3err.ErrNone {
writeErrorResponse(w, errCode, r)
s3err.WriteErrorResponse(w, errCode, r)
return return
} }
@ -84,7 +84,7 @@ func (s3a *S3ApiServer) CopyObjectHandler(w http.ResponseWriter, r *http.Request
LastModified: time.Now().UTC(), LastModified: time.Now().UTC(),
} }
writeSuccessResponseXML(w, encodeResponse(response))
writeSuccessResponseXML(w, response)
} }
@ -117,7 +117,7 @@ func (s3a *S3ApiServer) CopyObjectPartHandler(w http.ResponseWriter, r *http.Req
srcBucket, srcObject := pathToBucketAndObject(cpSrcPath) srcBucket, srcObject := pathToBucketAndObject(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, s3err.ErrInvalidCopySource, r)
s3err.WriteErrorResponse(w, s3err.ErrInvalidCopySource, r)
return return
} }
@ -126,13 +126,13 @@ func (s3a *S3ApiServer) CopyObjectPartHandler(w http.ResponseWriter, r *http.Req
partID, err := strconv.Atoi(partIDString) partID, err := strconv.Atoi(partIDString)
if err != nil { if err != nil {
writeErrorResponse(w, s3err.ErrInvalidPart, r)
s3err.WriteErrorResponse(w, s3err.ErrInvalidPart, r)
return return
} }
// check partID with maximum part ID for multipart objects // check partID with maximum part ID for multipart objects
if partID > globalMaxPartID { if partID > globalMaxPartID {
writeErrorResponse(w, s3err.ErrInvalidMaxParts, r)
s3err.WriteErrorResponse(w, s3err.ErrInvalidMaxParts, r)
return return
} }
@ -145,7 +145,7 @@ func (s3a *S3ApiServer) CopyObjectPartHandler(w http.ResponseWriter, r *http.Req
dataReader, err := util.ReadUrlAsReaderCloser(srcUrl, rangeHeader) dataReader, err := util.ReadUrlAsReaderCloser(srcUrl, rangeHeader)
if err != nil { if err != nil {
writeErrorResponse(w, s3err.ErrInvalidCopySource, r)
s3err.WriteErrorResponse(w, s3err.ErrInvalidCopySource, r)
return return
} }
defer dataReader.Close() defer dataReader.Close()
@ -154,7 +154,7 @@ func (s3a *S3ApiServer) CopyObjectPartHandler(w http.ResponseWriter, r *http.Req
etag, errCode := s3a.putToFiler(r, dstUrl, dataReader) etag, errCode := s3a.putToFiler(r, dstUrl, dataReader)
if errCode != s3err.ErrNone { if errCode != s3err.ErrNone {
writeErrorResponse(w, errCode, r)
s3err.WriteErrorResponse(w, errCode, r)
return return
} }
@ -165,7 +165,7 @@ func (s3a *S3ApiServer) CopyObjectPartHandler(w http.ResponseWriter, r *http.Req
LastModified: time.Now().UTC(), LastModified: time.Now().UTC(),
} }
writeSuccessResponseXML(w, encodeResponse(response))
writeSuccessResponseXML(w, response)
} }

30
weed/s3api/s3api_object_handlers.go

@ -44,20 +44,20 @@ func (s3a *S3ApiServer) PutObjectHandler(w http.ResponseWriter, r *http.Request)
_, err := validateContentMd5(r.Header) _, err := validateContentMd5(r.Header)
if err != nil { if err != nil {
writeErrorResponse(w, s3err.ErrInvalidDigest, r)
s3err.WriteErrorResponse(w, s3err.ErrInvalidDigest, r)
return return
} }
if r.Header.Get("Cache-Control") != "" { if r.Header.Get("Cache-Control") != "" {
if _, err = cacheobject.ParseRequestCacheControl(r.Header.Get("Cache-Control")); err != nil { if _, err = cacheobject.ParseRequestCacheControl(r.Header.Get("Cache-Control")); err != nil {
writeErrorResponse(w, s3err.ErrInvalidDigest, r)
s3err.WriteErrorResponse(w, s3err.ErrInvalidDigest, r)
return return
} }
} }
if r.Header.Get("Expires") != "" { if r.Header.Get("Expires") != "" {
if _, err = time.Parse(http.TimeFormat, r.Header.Get("Expires")); err != nil { if _, err = time.Parse(http.TimeFormat, r.Header.Get("Expires")); err != nil {
writeErrorResponse(w, s3err.ErrInvalidDigest, r)
s3err.WriteErrorResponse(w, s3err.ErrInvalidDigest, r)
return return
} }
} }
@ -75,12 +75,12 @@ func (s3a *S3ApiServer) PutObjectHandler(w http.ResponseWriter, r *http.Request)
_, s3ErrCode = s3a.iam.reqSignatureV4Verify(r) _, s3ErrCode = s3a.iam.reqSignatureV4Verify(r)
} }
if s3ErrCode != s3err.ErrNone { if s3ErrCode != s3err.ErrNone {
writeErrorResponse(w, s3ErrCode, r)
s3err.WriteErrorResponse(w, s3ErrCode, r)
return return
} }
} else { } else {
if authTypeStreamingSigned == rAuthType { if authTypeStreamingSigned == rAuthType {
writeErrorResponse(w, s3err.ErrAuthNotSetup, r)
s3err.WriteErrorResponse(w, s3err.ErrAuthNotSetup, r)
return return
} }
} }
@ -88,7 +88,7 @@ func (s3a *S3ApiServer) PutObjectHandler(w http.ResponseWriter, r *http.Request)
if strings.HasSuffix(object, "/") { if strings.HasSuffix(object, "/") {
if err := s3a.mkdir(s3a.option.BucketsPath, bucket+object, nil); err != nil { if err := s3a.mkdir(s3a.option.BucketsPath, bucket+object, nil); err != nil {
writeErrorResponse(w, s3err.ErrInternalError, r)
s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
return return
} }
} else { } else {
@ -97,7 +97,7 @@ func (s3a *S3ApiServer) PutObjectHandler(w http.ResponseWriter, r *http.Request)
etag, errCode := s3a.putToFiler(r, uploadUrl, dataReader) etag, errCode := s3a.putToFiler(r, uploadUrl, dataReader)
if errCode != s3err.ErrNone { if errCode != s3err.ErrNone {
writeErrorResponse(w, errCode, r)
s3err.WriteErrorResponse(w, errCode, r)
return return
} }
@ -120,7 +120,7 @@ func (s3a *S3ApiServer) GetObjectHandler(w http.ResponseWriter, r *http.Request)
bucket, object := getBucketAndObject(r) bucket, object := getBucketAndObject(r)
if strings.HasSuffix(r.URL.Path, "/") { if strings.HasSuffix(r.URL.Path, "/") {
writeErrorResponse(w, s3err.ErrNotImplemented, r)
s3err.WriteErrorResponse(w, s3err.ErrNotImplemented, r)
return return
} }
@ -195,13 +195,13 @@ func (s3a *S3ApiServer) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *h
deleteXMLBytes, err := ioutil.ReadAll(r.Body) deleteXMLBytes, err := ioutil.ReadAll(r.Body)
if err != nil { if err != nil {
writeErrorResponse(w, s3err.ErrInternalError, r)
s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
return return
} }
deleteObjects := &DeleteObjectsRequest{} deleteObjects := &DeleteObjectsRequest{}
if err := xml.Unmarshal(deleteXMLBytes, deleteObjects); err != nil { if err := xml.Unmarshal(deleteXMLBytes, deleteObjects); err != nil {
writeErrorResponse(w, s3err.ErrMalformedXML, r)
s3err.WriteErrorResponse(w, s3err.ErrMalformedXML, r)
return return
} }
@ -253,7 +253,7 @@ func (s3a *S3ApiServer) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *h
} }
deleteResp.Errors = deleteErrors deleteResp.Errors = deleteErrors
writeSuccessResponseXML(w, encodeResponse(deleteResp))
writeSuccessResponseXML(w, deleteResp)
} }
@ -297,7 +297,7 @@ func (s3a *S3ApiServer) proxyToFiler(w http.ResponseWriter, r *http.Request, des
if err != nil { if err != nil {
glog.Errorf("NewRequest %s: %v", destUrl, err) glog.Errorf("NewRequest %s: %v", destUrl, err)
writeErrorResponse(w, s3err.ErrInternalError, r)
s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
return return
} }
@ -327,19 +327,19 @@ func (s3a *S3ApiServer) proxyToFiler(w http.ResponseWriter, r *http.Request, des
if postErr != nil { if postErr != nil {
glog.Errorf("post to filer: %v", postErr) glog.Errorf("post to filer: %v", postErr)
writeErrorResponse(w, s3err.ErrInternalError, r)
s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
return return
} }
defer util.CloseResponse(resp) defer util.CloseResponse(resp)
if resp.StatusCode == http.StatusPreconditionFailed { if resp.StatusCode == http.StatusPreconditionFailed {
writeErrorResponse(w, s3err.ErrPreconditionFailed, r)
s3err.WriteErrorResponse(w, s3err.ErrPreconditionFailed, r)
return return
} }
if (resp.ContentLength == -1 || resp.StatusCode == 404) && resp.StatusCode != 304 { if (resp.ContentLength == -1 || resp.StatusCode == 404) && resp.StatusCode != 304 {
if r.Method != "DELETE" { if r.Method != "DELETE" {
writeErrorResponse(w, s3err.ErrNoSuchKey, r)
s3err.WriteErrorResponse(w, s3err.ErrNoSuchKey, r)
return return
} }
} }

32
weed/s3api/s3api_object_handlers_postpolicy.go

@ -26,23 +26,23 @@ func (s3a *S3ApiServer) PostPolicyBucketHandler(w http.ResponseWriter, r *http.R
reader, err := r.MultipartReader() reader, err := r.MultipartReader()
if err != nil { if err != nil {
writeErrorResponse(w, s3err.ErrMalformedPOSTRequest, r)
s3err.WriteErrorResponse(w, s3err.ErrMalformedPOSTRequest, r)
return return
} }
form, err := reader.ReadForm(int64(5 * humanize.MiByte)) form, err := reader.ReadForm(int64(5 * humanize.MiByte))
if err != nil { if err != nil {
writeErrorResponse(w, s3err.ErrMalformedPOSTRequest, r)
s3err.WriteErrorResponse(w, s3err.ErrMalformedPOSTRequest, r)
return return
} }
defer form.RemoveAll() defer form.RemoveAll()
fileBody, fileName, fileSize, formValues, err := extractPostPolicyFormValues(form) fileBody, fileName, fileSize, formValues, err := extractPostPolicyFormValues(form)
if err != nil { if err != nil {
writeErrorResponse(w, s3err.ErrMalformedPOSTRequest, r)
s3err.WriteErrorResponse(w, s3err.ErrMalformedPOSTRequest, r)
return return
} }
if fileBody == nil { if fileBody == nil {
writeErrorResponse(w, s3err.ErrPOSTFileRequired, r)
s3err.WriteErrorResponse(w, s3err.ErrPOSTFileRequired, r)
return return
} }
defer fileBody.Close() defer fileBody.Close()
@ -60,7 +60,7 @@ func (s3a *S3ApiServer) PostPolicyBucketHandler(w http.ResponseWriter, r *http.R
if successRedirect != "" { if successRedirect != "" {
redirectURL, err = url.Parse(successRedirect) redirectURL, err = url.Parse(successRedirect)
if err != nil { if err != nil {
writeErrorResponse(w, s3err.ErrMalformedPOSTRequest, r)
s3err.WriteErrorResponse(w, s3err.ErrMalformedPOSTRequest, r)
return return
} }
} }
@ -68,13 +68,13 @@ func (s3a *S3ApiServer) PostPolicyBucketHandler(w http.ResponseWriter, r *http.R
// Verify policy signature. // Verify policy signature.
errCode := s3a.iam.doesPolicySignatureMatch(formValues) errCode := s3a.iam.doesPolicySignatureMatch(formValues)
if errCode != s3err.ErrNone { if errCode != s3err.ErrNone {
writeErrorResponse(w, errCode, r)
s3err.WriteErrorResponse(w, errCode, r)
return return
} }
policyBytes, err := base64.StdEncoding.DecodeString(formValues.Get("Policy")) policyBytes, err := base64.StdEncoding.DecodeString(formValues.Get("Policy"))
if err != nil { if err != nil {
writeErrorResponse(w, s3err.ErrMalformedPOSTRequest, r)
s3err.WriteErrorResponse(w, s3err.ErrMalformedPOSTRequest, r)
return return
} }
@ -83,7 +83,7 @@ func (s3a *S3ApiServer) PostPolicyBucketHandler(w http.ResponseWriter, r *http.R
postPolicyForm, err := policy.ParsePostPolicyForm(string(policyBytes)) postPolicyForm, err := policy.ParsePostPolicyForm(string(policyBytes))
if err != nil { if err != nil {
writeErrorResponse(w, s3err.ErrPostPolicyConditionInvalidFormat, r)
s3err.WriteErrorResponse(w, s3err.ErrPostPolicyConditionInvalidFormat, r)
return return
} }
@ -99,12 +99,12 @@ func (s3a *S3ApiServer) PostPolicyBucketHandler(w http.ResponseWriter, r *http.R
lengthRange := postPolicyForm.Conditions.ContentLengthRange lengthRange := postPolicyForm.Conditions.ContentLengthRange
if lengthRange.Valid { if lengthRange.Valid {
if fileSize < lengthRange.Min { if fileSize < lengthRange.Min {
writeErrorResponse(w, s3err.ErrEntityTooSmall, r)
s3err.WriteErrorResponse(w, s3err.ErrEntityTooSmall, r)
return return
} }
if fileSize > lengthRange.Max { if fileSize > lengthRange.Max {
writeErrorResponse(w, s3err.ErrEntityTooLarge, r)
s3err.WriteErrorResponse(w, s3err.ErrEntityTooLarge, r)
return return
} }
} }
@ -115,7 +115,7 @@ func (s3a *S3ApiServer) PostPolicyBucketHandler(w http.ResponseWriter, r *http.R
etag, errCode := s3a.putToFiler(r, uploadUrl, fileBody) etag, errCode := s3a.putToFiler(r, uploadUrl, fileBody)
if errCode != s3err.ErrNone { if errCode != s3err.ErrNone {
writeErrorResponse(w, errCode, r)
s3err.WriteErrorResponse(w, errCode, r)
return return
} }
@ -123,7 +123,7 @@ func (s3a *S3ApiServer) PostPolicyBucketHandler(w http.ResponseWriter, r *http.R
// Replace raw query params.. // Replace raw query params..
redirectURL.RawQuery = getRedirectPostRawQuery(bucket, object, etag) redirectURL.RawQuery = getRedirectPostRawQuery(bucket, object, etag)
w.Header().Set("Location", redirectURL.String()) w.Header().Set("Location", redirectURL.String())
writeResponse(w, http.StatusSeeOther, nil, mimeNone)
s3err.WriteEmptyResponse(w, http.StatusSeeOther)
return return
} }
@ -132,15 +132,15 @@ func (s3a *S3ApiServer) PostPolicyBucketHandler(w http.ResponseWriter, r *http.R
// Decide what http response to send depending on success_action_status parameter // Decide what http response to send depending on success_action_status parameter
switch successStatus { switch successStatus {
case "201": case "201":
resp := encodeResponse(PostResponse{
resp := PostResponse{
Bucket: bucket, Bucket: bucket,
Key: object, Key: object,
ETag: `"` + etag + `"`, ETag: `"` + etag + `"`,
Location: w.Header().Get("Location"), Location: w.Header().Get("Location"),
})
writeResponse(w, http.StatusCreated, resp, mimeXML)
}
s3err.WriteXMLResponse(w, http.StatusCreated, resp)
case "200": case "200":
writeResponse(w, http.StatusOK, nil, mimeNone)
s3err.WriteEmptyResponse(w, http.StatusOK)
default: default:
writeSuccessResponseEmpty(w) writeSuccessResponseEmpty(w)
} }

48
weed/s3api/s3api_object_multipart_handlers.go

@ -29,14 +29,14 @@ func (s3a *S3ApiServer) NewMultipartUploadHandler(w http.ResponseWriter, r *http
Key: objectKey(aws.String(object)), Key: objectKey(aws.String(object)),
}) })
glog.V(2).Info("NewMultipartUploadHandler", string(encodeResponse(response)), errCode)
glog.V(2).Info("NewMultipartUploadHandler", s3err.EncodeXMLResponse(response), errCode)
if errCode != s3err.ErrNone { if errCode != s3err.ErrNone {
writeErrorResponse(w, errCode, r)
s3err.WriteErrorResponse(w, errCode, r)
return return
} }
writeSuccessResponseXML(w, encodeResponse(response))
writeSuccessResponseXML(w, response)
} }
@ -53,14 +53,14 @@ func (s3a *S3ApiServer) CompleteMultipartUploadHandler(w http.ResponseWriter, r
UploadId: aws.String(uploadID), UploadId: aws.String(uploadID),
}) })
glog.V(2).Info("CompleteMultipartUploadHandler", string(encodeResponse(response)), errCode)
glog.V(2).Info("CompleteMultipartUploadHandler", s3err.EncodeXMLResponse(response), errCode)
if errCode != s3err.ErrNone { if errCode != s3err.ErrNone {
writeErrorResponse(w, errCode, r)
s3err.WriteErrorResponse(w, errCode, r)
return return
} }
writeSuccessResponseXML(w, encodeResponse(response))
writeSuccessResponseXML(w, response)
} }
@ -78,13 +78,13 @@ func (s3a *S3ApiServer) AbortMultipartUploadHandler(w http.ResponseWriter, r *ht
}) })
if errCode != s3err.ErrNone { if errCode != s3err.ErrNone {
writeErrorResponse(w, errCode, r)
s3err.WriteErrorResponse(w, errCode, r)
return return
} }
glog.V(2).Info("AbortMultipartUploadHandler", string(encodeResponse(response)))
glog.V(2).Info("AbortMultipartUploadHandler", s3err.EncodeXMLResponse(response))
writeSuccessResponseXML(w, encodeResponse(response))
writeSuccessResponseXML(w, response)
} }
@ -94,13 +94,13 @@ func (s3a *S3ApiServer) ListMultipartUploadsHandler(w http.ResponseWriter, r *ht
prefix, keyMarker, uploadIDMarker, delimiter, maxUploads, encodingType := getBucketMultipartResources(r.URL.Query()) prefix, keyMarker, uploadIDMarker, delimiter, maxUploads, encodingType := getBucketMultipartResources(r.URL.Query())
if maxUploads < 0 { if maxUploads < 0 {
writeErrorResponse(w, s3err.ErrInvalidMaxUploads, r)
s3err.WriteErrorResponse(w, s3err.ErrInvalidMaxUploads, r)
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, s3err.ErrNotImplemented, r)
s3err.WriteErrorResponse(w, s3err.ErrNotImplemented, r)
return return
} }
} }
@ -115,16 +115,16 @@ func (s3a *S3ApiServer) ListMultipartUploadsHandler(w http.ResponseWriter, r *ht
UploadIdMarker: aws.String(uploadIDMarker), UploadIdMarker: aws.String(uploadIDMarker),
}) })
glog.V(2).Info("ListMultipartUploadsHandler", string(encodeResponse(response)), errCode)
glog.V(2).Info("ListMultipartUploadsHandler", s3err.EncodeXMLResponse(response), errCode)
if errCode != s3err.ErrNone { if errCode != s3err.ErrNone {
writeErrorResponse(w, errCode, r)
s3err.WriteErrorResponse(w, errCode, r)
return return
} }
// TODO handle encodingType // TODO handle encodingType
writeSuccessResponseXML(w, encodeResponse(response))
writeSuccessResponseXML(w, response)
} }
// ListObjectPartsHandler - Lists object parts in a multipart upload. // ListObjectPartsHandler - Lists object parts in a multipart upload.
@ -133,11 +133,11 @@ func (s3a *S3ApiServer) ListObjectPartsHandler(w http.ResponseWriter, r *http.Re
uploadID, partNumberMarker, maxParts, _ := getObjectResources(r.URL.Query()) uploadID, partNumberMarker, maxParts, _ := getObjectResources(r.URL.Query())
if partNumberMarker < 0 { if partNumberMarker < 0 {
writeErrorResponse(w, s3err.ErrInvalidPartNumberMarker, r)
s3err.WriteErrorResponse(w, s3err.ErrInvalidPartNumberMarker, r)
return return
} }
if maxParts < 0 { if maxParts < 0 {
writeErrorResponse(w, s3err.ErrInvalidMaxParts, r)
s3err.WriteErrorResponse(w, s3err.ErrInvalidMaxParts, r)
return return
} }
@ -149,14 +149,14 @@ func (s3a *S3ApiServer) ListObjectPartsHandler(w http.ResponseWriter, r *http.Re
UploadId: aws.String(uploadID), UploadId: aws.String(uploadID),
}) })
glog.V(2).Info("ListObjectPartsHandler", string(encodeResponse(response)), errCode)
glog.V(2).Info("ListObjectPartsHandler", s3err.EncodeXMLResponse(response), errCode)
if errCode != s3err.ErrNone { if errCode != s3err.ErrNone {
writeErrorResponse(w, errCode, r)
s3err.WriteErrorResponse(w, errCode, r)
return return
} }
writeSuccessResponseXML(w, encodeResponse(response))
writeSuccessResponseXML(w, response)
} }
@ -167,18 +167,18 @@ func (s3a *S3ApiServer) PutObjectPartHandler(w http.ResponseWriter, r *http.Requ
uploadID := r.URL.Query().Get("uploadId") uploadID := r.URL.Query().Get("uploadId")
exists, err := s3a.exists(s3a.genUploadsFolder(bucket), uploadID, true) exists, err := s3a.exists(s3a.genUploadsFolder(bucket), uploadID, true)
if !exists { if !exists {
writeErrorResponse(w, s3err.ErrNoSuchUpload, r)
s3err.WriteErrorResponse(w, s3err.ErrNoSuchUpload, r)
return return
} }
partIDString := r.URL.Query().Get("partNumber") partIDString := r.URL.Query().Get("partNumber")
partID, err := strconv.Atoi(partIDString) partID, err := strconv.Atoi(partIDString)
if err != nil { if err != nil {
writeErrorResponse(w, s3err.ErrInvalidPart, r)
s3err.WriteErrorResponse(w, s3err.ErrInvalidPart, r)
return return
} }
if partID > globalMaxPartID { if partID > globalMaxPartID {
writeErrorResponse(w, s3err.ErrInvalidMaxParts, r)
s3err.WriteErrorResponse(w, s3err.ErrInvalidMaxParts, r)
return return
} }
@ -195,7 +195,7 @@ func (s3a *S3ApiServer) PutObjectPartHandler(w http.ResponseWriter, r *http.Requ
_, s3ErrCode = s3a.iam.reqSignatureV4Verify(r) _, s3ErrCode = s3a.iam.reqSignatureV4Verify(r)
} }
if s3ErrCode != s3err.ErrNone { if s3ErrCode != s3err.ErrNone {
writeErrorResponse(w, s3ErrCode, r)
s3err.WriteErrorResponse(w, s3ErrCode, r)
return return
} }
} }
@ -207,7 +207,7 @@ func (s3a *S3ApiServer) PutObjectPartHandler(w http.ResponseWriter, r *http.Requ
etag, errCode := s3a.putToFiler(r, uploadUrl, dataReader) etag, errCode := s3a.putToFiler(r, uploadUrl, dataReader)
if errCode != s3err.ErrNone { if errCode != s3err.ErrNone {
writeErrorResponse(w, errCode, r)
s3err.WriteErrorResponse(w, errCode, r)
return return
} }

24
weed/s3api/s3api_object_tagging_handlers.go

@ -25,15 +25,15 @@ func (s3a *S3ApiServer) GetObjectTaggingHandler(w http.ResponseWriter, r *http.R
if err != nil { if err != nil {
if err == filer_pb.ErrNotFound { if err == filer_pb.ErrNotFound {
glog.Errorf("GetObjectTaggingHandler %s: %v", r.URL, err) glog.Errorf("GetObjectTaggingHandler %s: %v", r.URL, err)
writeErrorResponse(w, s3err.ErrNoSuchKey, r)
s3err.WriteErrorResponse(w, s3err.ErrNoSuchKey, r)
} else { } else {
glog.Errorf("GetObjectTaggingHandler %s: %v", r.URL, err) glog.Errorf("GetObjectTaggingHandler %s: %v", r.URL, err)
writeErrorResponse(w, s3err.ErrInternalError, r)
s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
} }
return return
} }
writeSuccessResponseXML(w, encodeResponse(FromTags(tags)))
writeSuccessResponseXML(w, FromTags(tags))
} }
@ -50,29 +50,29 @@ func (s3a *S3ApiServer) PutObjectTaggingHandler(w http.ResponseWriter, r *http.R
input, err := ioutil.ReadAll(io.LimitReader(r.Body, r.ContentLength)) input, err := ioutil.ReadAll(io.LimitReader(r.Body, r.ContentLength))
if err != nil { if err != nil {
glog.Errorf("PutObjectTaggingHandler read input %s: %v", r.URL, err) glog.Errorf("PutObjectTaggingHandler read input %s: %v", r.URL, err)
writeErrorResponse(w, s3err.ErrInternalError, r)
s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
return return
} }
if err = xml.Unmarshal(input, tagging); err != nil { if err = xml.Unmarshal(input, tagging); err != nil {
glog.Errorf("PutObjectTaggingHandler Unmarshal %s: %v", r.URL, err) glog.Errorf("PutObjectTaggingHandler Unmarshal %s: %v", r.URL, err)
writeErrorResponse(w, s3err.ErrMalformedXML, r)
s3err.WriteErrorResponse(w, s3err.ErrMalformedXML, r)
return return
} }
tags := tagging.ToTags() tags := tagging.ToTags()
if len(tags) > 10 { if len(tags) > 10 {
glog.Errorf("PutObjectTaggingHandler tags %s: %d tags more than 10", r.URL, len(tags)) glog.Errorf("PutObjectTaggingHandler tags %s: %d tags more than 10", r.URL, len(tags))
writeErrorResponse(w, s3err.ErrInvalidTag, r)
s3err.WriteErrorResponse(w, s3err.ErrInvalidTag, r)
return return
} }
for k, v := range tags { for k, v := range tags {
if len(k) > 128 { if len(k) > 128 {
glog.Errorf("PutObjectTaggingHandler tags %s: tag key %s longer than 128", r.URL, k) glog.Errorf("PutObjectTaggingHandler tags %s: tag key %s longer than 128", r.URL, k)
writeErrorResponse(w, s3err.ErrInvalidTag, r)
s3err.WriteErrorResponse(w, s3err.ErrInvalidTag, r)
return return
} }
if len(v) > 256 { if len(v) > 256 {
glog.Errorf("PutObjectTaggingHandler tags %s: tag value %s longer than 256", r.URL, v) glog.Errorf("PutObjectTaggingHandler tags %s: tag value %s longer than 256", r.URL, v)
writeErrorResponse(w, s3err.ErrInvalidTag, r)
s3err.WriteErrorResponse(w, s3err.ErrInvalidTag, r)
return return
} }
} }
@ -80,10 +80,10 @@ func (s3a *S3ApiServer) PutObjectTaggingHandler(w http.ResponseWriter, r *http.R
if err = s3a.setTags(dir, name, tagging.ToTags()); err != nil { if err = s3a.setTags(dir, name, tagging.ToTags()); err != nil {
if err == filer_pb.ErrNotFound { if err == filer_pb.ErrNotFound {
glog.Errorf("PutObjectTaggingHandler setTags %s: %v", r.URL, err) glog.Errorf("PutObjectTaggingHandler setTags %s: %v", r.URL, err)
writeErrorResponse(w, s3err.ErrNoSuchKey, r)
s3err.WriteErrorResponse(w, s3err.ErrNoSuchKey, r)
} else { } else {
glog.Errorf("PutObjectTaggingHandler setTags %s: %v", r.URL, err) glog.Errorf("PutObjectTaggingHandler setTags %s: %v", r.URL, err)
writeErrorResponse(w, s3err.ErrInternalError, r)
s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
} }
return return
} }
@ -105,10 +105,10 @@ func (s3a *S3ApiServer) DeleteObjectTaggingHandler(w http.ResponseWriter, r *htt
if err != nil { if err != nil {
if err == filer_pb.ErrNotFound { if err == filer_pb.ErrNotFound {
glog.Errorf("DeleteObjectTaggingHandler %s: %v", r.URL, err) glog.Errorf("DeleteObjectTaggingHandler %s: %v", r.URL, err)
writeErrorResponse(w, s3err.ErrNoSuchKey, r)
s3err.WriteErrorResponse(w, s3err.ErrNoSuchKey, r)
} else { } else {
glog.Errorf("DeleteObjectTaggingHandler %s: %v", r.URL, err) glog.Errorf("DeleteObjectTaggingHandler %s: %v", r.URL, err)
writeErrorResponse(w, s3err.ErrInternalError, r)
s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
} }
return return
} }

20
weed/s3api/s3api_objects_list_handlers.go

@ -44,11 +44,11 @@ func (s3a *S3ApiServer) ListObjectsV2Handler(w http.ResponseWriter, r *http.Requ
originalPrefix, continuationToken, startAfter, delimiter, _, maxKeys := getListObjectsV2Args(r.URL.Query()) originalPrefix, continuationToken, startAfter, delimiter, _, maxKeys := getListObjectsV2Args(r.URL.Query())
if maxKeys < 0 { if maxKeys < 0 {
writeErrorResponse(w, s3err.ErrInvalidMaxKeys, r)
s3err.WriteErrorResponse(w, s3err.ErrInvalidMaxKeys, r)
return return
} }
if delimiter != "" && delimiter != "/" { if delimiter != "" && delimiter != "/" {
writeErrorResponse(w, s3err.ErrNotImplemented, r)
s3err.WriteErrorResponse(w, s3err.ErrNotImplemented, r)
return return
} }
@ -60,13 +60,13 @@ func (s3a *S3ApiServer) ListObjectsV2Handler(w http.ResponseWriter, r *http.Requ
response, err := s3a.listFilerEntries(bucket, originalPrefix, maxKeys, marker, delimiter) response, err := s3a.listFilerEntries(bucket, originalPrefix, maxKeys, marker, delimiter)
if err != nil { if err != nil {
writeErrorResponse(w, s3err.ErrInternalError, r)
s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
return return
} }
if len(response.Contents) == 0 { if len(response.Contents) == 0 {
if exists, existErr := s3a.exists(s3a.option.BucketsPath, bucket, true); existErr == nil && !exists { if exists, existErr := s3a.exists(s3a.option.BucketsPath, bucket, true); existErr == nil && !exists {
writeErrorResponse(w, s3err.ErrNoSuchBucket, r)
s3err.WriteErrorResponse(w, s3err.ErrNoSuchBucket, r)
return return
} }
} }
@ -86,7 +86,7 @@ func (s3a *S3ApiServer) ListObjectsV2Handler(w http.ResponseWriter, r *http.Requ
StartAfter: startAfter, StartAfter: startAfter,
} }
writeSuccessResponseXML(w, encodeResponse(responseV2))
writeSuccessResponseXML(w, responseV2)
} }
func (s3a *S3ApiServer) ListObjectsV1Handler(w http.ResponseWriter, r *http.Request) { func (s3a *S3ApiServer) ListObjectsV1Handler(w http.ResponseWriter, r *http.Request) {
@ -99,29 +99,29 @@ func (s3a *S3ApiServer) ListObjectsV1Handler(w http.ResponseWriter, r *http.Requ
originalPrefix, marker, delimiter, maxKeys := getListObjectsV1Args(r.URL.Query()) originalPrefix, marker, delimiter, maxKeys := getListObjectsV1Args(r.URL.Query())
if maxKeys < 0 { if maxKeys < 0 {
writeErrorResponse(w, s3err.ErrInvalidMaxKeys, r)
s3err.WriteErrorResponse(w, s3err.ErrInvalidMaxKeys, r)
return return
} }
if delimiter != "" && delimiter != "/" { if delimiter != "" && delimiter != "/" {
writeErrorResponse(w, s3err.ErrNotImplemented, r)
s3err.WriteErrorResponse(w, s3err.ErrNotImplemented, r)
return return
} }
response, err := s3a.listFilerEntries(bucket, originalPrefix, maxKeys, marker, delimiter) response, err := s3a.listFilerEntries(bucket, originalPrefix, maxKeys, marker, delimiter)
if err != nil { if err != nil {
writeErrorResponse(w, s3err.ErrInternalError, r)
s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
return return
} }
if len(response.Contents) == 0 { if len(response.Contents) == 0 {
if exists, existErr := s3a.exists(s3a.option.BucketsPath, bucket, true); existErr == nil && !exists { if exists, existErr := s3a.exists(s3a.option.BucketsPath, bucket, true); existErr == nil && !exists {
writeErrorResponse(w, s3err.ErrNoSuchBucket, r)
s3err.WriteErrorResponse(w, s3err.ErrNoSuchBucket, r)
return return
} }
} }
writeSuccessResponseXML(w, encodeResponse(response))
writeSuccessResponseXML(w, response)
} }
func (s3a *S3ApiServer) listFilerEntries(bucket string, originalPrefix string, maxKeys int, marker string, delimiter string) (response ListBucketResult, err error) { func (s3a *S3ApiServer) listFilerEntries(bucket string, originalPrefix string, maxKeys int, marker string, delimiter string) (response ListBucketResult, err error) {

3
weed/s3api/s3api_objects_list_handlers_test.go

@ -1,6 +1,7 @@
package s3api package s3api
import ( import (
"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
"testing" "testing"
"time" "time"
) )
@ -31,7 +32,7 @@ func TestListObjectsHandler(t *testing.T) {
}}, }},
} }
encoded := string(encodeResponse(response))
encoded := string(s3err.EncodeXMLResponse(response))
if encoded != expected { if encoded != expected {
t.Errorf("unexpected output: %s\nexpecting:%s", encoded, expected) t.Errorf("unexpected output: %s\nexpecting:%s", encoded, expected)
} }

3
weed/s3api/s3api_server.go

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"github.com/chrislusf/seaweedfs/weed/filer" "github.com/chrislusf/seaweedfs/weed/filer"
. "github.com/chrislusf/seaweedfs/weed/s3api/s3_constants" . "github.com/chrislusf/seaweedfs/weed/s3api/s3_constants"
"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
"net/http" "net/http"
"strings" "strings"
"time" "time"
@ -132,6 +133,6 @@ func (s3a *S3ApiServer) registerRouter(router *mux.Router) {
apiRouter.Methods("GET").Path("/").HandlerFunc(track(s3a.ListBucketsHandler, "LIST")) apiRouter.Methods("GET").Path("/").HandlerFunc(track(s3a.ListBucketsHandler, "LIST"))
// NotFound // NotFound
apiRouter.NotFoundHandler = http.HandlerFunc(notFoundHandler)
apiRouter.NotFoundHandler = http.HandlerFunc(s3err.NotFoundHandler)
} }

5
weed/s3api/s3api_test.go

@ -1,6 +1,7 @@
package s3api package s3api
import ( import (
"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
"testing" "testing"
"time" "time"
) )
@ -14,7 +15,7 @@ func TestCopyObjectResponse(t *testing.T) {
LastModified: time.Now(), LastModified: time.Now(),
} }
println(string(encodeResponse(response)))
println(string(s3err.EncodeXMLResponse(response)))
} }
@ -27,6 +28,6 @@ func TestCopyPartResponse(t *testing.T) {
LastModified: time.Now(), LastModified: time.Now(),
} }
println(string(encodeResponse(response)))
println(string(s3err.EncodeXMLResponse(response)))
} }

81
weed/s3api/s3err/error_handler.go

@ -0,0 +1,81 @@
package s3err
import (
"bytes"
"encoding/xml"
"fmt"
"github.com/chrislusf/seaweedfs/weed/glog"
"net/http"
"strconv"
"time"
)
type mimeType string
const (
mimeNone mimeType = ""
MimeXML mimeType = "application/xml"
)
func WriteXMLResponse(w http.ResponseWriter, statusCode int, response interface{}) {
WriteResponse(w, statusCode, EncodeXMLResponse(response), MimeXML)
}
func WriteEmptyResponse(w http.ResponseWriter, statusCode int) {
WriteResponse(w, statusCode, []byte{}, mimeNone)
}
func WriteErrorResponse(w http.ResponseWriter, errorCode ErrorCode, r *http.Request) {
apiError := GetAPIError(errorCode)
errorResponse := getRESTErrorResponse(apiError, r.URL.Path)
encodedErrorResponse := EncodeXMLResponse(errorResponse)
WriteResponse(w, apiError.HTTPStatusCode, encodedErrorResponse, MimeXML)
}
func getRESTErrorResponse(err APIError, resource string) RESTErrorResponse {
return RESTErrorResponse{
Code: err.Code,
Message: err.Description,
Resource: resource,
RequestID: fmt.Sprintf("%d", time.Now().UnixNano()),
}
}
// Encodes the response headers into XML format.
func EncodeXMLResponse(response interface{}) []byte {
var bytesBuffer bytes.Buffer
bytesBuffer.WriteString(xml.Header)
e := xml.NewEncoder(&bytesBuffer)
e.Encode(response)
return bytesBuffer.Bytes()
}
func setCommonHeaders(w http.ResponseWriter) {
w.Header().Set("x-amz-request-id", fmt.Sprintf("%d", time.Now().UnixNano()))
w.Header().Set("Accept-Ranges", "bytes")
}
func WriteResponse(w http.ResponseWriter, statusCode int, response []byte, mType mimeType) {
setCommonHeaders(w)
if response != nil {
w.Header().Set("Content-Length", strconv.Itoa(len(response)))
}
if mType != mimeNone {
w.Header().Set("Content-Type", string(mType))
}
w.WriteHeader(statusCode)
if response != nil {
glog.V(4).Infof("status %d %s: %s", statusCode, mType, string(response))
_, err := w.Write(response)
if err != nil {
glog.V(0).Infof("write err: %v", err)
}
w.(http.Flusher).Flush()
}
}
// If none of the http routes match respond with MethodNotAllowed
func NotFoundHandler(w http.ResponseWriter, r *http.Request) {
glog.V(0).Infof("unsupported %s %s", r.Method, r.RequestURI)
WriteErrorResponse(w, ErrMethodNotAllowed, r)
}

3
weed/s3api/tags_test.go

@ -2,6 +2,7 @@ package s3api
import ( import (
"encoding/xml" "encoding/xml"
"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"testing" "testing"
) )
@ -41,7 +42,7 @@ func TestXMLMarshall(t *testing.T) {
}, },
} }
actual := string(encodeResponse(tags))
actual := string(s3err.EncodeXMLResponse(tags))
expected := `<?xml version="1.0" encoding="UTF-8"?> expected := `<?xml version="1.0" encoding="UTF-8"?>
<Tagging xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><TagSet><Tag><Key>key1</Key><Value>value1</Value></Tag></TagSet></Tagging>` <Tagging xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><TagSet><Tag><Key>key1</Key><Value>value1</Value></Tag></TagSet></Tagging>`

Loading…
Cancel
Save