return new offset after successful PATCH request

This commit is contained in:
Acconut 2015-03-23 19:02:12 +01:00
parent e6f058eeca
commit 290fea5dac
7 changed files with 27 additions and 16 deletions

View File

@ -132,7 +132,7 @@ func (s concatFinalStore) GetReader(id string) (io.Reader, error) {
return nil, ErrNotFound return nil, ErrNotFound
} }
func (s concatFinalStore) WriteChunk(id string, offset int64, src io.Reader) error { func (s concatFinalStore) WriteChunk(id string, offset int64, src io.Reader) (int64, error) {
if id != "foo" { if id != "foo" {
s.t.Error("unexpected file id") s.t.Error("unexpected file id")
} }
@ -146,7 +146,7 @@ func (s concatFinalStore) WriteChunk(id string, offset int64, src io.Reader) err
s.t.Error("unexpected content") s.t.Error("unexpected content")
} }
return nil return 10, nil
} }
func TestConcatFinal(t *testing.T) { func TestConcatFinal(t *testing.T) {

View File

@ -37,7 +37,8 @@ type DataStore interface {
// return an os.ErrNotExist which will be interpretet as a 404 Not Found. // return an os.ErrNotExist which will be interpretet as a 404 Not Found.
// It will also lock resources while they are written to ensure only one // It will also lock resources while they are written to ensure only one
// write happens per time. // write happens per time.
WriteChunk(id string, offset int64, src io.Reader) error // The function call must return the number of bytes written.
WriteChunk(id string, offset int64, src io.Reader) (int64, error)
// Read the fileinformation used to validate the offset and respond to HEAD // Read the fileinformation used to validate the offset and respond to HEAD
// requests. It may return an os.ErrNotExist which will be interpretet as a // requests. It may return an os.ErrNotExist which will be interpretet as a
// 404 Not Found. // 404 Not Found.

View File

@ -42,20 +42,20 @@ func (store FileStore) NewUpload(info tusd.FileInfo) (id string, err error) {
return return
} }
func (store FileStore) WriteChunk(id string, offset int64, src io.Reader) error { func (store FileStore) WriteChunk(id string, offset int64, src io.Reader) (int64, error) {
file, err := os.OpenFile(store.binPath(id), os.O_WRONLY|os.O_APPEND, defaultFilePerm) file, err := os.OpenFile(store.binPath(id), os.O_WRONLY|os.O_APPEND, defaultFilePerm)
if err != nil { if err != nil {
return err return 0, err
} }
defer file.Close() defer file.Close()
n, err := io.Copy(file, src) n, err := io.Copy(file, src)
if n > 0 { if n > 0 {
if err := store.setOffset(id, offset+n); err != nil { if err := store.setOffset(id, offset+n); err != nil {
return err return 0, err
} }
} }
return err return n, err
} }
func (store FileStore) GetInfo(id string) (tusd.FileInfo, error) { func (store FileStore) GetInfo(id string) (tusd.FileInfo, error) {

View File

@ -51,10 +51,13 @@ func TestFilestore(t *testing.T) {
} }
// Write data to upload // Write data to upload
err = store.WriteChunk(id, 0, strings.NewReader("hello world")) bytesWritten, err := store.WriteChunk(id, 0, strings.NewReader("hello world"))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if bytesWritten != int64(len("hello world")) {
t.Errorf("expected 11 bytes to be written")
}
// Check new offset // Check new offset
info, err = store.GetInfo(id) info, err = store.GetInfo(id)

View File

@ -314,12 +314,15 @@ func (handler *Handler) patchFile(w http.ResponseWriter, r *http.Request) {
// Limit the // Limit the
reader := io.LimitReader(r.Body, maxSize) reader := io.LimitReader(r.Body, maxSize)
err = handler.dataStore.WriteChunk(id, offset, reader) bytesWritten, err := handler.dataStore.WriteChunk(id, offset, reader)
if err != nil { if err != nil {
handler.sendError(w, err) handler.sendError(w, err)
return return
} }
// Send new offset to client
w.Header().Set("Upload-Offset", strconv.FormatInt(offset+bytesWritten, 10))
w.WriteHeader(http.StatusNoContent) w.WriteHeader(http.StatusNoContent)
} }
@ -462,8 +465,9 @@ func (handler *Handler) fillFinalUpload(id string, uploads []string) error {
} }
reader := io.MultiReader(readers...) reader := io.MultiReader(readers...)
_, err := handler.dataStore.WriteChunk(id, 0, reader)
return handler.dataStore.WriteChunk(id, 0, reader) return err
} }
// Parse the Upload-Metadata header as defined in the File Creation extension. // Parse the Upload-Metadata header as defined in the File Creation extension.

View File

@ -12,8 +12,8 @@ type zeroStore struct{}
func (store zeroStore) NewUpload(info FileInfo) (string, error) { func (store zeroStore) NewUpload(info FileInfo) (string, error) {
return "", nil return "", nil
} }
func (store zeroStore) WriteChunk(id string, offset int64, src io.Reader) error { func (store zeroStore) WriteChunk(id string, offset int64, src io.Reader) (int64, error) {
return nil return 0, nil
} }
func (store zeroStore) GetInfo(id string) (FileInfo, error) { func (store zeroStore) GetInfo(id string) (FileInfo, error) {

View File

@ -26,7 +26,7 @@ func (s patchStore) GetInfo(id string) (FileInfo, error) {
}, nil }, nil
} }
func (s patchStore) WriteChunk(id string, offset int64, src io.Reader) error { func (s patchStore) WriteChunk(id string, offset int64, src io.Reader) (int64, error) {
if s.called { if s.called {
s.t.Errorf("WriteChunk must be called only once") s.t.Errorf("WriteChunk must be called only once")
} }
@ -45,7 +45,7 @@ func (s patchStore) WriteChunk(id string, offset int64, src io.Reader) error {
s.t.Errorf("Expected source to be 'hello'") s.t.Errorf("Expected source to be 'hello'")
} }
return nil return 5, nil
} }
func TestPatch(t *testing.T) { func TestPatch(t *testing.T) {
@ -66,6 +66,9 @@ func TestPatch(t *testing.T) {
}, },
ReqBody: strings.NewReader("hello"), ReqBody: strings.NewReader("hello"),
Code: http.StatusNoContent, Code: http.StatusNoContent,
ResHeader: map[string]string{
"Upload-Offset": "10",
},
}).Run(handler, t) }).Run(handler, t)
(&httpTest{ (&httpTest{
@ -120,7 +123,7 @@ func (s overflowPatchStore) GetInfo(id string) (FileInfo, error) {
}, nil }, nil
} }
func (s overflowPatchStore) WriteChunk(id string, offset int64, src io.Reader) error { func (s overflowPatchStore) WriteChunk(id string, offset int64, src io.Reader) (int64, error) {
if s.called { if s.called {
s.t.Errorf("WriteChunk must be called only once") s.t.Errorf("WriteChunk must be called only once")
} }
@ -139,7 +142,7 @@ func (s overflowPatchStore) WriteChunk(id string, offset int64, src io.Reader) e
s.t.Errorf("Expected 15 bytes got %v", len(data)) s.t.Errorf("Expected 15 bytes got %v", len(data))
} }
return nil return 15, nil
} }
// noEOFReader implements io.Reader, io.Writer, io.Closer but does not return // noEOFReader implements io.Reader, io.Writer, io.Closer but does not return