diff --git a/openapi3filter/validate_request.go b/openapi3filter/validate_request.go index 4b0bd3413..beb47aaad 100644 --- a/openapi3filter/validate_request.go +++ b/openapi3filter/validate_request.go @@ -285,6 +285,7 @@ func ValidateRequestBody(ctx context.Context, input *RequestValidationInput, req } // Put the data back into the input req.Body = ioutil.NopCloser(bytes.NewReader(data)) + req.ContentLength = int64(len(data)) } return nil diff --git a/openapi3filter/validate_request_test.go b/openapi3filter/validate_request_test.go index 957b6925e..450ee5988 100644 --- a/openapi3filter/validate_request_test.go +++ b/openapi3filter/validate_request_test.go @@ -59,6 +59,9 @@ paths: properties: subCategory: type: string + category: + type: string + default: Sweets responses: '201': description: Created @@ -95,6 +98,7 @@ components: type testRequestBody struct { SubCategory string `json:"subCategory"` + Category string `json:"category,omitempty"` } type args struct { requestBody *testRequestBody @@ -102,18 +106,30 @@ components: apiKey string } tests := []struct { - name string - args args - expectedErr error + name string + args args + expectedModification bool + expectedErr error }{ { - name: "Valid request", + name: "Valid request with all fields set", + args: args{ + requestBody: &testRequestBody{SubCategory: "Chocolate", Category: "Food"}, + url: "/category?category=cookies", + apiKey: "SomeKey", + }, + expectedModification: false, + expectedErr: nil, + }, + { + name: "Valid request without certain fields", args: args{ requestBody: &testRequestBody{SubCategory: "Chocolate"}, url: "/category?category=cookies", apiKey: "SomeKey", }, - expectedErr: nil, + expectedModification: true, + expectedErr: nil, }, { name: "Invalid operation params", @@ -122,7 +138,8 @@ components: url: "/category?invalidCategory=badCookie", apiKey: "SomeKey", }, - expectedErr: &RequestError{}, + expectedModification: false, + expectedErr: &RequestError{}, }, { name: "Invalid request body", @@ -131,7 +148,8 @@ components: url: "/category?category=cookies", apiKey: "SomeKey", }, - expectedErr: &RequestError{}, + expectedModification: false, + expectedErr: &RequestError{}, }, { name: "Invalid security", @@ -140,7 +158,8 @@ components: url: "/category?category=cookies", apiKey: "", }, - expectedErr: &SecurityRequirementsError{}, + expectedModification: false, + expectedErr: &SecurityRequirementsError{}, }, { name: "Invalid request body and security", @@ -149,16 +168,19 @@ components: url: "/category?category=cookies", apiKey: "", }, - expectedErr: &SecurityRequirementsError{}, + expectedModification: false, + expectedErr: &SecurityRequirementsError{}, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { var requestBody io.Reader + var originalBodySize int if tc.args.requestBody != nil { testingBody, err := json.Marshal(tc.args.requestBody) require.NoError(t, err) requestBody = bytes.NewReader(testingBody) + originalBodySize = len(testingBody) } req, err := http.NewRequest(http.MethodPost, tc.args.url, requestBody) require.NoError(t, err) @@ -180,6 +202,16 @@ components: } err = ValidateRequest(context.Background(), validationInput) assert.IsType(t, tc.expectedErr, err, "ValidateRequest(): error = %v, expectedError %v", err, tc.expectedErr) + if tc.expectedErr != nil { + return + } + body, err := io.ReadAll(validationInput.Request.Body) + contentLen := int(validationInput.Request.ContentLength) + bodySize := len(body) + assert.NoError(t, err, "unable to read request body: %v", err) + assert.Equal(t, contentLen, bodySize, "expect ContentLength %d to equal body size %d", contentLen, bodySize) + bodyModified := originalBodySize != bodySize + assert.Equal(t, bodyModified, tc.expectedModification, "expect request body modification happened: %t, expected %t", bodyModified, tc.expectedModification) }) } }