-
Notifications
You must be signed in to change notification settings - Fork 21
Description
An HTTP request sent using Transfer-Encoding: Chunked to an Azure Function written in Javascript causes the body to be undefined
.
I discovered this issue when a C# client was communicating with a javascript azure function.
I refactored the client to change from StringContent to ObjectContent, and therefore it would stream the request directly to the HTTP request stream, instead of creating an intermediate string.
When sending the request this way, the Content Length isn't known, and so chunked transfer encoding is used.
When experimenting, the issue occurs whenever the Content-Length is not known before the request is sent.
Minimum reproduction:
A javascript azure function:
// index.js
module.exports = async function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
// req.rawBody produces the same result.
let body = req.body;
context.log(body);
let responseString = body.toString();
context.res = {
body: responseString
};
}
// function.json
{
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}
A console client in C#
// Program.cs
var content = new StringContent(Guid.NewGuid().ToString());
// Clear the ContentLength to trigger chunked transfer encoding
content.Headers.ContentLength = null;
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost:5000/api/HttpTrigger")
{
Content = content
};
var httpClient = new HttpClient();
var response = await httpClient.SendAsync(request);
Console.WriteLine(response.StatusCode);
In this example, req.body (or req.rawBody) will be set as undefined
in the javascript function.
Removing the line content.Headers.ContentLength
will set req.body
to the expected value.
This issue does not occur if the function is re-written in C#:
public static class ChunkedEncodingFunction
{
[FunctionName("HttpTrigger")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
// requestBody has the expected request content.
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
log.LogInformation(requestBody);
return new OkObjectResult(requestBody);
}
}
Our current workaround is to call HttpContent.LoadIntoBufferAsync();
.
The azure function we're calling is a mock for a real service, and the real service supports chunked encoding. So we're having to put in a check to see if the client is communicating with the mock. Obviously, we would rather not require this check.