http: download: improvement for range support and I/O (#330)

* http: download: adopt http.ServeContent

* http: download: deprecate unnecessary temp dir

* http: download: adopt http.ServeContent in inline mode
pull/333/head
Equim 2018-01-14 16:41:01 +08:00 committed by Henrique Dias
parent 94648c92a2
commit 30efa23a85
1 changed files with 21 additions and 45 deletions

View File

@ -1,8 +1,6 @@
package http package http
import ( import (
"io"
"io/ioutil"
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
@ -45,72 +43,41 @@ func downloadHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int
files = append(files, c.File.Path) files = append(files, c.File.Path)
} }
// If the format is true, just set it to "zip".
if query == "true" || query == "" {
query = "zip"
}
var ( var (
extension string extension string
temp string ar archiver.Archiver
err error
tempfile string
) )
// Create a temporary directory.
temp, err = ioutil.TempDir("", "")
if err != nil {
return http.StatusInternalServerError, err
}
defer os.RemoveAll(temp)
tempfile = filepath.Join(temp, "temp")
switch query { switch query {
case "zip": // If the format is true, just set it to "zip".
extension, err = ".zip", archiver.Zip.Make(tempfile, files) case "zip", "true", "":
extension, ar = ".zip", archiver.Zip
case "tar": case "tar":
extension, err = ".tar", archiver.Tar.Make(tempfile, files) extension, ar = ".tar", archiver.Tar
case "targz": case "targz":
extension, err = ".tar.gz", archiver.TarGz.Make(tempfile, files) extension, ar = ".tar.gz", archiver.TarGz
case "tarbz2": case "tarbz2":
extension, err = ".tar.bz2", archiver.TarBz2.Make(tempfile, files) extension, ar = ".tar.bz2", archiver.TarBz2
case "tarxz": case "tarxz":
extension, err = ".tar.xz", archiver.TarXZ.Make(tempfile, files) extension, ar = ".tar.xz", archiver.TarXZ
default: default:
return http.StatusNotImplemented, nil return http.StatusNotImplemented, nil
} }
if err != nil {
return http.StatusInternalServerError, err
}
// Defines the file name. // Defines the file name.
name := c.File.Name name := c.File.Name
if name == "." || name == "" { if name == "." || name == "" {
name = "download" name = "archive"
} }
name += extension name += extension
// Opens the file so it can be downloaded. w.Header().Set("Content-Disposition", "attachment; filename*=utf-8''"+url.QueryEscape(name))
file, err := os.Open(temp + "/temp") err := ar.Write(w, files)
if err != nil {
return http.StatusInternalServerError, err
}
defer file.Close()
w.Header().Set("Content-Disposition", "attachment; filename=\""+name+"\"")
_, err = io.Copy(w, file)
return 0, err return 0, err
} }
func downloadFileHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, error) { func downloadFileHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, error) {
if r.URL.Query().Get("inline") == "true" {
w.Header().Set("Content-Disposition", "inline")
} else {
w.Header().Set("Content-Disposition", `attachment; filename="`+c.File.Name+`"`)
}
file, err := os.Open(c.File.Path) file, err := os.Open(c.File.Path)
defer file.Close() defer file.Close()
@ -118,10 +85,19 @@ func downloadFileHandler(c *fm.Context, w http.ResponseWriter, r *http.Request)
return http.StatusInternalServerError, err return http.StatusInternalServerError, err
} }
_, err = io.Copy(w, file) stat, err := file.Stat()
if err != nil { if err != nil {
return http.StatusInternalServerError, err return http.StatusInternalServerError, err
} }
if r.URL.Query().Get("inline") == "true" {
w.Header().Set("Content-Disposition", "inline")
} else {
// As per RFC6266 section 4.3
w.Header().Set("Content-Disposition", "attachment; filename*=utf-8''"+url.QueryEscape(c.File.Name))
}
http.ServeContent(w, r, stat.Name(), stat.ModTime(), file)
return 0, nil return 0, nil
} }