From 852c081068046240174e17ef0876046f89bbefc3 Mon Sep 17 00:00:00 2001 From: p1c2u Date: Wed, 24 Mar 2021 21:35:39 +0000 Subject: [PATCH] deserialize data form media type --- .../deserializing/media_types/factories.py | 7 +++- .../deserializing/media_types/util.py | 17 +++++++- .../test_media_types_deserializers.py | 42 ++++++++++++++++++- 3 files changed, 61 insertions(+), 5 deletions(-) diff --git a/openapi_core/deserializing/media_types/factories.py b/openapi_core/deserializing/media_types/factories.py index b174bef..f44a5c0 100644 --- a/openapi_core/deserializing/media_types/factories.py +++ b/openapi_core/deserializing/media_types/factories.py @@ -1,4 +1,6 @@ -from openapi_core.deserializing.media_types.util import json_loads, form_loads +from openapi_core.deserializing.media_types.util import ( + json_loads, urlencoded_form_loads, data_form_loads, +) from openapi_core.deserializing.media_types.deserializers import ( PrimitiveDeserializer, @@ -9,7 +11,8 @@ class MediaTypeDeserializersFactory(object): MEDIA_TYPE_DESERIALIZERS = { 'application/json': json_loads, - 'application/x-www-form-urlencoded': form_loads, + 'application/x-www-form-urlencoded': urlencoded_form_loads, + 'multipart/form-data': data_form_loads, } def __init__(self, custom_deserializers=None): diff --git a/openapi_core/deserializing/media_types/util.py b/openapi_core/deserializing/media_types/util.py index bc5a88f..e4d3100 100644 --- a/openapi_core/deserializing/media_types/util.py +++ b/openapi_core/deserializing/media_types/util.py @@ -1,3 +1,4 @@ +from email.parser import BytesParser from json import loads from six import binary_type @@ -11,5 +12,19 @@ def json_loads(value): return loads(value) -def form_loads(value): +def urlencoded_form_loads(value): return dict(parse_qsl(value)) + + +def data_form_loads(value): + if issubclass(type(value), str): + value = value.encode() + parser = BytesParser() + parts = parser.parsebytes(value) + return dict( + ( + part.get_param('name', header='content-disposition'), + part.get_payload(decode=True), + ) + for part in parts.get_payload() + ) diff --git a/tests/unit/deserializing/test_media_types_deserializers.py b/tests/unit/deserializing/test_media_types_deserializers.py index 435feb4..683a3b4 100644 --- a/tests/unit/deserializing/test_media_types_deserializers.py +++ b/tests/unit/deserializing/test_media_types_deserializers.py @@ -1,3 +1,6 @@ +from email.mime.multipart import MIMEMultipart +from email.mime.nonmultipart import MIMENonMultipart + import pytest from openapi_core.deserializing.exceptions import DeserializeError @@ -7,6 +10,24 @@ from openapi_core.deserializing.media_types.factories import ( from openapi_core.schema.media_types.models import MediaType +class MIMEFormdata(MIMENonMultipart): + def __init__(self, keyname, *args, **kwargs): + super(MIMEFormdata, self).__init__(*args, **kwargs) + self.add_header( + "Content-Disposition", "form-data; name=\"%s\"" % keyname) + + +def encode_multipart_formdata(fields): + m = MIMEMultipart("form-data") + + for field, value in fields.items(): + data = MIMEFormdata(field, "text", "plain") + data.set_payload(value) + m.attach(data) + + return m + + class TestMediaTypeDeserializer(object): @pytest.fixture @@ -31,7 +52,7 @@ class TestMediaTypeDeserializer(object): assert result == {} - def test_form_urlencoded_empty(self, deserializer_factory): + def test_urlencoded_form_empty(self, deserializer_factory): media_type = MediaType('application/x-www-form-urlencoded') value = '' @@ -39,7 +60,7 @@ class TestMediaTypeDeserializer(object): assert result == {} - def test_form_urlencoded_simple(self, deserializer_factory): + def test_urlencoded_form_simple(self, deserializer_factory): media_type = MediaType('application/x-www-form-urlencoded') value = 'param1=test' @@ -47,6 +68,23 @@ class TestMediaTypeDeserializer(object): assert result == {'param1': 'test'} + @pytest.mark.parametrize('value', [b'', '']) + def test_data_form_empty(self, deserializer_factory, value): + media_type = MediaType('multipart/form-data') + + result = deserializer_factory(media_type)(value) + + assert result == {} + + def test_data_form_simple(self, deserializer_factory): + media_type = MediaType('multipart/form-data') + formdata = encode_multipart_formdata({'param1': 'test'}) + value = str(formdata) + + result = deserializer_factory(media_type)(value) + + assert result == {'param1': b'test'} + def test_custom_simple(self, deserializer_factory): custom_mimetype = 'application/custom' media_type = MediaType(custom_mimetype)