MM-10381: Change the file downloading API to stream file (#9144)
* Change the file downloading to stream file * Change file downloading to chunk only for preview * Remove unnecessary else case
Этот коммит содержится в:
коммит произвёл
Christopher Speller
родитель
c8d3e42139
Коммит
8387d92ea2
25
api4/file.go
25
api4/file.go
@@ -154,14 +154,14 @@ func getFile(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := c.App.ReadFile(info.Path)
|
fileReader, err := c.App.FileReader(info.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Err = err
|
c.Err = err
|
||||||
c.Err.StatusCode = http.StatusNotFound
|
c.Err.StatusCode = http.StatusNotFound
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = writeFileResponse(info.Name, info.MimeType, data, forceDownload, w, r)
|
err = writeFileResponse(info.Name, info.MimeType, info.Size, fileReader, forceDownload, w, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Err = err
|
c.Err = err
|
||||||
return
|
return
|
||||||
@@ -195,10 +195,10 @@ func getFileThumbnail(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if data, err := c.App.ReadFile(info.ThumbnailPath); err != nil {
|
if fileReader, err := c.App.FileReader(info.ThumbnailPath); err != nil {
|
||||||
c.Err = err
|
c.Err = err
|
||||||
c.Err.StatusCode = http.StatusNotFound
|
c.Err.StatusCode = http.StatusNotFound
|
||||||
} else if err := writeFileResponse(info.Name, THUMBNAIL_IMAGE_TYPE, data, forceDownload, w, r); err != nil {
|
} else if err := writeFileResponse(info.Name, THUMBNAIL_IMAGE_TYPE, 0, fileReader, forceDownload, w, r); err != nil {
|
||||||
c.Err = err
|
c.Err = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -264,10 +264,10 @@ func getFilePreview(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if data, err := c.App.ReadFile(info.PreviewPath); err != nil {
|
if fileReader, err := c.App.FileReader(info.PreviewPath); err != nil {
|
||||||
c.Err = err
|
c.Err = err
|
||||||
c.Err.StatusCode = http.StatusNotFound
|
c.Err.StatusCode = http.StatusNotFound
|
||||||
} else if err := writeFileResponse(info.Name, PREVIEW_IMAGE_TYPE, data, forceDownload, w, r); err != nil {
|
} else if err := writeFileResponse(info.Name, PREVIEW_IMAGE_TYPE, 0, fileReader, forceDownload, w, r); err != nil {
|
||||||
c.Err = err
|
c.Err = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -325,20 +325,23 @@ func getPublicFile(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if data, err := c.App.ReadFile(info.Path); err != nil {
|
if fileReader, err := c.App.FileReader(info.Path); err != nil {
|
||||||
c.Err = err
|
c.Err = err
|
||||||
c.Err.StatusCode = http.StatusNotFound
|
c.Err.StatusCode = http.StatusNotFound
|
||||||
} else if err := writeFileResponse(info.Name, info.MimeType, data, true, w, r); err != nil {
|
} else if err := writeFileResponse(info.Name, info.MimeType, info.Size, fileReader, true, w, r); err != nil {
|
||||||
c.Err = err
|
c.Err = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeFileResponse(filename string, contentType string, bytes []byte, forceDownload bool, w http.ResponseWriter, r *http.Request) *model.AppError {
|
func writeFileResponse(filename string, contentType string, contentSize int64, fileReader io.Reader, forceDownload bool, w http.ResponseWriter, r *http.Request) *model.AppError {
|
||||||
w.Header().Set("Cache-Control", "max-age=2592000, private")
|
w.Header().Set("Cache-Control", "max-age=2592000, private")
|
||||||
w.Header().Set("Content-Length", strconv.Itoa(len(bytes)))
|
|
||||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||||
|
|
||||||
|
if contentSize > 0 {
|
||||||
|
w.Header().Set("Content-Length", strconv.Itoa(int(contentSize)))
|
||||||
|
}
|
||||||
|
|
||||||
if contentType == "" {
|
if contentType == "" {
|
||||||
contentType = "application/octet-stream"
|
contentType = "application/octet-stream"
|
||||||
} else {
|
} else {
|
||||||
@@ -380,7 +383,7 @@ func writeFileResponse(filename string, contentType string, bytes []byte, forceD
|
|||||||
w.Header().Set("X-Frame-Options", "DENY")
|
w.Header().Set("X-Frame-Options", "DENY")
|
||||||
w.Header().Set("Content-Security-Policy", "Frame-ancestors 'none'")
|
w.Header().Set("Content-Security-Policy", "Frame-ancestors 'none'")
|
||||||
|
|
||||||
w.Write(bytes)
|
io.Copy(w, fileReader)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,6 +70,14 @@ func (a *App) ReadFile(path string) ([]byte, *model.AppError) {
|
|||||||
return backend.ReadFile(path)
|
return backend.ReadFile(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) FileReader(path string) (io.Reader, *model.AppError) {
|
||||||
|
backend, err := a.FileBackend()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return backend.Reader(path)
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) FileExists(path string) (bool, *model.AppError) {
|
func (a *App) FileExists(path string) (bool, *model.AppError) {
|
||||||
backend, err := a.FileBackend()
|
backend, err := a.FileBackend()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user