diff --git a/src/http/handler.go b/src/http/handler.go index 2ada4a3..1a09f61 100644 --- a/src/http/handler.go +++ b/src/http/handler.go @@ -93,14 +93,17 @@ func (h *Handler) createFile(w http.ResponseWriter, r *http.Request) { finalLength, err := strconv.ParseInt(r.Header.Get("Final-Length"), 10, 64) if err != nil { - err = errors.New("invalid Final-Length header: "+err.Error()) + err = errors.New("invalid Final-Length header: " + err.Error()) h.err(err, w, http.StatusBadRequest) return } - // @TODO: What happens if Final-Length is <= 0 + if finalLength < 0 { + h.err(errors.New("negative Final-Length values not supported"), w, http.StatusBadRequest) + return + } - // @TODO: Provide meta data + // @TODO: Define meta data extension and implement it here // @TODO: Make max finalLength configurable, reply with error if exceeded. // This should go into the protocol as well. if err := h.store.CreateFile(id, finalLength, nil); err != nil { @@ -108,8 +111,8 @@ func (h *Handler) createFile(w http.ResponseWriter, r *http.Request) { return } - w.WriteHeader(http.StatusCreated) w.Header().Set("Location", h.absUrl(r, "/"+id)) + w.WriteHeader(http.StatusCreated) } // absUrl turn a relPath (e.g. "/foo") into an absolute url (e.g. diff --git a/src/http/handler_test.go b/src/http/handler_test.go new file mode 100644 index 0000000..24895c1 --- /dev/null +++ b/src/http/handler_test.go @@ -0,0 +1,120 @@ +package http + +import ( + "io/ioutil" + "net/http" + "net/http/httptest" + "os" + "regexp" + "testing" +) + +const basePath = "/files/" + +var Protocol_FileCreation_Tests = []struct { + Description string + Method string + Headers map[string]string + ExpectStatusCode int + ExpectHeaders map[string]string + MatchLocation *regexp.Regexp +}{ + { + Description: "Bad method", + Method: "PUT", + ExpectStatusCode: http.StatusMethodNotAllowed, + ExpectHeaders: map[string]string{"Allow": "POST"}, + }, + { + Description: "Missing Final-Length header", + ExpectStatusCode: http.StatusBadRequest, + }, + { + Description: "Invalid Final-Length header", + Headers: map[string]string{"Final-Length": "fuck"}, + ExpectStatusCode: http.StatusBadRequest, + }, + { + Description: "Negative Final-Length header", + Headers: map[string]string{"Final-Length": "-10"}, + ExpectStatusCode: http.StatusBadRequest, + }, + { + Description: "Valid Request", + Headers: map[string]string{"Final-Length": "1024"}, + ExpectStatusCode: http.StatusCreated, + MatchLocation: regexp.MustCompile("^http://.+" + regexp.QuoteMeta(basePath) + "[a-z0-9]{32}$"), + }, +} + +func TestProtocol_FileCreation(t *testing.T) { + dir, err := ioutil.TempDir("", "tus_handler_test") + if err != nil { + t.Fatal(err) + } + defer os.Remove(dir) + + config := HandlerConfig{ + Dir: dir, + MaxSize: 1024 * 1024, + BasePath: basePath, + } + + handler, err := NewHandler(config) + if err != nil { + t.Fatal(err) + } + + server := httptest.NewServer(handler) + defer server.Close() + +Tests: + for _, test := range Protocol_FileCreation_Tests { + t.Logf("test: %s", test.Description) + + method := test.Method + if method == "" { + method = "POST" + } + + req, err := http.NewRequest(method, server.URL+config.BasePath, nil) + if err != nil { + t.Fatal(err) + } + + for key, val := range test.Headers { + req.Header.Set(key, val) + } + + res, err := http.DefaultClient.Do(req) + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + t.Fatal(err) + } + + if test.ExpectStatusCode != 0 && test.ExpectStatusCode != res.StatusCode { + t.Errorf("bad status: %d, expected: %d - %s", res.StatusCode, test.ExpectStatusCode, body) + continue Tests + } + + for key, val := range test.ExpectHeaders { + if got := res.Header.Get(key); got != val { + t.Errorf("expected \"%s: %s\" header, but got: \"%s: %s\"", key, val, key, got) + continue Tests + } + } + + if test.MatchLocation != nil { + location := res.Header.Get("Location") + if !test.MatchLocation.MatchString(location) { + t.Errorf("location \"%s\" did not match: \"%s\"", location, test.MatchLocation.String()) + continue Tests + } + } + } +}