Skip to content

Commit 156b7ea

Browse files
authored
fix panic when multipart form contains extra parts not present i… (#200)
* fix panic when multipart form contains extra parts not present in schema * extra data ignored if additionalProperties true * decoding of additional props declared * fix create new map all properties * check for additionalProperties: false
1 parent 989d00f commit 156b7ea

File tree

2 files changed

+93
-2
lines changed

2 files changed

+93
-2
lines changed

openapi3filter/req_resp_decoder.go

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -923,7 +923,29 @@ func multipartBodyDecoder(body io.Reader, header http.Header, schema *openapi3.S
923923
subEncFn := func(string) *openapi3.Encoding { return enc }
924924
// If the property's schema has type "array" it is means that the form contains a few parts with the same name.
925925
// Every such part has a type that is defined by an items schema in the property's schema.
926-
valueSchema := schema.Value.Properties[name]
926+
var valueSchema *openapi3.SchemaRef
927+
var exists bool
928+
valueSchema, exists = schema.Value.Properties[name]
929+
if !exists {
930+
anyProperties := schema.Value.AdditionalPropertiesAllowed
931+
if anyProperties != nil {
932+
switch *anyProperties {
933+
case true:
934+
//additionalProperties: true
935+
continue
936+
default:
937+
//additionalProperties: false
938+
return nil, &ParseError{Kind: KindOther, Cause: fmt.Errorf("part %s: undefined", name)}
939+
}
940+
}
941+
if schema.Value.AdditionalProperties == nil {
942+
return nil, &ParseError{Kind: KindOther, Cause: fmt.Errorf("part %s: undefined", name)}
943+
}
944+
valueSchema, exists = schema.Value.AdditionalProperties.Value.Properties[name]
945+
if !exists {
946+
return nil, &ParseError{Kind: KindOther, Cause: fmt.Errorf("part %s: undefined", name)}
947+
}
948+
}
927949
if valueSchema.Value.Type == "array" {
928950
valueSchema = valueSchema.Value.Items
929951
}
@@ -938,9 +960,18 @@ func multipartBodyDecoder(body io.Reader, header http.Header, schema *openapi3.S
938960
values[name] = append(values[name], value)
939961
}
940962

963+
allTheProperties := make(map[string]*openapi3.SchemaRef)
964+
for k, v := range schema.Value.Properties {
965+
allTheProperties[k] = v
966+
}
967+
if schema.Value.AdditionalProperties != nil {
968+
for k, v := range schema.Value.AdditionalProperties.Value.Properties {
969+
allTheProperties[k] = v
970+
}
971+
}
941972
// Make an object value from form values.
942973
obj := make(map[string]interface{})
943-
for name, prop := range schema.Value.Properties {
974+
for name, prop := range allTheProperties {
944975
vv := values[name]
945976
if len(vv) == 0 {
946977
continue

openapi3filter/req_resp_decoder_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -980,6 +980,27 @@ func TestDecodeBody(t *testing.T) {
980980
})
981981
require.NoError(t, err)
982982

983+
multipartFormExtraPart, multipartFormMimeExtraPart, err := newTestMultipartForm([]*testFormPart{
984+
{name: "a", contentType: "text/plain", data: strings.NewReader("a1")},
985+
{name: "x", contentType: "text/plain", data: strings.NewReader("x1")},
986+
})
987+
require.NoError(t, err)
988+
989+
multipartAnyAdditionalProps, multipartMimeAnyAdditionalProps, err := newTestMultipartForm([]*testFormPart{
990+
{name: "a", contentType: "text/plain", data: strings.NewReader("a1")},
991+
{name: "x", contentType: "text/plain", data: strings.NewReader("x1")},
992+
})
993+
multipartAdditionalProps, multipartMimeAdditionalProps, err := newTestMultipartForm([]*testFormPart{
994+
{name: "a", contentType: "text/plain", data: strings.NewReader("a1")},
995+
{name: "x", contentType: "text/plain", data: strings.NewReader("x1")},
996+
})
997+
multipartAdditionalPropsErr, multipartMimeAdditionalPropsErr, err := newTestMultipartForm([]*testFormPart{
998+
{name: "a", contentType: "text/plain", data: strings.NewReader("a1")},
999+
{name: "x", contentType: "text/plain", data: strings.NewReader("x1")},
1000+
{name: "y", contentType: "text/plain", data: strings.NewReader("y1")},
1001+
})
1002+
require.NoError(t, err)
1003+
9831004
testCases := []struct {
9841005
name string
9851006
mime string
@@ -1060,6 +1081,45 @@ func TestDecodeBody(t *testing.T) {
10601081
WithProperty("f", openapi3.NewStringSchema().WithFormat("binary")),
10611082
want: map[string]interface{}{"a": "a1", "b": float64(10), "c": []interface{}{"c1", "c2"}, "d": map[string]interface{}{"d1": "d1"}, "f": "foo"},
10621083
},
1084+
{
1085+
name: "multipartExtraPart",
1086+
mime: multipartFormMimeExtraPart,
1087+
body: multipartFormExtraPart,
1088+
schema: openapi3.NewObjectSchema().
1089+
WithProperty("a", openapi3.NewStringSchema()),
1090+
want: map[string]interface{}{"a": "a1"},
1091+
wantErr: &ParseError{Kind: KindOther},
1092+
},
1093+
{
1094+
name: "multipartAnyAdditionalProperties",
1095+
mime: multipartMimeAnyAdditionalProps,
1096+
body: multipartAnyAdditionalProps,
1097+
schema: openapi3.NewObjectSchema().
1098+
WithAnyAdditionalProperties().
1099+
WithProperty("a", openapi3.NewStringSchema()),
1100+
want: map[string]interface{}{"a": "a1"},
1101+
},
1102+
{
1103+
name: "multipartWithAdditionalProperties",
1104+
mime: multipartMimeAdditionalProps,
1105+
body: multipartAdditionalProps,
1106+
schema: openapi3.NewObjectSchema().
1107+
WithAdditionalProperties(openapi3.NewObjectSchema().
1108+
WithProperty("x", openapi3.NewStringSchema())).
1109+
WithProperty("a", openapi3.NewStringSchema()),
1110+
want: map[string]interface{}{"a": "a1", "x": "x1"},
1111+
},
1112+
{
1113+
name: "multipartWithAdditionalPropertiesError",
1114+
mime: multipartMimeAdditionalPropsErr,
1115+
body: multipartAdditionalPropsErr,
1116+
schema: openapi3.NewObjectSchema().
1117+
WithAdditionalProperties(openapi3.NewObjectSchema().
1118+
WithProperty("x", openapi3.NewStringSchema())).
1119+
WithProperty("a", openapi3.NewStringSchema()),
1120+
want: map[string]interface{}{"a": "a1", "x": "x1"},
1121+
wantErr: &ParseError{Kind: KindOther},
1122+
},
10631123
{
10641124
name: "file",
10651125
mime: "application/octet-stream",

0 commit comments

Comments
 (0)