From b0dd68152d7ce274da9032515c3f09271a1d76c8 Mon Sep 17 00:00:00 2001 From: fanpei-tes Date: Wed, 8 Jul 2020 15:15:41 +0800 Subject: [PATCH] support Range --- pkg/filestore/filestore.go | 5 +++-- pkg/gcsstore/gcsstore.go | 6 +++--- pkg/handler/datastore.go | 2 +- pkg/handler/unrouted_handler.go | 17 ++++++++++++----- pkg/s3store/s3store.go | 29 +++++++++++++---------------- 5 files changed, 32 insertions(+), 27 deletions(-) diff --git a/pkg/filestore/filestore.go b/pkg/filestore/filestore.go index 62e28bfcb..a381ae392 100644 --- a/pkg/filestore/filestore.go +++ b/pkg/filestore/filestore.go @@ -169,8 +169,9 @@ func (upload *fileUpload) WriteChunk(ctx context.Context, offset int64, src io.R return n, err } -func (upload *fileUpload) GetReader(ctx context.Context, rw http.ResponseWriter, req *http.Request) (io.Reader, error) { - return os.Open(upload.binPath) +func (upload *fileUpload) GetReader(ctx context.Context, req *http.Request) (io.Reader, string, int, error) { + src, err := os.Open(upload.binPath) + return src, "", 0, err } func (upload *fileUpload) Terminate(ctx context.Context) error { diff --git a/pkg/gcsstore/gcsstore.go b/pkg/gcsstore/gcsstore.go index 5ef1d8fe3..1cf63b2d2 100644 --- a/pkg/gcsstore/gcsstore.go +++ b/pkg/gcsstore/gcsstore.go @@ -322,7 +322,7 @@ func (upload gcsUpload) Terminate(ctx context.Context) error { return nil } -func (upload gcsUpload) GetReader(ctx context.Context, rw http.ResponseWriter, req *http.Request) (io.Reader, error) { +func (upload gcsUpload) GetReader(ctx context.Context, req *http.Request) (io.Reader, string, int, error) { id := upload.id store := upload.store @@ -333,10 +333,10 @@ func (upload gcsUpload) GetReader(ctx context.Context, rw http.ResponseWriter, r r, err := store.Service.ReadObject(ctx, params) if err != nil { - return nil, err + return nil, "", 0, err } - return r, nil + return r, "", 0, nil } func (store GCSStore) keyWithPrefix(key string) string { diff --git a/pkg/handler/datastore.go b/pkg/handler/datastore.go index aeb6255b2..469724496 100644 --- a/pkg/handler/datastore.go +++ b/pkg/handler/datastore.go @@ -68,7 +68,7 @@ type Upload interface { // Close() method will be invoked once everything has been read. // If the given upload could not be found, the error tusd.ErrNotFound should // be returned. - GetReader(ctx context.Context, rw http.ResponseWriter, req *http.Request) (io.Reader, error) + GetReader(ctx context.Context, req *http.Request) (io.Reader, string, int, error) // FinisherDataStore is the interface which can be implemented by DataStores // which need to do additional operations once an entire upload has been // completed. These tasks may include but are not limited to freeing unused diff --git a/pkg/handler/unrouted_handler.go b/pkg/handler/unrouted_handler.go index bb1f1afaa..9b17e43e2 100644 --- a/pkg/handler/unrouted_handler.go +++ b/pkg/handler/unrouted_handler.go @@ -744,26 +744,33 @@ func (handler *UnroutedHandler) GetFile(w http.ResponseWriter, r *http.Request) return } - // Set headers before sending responses - w.Header().Set("Content-Length", strconv.FormatInt(info.Offset, 10)) - contentType, _ := filterContentType(info) w.Header().Set("Content-Type", contentType) //w.Header().Set("Content-Disposition", contentDisposition) // If no data has been uploaded yet, respond with an empty "204 No Content" status. if info.Offset == 0 { + w.Header().Set("Content-Length", "0") handler.sendResp(w, r, http.StatusNoContent) return } - src, err := upload.GetReader(ctx, w, r) + src, contentRange, contentLength, err := upload.GetReader(ctx, r) if err != nil { handler.sendError(w, r, err) return } - handler.sendResp(w, r, http.StatusOK) + if contentRange != "" && contentLength > 0 { + w.Header().Set("Content-Length", strconv.FormatInt(int64(contentLength), 10)) + w.Header().Set("Content-Range", contentRange) + w.Header().Set("Accept-Ranges", "bytes") + handler.sendResp(w, r, http.StatusPartialContent) + } else { + w.Header().Set("Content-Length", strconv.FormatInt(info.Offset, 10)) + handler.sendResp(w, r, http.StatusOK) + } + io.Copy(w, src) // Try to close the reader if the io.Closer interface is implemented diff --git a/pkg/s3store/s3store.go b/pkg/s3store/s3store.go index 3cd9246bd..f89b453c8 100644 --- a/pkg/s3store/s3store.go +++ b/pkg/s3store/s3store.go @@ -457,7 +457,7 @@ func (upload s3Upload) fetchInfo(ctx context.Context) (info handler.FileInfo, er return } -func (upload s3Upload) GetReader(ctx context.Context, rw http.ResponseWriter, req *http.Request) (io.Reader, error) { +func (upload s3Upload) GetReader(ctx context.Context, req *http.Request) (io.Reader, string, int, error) { id := upload.id store := upload.store uploadId := id @@ -465,7 +465,7 @@ func (upload s3Upload) GetReader(ctx context.Context, rw http.ResponseWriter, re if upload.info == nil { info, err := upload.fetchInfo(ctx) if err != nil { - return nil, err + return nil, "", 0, err } upload.info = &info } @@ -480,28 +480,25 @@ func (upload s3Upload) GetReader(ctx context.Context, rw http.ResponseWriter, re input.SetRange(req.Header.Get("Range")) } + var contentLength int + var contentRange string + res, err := store.Service.GetObjectWithContext(ctx, input) if err == nil { // No error occurred, and we are able to stream the object - if req != nil && rw != nil { - if req.Header.Get("Range") != "" && res.ContentRange != nil { - rw.WriteHeader(http.StatusPartialContent) - rw.Header().Set("Content-Range", *res.ContentRange) - } - - if res.AcceptRanges != nil { - rw.Header().Set("Accept-Ranges", *res.AcceptRanges) - } + if req != nil && req.Header.Get("Range") != "" && res.ContentRange != nil && res.ContentLength != nil { + contentRange = *res.ContentRange + contentLength = int(*res.ContentLength) } - return res.Body, nil + return res.Body, contentRange, contentLength, nil } // If the file cannot be found, we ignore this error and continue since the // upload may not have been finished yet. In this case we do not want to // return a ErrNotFound but a more meaning-full message. if !isAwsError(err, "NoSuchKey") { - return nil, err + return nil, "", 0, err } // Test whether the multipart upload exists to find out if the upload @@ -514,15 +511,15 @@ func (upload s3Upload) GetReader(ctx context.Context, rw http.ResponseWriter, re }) if err == nil { // The multipart upload still exists, which means we cannot download it yet - return nil, errors.New("cannot stream non-finished upload") + return nil, "", 0, errors.New("cannot stream non-finished upload") } if isAwsError(err, "NoSuchUpload") { // Neither the object nor the multipart upload exists, so we return a 404 - return nil, handler.ErrNotFound + return nil, "", 0, handler.ErrNotFound } - return nil, err + return nil, "", 0, err } func (upload s3Upload) Terminate(ctx context.Context) error {