contentType: Reply back proper contentTypes based on the file extension.

Currently the server would set 'application/octet-stream' for all
objects, set this value based on the file extension transparently.

This is useful in case of minio browser to facilitate displaying
proper icons for the different mime data types.
This commit is contained in:
Harshavardhana 2016-02-01 12:19:54 -08:00
parent 23ca11f75b
commit 0aedb67de0
9 changed files with 45 additions and 10 deletions

View File

@ -78,7 +78,7 @@ func setObjectHeaders(w http.ResponseWriter, metadata fs.ObjectMetadata, content
// set object headers // set object headers
lastModified := metadata.Created.Format(http.TimeFormat) lastModified := metadata.Created.Format(http.TimeFormat)
// object related headers // object related headers
w.Header().Set("Content-Type", "application/octet-stream") w.Header().Set("Content-Type", metadata.ContentType)
if metadata.Md5 != "" { if metadata.Md5 != "" {
w.Header().Set("ETag", "\""+metadata.Md5+"\"") w.Header().Set("ETag", "\""+metadata.Md5+"\"")
} }

View File

@ -108,7 +108,9 @@ func generateListObjectsResponse(bucket, prefix, marker, delimiter string, maxKe
} }
content.Key = object.Object content.Key = object.Object
content.LastModified = object.Created.Format(rfcFormat) content.LastModified = object.Created.Format(rfcFormat)
if object.Md5 != "" {
content.ETag = "\"" + object.Md5 + "\"" content.ETag = "\"" + object.Md5 + "\""
}
content.Size = object.Size content.Size = object.Size
content.StorageClass = "STANDARD" content.StorageClass = "STANDARD"
content.Owner = owner content.Owner = owner

View File

@ -361,7 +361,9 @@ func (api CloudStorageAPI) PostPolicyBucketHandler(w http.ResponseWriter, req *h
} }
return return
} }
if metadata.Md5 != "" {
w.Header().Set("ETag", "\""+metadata.Md5+"\"") w.Header().Set("ETag", "\""+metadata.Md5+"\"")
}
writeSuccessResponse(w, nil) writeSuccessResponse(w, nil)
} }

View File

@ -204,7 +204,9 @@ func (api CloudStorageAPI) PutObjectHandler(w http.ResponseWriter, req *http.Req
} }
return return
} }
if metadata.Md5 != "" {
w.Header().Set("ETag", "\""+metadata.Md5+"\"") w.Header().Set("ETag", "\""+metadata.Md5+"\"")
}
writeSuccessResponse(w, nil) writeSuccessResponse(w, nil)
} }
@ -347,7 +349,9 @@ func (api CloudStorageAPI) PutObjectPartHandler(w http.ResponseWriter, req *http
} }
return return
} }
if calculatedMD5 != "" {
w.Header().Set("ETag", "\""+calculatedMD5+"\"") w.Header().Set("ETag", "\""+calculatedMD5+"\"")
}
writeSuccessResponse(w, nil) writeSuccessResponse(w, nil)
} }

View File

@ -38,6 +38,7 @@ import (
"github.com/minio/minio-xl/pkg/crypto/sha256" "github.com/minio/minio-xl/pkg/crypto/sha256"
"github.com/minio/minio-xl/pkg/crypto/sha512" "github.com/minio/minio-xl/pkg/crypto/sha512"
"github.com/minio/minio-xl/pkg/probe" "github.com/minio/minio-xl/pkg/probe"
"github.com/minio/minio/pkg/contentdb"
"github.com/minio/minio/pkg/disk" "github.com/minio/minio/pkg/disk"
) )
@ -432,12 +433,16 @@ func (fs Filesystem) CompleteMultipartUpload(bucket, object, uploadID string, da
if err != nil { if err != nil {
return ObjectMetadata{}, probe.NewError(err) return ObjectMetadata{}, probe.NewError(err)
} }
contentType := "application/octet-stream"
if objectExt := filepath.Ext(objectPath); objectExt != "" {
contentType = contentdb.MustLookup(strings.TrimPrefix(objectExt, "."))
}
newObject := ObjectMetadata{ newObject := ObjectMetadata{
Bucket: bucket, Bucket: bucket,
Object: object, Object: object,
Created: st.ModTime(), Created: st.ModTime(),
Size: st.Size(), Size: st.Size(),
ContentType: "application/octet-stream", ContentType: contentType,
Md5: hex.EncodeToString(h.Sum(nil)), Md5: hex.EncodeToString(h.Sum(nil)),
} }
return newObject, nil return newObject, nil

View File

@ -32,6 +32,7 @@ import (
"github.com/minio/minio-xl/pkg/atomic" "github.com/minio/minio-xl/pkg/atomic"
"github.com/minio/minio-xl/pkg/crypto/sha256" "github.com/minio/minio-xl/pkg/crypto/sha256"
"github.com/minio/minio-xl/pkg/probe" "github.com/minio/minio-xl/pkg/probe"
"github.com/minio/minio/pkg/contentdb"
"github.com/minio/minio/pkg/disk" "github.com/minio/minio/pkg/disk"
) )
@ -153,6 +154,9 @@ func getMetadata(rootPath, bucket, object string) (ObjectMetadata, *probe.Error)
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
object = sanitizeWindowsPath(object) object = sanitizeWindowsPath(object)
} }
if objectExt := filepath.Ext(object); objectExt != "" {
contentType = contentdb.MustLookup(strings.TrimPrefix(objectExt, "."))
}
metadata := ObjectMetadata{ metadata := ObjectMetadata{
Bucket: bucket, Bucket: bucket,
Object: object, Object: object,
@ -279,12 +283,16 @@ func (fs Filesystem) CreateObject(bucket, object, expectedMD5Sum string, size in
if err != nil { if err != nil {
return ObjectMetadata{}, probe.NewError(err) return ObjectMetadata{}, probe.NewError(err)
} }
contentType := "application/octet-stream"
if objectExt := filepath.Ext(objectPath); objectExt != "" {
contentType = contentdb.MustLookup(strings.TrimPrefix(objectExt, "."))
}
newObject := ObjectMetadata{ newObject := ObjectMetadata{
Bucket: bucket, Bucket: bucket,
Object: object, Object: object,
Created: st.ModTime(), Created: st.ModTime(),
Size: st.Size(), Size: st.Size(),
ContentType: "application/octet-stream", ContentType: contentType,
Md5: md5Sum, Md5: md5Sum,
} }
return newObject, nil return newObject, nil

View File

@ -23,6 +23,7 @@ import (
"time" "time"
"github.com/minio/minio-xl/pkg/probe" "github.com/minio/minio-xl/pkg/probe"
"github.com/minio/minio/pkg/contentdb"
) )
// Filesystem - local variables // Filesystem - local variables
@ -79,6 +80,9 @@ func New(rootPath string) (Filesystem, *probe.Error) {
return Filesystem{}, err.Trace() return Filesystem{}, err.Trace()
} }
} }
// Initialize content db.
contentdb.Init()
var buckets *Buckets var buckets *Buckets
buckets, err = loadBucketsMetadata() buckets, err = loadBucketsMetadata()
if err != nil { if err != nil {

View File

@ -51,6 +51,8 @@ type ObjectInfo struct {
LastModified time.Time `json:"lastModified"` LastModified time.Time `json:"lastModified"`
// Size in bytes of the object. // Size in bytes of the object.
Size int64 `json:"size"` Size int64 `json:"size"`
// ContentType is mime type of the object.
ContentType string `json:"contentType"`
} }
// PutObjectURLArgs - args to generate url for upload access. // PutObjectURLArgs - args to generate url for upload access.

View File

@ -95,10 +95,18 @@ func (web *WebAPI) ListObjects(r *http.Request, args *ListObjectsArgs, reply *[]
if object.Err != nil { if object.Err != nil {
return object.Err 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{ *reply = append(*reply, ObjectInfo{
Key: object.Key, Key: objectInfo.Key,
LastModified: object.LastModified, LastModified: objectInfo.LastModified,
Size: object.Size, Size: objectInfo.Size,
ContentType: objectInfo.ContentType,
}) })
} }
return nil return nil