diff --git a/api/handler/put.go b/api/handler/put.go index 3e5e287f..ee8764ef 100644 --- a/api/handler/put.go +++ b/api/handler/put.go @@ -54,17 +54,29 @@ func (p *postPolicy) condition(key string) *policyCondition { return nil } -func (p *postPolicy) CheckContentLength(size uint64) bool { +func (p *postPolicy) CheckContentLength(size uint64) error { if p.empty { - return true + return nil } for _, condition := range p.Conditions { if condition.Matching == "content-length-range" { - length := strconv.FormatUint(size, 10) - return condition.Key <= length && length <= condition.Value + start, err := strconv.ParseUint(condition.Key, 10, 64) + if err != nil { + return errInvalidCondition + } + + end, err := strconv.ParseUint(condition.Value, 10, 64) + if err != nil { + return errInvalidCondition + } + + if start <= size && size <= end { + return nil + } + return fmt.Errorf("length of the content did not fall within the range specified in the condition") } } - return true + return nil } func (p *policyCondition) match(value string) bool { @@ -560,8 +572,8 @@ func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) { return } - if !policy.CheckContentLength(size) { - h.logAndSendError(ctx, w, "invalid content-length", reqInfo, apierr.GetAPIError(apierr.ErrInvalidArgument)) + if err := policy.CheckContentLength(size); err != nil { + h.logAndSendError(ctx, w, err.Error(), reqInfo, apierr.GetAPIError(apierr.ErrPostPolicyConditionInvalidFormat)) return } diff --git a/api/handler/put_test.go b/api/handler/put_test.go index 5178efce..bc4a063f 100644 --- a/api/handler/put_test.go +++ b/api/handler/put_test.go @@ -1206,6 +1206,104 @@ func TestFormEncryptionParamsBase(t *testing.T) { } } +func TestCheckContentLength(t *testing.T) { + contentLength := "content-length-range" + notFallError := "length of the content did not fall within the range specified in the condition" + parseError := "invalid condition" + for _, tc := range []struct { + name string + matching string + key string + value string + size uint64 + errMsg string + emptyPolicy bool + }{ + { + name: "valid", + matching: contentLength, + key: "0", + value: "1000", + size: 50, + }, + { + name: "valid lower limit", + matching: contentLength, + key: "5", + value: "100", + size: 5, + }, + { + name: "valid upper limit", + matching: contentLength, + key: "5", + value: "100", + size: 100, + }, + { + name: "invalid size value (too small)", + matching: contentLength, + key: "5", + value: "100", + size: 2, + errMsg: notFallError, + }, + { + name: "invalid size value (to high)", + matching: contentLength, + key: "5", + value: "100", + size: 200, + errMsg: notFallError, + }, + { + name: "no matching", + }, + { + name: "invalid key type", + matching: contentLength, + key: "invalid", + value: "100", + size: 10, + errMsg: parseError, + }, + { + name: "invalid value type", + matching: contentLength, + key: "5", + value: "invalid", + size: 10, + errMsg: parseError, + }, + { + name: "empty policy", + emptyPolicy: true, + }, + } { + t.Run(tc.name, func(t *testing.T) { + policy := &postPolicy{ + Conditions: []*policyCondition{ + { + Matching: tc.matching, + Key: tc.key, + Value: tc.value, + }, + }, + empty: tc.emptyPolicy, + } + + err := policy.CheckContentLength(tc.size) + if tc.errMsg != "" { + require.Error(t, err) + require.Contains(t, err.Error(), tc.errMsg) + return + } + + require.NoError(t, err) + }) + } +} + func prepareRequestForEncryption(hc *handlerContext, algo, key, md5, tlsTermination string, reqWithoutTLS, reqWithoutSSE, isCopySource bool) *http.Request { r := httptest.NewRequest(http.MethodPost, "/", nil)