fix(quota): allowed to put blob which size is zero (#11314)

Closes #11239

Signed-off-by: He Weiwei <hweiwei@vmware.com>
This commit is contained in:
He Weiwei 2020-03-27 14:39:25 +08:00 committed by GitHub
parent 9440df1090
commit 033d6dac6b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 81 additions and 29 deletions

View File

@ -305,6 +305,10 @@ func (c *controller) GetAcceptedBlobSize(sessionID string) (int64, error) {
key := fmt.Sprintf("upload:%s:size", sessionID) key := fmt.Sprintf("upload:%s:size", sessionID)
size, err := redis.Int64(conn.Do("GET", key)) size, err := redis.Int64(conn.Do("GET", key))
if err != nil { if err != nil {
if err == redis.ErrNil {
return 0, nil
}
return 0, err return 0, err
} }

View File

@ -257,7 +257,8 @@ func (suite *ControllerTestSuite) TestGetSetAcceptedBlobSize() {
sessionID := uuid.New().String() sessionID := uuid.New().String()
size, err := Ctl.GetAcceptedBlobSize(sessionID) size, err := Ctl.GetAcceptedBlobSize(sessionID)
suite.NotNil(err) suite.Nil(err)
suite.Equal(int64(0), size)
suite.Nil(Ctl.SetAcceptedBlobSize(sessionID, 100)) suite.Nil(Ctl.SetAcceptedBlobSize(sessionID, 100))

View File

@ -44,6 +44,11 @@ func putBlobUploadResources(r *http.Request, reference, referenceID string) (typ
return nil, err return nil, err
} }
if size == 0 {
logger.Debug("blob size is 0")
return nil, nil
}
projectID, _ := strconv.ParseInt(referenceID, 10, 64) projectID, _ := strconv.ParseInt(referenceID, 10, 64)
digest := r.URL.Query().Get("digest") digest := r.URL.Query().Get("digest")

View File

@ -15,8 +15,10 @@
package quota package quota
import ( import (
"fmt"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"strconv"
"testing" "testing"
"github.com/goharbor/harbor/src/pkg/types" "github.com/goharbor/harbor/src/pkg/types"
@ -26,46 +28,86 @@ import (
type PutBlobUploadMiddlewareTestSuite struct { type PutBlobUploadMiddlewareTestSuite struct {
RequestMiddlewareTestSuite RequestMiddlewareTestSuite
handler http.Handler
} }
func (suite *PutBlobUploadMiddlewareTestSuite) TestMiddleware() { func (suite *PutBlobUploadMiddlewareTestSuite) SetupTest() {
mock.OnAnything(suite.quotaController, "IsEnabled").Return(true, nil) suite.RequestMiddlewareTestSuite.SetupTest()
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
}) })
suite.handler = PutBlobUploadMiddleware()(next)
mock.OnAnything(suite.quotaController, "IsEnabled").Return(true, nil)
}
func (suite *PutBlobUploadMiddlewareTestSuite) makeRequest(contentLength int) *http.Request {
url := "/v2/library/photon/blobs/uploads/cbabe458-28a1-4e1b-ad15-0cb0229df4e8?digest=sha256:57c2ec3bf82f09c94be2e5c5beb124b86fcbb42e76fb82c99066c054422010e4" url := "/v2/library/photon/blobs/uploads/cbabe458-28a1-4e1b-ad15-0cb0229df4e8?digest=sha256:57c2ec3bf82f09c94be2e5c5beb124b86fcbb42e76fb82c99066c054422010e4"
req := httptest.NewRequest(http.MethodPut, url, nil)
req.Header.Set("Content-Length", strconv.Itoa(contentLength))
{ return req
mock.OnAnything(suite.blobController, "Exist").Return(true, nil).Once() }
req := httptest.NewRequest(http.MethodPut, url, nil) func (suite *PutBlobUploadMiddlewareTestSuite) TestBlobSizeIsZero() {
req.Header.Set("Content-Length", "100") mock.OnAnything(suite.blobController, "GetAcceptedBlobSize").Return(int64(0), nil)
rr := httptest.NewRecorder()
PutBlobUploadMiddleware()(next).ServeHTTP(rr, req) req := suite.makeRequest(0)
suite.Equal(http.StatusOK, rr.Code) rr := httptest.NewRecorder()
}
{ suite.handler.ServeHTTP(rr, req)
mock.OnAnything(suite.blobController, "Exist").Return(false, nil).Once() suite.Equal(http.StatusOK, rr.Code)
mock.OnAnything(suite.quotaController, "Request").Return(nil).Once().Run(func(args mock.Arguments) { }
resources := args.Get(3).(types.ResourceList)
suite.Len(resources, 1)
suite.Equal(resources[types.ResourceStorage], int64(100))
f := args.Get(4).(func() error) func (suite *PutBlobUploadMiddlewareTestSuite) TestGetAcceptedBlobSizeFailed() {
f() mock.OnAnything(suite.blobController, "GetAcceptedBlobSize").Return(int64(0), fmt.Errorf("error"))
})
req := httptest.NewRequest(http.MethodPut, url, nil) req := suite.makeRequest(0)
req.Header.Set("Content-Length", "100") rr := httptest.NewRecorder()
rr := httptest.NewRecorder()
PutBlobUploadMiddleware()(next).ServeHTTP(rr, req) suite.handler.ServeHTTP(rr, req)
suite.Equal(http.StatusOK, rr.Code) suite.Equal(http.StatusInternalServerError, rr.Code)
} }
func (suite *PutBlobUploadMiddlewareTestSuite) TestBlobExist() {
mock.OnAnything(suite.blobController, "Exist").Return(true, nil)
req := suite.makeRequest(100)
rr := httptest.NewRecorder()
suite.handler.ServeHTTP(rr, req)
suite.Equal(http.StatusOK, rr.Code)
}
func (suite *PutBlobUploadMiddlewareTestSuite) TestBlobNotExist() {
mock.OnAnything(suite.blobController, "Exist").Return(false, nil).Once()
mock.OnAnything(suite.quotaController, "Request").Return(nil).Once().Run(func(args mock.Arguments) {
resources := args.Get(3).(types.ResourceList)
suite.Len(resources, 1)
suite.Equal(resources[types.ResourceStorage], int64(100))
f := args.Get(4).(func() error)
f()
})
req := suite.makeRequest(100)
rr := httptest.NewRecorder()
suite.handler.ServeHTTP(rr, req)
suite.Equal(http.StatusOK, rr.Code)
}
func (suite *PutBlobUploadMiddlewareTestSuite) TestBlobExistFailed() {
mock.OnAnything(suite.blobController, "Exist").Return(false, fmt.Errorf("error"))
req := suite.makeRequest(100)
rr := httptest.NewRecorder()
suite.handler.ServeHTTP(rr, req)
suite.Equal(http.StatusInternalServerError, rr.Code)
} }
func TestPutBlobUploadMiddlewareTestSuite(t *testing.T) { func TestPutBlobUploadMiddlewareTestSuite(t *testing.T) {

View File

@ -83,7 +83,7 @@ func RequestMiddleware(config RequestConfig, skippers ...middleware.Skipper) fun
if !enabled { if !enabled {
// quota is disabled for the reference object, so direct to next handler // quota is disabled for the reference object, so direct to next handler
logger.Infof("quota is disabled for %s %s, so direct to next handler", reference, referenceID) logger.Debugf("quota is disabled for %s %s, so direct to next handler", reference, referenceID)
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
return return
} }
@ -98,7 +98,7 @@ func RequestMiddleware(config RequestConfig, skippers ...middleware.Skipper) fun
if len(resources) == 0 { if len(resources) == 0 {
// no resources request for this http request, so direct to next handler // no resources request for this http request, so direct to next handler
logger.Info("no resources request for this http request, so direct to next handler") logger.Debug("no resources request for this http request, so direct to next handler")
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
return return
} }
@ -206,7 +206,7 @@ func RefreshMiddleware(config RefreshConfig, skipers ...middleware.Skipper) func
} }
if !enabled { if !enabled {
logger.Infof("quota is disabled for %s %s, so return directly", reference, referenceID) logger.Debugf("quota is disabled for %s %s, so return directly", reference, referenceID)
return nil return nil
} }