return new offset after successful PATCH request
This commit is contained in:
parent
e6f058eeca
commit
290fea5dac
|
@ -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) {
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue