diff --git a/middleware/concurrent_limiter.go b/middleware/concurrent_limiter.go index 724e936..a6f2777 100644 --- a/middleware/concurrent_limiter.go +++ b/middleware/concurrent_limiter.go @@ -39,6 +39,11 @@ var ( Message: "submit too frequently", Category: ErrConcurrentLimiterCategory, } + ErrNotAllowEmpty = &hes.Error{ + StatusCode: http.StatusBadRequest, + Message: "empty value is not allowed", + Category: ErrConcurrentLimiterCategory, + } ErrRequireLockFunction = errors.New("require lock function") ) @@ -61,6 +66,8 @@ type ( // Lock lock function Lock ConcurrentLimiterLock Skipper elton.Skipper + // NotAllowEmpty is value is empty, will return error + NotAllowEmpty bool } // concurrentLimiterKeyInfo the concurrent key's info concurrentLimiterKeyInfo struct { @@ -142,6 +149,10 @@ func NewConcurrentLimiter(config ConcurrentLimiterConfig) elton.Handler { } else { v = gjson.GetBytes(c.RequestBody, name).String() } + if config.NotAllowEmpty && len(v) == 0 { + err = ErrNotAllowEmpty + return + } sb.WriteString(v) if i < keyLength-1 { sb.WriteRune(',') diff --git a/middleware/concurrent_limiter_test.go b/middleware/concurrent_limiter_test.go index 0ede2fa..8a9af16 100644 --- a/middleware/concurrent_limiter_test.go +++ b/middleware/concurrent_limiter_test.go @@ -119,4 +119,20 @@ func TestConcurrentLimiter(t *testing.T) { err := fn(c) assert.Equal("message=key is invalid", err.Error()) }) + + t.Run("not allow empty", func(t *testing.T) { + assert := assert.New(t) + fn := NewConcurrentLimiter(ConcurrentLimiterConfig{ + NotAllowEmpty: true, + Keys: []string{ + "p:id", + }, + Lock: func(key string, c *elton.Context) (success bool, unlock func(), err error) { + return + }, + }) + c := elton.NewContext(nil, httptest.NewRequest("GET", "/", nil)) + err := fn(c) + assert.Equal(ErrNotAllowEmpty, err) + }) }