mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-21 21:44:22 +02:00
s3: answer a conditional write on a missing object with 404, not 412 (#11882)
This commit is contained in:
1 parent
379abbe278
commit
c90da999f2
2 files changed
+60
-1
No files matched your search
@@ -0,0 +1,58 @@
|
||||
package s3api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
|
||||
)
|
||||
|
||||
// A conditional write with If-Match has nothing to compare against when the key has
|
||||
// no current version; AWS answers 404 there, not 412.
|
||||
func TestValidateConditionalHeadersMissingObject(t *testing.T) {
|
||||
s3a := &S3ApiServer{}
|
||||
|
||||
existing := &filer_pb.Entry{
|
||||
Attributes: &filer_pb.FuseAttributes{Mtime: time.Now().Unix()},
|
||||
Extended: map[string][]byte{s3_constants.ExtETagKey: []byte("d41d8cd98f00b204e9800998ecf8427e")},
|
||||
}
|
||||
deleteMarker := &filer_pb.Entry{
|
||||
Attributes: &filer_pb.FuseAttributes{Mtime: time.Now().Unix()},
|
||||
Extended: map[string][]byte{s3_constants.ExtDeleteMarkerKey: []byte("true")},
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
header string
|
||||
value string
|
||||
entry *filer_pb.Entry
|
||||
want s3err.ErrorCode
|
||||
}{
|
||||
{"if-match on missing object", s3_constants.IfMatch, "d41d8cd98f00b204e9800998ecf8427e", nil, s3err.ErrNoSuchKey},
|
||||
{"if-match star on missing object", s3_constants.IfMatch, "*", nil, s3err.ErrNoSuchKey},
|
||||
{"if-match on delete marker", s3_constants.IfMatch, "d41d8cd98f00b204e9800998ecf8427e", deleteMarker, s3err.ErrNoSuchKey},
|
||||
{"if-match mismatch on existing object", s3_constants.IfMatch, "0000", existing, s3err.ErrPreconditionFailed},
|
||||
{"if-match hit on existing object", s3_constants.IfMatch, "d41d8cd98f00b204e9800998ecf8427e", existing, s3err.ErrNone},
|
||||
{"if-none-match star on missing object", s3_constants.IfNoneMatch, "*", nil, s3err.ErrNone},
|
||||
{"if-none-match star on delete marker", s3_constants.IfNoneMatch, "*", deleteMarker, s3err.ErrNone},
|
||||
{"if-none-match star on existing object", s3_constants.IfNoneMatch, "*", existing, s3err.ErrPreconditionFailed},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
r := httptest.NewRequest(http.MethodPut, "/bucket/object", nil)
|
||||
r.Header.Set(tc.header, tc.value)
|
||||
headers, errCode := parseConditionalHeaders(r)
|
||||
if errCode != s3err.ErrNone {
|
||||
t.Fatalf("parseConditionalHeaders: %v", errCode)
|
||||
}
|
||||
if got := s3a.validateConditionalHeaders(r, headers, tc.entry, "bucket", "object"); got != tc.want {
|
||||
t.Errorf("got %v, want %v", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -2796,8 +2796,9 @@ func (s3a *S3ApiServer) validateConditionalHeaders(r *http.Request, headers cond
|
||||
|
||||
// 1. Check If-Match
|
||||
if headers.ifMatch != "" {
|
||||
// AWS answers 404 when there is no current version (or it is a delete marker)
|
||||
if !objectExists {
|
||||
return s3err.ErrPreconditionFailed
|
||||
return s3err.ErrNoSuchKey
|
||||
}
|
||||
// If `ifMatch` is "*", the condition is met if the object exists.
|
||||
// Otherwise, we need to check the ETag.
|
||||
|
||||
Reference in new issue
Block a user