aboutsummaryrefslogtreecommitdiff
path: root/weed/s3api
diff options
context:
space:
mode:
authorhilimd <68371223+hilimd@users.noreply.github.com>2021-11-11 16:00:21 +0800
committerGitHub <noreply@github.com>2021-11-11 16:00:21 +0800
commit34240606f78395345ca7f6d7fe66a223c9bdf072 (patch)
tree914f76c6587989a39fe1c0f421782126248fbe8e /weed/s3api
parentb5389c3b23502da7315dd258715e146be7cc0fc9 (diff)
parent835e2d2ddf959dc8dd234021ac3cde72bd9e9246 (diff)
downloadseaweedfs-34240606f78395345ca7f6d7fe66a223c9bdf072.tar.xz
seaweedfs-34240606f78395345ca7f6d7fe66a223c9bdf072.zip
Merge pull request #87 from chrislusf/master
sync
Diffstat (limited to 'weed/s3api')
-rw-r--r--weed/s3api/auth_credentials.go20
-rw-r--r--weed/s3api/s3api_bucket_handlers.go47
-rw-r--r--weed/s3api/s3api_handlers.go8
-rw-r--r--weed/s3api/s3api_object_copy_handlers.go30
-rw-r--r--weed/s3api/s3api_object_handlers.go32
-rw-r--r--weed/s3api/s3api_object_handlers_postpolicy.go30
-rw-r--r--weed/s3api/s3api_object_multipart_handlers.go40
-rw-r--r--weed/s3api/s3api_object_tagging_handlers.go24
-rw-r--r--weed/s3api/s3api_objects_list_handlers.go24
-rw-r--r--weed/s3api/s3api_server.go4
-rw-r--r--weed/s3api/s3api_status_handlers.go2
-rw-r--r--weed/s3api/s3err/error_handler.go24
-rw-r--r--weed/s3api/stats.go3
13 files changed, 157 insertions, 131 deletions
diff --git a/weed/s3api/auth_credentials.go b/weed/s3api/auth_credentials.go
index 998a74625..d29e8692f 100644
--- a/weed/s3api/auth_credentials.go
+++ b/weed/s3api/auth_credentials.go
@@ -5,6 +5,7 @@ import (
"net/http"
"os"
"strings"
+ "sync"
"github.com/chrislusf/seaweedfs/weed/filer"
"github.com/chrislusf/seaweedfs/weed/glog"
@@ -23,6 +24,8 @@ type Iam interface {
}
type IdentityAccessManagement struct {
+ m sync.RWMutex
+
identities []*Identity
domain string
}
@@ -131,31 +134,38 @@ func (iam *IdentityAccessManagement) loadS3ApiConfiguration(config *iam_pb.S3Api
}
identities = append(identities, t)
}
-
+ iam.m.Lock()
// atomically switch
iam.identities = identities
+ iam.m.Unlock()
return nil
}
func (iam *IdentityAccessManagement) isEnabled() bool {
-
+ iam.m.RLock()
+ defer iam.m.RUnlock()
return len(iam.identities) > 0
}
func (iam *IdentityAccessManagement) lookupByAccessKey(accessKey string) (identity *Identity, cred *Credential, found bool) {
+ iam.m.RLock()
+ defer iam.m.RUnlock()
for _, ident := range iam.identities {
for _, cred := range ident.Credentials {
+ // println("checking", ident.Name, cred.AccessKey)
if cred.AccessKey == accessKey {
return ident, cred, true
}
}
}
+ glog.V(1).Infof("could not find accessKey %s", accessKey)
return nil, nil, false
}
func (iam *IdentityAccessManagement) lookupAnonymous() (identity *Identity, found bool) {
-
+ iam.m.RLock()
+ defer iam.m.RUnlock()
for _, ident := range iam.identities {
if ident.Name == "anonymous" {
return ident, true
@@ -177,12 +187,14 @@ func (iam *IdentityAccessManagement) Auth(f http.HandlerFunc, action Action) htt
r.Header.Set(xhttp.AmzIdentityId, identity.Name)
if identity.isAdmin() {
r.Header.Set(xhttp.AmzIsAdmin, "true")
+ } else if _, ok := r.Header[xhttp.AmzIsAdmin]; ok {
+ r.Header.Del(xhttp.AmzIsAdmin)
}
}
f(w, r)
return
}
- s3err.WriteErrorResponse(w, errCode, r)
+ s3err.WriteErrorResponse(w, r, errCode)
}
}
diff --git a/weed/s3api/s3api_bucket_handlers.go b/weed/s3api/s3api_bucket_handlers.go
index c45210b92..e8ca20cb0 100644
--- a/weed/s3api/s3api_bucket_handlers.go
+++ b/weed/s3api/s3api_bucket_handlers.go
@@ -36,7 +36,7 @@ func (s3a *S3ApiServer) ListBucketsHandler(w http.ResponseWriter, r *http.Reques
if s3a.iam.isEnabled() {
identity, s3Err = s3a.iam.authUser(r)
if s3Err != s3err.ErrNone {
- s3err.WriteErrorResponse(w, s3Err, r)
+ s3err.WriteErrorResponse(w, r, s3Err)
return
}
}
@@ -46,7 +46,7 @@ func (s3a *S3ApiServer) ListBucketsHandler(w http.ResponseWriter, r *http.Reques
entries, _, err := s3a.list(s3a.option.BucketsPath, "", "", false, math.MaxInt32)
if err != nil {
- s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
return
}
@@ -73,7 +73,7 @@ func (s3a *S3ApiServer) ListBucketsHandler(w http.ResponseWriter, r *http.Reques
Buckets: buckets,
}
- writeSuccessResponseXML(w, response)
+ writeSuccessResponseXML(w, r, response)
}
func (s3a *S3ApiServer) PutBucketHandler(w http.ResponseWriter, r *http.Request) {
@@ -100,17 +100,24 @@ func (s3a *S3ApiServer) PutBucketHandler(w http.ResponseWriter, r *http.Request)
}
return nil
}); err != nil {
- s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
return
}
if exist, err := s3a.exists(s3a.option.BucketsPath, bucket, true); err == nil && exist {
errCode = s3err.ErrBucketAlreadyExists
}
if errCode != s3err.ErrNone {
- s3err.WriteErrorResponse(w, errCode, r)
+ s3err.WriteErrorResponse(w, r, errCode)
return
}
+ if s3a.iam.isEnabled() {
+ if _, errCode = s3a.iam.authRequest(r, s3_constants.ACTION_ADMIN); errCode != s3err.ErrNone {
+ s3err.WriteErrorResponse(w, r, errCode)
+ return
+ }
+ }
+
fn := func(entry *filer_pb.Entry) {
if identityId := r.Header.Get(xhttp.AmzIdentityId); identityId != "" {
if entry.Extended == nil {
@@ -123,11 +130,11 @@ func (s3a *S3ApiServer) PutBucketHandler(w http.ResponseWriter, r *http.Request)
// create the folder for bucket, but lazily create actual collection
if err := s3a.mkdir(s3a.option.BucketsPath, bucket, fn); err != nil {
glog.Errorf("PutBucketHandler mkdir: %v", err)
- s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
return
}
- writeSuccessResponseEmpty(w)
+ writeSuccessResponseEmpty(w, r)
}
func (s3a *S3ApiServer) DeleteBucketHandler(w http.ResponseWriter, r *http.Request) {
@@ -136,7 +143,7 @@ func (s3a *S3ApiServer) DeleteBucketHandler(w http.ResponseWriter, r *http.Reque
glog.V(3).Infof("DeleteBucketHandler %s", bucket)
if err := s3a.checkBucket(r, bucket); err != s3err.ErrNone {
- s3err.WriteErrorResponse(w, err, r)
+ s3err.WriteErrorResponse(w, r, err)
return
}
@@ -158,11 +165,11 @@ func (s3a *S3ApiServer) DeleteBucketHandler(w http.ResponseWriter, r *http.Reque
err = s3a.rm(s3a.option.BucketsPath, bucket, false, true)
if err != nil {
- s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
return
}
- s3err.WriteEmptyResponse(w, http.StatusNoContent)
+ s3err.WriteEmptyResponse(w, r, http.StatusNoContent)
}
func (s3a *S3ApiServer) HeadBucketHandler(w http.ResponseWriter, r *http.Request) {
@@ -171,11 +178,11 @@ func (s3a *S3ApiServer) HeadBucketHandler(w http.ResponseWriter, r *http.Request
glog.V(3).Infof("HeadBucketHandler %s", bucket)
if err := s3a.checkBucket(r, bucket); err != s3err.ErrNone {
- s3err.WriteErrorResponse(w, err, r)
+ s3err.WriteErrorResponse(w, r, err)
return
}
- writeSuccessResponseEmpty(w)
+ writeSuccessResponseEmpty(w, r)
}
func (s3a *S3ApiServer) checkBucket(r *http.Request, bucket string) s3err.ErrorCode {
@@ -216,7 +223,7 @@ func (s3a *S3ApiServer) GetBucketAclHandler(w http.ResponseWriter, r *http.Reque
glog.V(3).Infof("GetBucketAclHandler %s", bucket)
if err := s3a.checkBucket(r, bucket); err != s3err.ErrNone {
- s3err.WriteErrorResponse(w, err, r)
+ s3err.WriteErrorResponse(w, r, err)
return
}
@@ -245,7 +252,7 @@ func (s3a *S3ApiServer) GetBucketAclHandler(w http.ResponseWriter, r *http.Reque
})
}
}
- writeSuccessResponseXML(w, response)
+ writeSuccessResponseXML(w, r, response)
}
// GetBucketLifecycleConfigurationHandler Get Bucket Lifecycle configuration
@@ -256,18 +263,18 @@ func (s3a *S3ApiServer) GetBucketLifecycleConfigurationHandler(w http.ResponseWr
glog.V(3).Infof("GetBucketAclHandler %s", bucket)
if err := s3a.checkBucket(r, bucket); err != s3err.ErrNone {
- s3err.WriteErrorResponse(w, err, r)
+ s3err.WriteErrorResponse(w, r, err)
return
}
fc, err := filer.ReadFilerConf(s3a.option.Filer, s3a.option.GrpcDialOption, nil)
if err != nil {
glog.Errorf("GetBucketLifecycleConfigurationHandler: %s", err)
- s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
return
}
ttls := fc.GetCollectionTtls(bucket)
if len(ttls) == 0 {
- s3err.WriteErrorResponse(w, s3err.ErrNoSuchLifecycleConfiguration, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchLifecycleConfiguration)
return
}
response := Lifecycle{}
@@ -285,14 +292,14 @@ func (s3a *S3ApiServer) GetBucketLifecycleConfigurationHandler(w http.ResponseWr
Expiration: Expiration{Days: days, set: true},
})
}
- writeSuccessResponseXML(w, response)
+ writeSuccessResponseXML(w, r, response)
}
// PutBucketLifecycleConfigurationHandler Put Bucket Lifecycle configuration
// https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLifecycleConfiguration.html
func (s3a *S3ApiServer) PutBucketLifecycleConfigurationHandler(w http.ResponseWriter, r *http.Request) {
- s3err.WriteErrorResponse(w, s3err.ErrNotImplemented, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrNotImplemented)
}
@@ -300,6 +307,6 @@ func (s3a *S3ApiServer) PutBucketLifecycleConfigurationHandler(w http.ResponseWr
// https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketLifecycle.html
func (s3a *S3ApiServer) DeleteBucketLifecycleHandler(w http.ResponseWriter, r *http.Request) {
- s3err.WriteEmptyResponse(w, http.StatusNoContent)
+ s3err.WriteEmptyResponse(w, r, http.StatusNoContent)
}
diff --git a/weed/s3api/s3api_handlers.go b/weed/s3api/s3api_handlers.go
index e99abb8e2..5bc94bb04 100644
--- a/weed/s3api/s3api_handlers.go
+++ b/weed/s3api/s3api_handlers.go
@@ -26,12 +26,12 @@ func (s3a *S3ApiServer) AdjustedUrl(location *filer_pb.Location) string {
return location.Url
}
-func writeSuccessResponseXML(w http.ResponseWriter, response interface{}) {
- s3err.WriteXMLResponse(w, http.StatusOK, response)
+func writeSuccessResponseXML(w http.ResponseWriter, r *http.Request, response interface{}) {
+ s3err.WriteXMLResponse(w, r, http.StatusOK, response)
}
-func writeSuccessResponseEmpty(w http.ResponseWriter) {
- s3err.WriteEmptyResponse(w, http.StatusOK)
+func writeSuccessResponseEmpty(w http.ResponseWriter, r *http.Request) {
+ s3err.WriteEmptyResponse(w, r, http.StatusOK)
}
func validateContentMd5(h http.Header) ([]byte, error) {
diff --git a/weed/s3api/s3api_object_copy_handlers.go b/weed/s3api/s3api_object_copy_handlers.go
index 59040997c..e2b191435 100644
--- a/weed/s3api/s3api_object_copy_handlers.go
+++ b/weed/s3api/s3api_object_copy_handlers.go
@@ -34,16 +34,16 @@ func (s3a *S3ApiServer) CopyObjectHandler(w http.ResponseWriter, r *http.Request
dir, name := fullPath.DirAndName()
entry, err := s3a.getEntry(dir, name)
if err != nil {
- s3err.WriteErrorResponse(w, s3err.ErrInvalidCopySource, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInvalidCopySource)
return
}
entry.Extended = weed_server.SaveAmzMetaData(r, entry.Extended, isReplace(r))
err = s3a.touch(dir, name, entry)
if err != nil {
- s3err.WriteErrorResponse(w, s3err.ErrInvalidCopySource, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInvalidCopySource)
return
}
- writeSuccessResponseXML(w, CopyObjectResult{
+ writeSuccessResponseXML(w, r, CopyObjectResult{
ETag: fmt.Sprintf("%x", entry.Attributes.Md5),
LastModified: time.Now().UTC(),
})
@@ -52,19 +52,19 @@ func (s3a *S3ApiServer) CopyObjectHandler(w http.ResponseWriter, r *http.Request
// If source object is empty or bucket is empty, reply back invalid copy source.
if srcObject == "" || srcBucket == "" {
- s3err.WriteErrorResponse(w, s3err.ErrInvalidCopySource, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInvalidCopySource)
return
}
srcPath := util.FullPath(fmt.Sprintf("%s/%s%s", s3a.option.BucketsPath, srcBucket, srcObject))
dir, name := srcPath.DirAndName()
_, err = s3a.getEntry(dir, name)
if err != nil {
- s3err.WriteErrorResponse(w, s3err.ErrInvalidCopySource, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInvalidCopySource)
return
}
if srcBucket == dstBucket && srcObject == dstObject {
- s3err.WriteErrorResponse(w, s3err.ErrInvalidCopyDest, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInvalidCopyDest)
return
}
@@ -75,7 +75,7 @@ func (s3a *S3ApiServer) CopyObjectHandler(w http.ResponseWriter, r *http.Request
_, _, resp, err := util.DownloadFile(srcUrl, "")
if err != nil {
- s3err.WriteErrorResponse(w, s3err.ErrInvalidCopySource, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInvalidCopySource)
return
}
defer util.CloseResponse(resp)
@@ -84,7 +84,7 @@ func (s3a *S3ApiServer) CopyObjectHandler(w http.ResponseWriter, r *http.Request
etag, errCode := s3a.putToFiler(r, dstUrl, resp.Body)
if errCode != s3err.ErrNone {
- s3err.WriteErrorResponse(w, errCode, r)
+ s3err.WriteErrorResponse(w, r, errCode)
return
}
@@ -95,7 +95,7 @@ func (s3a *S3ApiServer) CopyObjectHandler(w http.ResponseWriter, r *http.Request
LastModified: time.Now().UTC(),
}
- writeSuccessResponseXML(w, response)
+ writeSuccessResponseXML(w, r, response)
}
@@ -128,7 +128,7 @@ func (s3a *S3ApiServer) CopyObjectPartHandler(w http.ResponseWriter, r *http.Req
srcBucket, srcObject := pathToBucketAndObject(cpSrcPath)
// If source object is empty or bucket is empty, reply back invalid copy source.
if srcObject == "" || srcBucket == "" {
- s3err.WriteErrorResponse(w, s3err.ErrInvalidCopySource, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInvalidCopySource)
return
}
@@ -137,7 +137,7 @@ func (s3a *S3ApiServer) CopyObjectPartHandler(w http.ResponseWriter, r *http.Req
partID, err := strconv.Atoi(partIDString)
if err != nil {
- s3err.WriteErrorResponse(w, s3err.ErrInvalidPart, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInvalidPart)
return
}
@@ -145,7 +145,7 @@ func (s3a *S3ApiServer) CopyObjectPartHandler(w http.ResponseWriter, r *http.Req
// check partID with maximum part ID for multipart objects
if partID > globalMaxPartID {
- s3err.WriteErrorResponse(w, s3err.ErrInvalidMaxParts, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInvalidMaxParts)
return
}
@@ -158,7 +158,7 @@ func (s3a *S3ApiServer) CopyObjectPartHandler(w http.ResponseWriter, r *http.Req
dataReader, err := util.ReadUrlAsReaderCloser(srcUrl, rangeHeader)
if err != nil {
- s3err.WriteErrorResponse(w, s3err.ErrInvalidCopySource, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInvalidCopySource)
return
}
defer dataReader.Close()
@@ -167,7 +167,7 @@ func (s3a *S3ApiServer) CopyObjectPartHandler(w http.ResponseWriter, r *http.Req
etag, errCode := s3a.putToFiler(r, dstUrl, dataReader)
if errCode != s3err.ErrNone {
- s3err.WriteErrorResponse(w, errCode, r)
+ s3err.WriteErrorResponse(w, r, errCode)
return
}
@@ -178,7 +178,7 @@ func (s3a *S3ApiServer) CopyObjectPartHandler(w http.ResponseWriter, r *http.Req
LastModified: time.Now().UTC(),
}
- writeSuccessResponseXML(w, response)
+ writeSuccessResponseXML(w, r, response)
}
diff --git a/weed/s3api/s3api_object_handlers.go b/weed/s3api/s3api_object_handlers.go
index e5513a703..4defe28da 100644
--- a/weed/s3api/s3api_object_handlers.go
+++ b/weed/s3api/s3api_object_handlers.go
@@ -56,20 +56,20 @@ func (s3a *S3ApiServer) PutObjectHandler(w http.ResponseWriter, r *http.Request)
_, err := validateContentMd5(r.Header)
if err != nil {
- s3err.WriteErrorResponse(w, s3err.ErrInvalidDigest, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInvalidDigest)
return
}
if r.Header.Get("Cache-Control") != "" {
if _, err = cacheobject.ParseRequestCacheControl(r.Header.Get("Cache-Control")); err != nil {
- s3err.WriteErrorResponse(w, s3err.ErrInvalidDigest, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInvalidDigest)
return
}
}
if r.Header.Get("Expires") != "" {
if _, err = time.Parse(http.TimeFormat, r.Header.Get("Expires")); err != nil {
- s3err.WriteErrorResponse(w, s3err.ErrInvalidDigest, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInvalidDigest)
return
}
}
@@ -87,12 +87,12 @@ func (s3a *S3ApiServer) PutObjectHandler(w http.ResponseWriter, r *http.Request)
_, s3ErrCode = s3a.iam.reqSignatureV4Verify(r)
}
if s3ErrCode != s3err.ErrNone {
- s3err.WriteErrorResponse(w, s3ErrCode, r)
+ s3err.WriteErrorResponse(w, r, s3ErrCode)
return
}
} else {
if authTypeStreamingSigned == rAuthType {
- s3err.WriteErrorResponse(w, s3err.ErrAuthNotSetup, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrAuthNotSetup)
return
}
}
@@ -100,7 +100,7 @@ func (s3a *S3ApiServer) PutObjectHandler(w http.ResponseWriter, r *http.Request)
if strings.HasSuffix(object, "/") {
if err := s3a.mkdir(s3a.option.BucketsPath, bucket+object, nil); err != nil {
- s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
return
}
} else {
@@ -113,14 +113,14 @@ func (s3a *S3ApiServer) PutObjectHandler(w http.ResponseWriter, r *http.Request)
etag, errCode := s3a.putToFiler(r, uploadUrl, dataReader)
if errCode != s3err.ErrNone {
- s3err.WriteErrorResponse(w, errCode, r)
+ s3err.WriteErrorResponse(w, r, errCode)
return
}
setEtag(w, etag)
}
- writeSuccessResponseEmpty(w)
+ writeSuccessResponseEmpty(w, r)
}
func urlPathEscape(object string) string {
@@ -137,7 +137,7 @@ func (s3a *S3ApiServer) GetObjectHandler(w http.ResponseWriter, r *http.Request)
glog.V(3).Infof("GetObjectHandler %s %s", bucket, object)
if strings.HasSuffix(r.URL.Path, "/") {
- s3err.WriteErrorResponse(w, s3err.ErrNotImplemented, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrNotImplemented)
return
}
@@ -215,13 +215,13 @@ func (s3a *S3ApiServer) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *h
deleteXMLBytes, err := io.ReadAll(r.Body)
if err != nil {
- s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
return
}
deleteObjects := &DeleteObjectsRequest{}
if err := xml.Unmarshal(deleteXMLBytes, deleteObjects); err != nil {
- s3err.WriteErrorResponse(w, s3err.ErrMalformedXML, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrMalformedXML)
return
}
@@ -273,7 +273,7 @@ func (s3a *S3ApiServer) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *h
}
deleteResp.Errors = deleteErrors
- writeSuccessResponseXML(w, deleteResp)
+ writeSuccessResponseXML(w, r, deleteResp)
}
@@ -317,7 +317,7 @@ func (s3a *S3ApiServer) proxyToFiler(w http.ResponseWriter, r *http.Request, des
if err != nil {
glog.Errorf("NewRequest %s: %v", destUrl, err)
- s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
return
}
@@ -346,19 +346,19 @@ func (s3a *S3ApiServer) proxyToFiler(w http.ResponseWriter, r *http.Request, des
if postErr != nil {
glog.Errorf("post to filer: %v", postErr)
- s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
return
}
defer util.CloseResponse(resp)
if resp.StatusCode == http.StatusPreconditionFailed {
- s3err.WriteErrorResponse(w, s3err.ErrPreconditionFailed, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrPreconditionFailed)
return
}
if (resp.ContentLength == -1 || resp.StatusCode == 404) && resp.StatusCode != 304 {
if r.Method != "DELETE" {
- s3err.WriteErrorResponse(w, s3err.ErrNoSuchKey, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchKey)
return
}
}
diff --git a/weed/s3api/s3api_object_handlers_postpolicy.go b/weed/s3api/s3api_object_handlers_postpolicy.go
index cccbd2442..23027253e 100644
--- a/weed/s3api/s3api_object_handlers_postpolicy.go
+++ b/weed/s3api/s3api_object_handlers_postpolicy.go
@@ -29,23 +29,23 @@ func (s3a *S3ApiServer) PostPolicyBucketHandler(w http.ResponseWriter, r *http.R
reader, err := r.MultipartReader()
if err != nil {
- s3err.WriteErrorResponse(w, s3err.ErrMalformedPOSTRequest, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrMalformedPOSTRequest)
return
}
form, err := reader.ReadForm(int64(5 * humanize.MiByte))
if err != nil {
- s3err.WriteErrorResponse(w, s3err.ErrMalformedPOSTRequest, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrMalformedPOSTRequest)
return
}
defer form.RemoveAll()
fileBody, fileName, fileSize, formValues, err := extractPostPolicyFormValues(form)
if err != nil {
- s3err.WriteErrorResponse(w, s3err.ErrMalformedPOSTRequest, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrMalformedPOSTRequest)
return
}
if fileBody == nil {
- s3err.WriteErrorResponse(w, s3err.ErrPOSTFileRequired, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrPOSTFileRequired)
return
}
defer fileBody.Close()
@@ -63,7 +63,7 @@ func (s3a *S3ApiServer) PostPolicyBucketHandler(w http.ResponseWriter, r *http.R
if successRedirect != "" {
redirectURL, err = url.Parse(successRedirect)
if err != nil {
- s3err.WriteErrorResponse(w, s3err.ErrMalformedPOSTRequest, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrMalformedPOSTRequest)
return
}
}
@@ -71,13 +71,13 @@ func (s3a *S3ApiServer) PostPolicyBucketHandler(w http.ResponseWriter, r *http.R
// Verify policy signature.
errCode := s3a.iam.doesPolicySignatureMatch(formValues)
if errCode != s3err.ErrNone {
- s3err.WriteErrorResponse(w, errCode, r)
+ s3err.WriteErrorResponse(w, r, errCode)
return
}
policyBytes, err := base64.StdEncoding.DecodeString(formValues.Get("Policy"))
if err != nil {
- s3err.WriteErrorResponse(w, s3err.ErrMalformedPOSTRequest, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrMalformedPOSTRequest)
return
}
@@ -86,7 +86,7 @@ func (s3a *S3ApiServer) PostPolicyBucketHandler(w http.ResponseWriter, r *http.R
postPolicyForm, err := policy.ParsePostPolicyForm(string(policyBytes))
if err != nil {
- s3err.WriteErrorResponse(w, s3err.ErrPostPolicyConditionInvalidFormat, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrPostPolicyConditionInvalidFormat)
return
}
@@ -102,12 +102,12 @@ func (s3a *S3ApiServer) PostPolicyBucketHandler(w http.ResponseWriter, r *http.R
lengthRange := postPolicyForm.Conditions.ContentLengthRange
if lengthRange.Valid {
if fileSize < lengthRange.Min {
- s3err.WriteErrorResponse(w, s3err.ErrEntityTooSmall, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrEntityTooSmall)
return
}
if fileSize > lengthRange.Max {
- s3err.WriteErrorResponse(w, s3err.ErrEntityTooLarge, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrEntityTooLarge)
return
}
}
@@ -118,7 +118,7 @@ func (s3a *S3ApiServer) PostPolicyBucketHandler(w http.ResponseWriter, r *http.R
etag, errCode := s3a.putToFiler(r, uploadUrl, fileBody)
if errCode != s3err.ErrNone {
- s3err.WriteErrorResponse(w, errCode, r)
+ s3err.WriteErrorResponse(w, r, errCode)
return
}
@@ -126,7 +126,7 @@ func (s3a *S3ApiServer) PostPolicyBucketHandler(w http.ResponseWriter, r *http.R
// Replace raw query params..
redirectURL.RawQuery = getRedirectPostRawQuery(bucket, object, etag)
w.Header().Set("Location", redirectURL.String())
- s3err.WriteEmptyResponse(w, http.StatusSeeOther)
+ s3err.WriteEmptyResponse(w, r, http.StatusSeeOther)
return
}
@@ -141,11 +141,11 @@ func (s3a *S3ApiServer) PostPolicyBucketHandler(w http.ResponseWriter, r *http.R
ETag: `"` + etag + `"`,
Location: w.Header().Get("Location"),
}
- s3err.WriteXMLResponse(w, http.StatusCreated, resp)
+ s3err.WriteXMLResponse(w, r, http.StatusCreated, resp)
case "200":
- s3err.WriteEmptyResponse(w, http.StatusOK)
+ s3err.WriteEmptyResponse(w, r, http.StatusOK)
default:
- writeSuccessResponseEmpty(w)
+ writeSuccessResponseEmpty(w, r)
}
}
diff --git a/weed/s3api/s3api_object_multipart_handlers.go b/weed/s3api/s3api_object_multipart_handlers.go
index ea3aba64d..926e048a8 100644
--- a/weed/s3api/s3api_object_multipart_handlers.go
+++ b/weed/s3api/s3api_object_multipart_handlers.go
@@ -45,11 +45,11 @@ func (s3a *S3ApiServer) NewMultipartUploadHandler(w http.ResponseWriter, r *http
glog.V(2).Info("NewMultipartUploadHandler", string(s3err.EncodeXMLResponse(response)), errCode)
if errCode != s3err.ErrNone {
- s3err.WriteErrorResponse(w, errCode, r)
+ s3err.WriteErrorResponse(w, r, errCode)
return
}
- writeSuccessResponseXML(w, response)
+ writeSuccessResponseXML(w, r, response)
}
@@ -69,11 +69,11 @@ func (s3a *S3ApiServer) CompleteMultipartUploadHandler(w http.ResponseWriter, r
glog.V(2).Info("CompleteMultipartUploadHandler", string(s3err.EncodeXMLResponse(response)), errCode)
if errCode != s3err.ErrNone {
- s3err.WriteErrorResponse(w, errCode, r)
+ s3err.WriteErrorResponse(w, r, errCode)
return
}
- writeSuccessResponseXML(w, response)
+ writeSuccessResponseXML(w, r, response)
}
@@ -91,13 +91,13 @@ func (s3a *S3ApiServer) AbortMultipartUploadHandler(w http.ResponseWriter, r *ht
})
if errCode != s3err.ErrNone {
- s3err.WriteErrorResponse(w, errCode, r)
+ s3err.WriteErrorResponse(w, r, errCode)
return
}
glog.V(2).Info("AbortMultipartUploadHandler", string(s3err.EncodeXMLResponse(response)))
- writeSuccessResponseXML(w, response)
+ writeSuccessResponseXML(w, r, response)
}
@@ -107,13 +107,13 @@ func (s3a *S3ApiServer) ListMultipartUploadsHandler(w http.ResponseWriter, r *ht
prefix, keyMarker, uploadIDMarker, delimiter, maxUploads, encodingType := getBucketMultipartResources(r.URL.Query())
if maxUploads < 0 {
- s3err.WriteErrorResponse(w, s3err.ErrInvalidMaxUploads, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInvalidMaxUploads)
return
}
if keyMarker != "" {
// Marker not common with prefix is not implemented.
if !strings.HasPrefix(keyMarker, prefix) {
- s3err.WriteErrorResponse(w, s3err.ErrNotImplemented, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrNotImplemented)
return
}
}
@@ -131,13 +131,13 @@ func (s3a *S3ApiServer) ListMultipartUploadsHandler(w http.ResponseWriter, r *ht
glog.V(2).Infof("ListMultipartUploadsHandler %s errCode=%d", string(s3err.EncodeXMLResponse(response)), errCode)
if errCode != s3err.ErrNone {
- s3err.WriteErrorResponse(w, errCode, r)
+ s3err.WriteErrorResponse(w, r, errCode)
return
}
// TODO handle encodingType
- writeSuccessResponseXML(w, response)
+ writeSuccessResponseXML(w, r, response)
}
// ListObjectPartsHandler - Lists object parts in a multipart upload.
@@ -146,11 +146,11 @@ func (s3a *S3ApiServer) ListObjectPartsHandler(w http.ResponseWriter, r *http.Re
uploadID, partNumberMarker, maxParts, _ := getObjectResources(r.URL.Query())
if partNumberMarker < 0 {
- s3err.WriteErrorResponse(w, s3err.ErrInvalidPartNumberMarker, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInvalidPartNumberMarker)
return
}
if maxParts < 0 {
- s3err.WriteErrorResponse(w, s3err.ErrInvalidMaxParts, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInvalidMaxParts)
return
}
@@ -165,11 +165,11 @@ func (s3a *S3ApiServer) ListObjectPartsHandler(w http.ResponseWriter, r *http.Re
glog.V(2).Infof("ListObjectPartsHandler %s count=%d", string(s3err.EncodeXMLResponse(response)), len(response.Part))
if errCode != s3err.ErrNone {
- s3err.WriteErrorResponse(w, errCode, r)
+ s3err.WriteErrorResponse(w, r, errCode)
return
}
- writeSuccessResponseXML(w, response)
+ writeSuccessResponseXML(w, r, response)
}
@@ -180,18 +180,18 @@ func (s3a *S3ApiServer) PutObjectPartHandler(w http.ResponseWriter, r *http.Requ
uploadID := r.URL.Query().Get("uploadId")
exists, err := s3a.exists(s3a.genUploadsFolder(bucket), uploadID, true)
if !exists {
- s3err.WriteErrorResponse(w, s3err.ErrNoSuchUpload, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchUpload)
return
}
partIDString := r.URL.Query().Get("partNumber")
partID, err := strconv.Atoi(partIDString)
if err != nil {
- s3err.WriteErrorResponse(w, s3err.ErrInvalidPart, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInvalidPart)
return
}
if partID > globalMaxPartID {
- s3err.WriteErrorResponse(w, s3err.ErrInvalidMaxParts, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInvalidMaxParts)
return
}
@@ -208,7 +208,7 @@ func (s3a *S3ApiServer) PutObjectPartHandler(w http.ResponseWriter, r *http.Requ
_, s3ErrCode = s3a.iam.reqSignatureV4Verify(r)
}
if s3ErrCode != s3err.ErrNone {
- s3err.WriteErrorResponse(w, s3ErrCode, r)
+ s3err.WriteErrorResponse(w, r, s3ErrCode)
return
}
}
@@ -225,13 +225,13 @@ func (s3a *S3ApiServer) PutObjectPartHandler(w http.ResponseWriter, r *http.Requ
etag, errCode := s3a.putToFiler(r, uploadUrl, dataReader)
if errCode != s3err.ErrNone {
- s3err.WriteErrorResponse(w, errCode, r)
+ s3err.WriteErrorResponse(w, r, errCode)
return
}
setEtag(w, etag)
- writeSuccessResponseEmpty(w)
+ writeSuccessResponseEmpty(w, r)
}
diff --git a/weed/s3api/s3api_object_tagging_handlers.go b/weed/s3api/s3api_object_tagging_handlers.go
index 1ba1fb52d..f97f32f0b 100644
--- a/weed/s3api/s3api_object_tagging_handlers.go
+++ b/weed/s3api/s3api_object_tagging_handlers.go
@@ -26,15 +26,15 @@ func (s3a *S3ApiServer) GetObjectTaggingHandler(w http.ResponseWriter, r *http.R
if err != nil {
if err == filer_pb.ErrNotFound {
glog.Errorf("GetObjectTaggingHandler %s: %v", r.URL, err)
- s3err.WriteErrorResponse(w, s3err.ErrNoSuchKey, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchKey)
} else {
glog.Errorf("GetObjectTaggingHandler %s: %v", r.URL, err)
- s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
}
return
}
- writeSuccessResponseXML(w, FromTags(tags))
+ writeSuccessResponseXML(w, r, FromTags(tags))
}
@@ -52,29 +52,29 @@ func (s3a *S3ApiServer) PutObjectTaggingHandler(w http.ResponseWriter, r *http.R
input, err := io.ReadAll(io.LimitReader(r.Body, r.ContentLength))
if err != nil {
glog.Errorf("PutObjectTaggingHandler read input %s: %v", r.URL, err)
- s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
return
}
if err = xml.Unmarshal(input, tagging); err != nil {
glog.Errorf("PutObjectTaggingHandler Unmarshal %s: %v", r.URL, err)
- s3err.WriteErrorResponse(w, s3err.ErrMalformedXML, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrMalformedXML)
return
}
tags := tagging.ToTags()
if len(tags) > 10 {
glog.Errorf("PutObjectTaggingHandler tags %s: %d tags more than 10", r.URL, len(tags))
- s3err.WriteErrorResponse(w, s3err.ErrInvalidTag, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInvalidTag)
return
}
for k, v := range tags {
if len(k) > 128 {
glog.Errorf("PutObjectTaggingHandler tags %s: tag key %s longer than 128", r.URL, k)
- s3err.WriteErrorResponse(w, s3err.ErrInvalidTag, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInvalidTag)
return
}
if len(v) > 256 {
glog.Errorf("PutObjectTaggingHandler tags %s: tag value %s longer than 256", r.URL, v)
- s3err.WriteErrorResponse(w, s3err.ErrInvalidTag, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInvalidTag)
return
}
}
@@ -82,10 +82,10 @@ func (s3a *S3ApiServer) PutObjectTaggingHandler(w http.ResponseWriter, r *http.R
if err = s3a.setTags(dir, name, tagging.ToTags()); err != nil {
if err == filer_pb.ErrNotFound {
glog.Errorf("PutObjectTaggingHandler setTags %s: %v", r.URL, err)
- s3err.WriteErrorResponse(w, s3err.ErrNoSuchKey, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchKey)
} else {
glog.Errorf("PutObjectTaggingHandler setTags %s: %v", r.URL, err)
- s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
}
return
}
@@ -108,10 +108,10 @@ func (s3a *S3ApiServer) DeleteObjectTaggingHandler(w http.ResponseWriter, r *htt
if err != nil {
if err == filer_pb.ErrNotFound {
glog.Errorf("DeleteObjectTaggingHandler %s: %v", r.URL, err)
- s3err.WriteErrorResponse(w, s3err.ErrNoSuchKey, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchKey)
} else {
glog.Errorf("DeleteObjectTaggingHandler %s: %v", r.URL, err)
- s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
}
return
}
diff --git a/weed/s3api/s3api_objects_list_handlers.go b/weed/s3api/s3api_objects_list_handlers.go
index c1d226e32..20ab1d4d6 100644
--- a/weed/s3api/s3api_objects_list_handlers.go
+++ b/weed/s3api/s3api_objects_list_handlers.go
@@ -45,11 +45,11 @@ func (s3a *S3ApiServer) ListObjectsV2Handler(w http.ResponseWriter, r *http.Requ
originalPrefix, continuationToken, startAfter, delimiter, _, maxKeys := getListObjectsV2Args(r.URL.Query())
if maxKeys < 0 {
- s3err.WriteErrorResponse(w, s3err.ErrInvalidMaxKeys, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInvalidMaxKeys)
return
}
if delimiter != "" && delimiter != "/" {
- s3err.WriteErrorResponse(w, s3err.ErrNotImplemented, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrNotImplemented)
return
}
@@ -61,13 +61,13 @@ func (s3a *S3ApiServer) ListObjectsV2Handler(w http.ResponseWriter, r *http.Requ
response, err := s3a.listFilerEntries(bucket, originalPrefix, maxKeys, marker, delimiter)
if err != nil {
- s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
return
}
if len(response.Contents) == 0 {
if exists, existErr := s3a.exists(s3a.option.BucketsPath, bucket, true); existErr == nil && !exists {
- s3err.WriteErrorResponse(w, s3err.ErrNoSuchBucket, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchBucket)
return
}
}
@@ -87,7 +87,7 @@ func (s3a *S3ApiServer) ListObjectsV2Handler(w http.ResponseWriter, r *http.Requ
StartAfter: startAfter,
}
- writeSuccessResponseXML(w, responseV2)
+ writeSuccessResponseXML(w, r, responseV2)
}
func (s3a *S3ApiServer) ListObjectsV1Handler(w http.ResponseWriter, r *http.Request) {
@@ -101,29 +101,29 @@ func (s3a *S3ApiServer) ListObjectsV1Handler(w http.ResponseWriter, r *http.Requ
originalPrefix, marker, delimiter, maxKeys := getListObjectsV1Args(r.URL.Query())
if maxKeys < 0 {
- s3err.WriteErrorResponse(w, s3err.ErrInvalidMaxKeys, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInvalidMaxKeys)
return
}
if delimiter != "" && delimiter != "/" {
- s3err.WriteErrorResponse(w, s3err.ErrNotImplemented, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrNotImplemented)
return
}
response, err := s3a.listFilerEntries(bucket, originalPrefix, maxKeys, marker, delimiter)
if err != nil {
- s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
return
}
if len(response.Contents) == 0 {
if exists, existErr := s3a.exists(s3a.option.BucketsPath, bucket, true); existErr == nil && !exists {
- s3err.WriteErrorResponse(w, s3err.ErrNoSuchBucket, r)
+ s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchBucket)
return
}
}
- writeSuccessResponseXML(w, response)
+ writeSuccessResponseXML(w, r, response)
}
func (s3a *S3ApiServer) listFilerEntries(bucket string, originalPrefix string, maxKeys int, marker string, delimiter string) (response ListBucketResult, err error) {
@@ -220,12 +220,16 @@ func (s3a *S3ApiServer) doListFilerEntries(client filer_pb.SeaweedFilerClient, d
err = subErr
return
}
+ counter += subCounter
isTruncated = isTruncated || subIsTruncated
maxKeys -= subCounter
nextMarker = subDir + "/" + subNextMarker
// finished processing this sub directory
marker = subDir
}
+ if maxKeys <= 0 {
+ return
+ }
// now marker is also a direct child of dir
request := &filer_pb.ListEntriesRequest{
diff --git a/weed/s3api/s3api_server.go b/weed/s3api/s3api_server.go
index 1f948a9cb..6f7767d66 100644
--- a/weed/s3api/s3api_server.go
+++ b/weed/s3api/s3api_server.go
@@ -66,7 +66,7 @@ func (s3a *S3ApiServer) registerRouter(router *mux.Router) {
// HeadObject
bucket.Methods("HEAD").Path("/{object:.+}").HandlerFunc(track(s3a.iam.Auth(s3a.HeadObjectHandler, ACTION_READ), "GET"))
// HeadBucket
- bucket.Methods("HEAD").HandlerFunc(track(s3a.iam.Auth(s3a.HeadBucketHandler, ACTION_ADMIN), "GET"))
+ bucket.Methods("HEAD").HandlerFunc(track(s3a.iam.Auth(s3a.HeadBucketHandler, ACTION_READ), "GET"))
// CopyObjectPart
bucket.Methods("PUT").Path("/{object:.+}").HeadersRegexp("X-Amz-Copy-Source", `.*?(\/|%2F).*?`).HandlerFunc(track(s3a.iam.Auth(s3a.CopyObjectPartHandler, ACTION_WRITE), "PUT")).Queries("partNumber", "{partNumber:[0-9]+}", "uploadId", "{uploadId:.*}")
@@ -137,7 +137,7 @@ func (s3a *S3ApiServer) registerRouter(router *mux.Router) {
bucket.Methods("GET").HandlerFunc(track(s3a.iam.Auth(s3a.ListObjectsV1Handler, ACTION_LIST), "LIST"))
// PutBucket
- bucket.Methods("PUT").HandlerFunc(track(s3a.iam.Auth(s3a.PutBucketHandler, ACTION_ADMIN), "PUT"))
+ bucket.Methods("PUT").HandlerFunc(track(s3a.PutBucketHandler, "PUT"))
// DeleteBucket
bucket.Methods("DELETE").HandlerFunc(track(s3a.iam.Auth(s3a.DeleteBucketHandler, ACTION_WRITE), "DELETE"))
diff --git a/weed/s3api/s3api_status_handlers.go b/weed/s3api/s3api_status_handlers.go
index 914c27f40..2ee6c37b2 100644
--- a/weed/s3api/s3api_status_handlers.go
+++ b/weed/s3api/s3api_status_handlers.go
@@ -4,5 +4,5 @@ import "net/http"
func (s3a *S3ApiServer) StatusHandler(w http.ResponseWriter, r *http.Request) {
// write out the response code and content type header
- writeSuccessResponseEmpty(w)
+ writeSuccessResponseEmpty(w, r)
}
diff --git a/weed/s3api/s3err/error_handler.go b/weed/s3api/s3err/error_handler.go
index c1065fffc..3cfdaafef 100644
--- a/weed/s3api/s3err/error_handler.go
+++ b/weed/s3api/s3err/error_handler.go
@@ -19,15 +19,15 @@ const (
MimeXML mimeType = "application/xml"
)
-func WriteXMLResponse(w http.ResponseWriter, statusCode int, response interface{}) {
- WriteResponse(w, statusCode, EncodeXMLResponse(response), MimeXML)
+func WriteXMLResponse(w http.ResponseWriter, r *http.Request, statusCode int, response interface{}) {
+ WriteResponse(w, r, statusCode, EncodeXMLResponse(response), MimeXML)
}
-func WriteEmptyResponse(w http.ResponseWriter, statusCode int) {
- WriteResponse(w, statusCode, []byte{}, mimeNone)
+func WriteEmptyResponse(w http.ResponseWriter, r *http.Request, statusCode int) {
+ WriteResponse(w, r, statusCode, []byte{}, mimeNone)
}
-func WriteErrorResponse(w http.ResponseWriter, errorCode ErrorCode, r *http.Request) {
+func WriteErrorResponse(w http.ResponseWriter, r *http.Request, errorCode ErrorCode) {
vars := mux.Vars(r)
bucket := vars["bucket"]
object := vars["object"]
@@ -38,7 +38,7 @@ func WriteErrorResponse(w http.ResponseWriter, errorCode ErrorCode, r *http.Requ
apiError := GetAPIError(errorCode)
errorResponse := getRESTErrorResponse(apiError, r.URL.Path, bucket, object)
encodedErrorResponse := EncodeXMLResponse(errorResponse)
- WriteResponse(w, apiError.HTTPStatusCode, encodedErrorResponse, MimeXML)
+ WriteResponse(w, r, apiError.HTTPStatusCode, encodedErrorResponse, MimeXML)
}
func getRESTErrorResponse(err APIError, resource string, bucket, object string) RESTErrorResponse {
@@ -61,13 +61,17 @@ func EncodeXMLResponse(response interface{}) []byte {
return bytesBuffer.Bytes()
}
-func setCommonHeaders(w http.ResponseWriter) {
+func setCommonHeaders(w http.ResponseWriter, r *http.Request) {
w.Header().Set("x-amz-request-id", fmt.Sprintf("%d", time.Now().UnixNano()))
w.Header().Set("Accept-Ranges", "bytes")
+ if r.Header.Get("Origin") != "" {
+ w.Header().Set("Access-Control-Allow-Origin", "*")
+ w.Header().Set("Access-Control-Allow-Credentials", "true")
+ }
}
-func WriteResponse(w http.ResponseWriter, statusCode int, response []byte, mType mimeType) {
- setCommonHeaders(w)
+func WriteResponse(w http.ResponseWriter, r *http.Request, statusCode int, response []byte, mType mimeType) {
+ setCommonHeaders(w, r)
if response != nil {
w.Header().Set("Content-Length", strconv.Itoa(len(response)))
}
@@ -88,5 +92,5 @@ func WriteResponse(w http.ResponseWriter, statusCode int, response []byte, mType
// 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)
+ WriteErrorResponse(w, r, ErrMethodNotAllowed)
}
diff --git a/weed/s3api/stats.go b/weed/s3api/stats.go
index b667b32a0..973d8c0eb 100644
--- a/weed/s3api/stats.go
+++ b/weed/s3api/stats.go
@@ -2,7 +2,6 @@ package s3api
import (
stats_collect "github.com/chrislusf/seaweedfs/weed/stats"
- "github.com/chrislusf/seaweedfs/weed/util"
"net/http"
"strconv"
"time"
@@ -28,7 +27,7 @@ func (r *StatusRecorder) Flush() {
func track(f http.HandlerFunc, action string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Server", "SeaweedFS S3 "+util.VERSION)
+ w.Header().Set("Server", "SeaweedFS S3")
recorder := NewStatusResponseWriter(w)
start := time.Now()
f(recorder, r)