From 18cffb2b03e13a6b0474075855e1e56d216a3c24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Geisendo=CC=88rfer?= Date: Fri, 3 May 2013 12:52:25 +0200 Subject: [PATCH] Return url for new file resources --- src/http/handler.go | 48 +++++++++++++++++++++++++---------- src/{cmd/tusd => http}/uid.go | 2 +- 2 files changed, 36 insertions(+), 14 deletions(-) rename src/{cmd/tusd => http}/uid.go (97%) diff --git a/src/http/handler.go b/src/http/handler.go index b70a823..99601ad 100644 --- a/src/http/handler.go +++ b/src/http/handler.go @@ -5,6 +5,7 @@ import ( "io" "net/http" "os" + "path" "strings" ) @@ -38,7 +39,7 @@ func NewHandler(config HandlerConfig) (*Handler, error) { return &Handler{ store: newDataStore(config.Dir, config.MaxSize), - basePath: config.BasePath, + config: config, Error: errChan, sendError: errChan, }, nil @@ -46,8 +47,8 @@ func NewHandler(config HandlerConfig) (*Handler, error) { // Handler is a http.Handler that implements tus resumable upload protocol. type Handler struct { - store *DataStore - basePath string + store *DataStore + config HandlerConfig // Error provides error events for logging purposes. Error <-chan error @@ -56,30 +57,51 @@ type Handler struct { } func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + // Verify that url matches BasePath absPath := r.URL.Path - if !strings.HasPrefix(absPath, h.basePath) { - err := errors.New("invalid url path: " + absPath + " - does not match basePath: " + h.basePath) + if !strings.HasPrefix(absPath, h.config.BasePath) { + err := errors.New("unknown url: " + absPath + " - does not match BasePath: " + h.config.BasePath) h.err(err, w, http.StatusNotFound) return } - relPath := absPath[len(h.basePath)-1:] + // example relPath results: "/", "/f81d4fae7dec11d0a765-00a0c91e6bf6", etc. + relPath := absPath[len(h.config.BasePath)-1:] - // File creation request + // file creation request if relPath == "/" { - // Must use POST method according to tus protocol - if r.Method != "POST" { - w.Header().Set("Allow", "POST") - err := errors.New(r.Method + " used against file creation url. Only POST is allowed.") - h.err(err, w, http.StatusMethodNotAllowed) + if r.Method == "POST" { + h.createFile(w, r) return } + + // handle invalid method + w.Header().Set("Allow", "POST") + err := errors.New(r.Method + " used against file creation url. Only POST is allowed.") + h.err(err, w, http.StatusMethodNotAllowed) + return } - err := errors.New("invalid url path: " + absPath + " - does not match file pattern") + // handle unknown url + err := errors.New("unknown url: " + absPath + " - does not match file pattern") h.err(err, w, http.StatusNotFound) } +func (h *Handler) createFile(w http.ResponseWriter, r *http.Request) { + id := uid() + w.Header().Set("Location", h.absUrl(r, "/"+id)) +} + +// absUrl turn a relPath (e.g. "/foo") into an absolute url (e.g. +// "http://example.com/foo"). +// +// @TODO: Look at r.TLS to determine the url scheme. +// @TODO: Make url prefix user configurable (optional) to deal with reverse +// proxies. +func (h *Handler) absUrl(r *http.Request, relPath string) string { + return "http://" + r.Host + path.Clean(h.config.BasePath+relPath) +} + // err sends a http error response and publishes to the Error channel. func (h *Handler) err(err error, w http.ResponseWriter, status int) { w.WriteHeader(status) diff --git a/src/cmd/tusd/uid.go b/src/http/uid.go similarity index 97% rename from src/cmd/tusd/uid.go rename to src/http/uid.go index a9d4eb9..da3a468 100644 --- a/src/cmd/tusd/uid.go +++ b/src/http/uid.go @@ -1,4 +1,4 @@ -package main +package http import ( "crypto/rand"