Support Content-Disposition
This commit is contained in:
parent
145af6dbfb
commit
79db40bf51
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,6 +135,7 @@ func (s *DataStore) logPath(id string) string {
|
||||||
|
|
||||||
type fileMeta struct {
|
type fileMeta struct {
|
||||||
ContentType string
|
ContentType string
|
||||||
|
ContentDisposition string
|
||||||
Size int64
|
Size int64
|
||||||
Chunks chunkSet
|
Chunks chunkSet
|
||||||
}
|
}
|
||||||
|
@ -145,4 +151,5 @@ type chunkEntry struct {
|
||||||
type metaEntry struct {
|
type metaEntry struct {
|
||||||
Size int64
|
Size int64
|
||||||
ContentType string
|
ContentType string
|
||||||
|
ContentDisposition string
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue