diff options
| author | hilimd <68371223+hilimd@users.noreply.github.com> | 2021-11-11 16:00:21 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-11-11 16:00:21 +0800 |
| commit | 34240606f78395345ca7f6d7fe66a223c9bdf072 (patch) | |
| tree | 914f76c6587989a39fe1c0f421782126248fbe8e /weed/s3api | |
| parent | b5389c3b23502da7315dd258715e146be7cc0fc9 (diff) | |
| parent | 835e2d2ddf959dc8dd234021ac3cde72bd9e9246 (diff) | |
| download | seaweedfs-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.go | 20 | ||||
| -rw-r--r-- | weed/s3api/s3api_bucket_handlers.go | 47 | ||||
| -rw-r--r-- | weed/s3api/s3api_handlers.go | 8 | ||||
| -rw-r--r-- | weed/s3api/s3api_object_copy_handlers.go | 30 | ||||
| -rw-r--r-- | weed/s3api/s3api_object_handlers.go | 32 | ||||
| -rw-r--r-- | weed/s3api/s3api_object_handlers_postpolicy.go | 30 | ||||
| -rw-r--r-- | weed/s3api/s3api_object_multipart_handlers.go | 40 | ||||
| -rw-r--r-- | weed/s3api/s3api_object_tagging_handlers.go | 24 | ||||
| -rw-r--r-- | weed/s3api/s3api_objects_list_handlers.go | 24 | ||||
| -rw-r--r-- | weed/s3api/s3api_server.go | 4 | ||||
| -rw-r--r-- | weed/s3api/s3api_status_handlers.go | 2 | ||||
| -rw-r--r-- | weed/s3api/s3err/error_handler.go | 24 | ||||
| -rw-r--r-- | weed/s3api/stats.go | 3 |
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) |
