Skip to content

Commit

Permalink
Merge pull request #786 from versity/ben/content_type
Browse files Browse the repository at this point in the history
fix: set content type on put object
  • Loading branch information
benmcclelland authored Sep 10, 2024
2 parents 6ad1e25 + dc71365 commit 448765b
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 22 deletions.
69 changes: 55 additions & 14 deletions backend/posix/posix.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ const (
objectRetentionKey = "object-retention"
objectLegalHoldKey = "object-legal-hold"

// this is the media type for directories in AWS and Nextcloud
dirContentType = "application/x-directory"

doFalloc = true
skipFalloc = false
)
Expand Down Expand Up @@ -474,7 +477,8 @@ func (p *Posix) CreateMultipartUpload(ctx context.Context, mpu *s3.CreateMultipa
}

// set content-type
if *mpu.ContentType != "" {
ctype := getString(mpu.ContentType)
if ctype != "" {
err := p.meta.StoreAttribute(bucket, filepath.Join(objdir, uploadID),
contentTypeHdr, []byte(*mpu.ContentType))
if err != nil {
Expand All @@ -485,6 +489,19 @@ func (p *Posix) CreateMultipartUpload(ctx context.Context, mpu *s3.CreateMultipa
}
}

// set content-encoding
cenc := getString(mpu.ContentEncoding)
if cenc != "" {
err := p.meta.StoreAttribute(bucket, filepath.Join(objdir, uploadID), contentEncHdr,
[]byte(*mpu.ContentEncoding))
if err != nil {
// cleanup object if returning error
os.RemoveAll(filepath.Join(tmppath, uploadID))
os.Remove(tmppath)
return s3response.InitiateMultipartUploadResult{}, fmt.Errorf("set content-encoding: %w", err)
}
}

// set object legal hold
if mpu.ObjectLockLegalHoldStatus == types.ObjectLockLegalHoldStatusOn {
if err := p.PutObjectLegalHold(ctx, bucket, filepath.Join(objdir, uploadID), "", true); err != nil {
Expand Down Expand Up @@ -649,7 +666,7 @@ func (p *Posix) CompleteMultipartUpload(ctx context.Context, input *s3.CompleteM

userMetaData := make(map[string]string)
upiddir := filepath.Join(objdir, uploadID)
cType, _ := p.loadUserMetaData(bucket, upiddir, userMetaData)
cType, cEnc := p.loadUserMetaData(bucket, upiddir, userMetaData)

objname := filepath.Join(bucket, object)
dir := filepath.Dir(objname)
Expand Down Expand Up @@ -696,6 +713,15 @@ func (p *Posix) CompleteMultipartUpload(ctx context.Context, input *s3.CompleteM
}
}

// set content-encoding
if cEnc != "" {
if err := p.meta.StoreAttribute(bucket, object, contentEncHdr, []byte(cEnc)); err != nil {
// cleanup object
os.Remove(objname)
return nil, fmt.Errorf("set object content encoding: %w", err)
}
}

// load and set legal hold
lHold, err := p.meta.RetrieveAttribute(bucket, upiddir, objectLegalHoldKey)
if err == nil {
Expand Down Expand Up @@ -796,15 +822,9 @@ func (p *Posix) loadUserMetaData(bucket, object string, m map[string]string) (st
var contentType, contentEncoding string
b, _ := p.meta.RetrieveAttribute(bucket, object, contentTypeHdr)
contentType = string(b)
if contentType != "" {
m[contentTypeHdr] = contentType
}

b, _ = p.meta.RetrieveAttribute(bucket, object, contentEncHdr)
contentEncoding = string(b)
if contentEncoding != "" {
m[contentEncHdr] = contentEncoding
}

return contentType, contentEncoding
}
Expand Down Expand Up @@ -1408,7 +1428,8 @@ func (p *Posix) PutObject(ctx context.Context, po *s3.PutObjectInput) (string, e
}

// set etag attribute to signify this dir was specifically put
err = p.meta.StoreAttribute(*po.Bucket, *po.Key, etagkey, []byte(emptyMD5))
err = p.meta.StoreAttribute(*po.Bucket, *po.Key, etagkey,
[]byte(emptyMD5))
if err != nil {
return "", fmt.Errorf("set etag attr: %w", err)
}
Expand Down Expand Up @@ -1478,7 +1499,8 @@ func (p *Posix) PutObject(ctx context.Context, po *s3.PutObjectInput) (string, e

// Set object legal hold
if po.ObjectLockLegalHoldStatus == types.ObjectLockLegalHoldStatusOn {
if err := p.PutObjectLegalHold(ctx, *po.Bucket, *po.Key, "", true); err != nil {
err := p.PutObjectLegalHold(ctx, *po.Bucket, *po.Key, "", true)
if err != nil {
return "", err
}
}
Expand All @@ -1493,7 +1515,8 @@ func (p *Posix) PutObject(ctx context.Context, po *s3.PutObjectInput) (string, e
if err != nil {
return "", fmt.Errorf("parse object lock retention: %w", err)
}
if err := p.PutObjectRetention(ctx, *po.Bucket, *po.Key, "", true, retParsed); err != nil {
err = p.PutObjectRetention(ctx, *po.Bucket, *po.Key, "", true, retParsed)
if err != nil {
return "", err
}
}
Expand All @@ -1505,6 +1528,24 @@ func (p *Posix) PutObject(ctx context.Context, po *s3.PutObjectInput) (string, e
return "", fmt.Errorf("set etag attr: %w", err)
}

ctype := getString(po.ContentType)
if ctype != "" {
err := p.meta.StoreAttribute(*po.Bucket, *po.Key, contentTypeHdr,
[]byte(*po.ContentType))
if err != nil {
return "", fmt.Errorf("set content-type attr: %w", err)
}
}

cenc := getString(po.ContentEncoding)
if cenc != "" {
err := p.meta.StoreAttribute(*po.Bucket, *po.Key, contentEncHdr,
[]byte(*po.ContentEncoding))
if err != nil {
return "", fmt.Errorf("set content-encoding attr: %w", err)
}
}

return etag, nil
}

Expand Down Expand Up @@ -1697,7 +1738,8 @@ func (p *Posix) GetObject(_ context.Context, input *s3.GetObjectInput) (*s3.GetO
if fi.IsDir() {
userMetaData := make(map[string]string)

contentType, contentEncoding := p.loadUserMetaData(bucket, object, userMetaData)
_, contentEncoding := p.loadUserMetaData(bucket, object, userMetaData)
contentType := dirContentType

b, err := p.meta.RetrieveAttribute(bucket, object, etagkey)
etag := string(b)
Expand Down Expand Up @@ -1856,8 +1898,7 @@ func (p *Posix) HeadObject(ctx context.Context, input *s3.HeadObjectInput) (*s3.
contentType, contentEncoding := p.loadUserMetaData(bucket, object, userMetaData)

if fi.IsDir() {
// this is the media type for directories in AWS and Nextcloud
contentType = "application/x-directory"
contentType = dirContentType
}

b, err := p.meta.RetrieveAttribute(bucket, object, etagkey)
Expand Down
6 changes: 6 additions & 0 deletions s3api/controllers/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -1530,6 +1530,8 @@ func (c S3ApiController) PutActions(ctx *fiber.Ctx) error {
versionId := ctx.Query("versionId")
acct := ctx.Locals("account").(auth.Account)
isRoot := ctx.Locals("isRoot").(bool)
contentType := ctx.Get("Content-Type")
contentEncoding := ctx.Get("Content-Encoding")
parsedAcl := ctx.Locals("parsedAcl").(auth.ACL)
tagging := ctx.Get("x-amz-tagging")

Expand Down Expand Up @@ -2235,6 +2237,8 @@ func (c S3ApiController) PutActions(ctx *fiber.Ctx) error {
Bucket: &bucket,
Key: &keyStart,
ContentLength: &contentLength,
ContentType: &contentType,
ContentEncoding: &contentEncoding,
Metadata: metadata,
Body: body,
Tagging: &tagging,
Expand Down Expand Up @@ -2842,6 +2846,7 @@ func (c S3ApiController) CreateActions(ctx *fiber.Ctx) error {
isRoot := ctx.Locals("isRoot").(bool)
parsedAcl := ctx.Locals("parsedAcl").(auth.ACL)
contentType := ctx.Get("Content-Type")
contentEncoding := ctx.Get("Content-Encoding")
tagging := ctx.Get("X-Amz-Tagging")

if keyEnd != "" {
Expand Down Expand Up @@ -3071,6 +3076,7 @@ func (c S3ApiController) CreateActions(ctx *fiber.Ctx) error {
Key: &key,
Tagging: &tagging,
ContentType: &contentType,
ContentEncoding: &contentEncoding,
ObjectLockRetainUntilDate: &objLockState.RetainUntilDate,
ObjectLockMode: objLockState.ObjectLockMode,
ObjectLockLegalHoldStatus: objLockState.LegalHoldStatus,
Expand Down
4 changes: 4 additions & 0 deletions tests/integration/group-tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ func TestHeadObject(s *S3Conf) {
HeadObject_mp_success(s)
HeadObject_non_existing_dir_object(s)
HeadObject_name_too_long(s)
HeadObject_with_contenttype(s)
HeadObject_success(s)
}

Expand All @@ -161,6 +162,7 @@ func TestGetObject(s *S3Conf) {
GetObject_invalid_ranges(s)
GetObject_with_meta(s)
GetObject_success(s)
GetObject_directory_success(s)
GetObject_by_range_success(s)
GetObject_by_range_resp_status(s)
GetObject_non_existing_dir_object(s)
Expand Down Expand Up @@ -596,6 +598,7 @@ func GetIntTests() IntTests {
"HeadObject_mp_success": HeadObject_mp_success,
"HeadObject_non_existing_dir_object": HeadObject_non_existing_dir_object,
"HeadObject_name_too_long": HeadObject_name_too_long,
"HeadObject_with_contenttype": HeadObject_with_contenttype,
"HeadObject_success": HeadObject_success,
"GetObjectAttributes_non_existing_bucket": GetObjectAttributes_non_existing_bucket,
"GetObjectAttributes_non_existing_object": GetObjectAttributes_non_existing_object,
Expand All @@ -606,6 +609,7 @@ func GetIntTests() IntTests {
"GetObject_invalid_ranges": GetObject_invalid_ranges,
"GetObject_with_meta": GetObject_with_meta,
"GetObject_success": GetObject_success,
"GetObject_directory_success": GetObject_directory_success,
"GetObject_by_range_success": GetObject_by_range_success,
"GetObject_by_range_resp_status": GetObject_by_range_resp_status,
"GetObject_non_existing_dir_object": GetObject_non_existing_dir_object,
Expand Down
Loading

0 comments on commit 448765b

Please sign in to comment.