From 9095a0dec44609091b5f368ade3e2051b89105cb Mon Sep 17 00:00:00 2001 From: Laurent Mazuel Date: Mon, 22 Jun 2020 11:30:32 -0700 Subject: [PATCH 1/2] Smart text serialization --- sdk/core/azure-core/CHANGELOG.md | 1 + .../azure/core/pipeline/transport/_base.py | 25 +++++++++++++++++++ sdk/core/azure-core/tests/test_pipeline.py | 19 ++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/sdk/core/azure-core/CHANGELOG.md b/sdk/core/azure-core/CHANGELOG.md index 3e2a871b735d..4f6eda777df8 100644 --- a/sdk/core/azure-core/CHANGELOG.md +++ b/sdk/core/azure-core/CHANGELOG.md @@ -7,6 +7,7 @@ - `AzureKeyCredentialPolicy` will now accept (and ignore) passed in kwargs #11963 - Better error messages if passed endpoint is incorrect #12106 +- Do not JSON encore a string if content type is "text" #12137 ## 1.6.0 (2020-06-03) diff --git a/sdk/core/azure-core/azure/core/pipeline/transport/_base.py b/sdk/core/azure-core/azure/core/pipeline/transport/_base.py index f7e83aed4460..73ea08b3c1db 100644 --- a/sdk/core/azure-core/azure/core/pipeline/transport/_base.py +++ b/sdk/core/azure-core/azure/core/pipeline/transport/_base.py @@ -319,6 +319,19 @@ def set_streamed_data_body(self, data): self.data = data self.files = None + def set_text_body(self, data): + """Set a text as body of the request. + + :param data: A text to send as body. + :type data: str + """ + if data is None: + self.data = None + else: + self.data = data + self.headers["Content-Length"] = str(len(self.data)) + self.files = None + def set_xml_body(self, data): """Set an XML element tree as the body of the request. @@ -685,6 +698,11 @@ def _request( # type: (...) -> HttpRequest """Create HttpRequest object. + If content is not None, guesses will be used to set the right body: + - If content is an XML tree, will serialize as XML + - If content-type starts by "text/", set the content as text + - Else, try JSON serialization + :param str method: HTTP method (GET, HEAD, etc.) :param str url: URL for the request. :param dict params: URL query parameters. @@ -703,8 +721,15 @@ def _request( request.headers.update(headers) if content is not None: + content_type = request.headers.get("Content-Type") if isinstance(content, ET.Element): request.set_xml_body(content) + # https://github.com/Azure/azure-sdk-for-python/issues/12137 + # A string is valid JSON, make the difference between text + # and a plain JSON string. + # Content-Type is a good indicator of intent from user + elif content_type and content_type.startswith("text/"): + request.set_text_body(content) else: try: request.set_json_body(content) diff --git a/sdk/core/azure-core/tests/test_pipeline.py b/sdk/core/azure-core/tests/test_pipeline.py index bbbd37c09f5e..c87c2d0b5197 100644 --- a/sdk/core/azure-core/tests/test_pipeline.py +++ b/sdk/core/azure-core/tests/test_pipeline.py @@ -264,6 +264,25 @@ def test_request_url_with_params(self): self.assertIn(request.url, ["a/b/c?g=h&t=y", "a/b/c?t=y&g=h"]) + def test_request_text(self): + client = PipelineClientBase('http://example.org') + request = client.get( + "/", + content="foo" + ) + + # In absence of information, everything is JSON (double quote added) + assert request.data == json.dumps("foo") + + request = client.get( + "/", + headers={'content-type': 'text/whatever'}, + content="foo" + ) + + # We want a direct string + assert request.data == "foo" + if __name__ == "__main__": unittest.main() From cccf81eeceed08697c327da3d9a4401ecae60c35 Mon Sep 17 00:00:00 2001 From: Laurent Mazuel Date: Tue, 23 Jun 2020 12:06:36 -0700 Subject: [PATCH 2/2] Update test_pipeline.py --- sdk/core/azure-core/tests/test_pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/core/azure-core/tests/test_pipeline.py b/sdk/core/azure-core/tests/test_pipeline.py index c87c2d0b5197..7b4cff1753b4 100644 --- a/sdk/core/azure-core/tests/test_pipeline.py +++ b/sdk/core/azure-core/tests/test_pipeline.py @@ -274,7 +274,7 @@ def test_request_text(self): # In absence of information, everything is JSON (double quote added) assert request.data == json.dumps("foo") - request = client.get( + request = client.post( "/", headers={'content-type': 'text/whatever'}, content="foo"