From d8c2bf6f86432db27ae9b0c23d5b6d70898120a5 Mon Sep 17 00:00:00 2001 From: He Weiwei Date: Wed, 25 Sep 2019 09:13:53 +0000 Subject: [PATCH] fix(quota): handle range header missing in response Signed-off-by: He Weiwei --- src/core/middlewares/sizequota/builder.go | 4 +- src/core/middlewares/sizequota/util.go | 11 +++- src/core/middlewares/sizequota/util_test.go | 59 +++++++++++++++++++++ 3 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 src/core/middlewares/sizequota/util_test.go diff --git a/src/core/middlewares/sizequota/builder.go b/src/core/middlewares/sizequota/builder.go index b3085f4d6..d24277207 100644 --- a/src/core/middlewares/sizequota/builder.go +++ b/src/core/middlewares/sizequota/builder.go @@ -36,7 +36,7 @@ var ( } ) -// blobStreamUploadBuilder interceptor for PATCH /v2//blobs/uploads/ +// blobStreamUploadBuilder interceptor builder for PATCH /v2//blobs/uploads/ type blobStreamUploadBuilder struct{} func (*blobStreamUploadBuilder) Build(req *http.Request) (interceptor.Interceptor, error) { @@ -50,7 +50,7 @@ func (*blobStreamUploadBuilder) Build(req *http.Request) (interceptor.Intercepto onResponse := func(w http.ResponseWriter, req *http.Request) { size, err := parseUploadedBlobSize(w) if err != nil { - log.Errorf("failed to parse uploaded blob size for upload %s", uuid) + log.Errorf("failed to parse uploaded blob size for upload %s, error: %v", uuid, err) return } diff --git a/src/core/middlewares/sizequota/util.go b/src/core/middlewares/sizequota/util.go index 965b96c5b..26d1c8e0c 100644 --- a/src/core/middlewares/sizequota/util.go +++ b/src/core/middlewares/sizequota/util.go @@ -42,9 +42,16 @@ func parseUploadedBlobSize(w http.ResponseWriter) (int64, error) { // Range: Range indicating the current progress of the upload. // https://github.com/opencontainers/distribution-spec/blob/master/spec.md#get-blob-upload r := w.Header().Get("Range") + if r == "" { + return 0, errors.New("range header not found") + } - end := strings.Split(r, "-")[1] - size, err := strconv.ParseInt(end, 10, 64) + parts := strings.SplitN(r, "-", 2) + if len(parts) != 2 { + return 0, fmt.Errorf("range header bad value: %s", r) + } + + size, err := strconv.ParseInt(parts[1], 10, 64) if err != nil { return 0, err } diff --git a/src/core/middlewares/sizequota/util_test.go b/src/core/middlewares/sizequota/util_test.go new file mode 100644 index 000000000..93be6fcd9 --- /dev/null +++ b/src/core/middlewares/sizequota/util_test.go @@ -0,0 +1,59 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package sizequota + +import ( + "net/http" + "net/http/httptest" + "testing" +) + +func Test_parseUploadedBlobSize(t *testing.T) { + writer := func(header string) http.ResponseWriter { + rr := httptest.NewRecorder() + if header != "" { + rr.Header().Add("Range", header) + } + return rr + } + type args struct { + w http.ResponseWriter + } + tests := []struct { + name string + args args + want int64 + wantErr bool + }{ + {"success", args{writer("0-99")}, 100, false}, + {"ranage header not found", args{writer("")}, 0, true}, + {"ranage header bad value", args{writer("0")}, 0, true}, + {"ranage header bad value", args{writer("0-")}, 0, true}, + {"ranage header bad value", args{writer("0-a")}, 0, true}, + {"ranage header bad value", args{writer("0-1-2")}, 0, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := parseUploadedBlobSize(tt.args.w) + if (err != nil) != tt.wantErr { + t.Errorf("parseUploadedBlobSize() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("parseUploadedBlobSize() = %v, want %v", got, tt.want) + } + }) + } +}