From c22715ad1f7dc19cc2f7fdc90675cadca2a0ea55 Mon Sep 17 00:00:00 2001 From: David Chaiken Date: Tue, 18 Oct 2022 18:51:35 -0700 Subject: [PATCH] fix for issue #13722: send body for application/x-www-form-urlencoded data (#13723) * fix for issue #13722: send body for application/x-www-form-urlencoded data * fix python test_application_x_www_form_urlencoded_serialization * x-www-form-urlencoded data needs to be percent encoded * add verification endpoint test for x-www-form-urlencoded data Co-authored-by: David Chaiken --- .../resources/python/api_client.handlebars | 4 +-- .../src/main/resources/python/rest.handlebars | 1 + .../python/unit_test_api/api_client.py | 4 +-- .../python/unit_test_api/rest.py | 1 + .../python/dynamic_servers/api_client.py | 4 +-- .../python/dynamic_servers/rest.py | 1 + .../python/petstore_api/api_client.py | 4 +-- .../petstore/python/petstore_api/rest.py | 1 + .../python/tests_manual/test_fake_api.py | 29 ++++++++++++++++++- .../python/tests_manual/test_request_body.py | 4 +-- 10 files changed, 42 insertions(+), 11 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/python/api_client.handlebars b/modules/openapi-generator/src/main/resources/python/api_client.handlebars index bdcd4519ff4..81426853056 100644 --- a/modules/openapi-generator/src/main/resources/python/api_client.handlebars +++ b/modules/openapi-generator/src/main/resources/python/api_client.handlebars @@ -293,7 +293,7 @@ class StyleFormSerializer(ParameterSerializerBase): prefix_separator_iterator: typing.Optional[PrefixSeparatorIterator] = None ) -> str: if prefix_separator_iterator is None: - prefix_separator_iterator = PrefixSeparatorIterator('?', '&') + prefix_separator_iterator = PrefixSeparatorIterator('', '&') return self._ref6570_expansion( variable_name=name, in_data=in_data, @@ -1472,7 +1472,7 @@ class RequestBody(StyleFormSerializer, JSONDetector): raise ValueError( f'Unable to serialize {in_data} to application/x-www-form-urlencoded because it is not a dict of data') cast_in_data = self.__json_encoder.default(in_data) - value = self._serialize_form(cast_in_data, name='', explode=True, percent_encode=False) + value = self._serialize_form(cast_in_data, name='', explode=True, percent_encode=True) return dict(body=value) def serialize( diff --git a/modules/openapi-generator/src/main/resources/python/rest.handlebars b/modules/openapi-generator/src/main/resources/python/rest.handlebars index b1811396168..2ca16e1639e 100644 --- a/modules/openapi-generator/src/main/resources/python/rest.handlebars +++ b/modules/openapi-generator/src/main/resources/python/rest.handlebars @@ -139,6 +139,7 @@ class RESTClientObject(object): elif headers['Content-Type'] == 'application/x-www-form-urlencoded': # noqa: E501 r = self.pool_manager.request( method, url, + body=body, fields=fields, encode_multipart=False, preload_content=not stream, diff --git a/samples/openapi3/client/3_0_3_unit_test/python/unit_test_api/api_client.py b/samples/openapi3/client/3_0_3_unit_test/python/unit_test_api/api_client.py index dfbf6822aa2..6fa884fc7d8 100644 --- a/samples/openapi3/client/3_0_3_unit_test/python/unit_test_api/api_client.py +++ b/samples/openapi3/client/3_0_3_unit_test/python/unit_test_api/api_client.py @@ -297,7 +297,7 @@ class StyleFormSerializer(ParameterSerializerBase): prefix_separator_iterator: typing.Optional[PrefixSeparatorIterator] = None ) -> str: if prefix_separator_iterator is None: - prefix_separator_iterator = PrefixSeparatorIterator('?', '&') + prefix_separator_iterator = PrefixSeparatorIterator('', '&') return self._ref6570_expansion( variable_name=name, in_data=in_data, @@ -1462,7 +1462,7 @@ class RequestBody(StyleFormSerializer, JSONDetector): raise ValueError( f'Unable to serialize {in_data} to application/x-www-form-urlencoded because it is not a dict of data') cast_in_data = self.__json_encoder.default(in_data) - value = self._serialize_form(cast_in_data, name='', explode=True, percent_encode=False) + value = self._serialize_form(cast_in_data, name='', explode=True, percent_encode=True) return dict(body=value) def serialize( diff --git a/samples/openapi3/client/3_0_3_unit_test/python/unit_test_api/rest.py b/samples/openapi3/client/3_0_3_unit_test/python/unit_test_api/rest.py index 75a309eed90..fc2409d3862 100644 --- a/samples/openapi3/client/3_0_3_unit_test/python/unit_test_api/rest.py +++ b/samples/openapi3/client/3_0_3_unit_test/python/unit_test_api/rest.py @@ -146,6 +146,7 @@ class RESTClientObject(object): elif headers['Content-Type'] == 'application/x-www-form-urlencoded': # noqa: E501 r = self.pool_manager.request( method, url, + body=body, fields=fields, encode_multipart=False, preload_content=not stream, diff --git a/samples/openapi3/client/features/dynamic-servers/python/dynamic_servers/api_client.py b/samples/openapi3/client/features/dynamic-servers/python/dynamic_servers/api_client.py index b931cc044f9..d52c3115dd0 100644 --- a/samples/openapi3/client/features/dynamic-servers/python/dynamic_servers/api_client.py +++ b/samples/openapi3/client/features/dynamic-servers/python/dynamic_servers/api_client.py @@ -297,7 +297,7 @@ class StyleFormSerializer(ParameterSerializerBase): prefix_separator_iterator: typing.Optional[PrefixSeparatorIterator] = None ) -> str: if prefix_separator_iterator is None: - prefix_separator_iterator = PrefixSeparatorIterator('?', '&') + prefix_separator_iterator = PrefixSeparatorIterator('', '&') return self._ref6570_expansion( variable_name=name, in_data=in_data, @@ -1462,7 +1462,7 @@ class RequestBody(StyleFormSerializer, JSONDetector): raise ValueError( f'Unable to serialize {in_data} to application/x-www-form-urlencoded because it is not a dict of data') cast_in_data = self.__json_encoder.default(in_data) - value = self._serialize_form(cast_in_data, name='', explode=True, percent_encode=False) + value = self._serialize_form(cast_in_data, name='', explode=True, percent_encode=True) return dict(body=value) def serialize( diff --git a/samples/openapi3/client/features/dynamic-servers/python/dynamic_servers/rest.py b/samples/openapi3/client/features/dynamic-servers/python/dynamic_servers/rest.py index d1a0e37cb2f..d91b562efa3 100644 --- a/samples/openapi3/client/features/dynamic-servers/python/dynamic_servers/rest.py +++ b/samples/openapi3/client/features/dynamic-servers/python/dynamic_servers/rest.py @@ -146,6 +146,7 @@ class RESTClientObject(object): elif headers['Content-Type'] == 'application/x-www-form-urlencoded': # noqa: E501 r = self.pool_manager.request( method, url, + body=body, fields=fields, encode_multipart=False, preload_content=not stream, diff --git a/samples/openapi3/client/petstore/python/petstore_api/api_client.py b/samples/openapi3/client/petstore/python/petstore_api/api_client.py index d1b93ab5a68..9ee9ff13f68 100644 --- a/samples/openapi3/client/petstore/python/petstore_api/api_client.py +++ b/samples/openapi3/client/petstore/python/petstore_api/api_client.py @@ -297,7 +297,7 @@ class StyleFormSerializer(ParameterSerializerBase): prefix_separator_iterator: typing.Optional[PrefixSeparatorIterator] = None ) -> str: if prefix_separator_iterator is None: - prefix_separator_iterator = PrefixSeparatorIterator('?', '&') + prefix_separator_iterator = PrefixSeparatorIterator('', '&') return self._ref6570_expansion( variable_name=name, in_data=in_data, @@ -1471,7 +1471,7 @@ class RequestBody(StyleFormSerializer, JSONDetector): raise ValueError( f'Unable to serialize {in_data} to application/x-www-form-urlencoded because it is not a dict of data') cast_in_data = self.__json_encoder.default(in_data) - value = self._serialize_form(cast_in_data, name='', explode=True, percent_encode=False) + value = self._serialize_form(cast_in_data, name='', explode=True, percent_encode=True) return dict(body=value) def serialize( diff --git a/samples/openapi3/client/petstore/python/petstore_api/rest.py b/samples/openapi3/client/petstore/python/petstore_api/rest.py index 40e35989f9a..53103c28ffe 100644 --- a/samples/openapi3/client/petstore/python/petstore_api/rest.py +++ b/samples/openapi3/client/petstore/python/petstore_api/rest.py @@ -146,6 +146,7 @@ class RESTClientObject(object): elif headers['Content-Type'] == 'application/x-www-form-urlencoded': # noqa: E501 r = self.pool_manager.request( method, url, + body=body, fields=fields, encode_multipart=False, preload_content=not stream, diff --git a/samples/openapi3/client/petstore/python/tests_manual/test_fake_api.py b/samples/openapi3/client/petstore/python/tests_manual/test_fake_api.py index 7ce4a60e8f7..5bf64cee445 100644 --- a/samples/openapi3/client/petstore/python/tests_manual/test_fake_api.py +++ b/samples/openapi3/client/petstore/python/tests_manual/test_fake_api.py @@ -35,7 +35,8 @@ class MIMEFormdata(nonmultipart.MIMENonMultipart): class TestFakeApi(ApiTestMixin): """FakeApi unit test stubs""" configuration = petstore_api.Configuration() - api = FakeApi(api_client=api_client.ApiClient(configuration=configuration)) + api_client = api_client.ApiClient(configuration=configuration) + api = FakeApi(api_client=api_client) def test_array_model(self): from petstore_api.model import animal_farm, animal @@ -763,6 +764,32 @@ class TestFakeApi(ApiTestMixin): assert isinstance(api_response.body, schemas.Unset) assert isinstance(api_response.headers, schemas.Unset) + def test_x_www_form_urlencoded(self): + with patch.object(urllib3.PoolManager, 'request') as mock_request: + from urllib3._collections import HTTPHeaderDict + from petstore_api.apis.tags import pet_api + + pet_id = dict(petId=2345) + pet_values = dict( + name='mister furball award', + status='happy, fuzzy, and bouncy' + ) + mock_request.return_value = self.response("") + + api_instance = pet_api.PetApi(self.api_client) + api_instance.update_pet_with_form(path_params=pet_id, body=pet_values) + mock_request.assert_called_with( + 'POST', + 'http://petstore.swagger.io:80/v2/pet/2345', + body='name=mister%20furball%20award&status=happy%2C%20fuzzy%2C%20and%20bouncy', + fields={}, + encode_multipart=False, + preload_content=True, + timeout=None, + headers=HTTPHeaderDict({'User-Agent': self.user_agent, + 'Content-Type': 'application/x-www-form-urlencoded'}) + ) + def test_json_patch(self): with patch.object(urllib3.PoolManager, 'request') as mock_request: from petstore_api.model import json_patch_request diff --git a/samples/openapi3/client/petstore/python/tests_manual/test_request_body.py b/samples/openapi3/client/petstore/python/tests_manual/test_request_body.py index cbfb167754e..c1f78880e96 100644 --- a/samples/openapi3/client/petstore/python/tests_manual/test_request_body.py +++ b/samples/openapi3/client/petstore/python/tests_manual/test_request_body.py @@ -110,7 +110,7 @@ class TestParameter(unittest.TestCase): def test_application_x_www_form_urlencoded_serialization(self): payload = dict( some_null=None, - some_str='a', + some_str='hi, spacether!', some_int=1, some_float=3.14, some_list=[], @@ -123,7 +123,7 @@ class TestParameter(unittest.TestCase): serialization = request_body.serialize(payload, content_type) self.assertEqual( serialization, - dict(body='?some_str=a&some_int=1&some_float=3.14') + dict(body='some_str=hi%2C%20spacether%21&some_int=1&some_float=3.14') ) serialization = request_body.serialize({}, content_type)