Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/docs/openapi3filter.txt
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,9 @@ type Options struct {
// Set RegexCompiler to override the regex implementation
RegexCompiler openapi3.RegexCompilerFunc

// Set RejectWhenRequestBodyNotSpecified so ValidateRequest fails when request body is present but not defined in the specification
RejectWhenRequestBodyNotSpecified bool

// A document with security schemes defined will not pass validation
// unless an AuthenticationFunc is defined.
// See NoopAuthenticationFunc
Expand Down
3 changes: 3 additions & 0 deletions openapi3filter/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ type Options struct {
// Set RegexCompiler to override the regex implementation
RegexCompiler openapi3.RegexCompilerFunc

// Set RejectWhenRequestBodyNotSpecified so ValidateRequest fails when request body is present but not defined in the specification
RejectWhenRequestBodyNotSpecified bool

// A document with security schemes defined will not pass validation
// unless an AuthenticationFunc is defined.
// See NoopAuthenticationFunc
Expand Down
110 changes: 110 additions & 0 deletions openapi3filter/testdata/issue1100_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package openapi3filter

import (
"net/http"
"strings"
"testing"

"github.com/getkin/kin-openapi/openapi3filter"
"github.com/stretchr/testify/require"

"github.com/getkin/kin-openapi/openapi3"
"github.com/getkin/kin-openapi/routers/gorillamux"
)

func TestIssue1100(t *testing.T) {
spec := `
openapi: 3.0.3
info:
version: 1.0.0
title: sample api
description: api service paths to test the issue
paths:
/api/path:
post:
summary: path
tags:
- api
responses:
'200':
description: Ok
`[1:]

loader := openapi3.NewLoader()

doc, err := loader.LoadFromData([]byte(spec))
require.NoError(t, err)

err = doc.Validate(loader.Context)
require.NoError(t, err)

router, err := gorillamux.NewRouter(doc)
require.NoError(t, err)

for _, testcase := range []struct {
name string
endpoint string
ct string
data string
rejectBody bool
shouldFail bool
}{
{
name: "json success",
endpoint: "/api/path",
ct: "application/json",
data: ``,
rejectBody: false,
shouldFail: false,
},
{
name: "json failure",
endpoint: "/api/path",
ct: "application/json",
data: `{"data":"some+unexpected+data"}`,
rejectBody: false,
shouldFail: false,
},
{
name: "json success",
endpoint: "/api/path",
ct: "application/json",
data: ``,
rejectBody: true,
shouldFail: false,
},
{
name: "json failure",
endpoint: "/api/path",
ct: "application/json",
data: `{"data":"some+unexpected+data"}`,
rejectBody: true,
shouldFail: true,
},
} {
t.Run(
testcase.name, func(t *testing.T) {
data := strings.NewReader(testcase.data)
req, err := http.NewRequest("POST", testcase.endpoint, data)
require.NoError(t, err)
req.Header.Add("Content-Type", testcase.ct)

route, pathParams, err := router.FindRoute(req)
require.NoError(t, err)

validationInput := &openapi3filter.RequestValidationInput{
Request: req,
PathParams: pathParams,
Route: route,
Options: &openapi3filter.Options{RejectWhenRequestBodyNotSpecified: testcase.rejectBody},
}
err = openapi3filter.ValidateRequest(loader.Context, validationInput)
if testcase.shouldFail {
require.Error(t, err, "This test case should fail "+testcase.data)
} else {
require.NoError(t, err, "This test case should pass "+testcase.data)
}
},
)
}
}
19 changes: 17 additions & 2 deletions openapi3filter/validate_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,23 @@ func ValidateRequest(ctx context.Context, input *RequestValidationInput) error {

// RequestBody
requestBody := operation.RequestBody
if requestBody != nil && !options.ExcludeRequestBody {
if err := ValidateRequestBody(ctx, input, requestBody.Value); err != nil {
if !options.ExcludeRequestBody {
// Validate specification request body if present
if requestBody != nil {
if err := ValidateRequestBody(ctx, input, requestBody.Value); err != nil {
if !options.MultiError {
return err
}
me = append(me, err)
}
}

// Reject if specification request body if not present (not wanted) but is present in the HTTP request
if options.RejectWhenRequestBodyNotSpecified && input.Request.ContentLength > 0 {
err := &RequestError{
Input: input,
Err: fmt.Errorf("request body not allowed for this request"),
}
if !options.MultiError {
return err
}
Expand Down
Loading