diff options
-rw-r--r-- | api/file.go | 36 | ||||
-rw-r--r-- | model/file_info.go | 60 | ||||
-rw-r--r-- | model/file_info_test.go | 76 |
3 files changed, 146 insertions, 26 deletions
diff --git a/api/file.go b/api/file.go index 4339e610b..d31abfb1d 100644 --- a/api/file.go +++ b/api/file.go @@ -23,7 +23,6 @@ import ( "image/jpeg" "io" "io/ioutil" - "mime" "net/http" "net/url" "os" @@ -323,25 +322,22 @@ func getFileInfo(c *Context, w http.ResponseWriter, r *http.Request) { cchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, channelId, c.Session.UserId) path := "teams/" + c.Session.TeamId + "/channels/" + channelId + "/users/" + userId + "/" + filename - size := "" + var info *model.FileInfo - if s, ok := fileInfoCache.Get(path); ok { - size = s.(string) + if cached, ok := fileInfoCache.Get(path); ok { + info = cached.(*model.FileInfo) } else { - fileData := make(chan []byte) getFileAndForget(path, fileData) - f := <-fileData - - if f == nil { - c.Err = model.NewAppError("getFileInfo", "Could not find file.", "path="+path) - c.Err.StatusCode = http.StatusNotFound + newInfo, err := model.GetInfoForBytes(filename, <-fileData) + if err != nil { + c.Err = err return + } else { + fileInfoCache.Add(path, newInfo) + info = newInfo } - - size = strconv.Itoa(len(f)) - fileInfoCache.Add(path, size) } if !c.HasPermissionsToChannel(cchan, "getFileInfo") { @@ -350,19 +346,7 @@ func getFileInfo(c *Context, w http.ResponseWriter, r *http.Request) { w.Header().Set("Cache-Control", "max-age=2592000, public") - var mimeType string - ext := filepath.Ext(filename) - if model.IsFileExtImage(ext) { - mimeType = model.GetImageMimeType(ext) - } else { - mimeType = mime.TypeByExtension(ext) - } - - result := make(map[string]string) - result["filename"] = filename - result["size"] = size - result["mime"] = mimeType - w.Write([]byte(model.MapToJson(result))) + w.Write([]byte(info.ToJson())) } func getFile(c *Context, w http.ResponseWriter, r *http.Request) { diff --git a/model/file_info.go b/model/file_info.go new file mode 100644 index 000000000..d96723f32 --- /dev/null +++ b/model/file_info.go @@ -0,0 +1,60 @@ +// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package model + +import ( + "bytes" + "encoding/json" + "image/gif" + "mime" + "path/filepath" +) + +type FileInfo struct { + Filename string `json:"filename"` + Size int `json:"size"` + Extension string `json:"extension"` + MimeType string `json:"mime_type"` + HasPreviewImage bool `json:"has_preview_image"` +} + +func GetInfoForBytes(filename string, data []byte) (*FileInfo, *AppError) { + size := len(data) + + var mimeType string + extension := filepath.Ext(filename) + isImage := IsFileExtImage(extension) + if isImage { + mimeType = GetImageMimeType(extension) + } else { + mimeType = mime.TypeByExtension(extension) + } + + hasPreviewImage := isImage + if mimeType == "image/gif" { + // just show the gif itself instead of a preview image for animated gifs + if gifImage, err := gif.DecodeAll(bytes.NewReader(data)); err != nil { + return nil, NewAppError("GetInfoForBytes", "Could not decode gif.", "filename="+filename) + } else { + hasPreviewImage = len(gifImage.Image) == 1 + } + } + + return &FileInfo{ + Filename: filename, + Size: size, + Extension: extension[1:], + MimeType: mimeType, + HasPreviewImage: hasPreviewImage, + }, nil +} + +func (info *FileInfo) ToJson() string { + b, err := json.Marshal(info) + if err != nil { + return "" + } else { + return string(b) + } +} diff --git a/model/file_info_test.go b/model/file_info_test.go new file mode 100644 index 000000000..ecf0d509c --- /dev/null +++ b/model/file_info_test.go @@ -0,0 +1,76 @@ +// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package model + +import ( + "encoding/base64" + "io/ioutil" + "testing" +) + +func TestGetInfoForBytes(t *testing.T) { + fakeFile := make([]byte, 1000) + + if info, err := GetInfoForBytes("file.txt", fakeFile); err != nil { + t.Fatal(err) + } else if info.Filename != "file.txt" { + t.Fatalf("Got incorrect filename: %v", info.Filename) + } else if info.Size != 1000 { + t.Fatalf("Got incorrect size: %v", info.Size) + } else if info.Extension != "txt" { + t.Fatalf("Git incorrect file extension: %v", info.Extension) + } else if info.MimeType != "text/plain; charset=utf-8" { + t.Fatalf("Got incorrect mime type: %v", info.MimeType) + } else if info.HasPreviewImage { + t.Fatalf("Got HasPreviewImage = true for non-image file") + } + + if info, err := GetInfoForBytes("file.png", fakeFile); err != nil { + t.Fatal(err) + } else if info.Filename != "file.png" { + t.Fatalf("Got incorrect filename: %v", info.Filename) + } else if info.Size != 1000 { + t.Fatalf("Got incorrect size: %v", info.Size) + } else if info.Extension != "png" { + t.Fatalf("Git incorrect file extension: %v", info.Extension) + } else if info.MimeType != "image/png" { + t.Fatalf("Got incorrect mime type: %v", info.MimeType) + } else if !info.HasPreviewImage { + t.Fatalf("Got HasPreviewImage = false for image") + } + + // base 64 encoded version of handtinywhite.gif from http://probablyprogramming.com/2009/03/15/the-tiniest-gif-ever + gifFile, _ := base64.StdEncoding.DecodeString("R0lGODlhAQABAIABAP///wAAACwAAAAAAQABAAACAkQBADs=") + if info, err := GetInfoForBytes("handtinywhite.gif", gifFile); err != nil { + t.Fatal(err) + } else if info.Filename != "handtinywhite.gif" { + t.Fatalf("Got incorrect filename: %v", info.Filename) + } else if info.Size != 35 { + t.Fatalf("Got incorrect size: %v", info.Size) + } else if info.Extension != "gif" { + t.Fatalf("Git incorrect file extension: %v", info.Extension) + } else if info.MimeType != "image/gif" { + t.Fatalf("Got incorrect mime type: %v", info.MimeType) + } else if !info.HasPreviewImage { + t.Fatalf("Got HasPreviewImage = false for static gif") + } + + animatedGifFile, err := ioutil.ReadFile("../web/static/images/testgif.gif") + if err != nil { + t.Fatalf("Failed to load testgif.gif: %v", err.Error()) + } + if info, err := GetInfoForBytes("testgif.gif", animatedGifFile); err != nil { + t.Fatal(err) + } else if info.Filename != "testgif.gif" { + t.Fatalf("Got incorrect filename: %v", info.Filename) + } else if info.Size != 38689 { + t.Fatalf("Got incorrect size: %v", info.Size) + } else if info.Extension != "gif" { + t.Fatalf("Git incorrect file extension: %v", info.Extension) + } else if info.MimeType != "image/gif" { + t.Fatalf("Got incorrect mime type: %v", info.MimeType) + } else if info.HasPreviewImage { + t.Fatalf("Got HasPreviewImage = true for animated gif") + } +} |