diff --git a/openapi3filter/issue624_test.go b/openapi3filter/issue624_test.go index d93682e52..1fdbdea34 100644 --- a/openapi3filter/issue624_test.go +++ b/openapi3filter/issue624_test.go @@ -48,17 +48,22 @@ paths: router, err := gorillamux.NewRouter(doc) require.NoError(t, err) - httpReq, err := http.NewRequest(http.MethodGet, `/items?test=test1`, nil) - require.NoError(t, err) - route, pathParams, err := router.FindRoute(httpReq) - require.NoError(t, err) + for _, testcase := range []string{`test1`, `test[1`} { + t.Run(testcase, func(t *testing.T) { + httpReq, err := http.NewRequest(http.MethodGet, `/items?test=`+testcase, nil) + require.NoError(t, err) - requestValidationInput := &RequestValidationInput{ - Request: httpReq, - PathParams: pathParams, - Route: route, + route, pathParams, err := router.FindRoute(httpReq) + require.NoError(t, err) + + requestValidationInput := &RequestValidationInput{ + Request: httpReq, + PathParams: pathParams, + Route: route, + } + err = ValidateRequest(ctx, requestValidationInput) + require.NoError(t, err) + }) } - err = ValidateRequest(ctx, requestValidationInput) - require.NoError(t, err) } diff --git a/openapi3filter/req_resp_decoder.go b/openapi3filter/req_resp_decoder.go index 515d09cd1..dc83e5ac6 100644 --- a/openapi3filter/req_resp_decoder.go +++ b/openapi3filter/req_resp_decoder.go @@ -227,7 +227,7 @@ type valueDecoder interface { // decodeStyledParameter returns a value of an operation's parameter from HTTP request for // parameters defined using the style format, and whether the parameter is supplied in the input. // The function returns ParseError when HTTP request contains an invalid value of a parameter. -func decodeStyledParameter(param *openapi3.Parameter, input *RequestValidationInput) (interface{}, bool, error) { +func decodeStyledParameter(param *openapi3.Parameter, input *RequestValidationInput, schema *openapi3.SchemaRef) (interface{}, bool, error) { sm, err := param.SerializationMethod() if err != nil { return nil, false, err @@ -253,7 +253,7 @@ func decodeStyledParameter(param *openapi3.Parameter, input *RequestValidationIn return nil, false, fmt.Errorf("unsupported parameter's 'in': %s", param.In) } - return decodeValue(dec, param.Name, sm, param.Schema, param.Required) + return decodeValue(dec, param.Name, sm, schema, param.Required) } func decodeValue(dec valueDecoder, param string, sm *openapi3.SerializationMethod, schema *openapi3.SchemaRef, required bool) (interface{}, bool, error) { diff --git a/openapi3filter/validate_request.go b/openapi3filter/validate_request.go index b09987f74..b6db856a6 100644 --- a/openapi3filter/validate_request.go +++ b/openapi3filter/validate_request.go @@ -129,20 +129,29 @@ func ValidateParameter(ctx context.Context, input *RequestValidationInput, param var value interface{} var err error var found bool - var schema *openapi3.Schema + var schemaRef *openapi3.SchemaRef // Validation will ensure that we either have content or schema. - if parameter.Content != nil { - if value, schema, found, err = decodeContentParameter(parameter, input); err != nil { - return &RequestError{Input: input, Parameter: parameter, Err: err} - } + if parameter.Content == nil { + schemaRef = parameter.Schema + } else if len(parameter.Content) != 1 { + // We only know how to decode a parameter if it has one content, application/json + err = fmt.Errorf("multiple content types for parameter %q", parameter.Name) + return &RequestError{Input: input, Parameter: parameter, Err: err} } else { - if value, found, err = decodeStyledParameter(parameter, input); err != nil { + mt := parameter.Content.Get("application/json") + if mt == nil { + err = fmt.Errorf("parameter %q has no content schema", parameter.Name) return &RequestError{Input: input, Parameter: parameter, Err: err} } - schema = parameter.Schema.Value + schemaRef = mt.Schema + } + + if value, found, err = decodeStyledParameter(parameter, input, schemaRef); err != nil { + return &RequestError{Input: input, Parameter: parameter, Err: err} } + schema := schemaRef.Value // Set default value if needed if value == nil && schema != nil && schema.Default != nil { value = schema.Default diff --git a/openapi3filter/validation_test.go b/openapi3filter/validation_test.go index cd1fa8990..787d57e1f 100644 --- a/openapi3filter/validation_test.go +++ b/openapi3filter/validation_test.go @@ -328,7 +328,7 @@ func TestFilter(t *testing.T) { // enough. req = ExampleRequest{ Method: "POST", - URL: "http://example.com/api/prefix/v/suffix?contentArg={\"name\":\"bob\", \"id\":\"a\"}", + URL: `http://example.com/api/prefix/v/suffix?contentArg={"name":"bob", "id":"a"}`, } err = expect(req, resp) require.NoError(t, err) @@ -336,7 +336,7 @@ func TestFilter(t *testing.T) { // Now it should fail due the ID being too long req = ExampleRequest{ Method: "POST", - URL: "http://example.com/api/prefix/v/suffix?contentArg={\"name\":\"bob\", \"id\":\"EXCEEDS_MAX_LENGTH\"}", + URL: `http://example.com/api/prefix/v/suffix?contentArg={"name":"bob", "id":"EXCEEDS_MAX_LENGTH"}`, } err = expect(req, resp) require.IsType(t, &RequestError{}, err) @@ -351,7 +351,7 @@ func TestFilter(t *testing.T) { req = ExampleRequest{ Method: "POST", - URL: "http://example.com/api/prefix/v/suffix?contentArg2={\"name\":\"bob\", \"id\":\"a\"}", + URL: `http://example.com/api/prefix/v/suffix?contentArg2={"name":"bob", "id":"a"}`, } err = expectWithDecoder(req, resp, customDecoder) require.NoError(t, err) @@ -359,7 +359,7 @@ func TestFilter(t *testing.T) { // Now it should fail due the ID being too long req = ExampleRequest{ Method: "POST", - URL: "http://example.com/api/prefix/v/suffix?contentArg2={\"name\":\"bob\", \"id\":\"EXCEEDS_MAX_LENGTH\"}", + URL: `http://example.com/api/prefix/v/suffix?contentArg2={"name":"bob", "id":"EXCEEDS_MAX_LENGTH"}`, } err = expectWithDecoder(req, resp, customDecoder) require.IsType(t, &RequestError{}, err)