Skip to content

Commit 2a0b1c8

Browse files
elpransmaiqbal11
authored andcommitted
Always use raw HTTP body (#316)
`RpcHttp.body` may be reformatted by the Functions Host, and as such, may not be identical to the original body sent by the client. This has numerous problems (e.g invalid Content-Length etc.) Sidestep the issue by always using `RpcHttp.rawBody`. See also: Azure/azure-functions-host#3875 Fixes: #260
1 parent 8e92478 commit 2a0b1c8

File tree

4 files changed

+28
-5
lines changed

4 files changed

+28
-5
lines changed

azure/functions_worker/bindings/http.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,16 @@ def get_body(self) -> bytes:
4747
return self.__body_bytes
4848

4949
def get_json(self) -> typing.Any:
50-
if self.__body_type is meta.TypedDataKind.json:
50+
if (self.__body_type is meta.TypedDataKind.json
51+
or self.__body_type is meta.TypedDataKind.string):
5152
assert self.__body_str is not None
5253
return json.loads(self.__body_str)
53-
raise ValueError('HTTP request does not have JSON data attached')
54+
else:
55+
try:
56+
return json.loads(self.__body_bytes.decode())
57+
except ValueError as e:
58+
raise ValueError(
59+
'HTTP request does not contain valid JSON data') from e
5460

5561

5662
class HttpResponseConverter(meta.OutConverter, binding='http'):
@@ -105,7 +111,7 @@ def from_proto(cls, data: protos.TypedData, *,
105111
if data.WhichOneof('data') != 'http':
106112
raise NotImplementedError
107113

108-
body_rpc_val = data.http.body
114+
body_rpc_val = data.http.rawBody
109115
body_rpc_type = body_rpc_val.WhichOneof('data')
110116

111117
if body_rpc_type == 'json':
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
import json
2+
import hashlib
23

34
import azure.functions
45

56

67
def main(req: azure.functions.HttpRequest):
78
params = dict(req.params)
89
params.pop('code', None)
10+
body = req.get_body()
911
return json.dumps({
1012
'method': req.method,
1113
'url': req.url,
1214
'headers': dict(req.headers),
1315
'params': params,
14-
'get_body': req.get_body().decode(),
16+
'get_body': body.decode(),
17+
'body_hash': hashlib.sha256(body).hexdigest(),
1518
})

tests/test_http_functions.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import hashlib
2+
13
from azure.functions_worker import testutils
24

35

@@ -141,6 +143,18 @@ def test_post_return_request(self):
141143

142144
self.assertEqual(req['get_body'], 'key=value')
143145

146+
def test_post_json_request_is_untouched(self):
147+
body = b'{"foo": "bar", "two": 4}'
148+
body_hash = hashlib.sha256(body).hexdigest()
149+
r = self.webhost.request(
150+
'POST', 'return_request',
151+
headers={'Content-Type': 'application/json'},
152+
data=body)
153+
154+
self.assertEqual(r.status_code, 200)
155+
req = r.json()
156+
self.assertEqual(req['body_hash'], body_hash)
157+
144158
def test_accept_json(self):
145159
r = self.webhost.request(
146160
'POST', 'accept_json',

tests/test_types.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def test_http_request_bytes(self):
2828

2929
self.assertEqual(r.get_body(), b'abc')
3030

31-
with self.assertRaisesRegex(ValueError, 'does not have JSON'):
31+
with self.assertRaisesRegex(ValueError, 'does not contain valid JSON'):
3232
r.get_json()
3333

3434
h = r.headers

0 commit comments

Comments
 (0)