From 290fea5dac90245c9f6c140333fa8308babfddc1 Mon Sep 17 00:00:00 2001 From: Acconut Date: Mon, 23 Mar 2015 19:02:12 +0100 Subject: [PATCH] return new offset after successful PATCH request --- concat_test.go | 4 ++-- datastore.go | 3 ++- filestore/filestore.go | 8 ++++---- filestore/filestore_test.go | 5 ++++- handler.go | 8 ++++++-- handler_test.go | 4 ++-- patch_test.go | 11 +++++++---- 7 files changed, 27 insertions(+), 16 deletions(-) diff --git a/concat_test.go b/concat_test.go index 074b87d..7182a40 100644 --- a/concat_test.go +++ b/concat_test.go @@ -132,7 +132,7 @@ func (s concatFinalStore) GetReader(id string) (io.Reader, error) { 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" { 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") } - return nil + return 10, nil } func TestConcatFinal(t *testing.T) { diff --git a/datastore.go b/datastore.go index b7766d2..e536254 100644 --- a/datastore.go +++ b/datastore.go @@ -37,7 +37,8 @@ type DataStore interface { // 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 // 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 // requests. It may return an os.ErrNotExist which will be interpretet as a // 404 Not Found. diff --git a/filestore/filestore.go b/filestore/filestore.go index 1873e9a..a3a80b6 100644 --- a/filestore/filestore.go +++ b/filestore/filestore.go @@ -42,20 +42,20 @@ func (store FileStore) NewUpload(info tusd.FileInfo) (id string, err error) { 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) if err != nil { - return err + return 0, err } defer file.Close() n, err := io.Copy(file, src) if n > 0 { 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) { diff --git a/filestore/filestore_test.go b/filestore/filestore_test.go index fc983a6..74c4dfc 100644 --- a/filestore/filestore_test.go +++ b/filestore/filestore_test.go @@ -51,10 +51,13 @@ func TestFilestore(t *testing.T) { } // 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 { t.Fatal(err) } + if bytesWritten != int64(len("hello world")) { + t.Errorf("expected 11 bytes to be written") + } // Check new offset info, err = store.GetInfo(id) diff --git a/handler.go b/handler.go index 7dc5c79..49e59cf 100644 --- a/handler.go +++ b/handler.go @@ -314,12 +314,15 @@ func (handler *Handler) patchFile(w http.ResponseWriter, r *http.Request) { // Limit the reader := io.LimitReader(r.Body, maxSize) - err = handler.dataStore.WriteChunk(id, offset, reader) + bytesWritten, err := handler.dataStore.WriteChunk(id, offset, reader) if err != nil { handler.sendError(w, err) return } + // Send new offset to client + w.Header().Set("Upload-Offset", strconv.FormatInt(offset+bytesWritten, 10)) + w.WriteHeader(http.StatusNoContent) } @@ -462,8 +465,9 @@ func (handler *Handler) fillFinalUpload(id string, uploads []string) error { } 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. diff --git a/handler_test.go b/handler_test.go index 6c5a41b..4187248 100644 --- a/handler_test.go +++ b/handler_test.go @@ -12,8 +12,8 @@ type zeroStore struct{} func (store zeroStore) NewUpload(info FileInfo) (string, error) { return "", nil } -func (store zeroStore) WriteChunk(id string, offset int64, src io.Reader) error { - return nil +func (store zeroStore) WriteChunk(id string, offset int64, src io.Reader) (int64, error) { + return 0, nil } func (store zeroStore) GetInfo(id string) (FileInfo, error) { diff --git a/patch_test.go b/patch_test.go index 5edfe81..e67d859 100644 --- a/patch_test.go +++ b/patch_test.go @@ -26,7 +26,7 @@ func (s patchStore) GetInfo(id string) (FileInfo, error) { }, 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 { 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'") } - return nil + return 5, nil } func TestPatch(t *testing.T) { @@ -66,6 +66,9 @@ func TestPatch(t *testing.T) { }, ReqBody: strings.NewReader("hello"), Code: http.StatusNoContent, + ResHeader: map[string]string{ + "Upload-Offset": "10", + }, }).Run(handler, t) (&httpTest{ @@ -120,7 +123,7 @@ func (s overflowPatchStore) GetInfo(id string) (FileInfo, error) { }, 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 { 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)) } - return nil + return 15, nil } // noEOFReader implements io.Reader, io.Writer, io.Closer but does not return