diff options
Diffstat (limited to 'weed/s3api/s3api_object_handlers.go')
| -rw-r--r-- | weed/s3api/s3api_object_handlers.go | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/weed/s3api/s3api_object_handlers.go b/weed/s3api/s3api_object_handlers.go index 6b811a024..0aa96b21a 100644 --- a/weed/s3api/s3api_object_handlers.go +++ b/weed/s3api/s3api_object_handlers.go @@ -6,6 +6,7 @@ import ( "io" "net/http" "net/url" + "strconv" "strings" "time" @@ -195,6 +196,9 @@ func (s3a *S3ApiServer) GetObjectHandler(w http.ResponseWriter, r *http.Request) // Set version ID in response header w.Header().Set("x-amz-version-id", targetVersionId) + + // Add object lock metadata to response headers if present + s3a.addObjectLockHeadersToResponse(w, entry) } else { // Handle regular GET (non-versioned) destUrl = s3a.toFilerUrl(bucket, object) @@ -271,6 +275,9 @@ func (s3a *S3ApiServer) HeadObjectHandler(w http.ResponseWriter, r *http.Request // Set version ID in response header w.Header().Set("x-amz-version-id", targetVersionId) + + // Add object lock metadata to response headers if present + s3a.addObjectLockHeadersToResponse(w, entry) } else { // Handle regular HEAD (non-versioned) destUrl = s3a.toFilerUrl(bucket, object) @@ -435,3 +442,44 @@ func passThroughResponse(proxyResponse *http.Response, w http.ResponseWriter) (s } return statusCode, bytesTransferred } + +// addObjectLockHeadersToResponse extracts object lock metadata from entry Extended attributes +// and adds the appropriate S3 headers to the response +func (s3a *S3ApiServer) addObjectLockHeadersToResponse(w http.ResponseWriter, entry *filer_pb.Entry) { + if entry == nil || entry.Extended == nil { + return + } + + // Check if this entry has any object lock metadata (indicating it's from an object lock enabled bucket) + hasObjectLockMode := false + hasRetentionDate := false + + // Add object lock mode header if present + if modeBytes, exists := entry.Extended[s3_constants.ExtObjectLockModeKey]; exists && len(modeBytes) > 0 { + w.Header().Set(s3_constants.AmzObjectLockMode, string(modeBytes)) + hasObjectLockMode = true + } + + // Add retention until date header if present + if dateBytes, exists := entry.Extended[s3_constants.ExtRetentionUntilDateKey]; exists && len(dateBytes) > 0 { + dateStr := string(dateBytes) + // Convert Unix timestamp to ISO8601 format for S3 compatibility + if timestamp, err := strconv.ParseInt(dateStr, 10, 64); err == nil { + retainUntilDate := time.Unix(timestamp, 0).UTC() + w.Header().Set(s3_constants.AmzObjectLockRetainUntilDate, retainUntilDate.Format(time.RFC3339)) + hasRetentionDate = true + } else { + glog.Errorf("addObjectLockHeadersToResponse: failed to parse retention until date from stored metadata (dateStr: %s): %v", dateStr, err) + } + } + + // Add legal hold header - AWS S3 behavior: always include legal hold for object lock enabled buckets + if legalHoldBytes, exists := entry.Extended[s3_constants.ExtLegalHoldKey]; exists && len(legalHoldBytes) > 0 { + // Return stored S3 standard "ON"/"OFF" values directly + w.Header().Set(s3_constants.AmzObjectLockLegalHold, string(legalHoldBytes)) + } else if hasObjectLockMode || hasRetentionDate { + // If this entry has object lock metadata (indicating object lock enabled bucket) + // but no legal hold specifically set, default to "OFF" as per AWS S3 behavior + w.Header().Set(s3_constants.AmzObjectLockLegalHold, s3_constants.LegalHoldOff) + } +} |
