Initial PUT implementation

This commit is contained in:
Felix Geisendörfer 2013-03-18 11:24:18 +01:00
parent 62b35dde82
commit 07ac9a43f5
2 changed files with 51 additions and 3 deletions

View File

@ -3,6 +3,8 @@ package main
// This is very simple for now and will be enhanced as needed. // This is very simple for now and will be enhanced as needed.
import ( import (
"errors"
"io"
"os" "os"
"path" "path"
) )
@ -43,3 +45,27 @@ func initFile(fileId string, size int64, contentType string) error {
return nil return nil
} }
func putFileChunk(fileId string, start int64, end int64, r io.Reader) error {
d := dataPath(fileId)
file, err := os.OpenFile(d, os.O_WRONLY, 0666)
if err != nil {
return err
}
defer file.Close()
if n, err := file.Seek(start, os.SEEK_SET); err != nil {
return err
} else if n != start {
return errors.New("putFileChunk: seek failure")
}
size := end - start + 1
if n, err := io.CopyN(file, r, size); err != nil {
return err
} else if n != size {
return errors.New("putFileChunk: partial copy")
}
return nil
}

View File

@ -24,8 +24,9 @@ func route(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Server", "tusd") w.Header().Set("Server", "tusd")
if r.Method == "POST" && r.URL.Path == "/files" { if r.Method == "POST" && r.URL.Path == "/files" {
createFile(w, r) postFiles(w, r)
} else if match := fileRoute.FindStringSubmatch(r.URL.Path); match != nil { } else if match := fileRoute.FindStringSubmatch(r.URL.Path); match != nil {
id := match[1]
// WIP // WIP
switch r.Method { switch r.Method {
case "HEAD": case "HEAD":
@ -33,7 +34,7 @@ func route(w http.ResponseWriter, r *http.Request) {
case "GET": case "GET":
reply(w, http.StatusNotImplemented, "File download") reply(w, http.StatusNotImplemented, "File download")
case "PUT": case "PUT":
reply(w, http.StatusOK, "chunk created") putFile(w, r, id)
default: default:
reply(w, http.StatusMethodNotAllowed, "Invalid http method") reply(w, http.StatusMethodNotAllowed, "Invalid http method")
} }
@ -47,7 +48,7 @@ func reply(w http.ResponseWriter, code int, message string) {
fmt.Fprintf(w, "%d - %s: %s\n", code, http.StatusText(code), message) fmt.Fprintf(w, "%d - %s: %s\n", code, http.StatusText(code), message)
} }
func createFile(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 {
reply(w, http.StatusBadRequest, err.Error()) reply(w, http.StatusBadRequest, err.Error())
@ -75,6 +76,27 @@ func createFile(w http.ResponseWriter, r *http.Request) {
return return
} }
// @TODO: Return X-Resume header
w.Header().Set("Location", "/files/"+id) w.Header().Set("Location", "/files/"+id)
w.WriteHeader(http.StatusCreated) w.WriteHeader(http.StatusCreated)
} }
func putFile(w http.ResponseWriter, r *http.Request, fileId string) {
contentRange, err := parseContentRange(r.Header.Get("Content-Range"))
if err != nil {
reply(w, http.StatusBadRequest, err.Error())
return
}
// @TODO: Check that file exists
// @TODO: Make sure contentRange.Size matches file size
if err := putFileChunk(fileId, contentRange.Start, contentRange.End, r.Body); err != nil {
// @TODO: Could be a 404 as well
reply(w, http.StatusInternalServerError, err.Error())
return
}
// @TODO: Return X-Resume header
}