Revert "Turn every @todo 404 into an actual 404"

This reverts commit 7601e3a77e.
This commit is contained in:
Felix Geisendörfer 2013-03-28 15:20:28 +01:00
parent 7601e3a77e
commit 817129c2a5
2 changed files with 73 additions and 39 deletions

View File

@ -67,8 +67,3 @@ echo -ne "GET '${SERVICE}${location}' \t\t"
has_content=$(curl -s ${SERVICE}${location}) has_content=$(curl -s ${SERVICE}${location})
echo "<-- ${has_content}" echo "<-- ${has_content}"
# get 404 with GET
echo -ne "GET '${SERVICE}${location}a' \t\t"
has_content=$(curl -s ${SERVICE}${location})
echo "<-- ${has_content}"

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"log" "log"
@ -11,7 +12,11 @@ import (
"strconv" "strconv"
) )
// fileRoute matches /files/<id>. Go seems to use \r to terminate header
// values, so to ease bash scripting, the route ignores a trailing \r in the
// route. Better ideas are welcome.
var fileRoute = regexp.MustCompile("^/files/([^/\r\n]+)\r?$") var fileRoute = regexp.MustCompile("^/files/([^/\r\n]+)\r?$")
var filesRoute = regexp.MustCompile("^/files/?$") var filesRoute = regexp.MustCompile("^/files/?$")
var dataStore *DataStore var dataStore *DataStore
@ -22,16 +27,39 @@ func init() {
} }
dataDir := path.Join(wd, "tus_data") dataDir := path.Join(wd, "tus_data")
if configDir := os.Getenv("TUSD_DATA_DIR"); configDir != "" {
dataDir = configDir
}
// dataStoreSize limits the storage used by the data store. If exceeded, the
// data store will start garbage collection old files until enough storage is
// available again.
var dataStoreSize int64
dataStoreSize = 1024 * 1024 * 1024
if configStoreSize := os.Getenv("TUSD_DATA_STORE_MAXSIZE"); configStoreSize != "" {
parsed, err := strconv.ParseInt(configStoreSize, 10, 64)
if err != nil {
panic(errors.New("Invalid data store max size configured"))
}
dataStoreSize = parsed
}
log.Print("Datastore directory: ", dataDir)
log.Print("Datastore max size: ", dataStoreSize)
if err := os.MkdirAll(dataDir, 0777); err != nil { if err := os.MkdirAll(dataDir, 0777); err != nil {
panic(err) panic(err)
} }
dataStore = NewDataStore(dataDir) dataStore = NewDataStore(dataDir, dataStoreSize)
} }
func serveHttp() error { func serveHttp() error {
http.HandleFunc("/", route) http.HandleFunc("/", route)
addr := ":1080" addr := ":1080"
if port := os.Getenv("TUSD_PORT"); port != "" {
addr = ":" + port
}
log.Printf("serving clients at %s", addr) log.Printf("serving clients at %s", addr)
return http.ListenAndServe(addr, nil) return http.ListenAndServe(addr, nil)
@ -41,9 +69,13 @@ func route(w http.ResponseWriter, r *http.Request) {
log.Printf("request: %s %s", r.Method, r.URL.RequestURI()) log.Printf("request: %s %s", r.Method, r.URL.RequestURI())
w.Header().Set("Server", "tusd") w.Header().Set("Server", "tusd")
// Allow CORS for almost everything. This needs to be revisted / limited to
// routes and methods that need it.
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-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, "")
@ -59,8 +91,6 @@ func route(w http.ResponseWriter, r *http.Request) {
headFile(w, r, id) headFile(w, r, id)
case "GET": case "GET":
getFile(w, r, id) getFile(w, r, id)
case "POST":
putFile(w, r, id)
case "PUT": case "PUT":
putFile(w, r, id) putFile(w, r, id)
default: default:
@ -79,13 +109,11 @@ func reply(w http.ResponseWriter, code int, message string) {
func postFiles(w http.ResponseWriter, r *http.Request) { func postFiles(w http.ResponseWriter, r *http.Request) {
contentRange, err := parseContentRange(r.Header.Get("Content-Range")) contentRange, err := parseContentRange(r.Header.Get("Content-Range"))
if err != nil { if err != nil {
log.Print("FOO")
reply(w, http.StatusBadRequest, err.Error()) reply(w, http.StatusBadRequest, err.Error())
return return
} }
if contentRange.Size == -1 { if contentRange.Size == -1 {
log.Print("FOO2")
reply(w, http.StatusBadRequest, "Content-Range must indicate total file size.") reply(w, http.StatusBadRequest, "Content-Range must indicate total file size.")
return return
} }
@ -95,47 +123,55 @@ 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
} }
if contentRange.End != -1 { if contentRange.End != -1 {
err := dataStore.WriteFileChunk(id, contentRange.Start, contentRange.End, r.Body) if err := dataStore.WriteFileChunk(id, contentRange.Start, contentRange.End, r.Body); err != nil {
if os.IsNotExist(err) { // @TODO: Could be a 404 as well
reply(w, http.StatusNotFound, err.Error())
return
} else if err != nil {
reply(w, http.StatusInternalServerError, err.Error()) reply(w, http.StatusInternalServerError, err.Error())
return return
} }
} }
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)
} }
func headFile(w http.ResponseWriter, r *http.Request, fileId string) { func headFile(w http.ResponseWriter, r *http.Request, fileId string) {
setFileRangeHeader(w, fileId) // Work around a bug in Go that would cause HEAD responses to hang. Should be
// fixed in future release, see:
// http://code.google.com/p/go/issues/detail?id=4126
w.Header().Set("Content-Length", "0")
setFileHeaders(w, fileId)
} }
func getFile(w http.ResponseWriter, r *http.Request, fileId string) { func getFile(w http.ResponseWriter, r *http.Request, fileId string) {
data, size, err := dataStore.ReadFile(fileId) meta, err := dataStore.GetFileMeta(fileId)
if os.IsNotExist(err) { if err != nil {
reply(w, http.StatusNotFound, err.Error()) // @TODO: Could be a 404 as well
reply(w, http.StatusInternalServerError, err.Error())
return return
} else if err != nil { }
data, err := dataStore.ReadFile(fileId)
if err != nil {
// @TODO: Could be a 404 as well
reply(w, http.StatusInternalServerError, err.Error()) reply(w, http.StatusInternalServerError, err.Error())
return return
} }
defer data.Close() defer data.Close()
setFileRangeHeader(w, fileId) setFileHeaders(w, fileId)
w.Header().Set("Content-Length", strconv.FormatInt(size, 10)) w.Header().Set("Content-Length", strconv.FormatInt(meta.Size, 10))
if _, err := io.CopyN(w, data, size); err != nil { if _, err := io.CopyN(w, data, meta.Size); err != nil {
log.Printf("getFile: CopyN failed with: %s", err.Error()) log.Printf("getFile: CopyN failed with: %s", err.Error())
return return
} }
@ -168,7 +204,17 @@ func putFile(w http.ResponseWriter, r *http.Request, fileId string) {
// @TODO: Check that file exists // @TODO: Check that file exists
err = dataStore.WriteFileChunk(fileId, start, end, r.Body) if err := dataStore.WriteFileChunk(fileId, start, end, r.Body); err != nil {
// @TODO: Could be a 404 as well
reply(w, http.StatusInternalServerError, err.Error())
return
}
setFileHeaders(w, fileId)
}
func setFileHeaders(w http.ResponseWriter, fileId string) {
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())
return return
@ -177,20 +223,10 @@ func putFile(w http.ResponseWriter, r *http.Request, fileId string) {
return return
} }
setFileRangeHeader(w, fileId)
}
func setFileRangeHeader(w http.ResponseWriter, fileId string) {
chunks, err := dataStore.GetFileChunks(fileId)
if err != nil {
reply(w, http.StatusInternalServerError, err.Error())
return
}
rangeHeader := "" rangeHeader := ""
for i, chunk := range chunks { for i, chunk := range meta.Chunks {
rangeHeader += fmt.Sprintf("%d-%d", chunk.Start, chunk.End) rangeHeader += fmt.Sprintf("%d-%d", chunk.Start, chunk.End)
if i+1 < len(chunks) { if i+1 < len(meta.Chunks) {
rangeHeader += "," rangeHeader += ","
} }
} }
@ -198,4 +234,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)
} }