From 7723c187f9db19401ba66e91b27b5f133101d177 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 16 Sep 2024 15:11:19 -0600 Subject: [PATCH] avoid mutating request headers in-place Previously, the `spin_sdk.http.send` function automatically added a `content-length` header to the header dictionary supplied by the caller if one was not already present and if a request body was specified. However, since we were mutating the dictionary in-place, the change was visible to the caller. In addition to being potentially surprising to the caller, that can lead to issues if the same object is reused for another request later, at which point the header we added earlier will still be present but not necessarily accurate for the new request. To avoid such confusion, we now make a copy and add the `content-length` header to the copy. Signed-off-by: Joel Dice --- src/spin_sdk/http/__init__.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/spin_sdk/http/__init__.py b/src/spin_sdk/http/__init__.py index 3292d8e..24f5ec4 100644 --- a/src/spin_sdk/http/__init__.py +++ b/src/spin_sdk/http/__init__.py @@ -164,13 +164,20 @@ async def send_async(request: Request) -> Response: case _: scheme = Scheme_Other(url_parsed.scheme) - if request.headers.get('content-length') is None: + headers_dict = request.headers + + # Add a `content-length` header if the caller didn't include one, but did + # specify a body: + if headers_dict.get('content-length') is None: content_length = len(request.body) if request.body is not None else 0 - request.headers['content-length'] = str(content_length) + # Make a copy rather than mutate in place, since the caller might not + # expect us to mutate it: + headers_dict = headers_dict.copy() + headers_dict['content-length'] = str(content_length) headers = list(map( lambda pair: (pair[0], bytes(pair[1], "utf-8")), - request.headers.items() + headers_dict.items() )) outgoing_request = OutgoingRequest(Fields.from_list(headers))