Browse Source

refactor or remove obsolete logic on filer

pull/7523/head
chrislu 2 weeks ago
parent
commit
bbdd7903f8
  1. 87
      weed/s3api/s3_metadata_util.go
  2. 4
      weed/s3api/s3api_object_handlers_multipart.go
  3. 38
      weed/server/filer_server_handlers_read.go
  4. 81
      weed/server/filer_server_handlers_write_autochunk.go

87
weed/s3api/s3_metadata_util.go

@ -0,0 +1,87 @@
package s3api
import (
"net/http"
"net/url"
"strings"
"github.com/seaweedfs/seaweedfs/weed/glog"
"github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
)
// ParseS3Metadata extracts S3-specific metadata from HTTP request headers
// This includes: storage class, tags, user metadata, SSE headers, and ACL headers
// Used by S3 API handlers to prepare metadata before saving to filer
func ParseS3Metadata(r *http.Request, existing map[string][]byte, isReplace bool) (metadata map[string][]byte) {
metadata = make(map[string][]byte)
// Copy existing metadata unless replacing
if !isReplace {
for k, v := range existing {
metadata[k] = v
}
}
// Storage class
if sc := r.Header.Get(s3_constants.AmzStorageClass); sc != "" {
metadata[s3_constants.AmzStorageClass] = []byte(sc)
}
// Content-Encoding (standard HTTP header used by S3)
if ce := r.Header.Get("Content-Encoding"); ce != "" {
metadata["Content-Encoding"] = []byte(ce)
}
// Object tagging
if tags := r.Header.Get(s3_constants.AmzObjectTagging); tags != "" {
// Use url.ParseQuery for robust parsing and automatic URL decoding
parsedTags, err := url.ParseQuery(tags)
if err != nil {
glog.Errorf("Failed to parse S3 tags '%s': %v", tags, err)
} else {
for key, values := range parsedTags {
// According to S3 spec, if a key is provided multiple times, the last value is used.
// A tag value can be an empty string but not nil.
value := ""
if len(values) > 0 {
value = values[len(values)-1]
}
metadata[s3_constants.AmzObjectTagging+"-"+key] = []byte(value)
}
}
}
// User-defined metadata (x-amz-meta-* headers)
for header, values := range r.Header {
if strings.HasPrefix(header, s3_constants.AmzUserMetaPrefix) {
// Go's HTTP server canonicalizes headers (e.g., x-amz-meta-foo → X-Amz-Meta-Foo)
// We store them as they come in (after canonicalization) to preserve the user's intent
for _, value := range values {
metadata[header] = []byte(value)
}
}
}
// SSE-C headers
if algorithm := r.Header.Get(s3_constants.AmzServerSideEncryptionCustomerAlgorithm); algorithm != "" {
metadata[s3_constants.AmzServerSideEncryptionCustomerAlgorithm] = []byte(algorithm)
}
if keyMD5 := r.Header.Get(s3_constants.AmzServerSideEncryptionCustomerKeyMD5); keyMD5 != "" {
// Store as-is; SSE-C MD5 is base64 and case-sensitive
metadata[s3_constants.AmzServerSideEncryptionCustomerKeyMD5] = []byte(keyMD5)
}
// ACL owner
acpOwner := r.Header.Get(s3_constants.ExtAmzOwnerKey)
if len(acpOwner) > 0 {
metadata[s3_constants.ExtAmzOwnerKey] = []byte(acpOwner)
}
// ACL grants
acpGrants := r.Header.Get(s3_constants.ExtAmzAclKey)
if len(acpGrants) > 0 {
metadata[s3_constants.ExtAmzAclKey] = []byte(acpGrants)
}
return metadata
}

4
weed/s3api/s3api_object_handlers_multipart.go

@ -20,7 +20,6 @@ import (
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
"github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
"github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
weed_server "github.com/seaweedfs/seaweedfs/weed/server"
stats_collect "github.com/seaweedfs/seaweedfs/weed/stats"
)
@ -65,7 +64,8 @@ func (s3a *S3ApiServer) NewMultipartUploadHandler(w http.ResponseWriter, r *http
Metadata: make(map[string]*string),
}
metadata := weed_server.SaveAmzMetaData(r, nil, false)
// Parse S3 metadata from request headers
metadata := ParseS3Metadata(r, nil, false)
for k, v := range metadata {
createMultipartUploadInput.Metadata[k] = aws.String(string(v))
}

38
weed/server/filer_server_handlers_read.go

@ -13,12 +13,10 @@ import (
"strings"
"time"
"github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
"github.com/seaweedfs/seaweedfs/weed/security"
"github.com/seaweedfs/seaweedfs/weed/filer"
"github.com/seaweedfs/seaweedfs/weed/glog"
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
"github.com/seaweedfs/seaweedfs/weed/security"
"github.com/seaweedfs/seaweedfs/weed/stats"
"github.com/seaweedfs/seaweedfs/weed/util"
)
@ -120,22 +118,12 @@ func (fs *FilerServer) GetOrHeadHandler(w http.ResponseWriter, r *http.Request)
writeJsonQuiet(w, r, http.StatusOK, entry)
return
}
// For S3-created directories (FolderMimeType), return the directory object metadata itself
// rather than listing contents. Regular filer directories show listings.
if entry.Attr.Mime == "" {
// Regular filer directory - show listing if enabled
if !fs.option.ExposeDirectoryData {
writeJsonError(w, r, http.StatusForbidden, errors.New("directory listing is disabled"))
return
}
fs.listDirectoryHandler(w, r)
// Regular directory - show listing if enabled
if !fs.option.ExposeDirectoryData {
writeJsonError(w, r, http.StatusForbidden, errors.New("directory listing is disabled"))
return
}
// S3-created directory object (FolderMimeType) - fall through to serve metadata
}
if isForDirectory && entry.Attr.Mime != s3_constants.FolderMimeType {
w.WriteHeader(http.StatusNotFound)
fs.listDirectoryHandler(w, r)
return
}
@ -176,10 +164,9 @@ func (fs *FilerServer) GetOrHeadHandler(w http.ResponseWriter, r *http.Request)
}
// print out the header from extended properties
// Filter out xattr-* (filesystem extended attributes) and internal Seaweedfs-* headers
for k, v := range entry.Extended {
if !strings.HasPrefix(k, "xattr-") && !s3_constants.IsSeaweedFSInternalHeader(k) {
// "xattr-" prefix is set in filesys.XATTR_PREFIX
// IsSeaweedFSInternalHeader filters internal metadata that should not become HTTP headers
if !strings.HasPrefix(k, "xattr-") && !strings.HasPrefix(strings.ToLower(k), "x-seaweedfs-") {
w.Header().Set(k, string(v))
}
}
@ -194,17 +181,6 @@ func (fs *FilerServer) GetOrHeadHandler(w http.ResponseWriter, r *http.Request)
seaweedHeaders = append(seaweedHeaders, "Content-Disposition")
w.Header().Set("Access-Control-Expose-Headers", strings.Join(seaweedHeaders, ","))
//set tag count
tagCount := 0
for k := range entry.Extended {
if strings.HasPrefix(k, s3_constants.AmzObjectTagging+"-") {
tagCount++
}
}
if tagCount > 0 {
w.Header().Set(s3_constants.AmzTagCount, strconv.Itoa(tagCount))
}
SetEtag(w, etag)
filename := entry.Name()

81
weed/server/filer_server_handlers_write_autochunk.go

@ -7,7 +7,6 @@ import (
"fmt"
"io"
"net/http"
"net/url"
"os"
"path"
"strconv"
@ -18,7 +17,6 @@ import (
"github.com/seaweedfs/seaweedfs/weed/glog"
"github.com/seaweedfs/seaweedfs/weed/operation"
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
"github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
"github.com/seaweedfs/seaweedfs/weed/storage/needle"
"github.com/seaweedfs/seaweedfs/weed/util"
"github.com/seaweedfs/seaweedfs/weed/util/constants"
@ -326,16 +324,13 @@ func (fs *FilerServer) saveMetaData(ctx context.Context, r *http.Request, fileNa
Size: int64(entry.FileSize),
}
entry.Extended = SaveAmzMetaData(r, entry.Extended, false)
// Note: S3 API now sets SeaweedFSExpiresS3 directly in metadata via gRPC, not HTTP headers
// Save standard HTTP headers as extended attributes
// Note: S3 API now writes directly to volume servers and saves metadata via gRPC
// This handler is for non-S3 clients (WebDAV, SFTP, mount, curl, etc.)
for k, v := range r.Header {
if len(v) > 0 && len(v[0]) > 0 {
if strings.HasPrefix(k, needle.PairNamePrefix) || k == "Cache-Control" || k == "Expires" || k == "Content-Disposition" {
entry.Extended[k] = []byte(v[0])
// Log version ID header specifically for debugging
if k == "Seaweed-X-Amz-Version-Id" {
glog.V(0).Infof("filer: storing version ID header in Extended: %s=%s for path=%s", k, v[0], path)
}
}
if k == "Response-Content-Disposition" {
entry.Extended["Content-Disposition"] = []byte(v[0])
@ -447,73 +442,3 @@ func (fs *FilerServer) mkdir(ctx context.Context, w http.ResponseWriter, r *http
}
return filerResult, replyerr
}
func SaveAmzMetaData(r *http.Request, existing map[string][]byte, isReplace bool) (metadata map[string][]byte) {
metadata = make(map[string][]byte)
if !isReplace {
for k, v := range existing {
metadata[k] = v
}
}
if sc := r.Header.Get(s3_constants.AmzStorageClass); sc != "" {
metadata[s3_constants.AmzStorageClass] = []byte(sc)
}
if ce := r.Header.Get("Content-Encoding"); ce != "" {
metadata["Content-Encoding"] = []byte(ce)
}
if tags := r.Header.Get(s3_constants.AmzObjectTagging); tags != "" {
// Use url.ParseQuery for robust parsing and automatic URL decoding
parsedTags, err := url.ParseQuery(tags)
if err != nil {
glog.Errorf("Failed to parse S3 tags '%s': %v", tags, err)
} else {
for key, values := range parsedTags {
// According to S3 spec, if a key is provided multiple times, the last value is used.
// A tag value can be an empty string but not nil.
value := ""
if len(values) > 0 {
value = values[len(values)-1]
}
metadata[s3_constants.AmzObjectTagging+"-"+key] = []byte(value)
}
}
}
for header, values := range r.Header {
if strings.HasPrefix(header, s3_constants.AmzUserMetaPrefix) {
// Go's HTTP server canonicalizes headers (e.g., x-amz-meta-foo → X-Amz-Meta-Foo)
// We store them as they come in (after canonicalization) to preserve the user's intent
for _, value := range values {
metadata[header] = []byte(value)
}
}
}
// Handle SSE-C headers
if algorithm := r.Header.Get(s3_constants.AmzServerSideEncryptionCustomerAlgorithm); algorithm != "" {
metadata[s3_constants.AmzServerSideEncryptionCustomerAlgorithm] = []byte(algorithm)
}
if keyMD5 := r.Header.Get(s3_constants.AmzServerSideEncryptionCustomerKeyMD5); keyMD5 != "" {
// Store as-is; SSE-C MD5 is base64 and case-sensitive
metadata[s3_constants.AmzServerSideEncryptionCustomerKeyMD5] = []byte(keyMD5)
}
//acp-owner
acpOwner := r.Header.Get(s3_constants.ExtAmzOwnerKey)
if len(acpOwner) > 0 {
metadata[s3_constants.ExtAmzOwnerKey] = []byte(acpOwner)
}
//acp-grants
acpGrants := r.Header.Get(s3_constants.ExtAmzAclKey)
if len(acpGrants) > 0 {
metadata[s3_constants.ExtAmzAclKey] = []byte(acpGrants)
}
return
}
Loading…
Cancel
Save