From a5e60706a2a5eeb8188fd9614787083018cc102c Mon Sep 17 00:00:00 2001 From: Anis Elleuch Date: Tue, 14 Mar 2017 06:20:46 +0100 Subject: [PATCH] xl,fs: Return 404 if object ends with a separator (#3897) HEAD Object for FS and XL was returning invalid object name when an object name has a trailing slash separator, this PR changes the behavior and will always return 404 object not found, this guarantees a better compatibility with S3 spec. --- cmd/fs-v1.go | 6 ++++ cmd/object_api_suite_test.go | 58 +++++++++++++----------------------- cmd/xl-v1-object.go | 6 ++++ 3 files changed, 33 insertions(+), 37 deletions(-) diff --git a/cmd/fs-v1.go b/cmd/fs-v1.go index f651a6d52..fc1cd2d1b 100644 --- a/cmd/fs-v1.go +++ b/cmd/fs-v1.go @@ -470,6 +470,12 @@ func (fs fsObjects) getObjectInfo(bucket, object string) (ObjectInfo, error) { // GetObjectInfo - reads object metadata and replies back ObjectInfo. func (fs fsObjects) GetObjectInfo(bucket, object string) (ObjectInfo, error) { + // This is a special case with object whose name ends with + // a slash separator, we always return object not found here. + if hasSuffix(object, slashSeparator) { + return ObjectInfo{}, toObjectErr(traceError(errFileNotFound), bucket, object) + } + if err := checkGetObjArgs(bucket, object); err != nil { return ObjectInfo{}, err } diff --git a/cmd/object_api_suite_test.go b/cmd/object_api_suite_test.go index e382af73a..73af5b23d 100644 --- a/cmd/object_api_suite_test.go +++ b/cmd/object_api_suite_test.go @@ -735,12 +735,13 @@ func (s *ObjectLayerAPISuite) TestGetDirectoryReturnsObjectNotFound(c *C) { // Tests validate that GetObject on an existing directory fails as expected. func testGetDirectoryReturnsObjectNotFound(obj ObjectLayer, instanceType string, c TestErrHandler) { - err := obj.MakeBucket("bucket") + bucketName := "bucket" + err := obj.MakeBucket(bucketName) if err != nil { c.Fatalf("%s: %s", instanceType, err) } - _, err = obj.PutObject("bucket", "dir1/dir3/object", + _, err = obj.PutObject(bucketName, "dir1/dir3/object", int64(len("The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed.")), bytes.NewBufferString("One or more of the specified parts could not be found. The part might not have been uploaded, or the specified entity tag might not have matched the part's entity tag."), nil, "") @@ -748,41 +749,24 @@ func testGetDirectoryReturnsObjectNotFound(obj ObjectLayer, instanceType string, c.Fatalf("%s: %s", instanceType, err) } - _, err = obj.GetObjectInfo("bucket", "dir1") - if isErrObjectNotFound(err) { - err = errorCause(err) - err1 := err.(ObjectNotFound) - if err1.Bucket != "bucket" { - c.Errorf("%s: Expected the bucket name in the error message to be `%s`, but instead found `%s`", - instanceType, "bucket", err1.Bucket) - } - if err1.Object != "dir1" { - c.Errorf("%s: Expected the object name in the error message to be `%s`, but instead found `%s`", - instanceType, "dir1", err1.Object) - } - } else { - if err.Error() != "ObjectNotFound" { - c.Errorf("%s: Expected the error message to be `%s`, but instead found `%s`", instanceType, - "ObjectNotFound", err.Error()) - } - } - - _, err = obj.GetObjectInfo("bucket", "dir1/") - if isErrObjectNameInvalid(err) { - err = errorCause(err) - err1 := err.(ObjectNameInvalid) - if err1.Bucket != "bucket" { - c.Errorf("%s: Expected the bucket name in the error message to be `%s`, but instead found `%s`", - instanceType, "bucket", err1.Bucket) - } - if err1.Object != "dir1/" { - c.Errorf("%s: Expected the object name in the error message to be `%s`, but instead found `%s`", - instanceType, "dir1/", err1.Object) - } - } else { - // force a failure with a line number. - if err.Error() != "ObjectNotFound" { - c.Errorf("%s: Expected the error message to be `%s`, but instead found `%s`", instanceType, "ObjectNotFound", err.Error()) + for i, objName := range []string{"dir1", "dir1/", "dir1/dir3", "dir1/dir3/"} { + _, err = obj.GetObjectInfo(bucketName, objName) + if isErrObjectNotFound(err) { + err = errorCause(err) + err1 := err.(ObjectNotFound) + if err1.Bucket != bucketName { + c.Errorf("Test %d, %s: Expected the bucket name in the error message to be `%s`, but instead found `%s`", + i+1, instanceType, bucketName, err1.Bucket) + } + if err1.Object != objName { + c.Errorf("Test %d, %s: Expected the object name in the error message to be `%s`, but instead found `%s`", + i+1, instanceType, objName, err1.Object) + } + } else { + if err.Error() != "ObjectNotFound" { + c.Errorf("Test %d, %s: Expected the error message to be `%s`, but instead found `%s`", i+1, instanceType, + "ObjectNotFound", err.Error()) + } } } } diff --git a/cmd/xl-v1-object.go b/cmd/xl-v1-object.go index 0c85d3980..f7ecf76c9 100644 --- a/cmd/xl-v1-object.go +++ b/cmd/xl-v1-object.go @@ -321,6 +321,12 @@ func (xl xlObjects) GetObject(bucket, object string, startOffset int64, length i // GetObjectInfo - reads object metadata and replies back ObjectInfo. func (xl xlObjects) GetObjectInfo(bucket, object string) (ObjectInfo, error) { + // This is a special case with object whose name ends with + // a slash separator, we always return object not found here. + if hasSuffix(object, slashSeparator) { + return ObjectInfo{}, toObjectErr(traceError(errFileNotFound), bucket, object) + } + if err := checkGetObjArgs(bucket, object); err != nil { return ObjectInfo{}, err }