Support Content-Disposition

This commit is contained in:
Felix Geisendörfer 2013-03-25 11:02:47 +01:00
parent 145af6dbfb
commit 79db40bf51
2 changed files with 28 additions and 17 deletions

View File

@ -18,14 +18,18 @@ func NewDataStore(dir string) *DataStore {
return &DataStore{dir: dir} return &DataStore{dir: dir}
} }
func (s *DataStore) CreateFile(id string, size int64, contentType string) error { func (s *DataStore) CreateFile(id string, size int64, contentType string, contentDisposition string) error {
file, err := os.OpenFile(s.filePath(id), os.O_CREATE|os.O_WRONLY, 0666) file, err := os.OpenFile(s.filePath(id), os.O_CREATE|os.O_WRONLY, 0666)
if err != nil { if err != nil {
return err return err
} }
defer file.Close() defer file.Close()
entry := logEntry{Meta: &metaEntry{Size: size, ContentType: contentType}} entry := logEntry{Meta: &metaEntry{
Size: size,
ContentType: contentType,
ContentDisposition: contentDisposition,
}}
return s.appendFileLog(id, entry) return s.appendFileLog(id, entry)
} }
@ -45,7 +49,7 @@ func (s *DataStore) WriteFileChunk(id string, start int64, end int64, src io.Rea
size := end - start + 1 size := end - start + 1
n, err := io.CopyN(file, src, size) n, err := io.CopyN(file, src, size)
if n > 0 { if n > 0 {
entry := logEntry{Chunk: &chunkEntry{Start: start, End: start+n-1}} entry := logEntry{Chunk: &chunkEntry{Start: start, End: start + n - 1}}
if err := s.appendFileLog(id, entry); err != nil { if err := s.appendFileLog(id, entry); err != nil {
return err return err
} }
@ -85,6 +89,7 @@ func (s *DataStore) GetFileMeta(id string) (*fileMeta, error) {
if entry.Meta != nil { if entry.Meta != nil {
meta.ContentType = entry.Meta.ContentType meta.ContentType = entry.Meta.ContentType
meta.ContentDisposition = entry.Meta.ContentDisposition
meta.Size = entry.Meta.Size meta.Size = entry.Meta.Size
} }
} }
@ -129,9 +134,10 @@ func (s *DataStore) logPath(id string) string {
} }
type fileMeta struct { type fileMeta struct {
ContentType string ContentType string
Size int64 ContentDisposition string
Chunks chunkSet Size int64
Chunks chunkSet
} }
type logEntry struct { type logEntry struct {
@ -143,6 +149,7 @@ type chunkEntry struct {
Start, End int64 Start, End int64
} }
type metaEntry struct { type metaEntry struct {
Size int64 Size int64
ContentType string ContentType string
ContentDisposition string
} }

View File

@ -37,7 +37,7 @@ func serveHttp() error {
addr := ":1080" addr := ":1080"
if port := os.Getenv("TUSD_PORT"); port != "" { if port := os.Getenv("TUSD_PORT"); port != "" {
addr = ":"+port addr = ":" + port
} }
log.Printf("serving clients at %s", addr) log.Printf("serving clients at %s", addr)
@ -54,7 +54,7 @@ func route(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Access-Control-Allow-Origin", "*") w.Header().Add("Access-Control-Allow-Origin", "*")
w.Header().Add("Access-Control-Allow-Methods", "HEAD,GET,PUT,POST,DELETE") w.Header().Add("Access-Control-Allow-Methods", "HEAD,GET,PUT,POST,DELETE")
w.Header().Add("Access-Control-Allow-Headers", "Origin, x-requested-with, content-type, accept, Content-Range, Content-Disposition") w.Header().Add("Access-Control-Allow-Headers", "Origin, x-requested-with, content-type, accept, Content-Range, Content-Disposition")
w.Header().Add("Access-Control-Expose-Headers", "Location, Range") w.Header().Add("Access-Control-Expose-Headers", "Location, Range, Content-Disposition")
if r.Method == "OPTIONS" { if r.Method == "OPTIONS" {
reply(w, http.StatusOK, "") reply(w, http.StatusOK, "")
@ -102,8 +102,10 @@ func postFiles(w http.ResponseWriter, r *http.Request) {
contentType = "application/octet-stream" contentType = "application/octet-stream"
} }
contentDisposition := r.Header.Get("Content-Disposition")
id := uid() id := uid()
if err := dataStore.CreateFile(id, contentRange.Size, contentType); err != nil { if err := dataStore.CreateFile(id, contentRange.Size, contentType, contentDisposition); err != nil {
reply(w, http.StatusInternalServerError, err.Error()) reply(w, http.StatusInternalServerError, err.Error())
return return
} }
@ -117,7 +119,7 @@ func postFiles(w http.ResponseWriter, r *http.Request) {
} }
w.Header().Set("Location", "/files/"+id) w.Header().Set("Location", "/files/"+id)
setFileRangeHeader(w, id) setFileHeaders(w, id)
w.WriteHeader(http.StatusCreated) w.WriteHeader(http.StatusCreated)
} }
@ -126,7 +128,7 @@ func headFile(w http.ResponseWriter, r *http.Request, fileId string) {
// fixed in future release, see: // fixed in future release, see:
// http://code.google.com/p/go/issues/detail?id=4126 // http://code.google.com/p/go/issues/detail?id=4126
w.Header().Set("Content-Length", "0") w.Header().Set("Content-Length", "0")
setFileRangeHeader(w, fileId) setFileHeaders(w, fileId)
} }
func getFile(w http.ResponseWriter, r *http.Request, fileId string) { func getFile(w http.ResponseWriter, r *http.Request, fileId string) {
@ -145,8 +147,7 @@ func getFile(w http.ResponseWriter, r *http.Request, fileId string) {
} }
defer data.Close() defer data.Close()
setFileRangeHeader(w, fileId) setFileHeaders(w, fileId)
w.Header().Set("Content-Type", meta.ContentType)
w.Header().Set("Content-Length", strconv.FormatInt(meta.Size, 10)) w.Header().Set("Content-Length", strconv.FormatInt(meta.Size, 10))
if _, err := io.CopyN(w, data, meta.Size); err != nil { if _, err := io.CopyN(w, data, meta.Size); err != nil {
@ -188,10 +189,10 @@ func putFile(w http.ResponseWriter, r *http.Request, fileId string) {
return return
} }
setFileRangeHeader(w, fileId) setFileHeaders(w, fileId)
} }
func setFileRangeHeader(w http.ResponseWriter, fileId string) { func setFileHeaders(w http.ResponseWriter, fileId string) {
meta, err := dataStore.GetFileMeta(fileId) meta, err := dataStore.GetFileMeta(fileId)
if os.IsNotExist(err) { if os.IsNotExist(err) {
reply(w, http.StatusNotFound, err.Error()) reply(w, http.StatusNotFound, err.Error())
@ -212,4 +213,7 @@ func setFileRangeHeader(w http.ResponseWriter, fileId string) {
if rangeHeader != "" { if rangeHeader != "" {
w.Header().Set("Range", "bytes="+rangeHeader) w.Header().Set("Range", "bytes="+rangeHeader)
} }
w.Header().Set("Content-Type", meta.ContentType)
w.Header().Set("Content-Disposition", meta.ContentDisposition)
} }