diff --git a/api-headers.go b/api-headers.go index f1181512e..ba9ecaecd 100644 --- a/api-headers.go +++ b/api-headers.go @@ -78,7 +78,7 @@ func setObjectHeaders(w http.ResponseWriter, metadata fs.ObjectMetadata, content // set object headers lastModified := metadata.Created.Format(http.TimeFormat) // object related headers - w.Header().Set("Content-Type", "application/octet-stream") + w.Header().Set("Content-Type", metadata.ContentType) if metadata.Md5 != "" { w.Header().Set("ETag", "\""+metadata.Md5+"\"") } diff --git a/api-response.go b/api-response.go index f29013754..e294e7ffe 100644 --- a/api-response.go +++ b/api-response.go @@ -108,7 +108,9 @@ func generateListObjectsResponse(bucket, prefix, marker, delimiter string, maxKe } content.Key = object.Object content.LastModified = object.Created.Format(rfcFormat) - content.ETag = "\"" + object.Md5 + "\"" + if object.Md5 != "" { + content.ETag = "\"" + object.Md5 + "\"" + } content.Size = object.Size content.StorageClass = "STANDARD" content.Owner = owner diff --git a/bucket-handlers.go b/bucket-handlers.go index d413f7851..0956b44f1 100644 --- a/bucket-handlers.go +++ b/bucket-handlers.go @@ -361,7 +361,9 @@ func (api CloudStorageAPI) PostPolicyBucketHandler(w http.ResponseWriter, req *h } return } - w.Header().Set("ETag", "\""+metadata.Md5+"\"") + if metadata.Md5 != "" { + w.Header().Set("ETag", "\""+metadata.Md5+"\"") + } writeSuccessResponse(w, nil) } diff --git a/object-handlers.go b/object-handlers.go index 04a911f4e..686029d18 100644 --- a/object-handlers.go +++ b/object-handlers.go @@ -204,7 +204,9 @@ func (api CloudStorageAPI) PutObjectHandler(w http.ResponseWriter, req *http.Req } return } - w.Header().Set("ETag", "\""+metadata.Md5+"\"") + if metadata.Md5 != "" { + w.Header().Set("ETag", "\""+metadata.Md5+"\"") + } writeSuccessResponse(w, nil) } @@ -347,7 +349,9 @@ func (api CloudStorageAPI) PutObjectPartHandler(w http.ResponseWriter, req *http } return } - w.Header().Set("ETag", "\""+calculatedMD5+"\"") + if calculatedMD5 != "" { + w.Header().Set("ETag", "\""+calculatedMD5+"\"") + } writeSuccessResponse(w, nil) } diff --git a/pkg/fs/fs-multipart.go b/pkg/fs/fs-multipart.go index 2c2372414..1ee6c4754 100644 --- a/pkg/fs/fs-multipart.go +++ b/pkg/fs/fs-multipart.go @@ -38,6 +38,7 @@ import ( "github.com/minio/minio-xl/pkg/crypto/sha256" "github.com/minio/minio-xl/pkg/crypto/sha512" "github.com/minio/minio-xl/pkg/probe" + "github.com/minio/minio/pkg/contentdb" "github.com/minio/minio/pkg/disk" ) @@ -432,12 +433,16 @@ func (fs Filesystem) CompleteMultipartUpload(bucket, object, uploadID string, da if err != nil { return ObjectMetadata{}, probe.NewError(err) } + contentType := "application/octet-stream" + if objectExt := filepath.Ext(objectPath); objectExt != "" { + contentType = contentdb.MustLookup(strings.TrimPrefix(objectExt, ".")) + } newObject := ObjectMetadata{ Bucket: bucket, Object: object, Created: st.ModTime(), Size: st.Size(), - ContentType: "application/octet-stream", + ContentType: contentType, Md5: hex.EncodeToString(h.Sum(nil)), } return newObject, nil diff --git a/pkg/fs/fs-object.go b/pkg/fs/fs-object.go index cd28bb054..b4b14bf44 100644 --- a/pkg/fs/fs-object.go +++ b/pkg/fs/fs-object.go @@ -32,6 +32,7 @@ import ( "github.com/minio/minio-xl/pkg/atomic" "github.com/minio/minio-xl/pkg/crypto/sha256" "github.com/minio/minio-xl/pkg/probe" + "github.com/minio/minio/pkg/contentdb" "github.com/minio/minio/pkg/disk" ) @@ -153,6 +154,9 @@ func getMetadata(rootPath, bucket, object string) (ObjectMetadata, *probe.Error) if runtime.GOOS == "windows" { object = sanitizeWindowsPath(object) } + if objectExt := filepath.Ext(object); objectExt != "" { + contentType = contentdb.MustLookup(strings.TrimPrefix(objectExt, ".")) + } metadata := ObjectMetadata{ Bucket: bucket, Object: object, @@ -279,12 +283,16 @@ func (fs Filesystem) CreateObject(bucket, object, expectedMD5Sum string, size in if err != nil { return ObjectMetadata{}, probe.NewError(err) } + contentType := "application/octet-stream" + if objectExt := filepath.Ext(objectPath); objectExt != "" { + contentType = contentdb.MustLookup(strings.TrimPrefix(objectExt, ".")) + } newObject := ObjectMetadata{ Bucket: bucket, Object: object, Created: st.ModTime(), Size: st.Size(), - ContentType: "application/octet-stream", + ContentType: contentType, Md5: md5Sum, } return newObject, nil diff --git a/pkg/fs/fs.go b/pkg/fs/fs.go index ed88cf747..ae229e56a 100644 --- a/pkg/fs/fs.go +++ b/pkg/fs/fs.go @@ -23,6 +23,7 @@ import ( "time" "github.com/minio/minio-xl/pkg/probe" + "github.com/minio/minio/pkg/contentdb" ) // Filesystem - local variables @@ -79,6 +80,9 @@ func New(rootPath string) (Filesystem, *probe.Error) { return Filesystem{}, err.Trace() } } + // Initialize content db. + contentdb.Init() + var buckets *Buckets buckets, err = loadBucketsMetadata() if err != nil { diff --git a/web-definitions.go b/web-definitions.go index 0a413e3dd..ddcbd82f7 100644 --- a/web-definitions.go +++ b/web-definitions.go @@ -51,6 +51,8 @@ type ObjectInfo struct { LastModified time.Time `json:"lastModified"` // Size in bytes of the object. Size int64 `json:"size"` + // ContentType is mime type of the object. + ContentType string `json:"contentType"` } // PutObjectURLArgs - args to generate url for upload access. diff --git a/web-handlers.go b/web-handlers.go index d09068d9a..55afc7f04 100644 --- a/web-handlers.go +++ b/web-handlers.go @@ -95,10 +95,18 @@ func (web *WebAPI) ListObjects(r *http.Request, args *ListObjectsArgs, reply *[] if object.Err != nil { return object.Err } + // TODO - This can get slower for large directories, we can + // perhaps extend the ListObjects XML to reply back + // ContentType as well. + objectInfo, e := web.Client.StatObject(args.BucketName, object.Key) + if e != nil { + return e + } *reply = append(*reply, ObjectInfo{ - Key: object.Key, - LastModified: object.LastModified, - Size: object.Size, + Key: objectInfo.Key, + LastModified: objectInfo.LastModified, + Size: objectInfo.Size, + ContentType: objectInfo.ContentType, }) } return nil