Skip to content

Commit

Permalink
Support metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidZbarsky-at committed Sep 19, 2024
1 parent 054aa72 commit 5adc982
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 3 deletions.
26 changes: 23 additions & 3 deletions services/s3/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ func NewHandler(logger *slog.Logger, s3 *S3) func(w http.ResponseWriter, r *http
ServerSideEncryption: r.Form.Get("x-amz-server-side-encryption"),
ContentType: r.Form.Get("Content-Type"),
Data: f,
Metadata: extractMetadata(r.Header),
}
logger.Debug("Parsed input", "method", "PutObject", "input", input)
output, awserr := s3.PutObject(input)
Expand Down Expand Up @@ -128,7 +129,11 @@ func NewHandler(logger *slog.Logger, s3 *S3) func(w http.ResponseWriter, r *http
if r.Header.Get("x-amz-copy-source") != "" {
handle(w, r, logger.With("method", "CopyObject"), s3.CopyObject)
} else {
handle(w, r, logger.With("method", "PutObject"), s3.PutObject)
handle(w, r, logger.With("method", "PutObject"),
func(input PutObjectInput) (*PutObjectOutput, *awserrors.Error) {
input.Metadata = extractMetadata(r.Header)
return s3.PutObject(input)
})
}
case http.MethodDelete:
handle(w, r, logger.With("method", "DeleteObject"), s3.DeleteObject)
Expand All @@ -140,6 +145,16 @@ func NewHandler(logger *slog.Logger, s3 *S3) func(w http.ResponseWriter, r *http
}
}

func extractMetadata(header http.Header) map[string]string {
metadata := make(map[string]string)
for k := range header {
if strings.HasPrefix(strings.ToLower(k), "x-amz-meta-") {
metadata[k] = header.Get(k)
}
}
return metadata
}

func handle[Input any, Output any](
w http.ResponseWriter,
r *http.Request,
Expand Down Expand Up @@ -238,13 +253,18 @@ func marshal(w http.ResponseWriter, output any, awserr *awserrors.Error) {
v := reflect.ValueOf(output).Elem()
ty := v.Type()
for i := 0; i < ty.NumField(); i++ {
tag := ty.Field(i).Tag.Get("s3")
field := ty.Field(i)
tag := field.Tag.Get("s3")
if tag == "body" {
reflect.ValueOf(&body).Elem().Set(v.Field(i))
} else if tag == "http-status" {
httpStatus = int(v.Field(i).Int())
} else if tag == "metadata-headers" {
for _, mapKey := range v.Field(i).MapKeys() {
mapValue := v.Field(i).MapIndex(mapKey)
w.Header().Set(mapKey.String(), mapValue.String())
}
} else if h, ok := strings.CutPrefix(tag, "header:"); ok {
field := ty.Field(i)
switch field.Type.Kind() {
case reflect.Int, reflect.Int64:
w.Header().Set(h, strconv.Itoa(int(v.Field(i).Int())))
Expand Down
4 changes: 4 additions & 0 deletions services/s3/s3.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ type Object struct {
MD5 []byte
ETag string

Metadata map[string]string

ContentType string
ContentLength int64
Parts []Part
Expand Down Expand Up @@ -392,6 +394,7 @@ func (s *S3) getObject(input GetObjectInput, includeBody bool) (*GetObjectOutput
SSECustomerAlgorithm: object.SSECustomerAlgorithm,
SSECustomerKey: object.SSECustomerKey,
SSEKMSKeyId: object.SSEKMSKeyId,
Metadata: object.Metadata,
// Bafflingly, This format is expected here.
LastModified: time.Now().UTC().Format(timeFormat),
HttpStatus: http.StatusOK,
Expand Down Expand Up @@ -482,6 +485,7 @@ func (s *S3) PutObject(input PutObjectInput) (*PutObjectOutput, *awserrors.Error
ContentType: input.ContentType,
ContentLength: contentLength,

Metadata: input.Metadata,
Tagging: input.Tagging,
ServerSideEncryption: input.ServerSideEncryption,
SSEKMSKeyId: input.SSEKMSKeyId,
Expand Down
4 changes: 4 additions & 0 deletions services/s3/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ type GetObjectOutput struct {
SSECustomerAlgorithm string `s3:"header:x-amz-server-side-encryption-customer-algorithm"`
SSECustomerKey string `s3:"header:x-amz-server-side-encryption-customer-key"`
LastModified string `s3:"header:Last-Modified"`
// Note: Metadata is handled specially
Metadata map[string]string `s3:"metadata-headers"`
// TODO: md5
SSEKMSKeyId string `s3:"header:x-amz-server-side-encryption-aws-kms-key-id"`
//PartsCount int `s3:"header:x-amz-mp-parts-count"`
Expand All @@ -135,6 +137,8 @@ type PutObjectInput struct {
SSEKMSKeyId string `s3:"header:x-amz-server-side-encryption-aws-kms-key-id"`
SSEKMSEncryptionContext string `s3:"header:x-amz-server-side-encryption-context"`
SSECustomerAlgorithm string `s3:"header:x-amz-server-side-encryption-customer-algorithm"`
// Note: Metadata is handled specially
Metadata map[string]string
// TODO: md5 check
SSECustomerKey string `s3:"header:x-amz-server-side-encryption-customer-key"`
Tagging string `s3:"header:x-amz-tagging"`
Expand Down

0 comments on commit 5adc982

Please sign in to comment.