Browse Source

header case

pull/7481/head
chrislu 1 month ago
parent
commit
6b9f39789d
  1. 8
      weed/s3api/s3api_object_handlers.go
  2. 19
      weed/s3api/s3api_object_handlers_copy.go
  3. 8
      weed/s3api/s3api_object_handlers_put.go
  4. 8
      weed/server/filer_server_handlers_write_autochunk.go

8
weed/s3api/s3api_object_handlers.go

@ -1280,12 +1280,12 @@ func (s3a *S3ApiServer) setResponseHeaders(w http.ResponseWriter, entry *filer_p
for k, v := range entry.Extended { for k, v := range entry.Extended {
// Skip internal SeaweedFS headers // Skip internal SeaweedFS headers
if !strings.HasPrefix(k, "xattr-") && !s3_constants.IsSeaweedFSInternalHeader(k) { if !strings.HasPrefix(k, "xattr-") && !s3_constants.IsSeaweedFSInternalHeader(k) {
// Support backward compatibility: migrate old lowercase format to canonical format
// OLD: "x-amz-meta-foo" → NEW: "X-Amz-Meta-foo"
// Support backward compatibility: migrate old non-canonical format to canonical format
// OLD: "x-amz-meta-foo" → NEW: "X-Amz-Meta-foo" (preserving suffix case)
headerKey := k headerKey := k
if strings.HasPrefix(strings.ToLower(k), "x-amz-meta-") && !strings.HasPrefix(k, s3_constants.AmzUserMetaPrefix) { if strings.HasPrefix(strings.ToLower(k), "x-amz-meta-") && !strings.HasPrefix(k, s3_constants.AmzUserMetaPrefix) {
// Old format detected - normalize to canonical prefix
suffix := strings.ToLower(k[len("x-amz-meta-"):])
// Old format detected - normalize to canonical prefix, preserve suffix case
suffix := k[len("x-amz-meta-"):]
headerKey = s3_constants.AmzUserMetaPrefix + suffix headerKey = s3_constants.AmzUserMetaPrefix + suffix
glog.V(4).Infof("Migrating old user metadata header %q to %q in response", k, headerKey) glog.V(4).Infof("Migrating old user metadata header %q to %q in response", k, headerKey)
} }

19
weed/s3api/s3api_object_handlers_copy.go

@ -700,29 +700,22 @@ func processMetadataBytes(reqHeader http.Header, existing map[string][]byte, rep
if replaceMeta { if replaceMeta {
for header, values := range reqHeader { for header, values := range reqHeader {
if strings.HasPrefix(header, s3_constants.AmzUserMetaPrefix) { if strings.HasPrefix(header, s3_constants.AmzUserMetaPrefix) {
// AWS S3 stores user metadata keys in lowercase
// Go's HTTP server canonicalizes headers (e.g., x-amz-meta-foo → X-Amz-Meta-Foo) // Go's HTTP server canonicalizes headers (e.g., x-amz-meta-foo → X-Amz-Meta-Foo)
// Preserve the canonical prefix "X-Amz-Meta-" but lowercase the user-defined suffix
suffix := strings.ToLower(header[len(s3_constants.AmzUserMetaPrefix):])
normalizedKey := s3_constants.AmzUserMetaPrefix + suffix
// We store them as they come in (after canonicalization) to preserve the user's intent
for _, value := range values { for _, value := range values {
metadata[normalizedKey] = []byte(value)
metadata[header] = []byte(value)
} }
} }
} }
} else { } else {
// Copy existing metadata as-is (already normalized during storage)
// Support both old format (x-amz-meta-*) and new format (X-Amz-Meta-*) for backward compatibility
// Copy existing metadata as-is
for k, v := range existing { for k, v := range existing {
if strings.HasPrefix(k, s3_constants.AmzUserMetaPrefix) { if strings.HasPrefix(k, s3_constants.AmzUserMetaPrefix) {
// New format (X-Amz-Meta-foo) - copy as-is
metadata[k] = v metadata[k] = v
} else if strings.HasPrefix(strings.ToLower(k), "x-amz-meta-") { } else if strings.HasPrefix(strings.ToLower(k), "x-amz-meta-") {
// Old format (x-amz-meta-foo) - migrate to new format
suffix := strings.ToLower(k[len("x-amz-meta-"):])
normalizedKey := s3_constants.AmzUserMetaPrefix + suffix
metadata[normalizedKey] = v
glog.V(4).Infof("Migrating old user metadata key %q to %q", k, normalizedKey)
// Backward compatibility: old format (x-amz-meta-foo)
// Preserve the original key from storage for backward compatibility
metadata[k] = v
} }
} }
} }

8
weed/s3api/s3api_object_handlers_put.go

@ -447,13 +447,9 @@ func (s3a *S3ApiServer) putToFiler(r *http.Request, uploadUrl string, dataReader
for k, v := range r.Header { for k, v := range r.Header {
if len(v) > 0 && len(v[0]) > 0 { if len(v) > 0 && len(v[0]) > 0 {
if strings.HasPrefix(k, s3_constants.AmzUserMetaPrefix) { if strings.HasPrefix(k, s3_constants.AmzUserMetaPrefix) {
// AWS S3 stores user metadata keys in lowercase
// Go's HTTP server canonicalizes headers (e.g., x-amz-meta-foo → X-Amz-Meta-Foo) // Go's HTTP server canonicalizes headers (e.g., x-amz-meta-foo → X-Amz-Meta-Foo)
// Preserve the canonical prefix "X-Amz-Meta-" but lowercase the user-defined suffix
// This ensures the key is still detectable via prefix checks elsewhere
suffix := strings.ToLower(k[len(s3_constants.AmzUserMetaPrefix):])
normalizedKey := s3_constants.AmzUserMetaPrefix + suffix
entry.Extended[normalizedKey] = []byte(v[0])
// We store them as they come in (after canonicalization) to preserve the user's intent
entry.Extended[k] = []byte(v[0])
} else if k == "Cache-Control" || k == "Expires" || k == "Content-Disposition" { } else if k == "Cache-Control" || k == "Expires" || k == "Content-Disposition" {
entry.Extended[k] = []byte(v[0]) entry.Extended[k] = []byte(v[0])
} }

8
weed/server/filer_server_handlers_write_autochunk.go

@ -544,14 +544,10 @@ func SaveAmzMetaData(r *http.Request, existing map[string][]byte, isReplace bool
for header, values := range r.Header { for header, values := range r.Header {
if strings.HasPrefix(header, s3_constants.AmzUserMetaPrefix) { if strings.HasPrefix(header, s3_constants.AmzUserMetaPrefix) {
// AWS S3 stores user metadata keys in lowercase
// Go's HTTP server canonicalizes headers (e.g., x-amz-meta-foo → X-Amz-Meta-Foo) // Go's HTTP server canonicalizes headers (e.g., x-amz-meta-foo → X-Amz-Meta-Foo)
// Preserve the canonical prefix "X-Amz-Meta-" but lowercase the user-defined suffix
// This ensures the key is still detectable via prefix checks elsewhere
suffix := strings.ToLower(header[len(s3_constants.AmzUserMetaPrefix):])
normalizedKey := s3_constants.AmzUserMetaPrefix + suffix
// We store them as they come in (after canonicalization) to preserve the user's intent
for _, value := range values { for _, value := range values {
metadata[normalizedKey] = []byte(value)
metadata[header] = []byte(value)
} }
} }
} }

Loading…
Cancel
Save