Forum

9.4 reverse proxy: 100 continue vs chunked encoding

Klemens Schölhorn
24 March 2014, 23:35
Thanks again for the update, but I noticed a problem with the reverse proxy that does not occur in version 9.3 (I have not looked at 9.3.1):

I am using a HTTP 1.1 client that uses the Expect: 100-continue header by default for every POST request. A successful request should look like this: https://schoelhorn.eu/files/hiawatha_continue/dump-success-direct.txt (conversation between the .NET HTTPClient class and gunicorn)

With the hiawatha 9.3 reverse proxy in between, the conversation looks like this: https://schoelhorn.eu/files/hiawatha_continue/dump-success-9.3.txt
As you can see, the 100 Continue response is not forwarded immediately, but it does not break the client, because it just ignores the unexpected 100 Continue. The problem here is that the client waits his full timeout (350ms in the .NET case) before sending the request body after sending the headers with the Expect header. (can be seen easily in the wireshark dump that I can send you if you want)

With hiawatha 9.4 this is the result: https://schoelhorn.eu/files/hiawatha_continue/dump-fail-9.4.txt
As you can see, the 100 Continue response is not only cached, but a Transfer-Encoding: chunked header is added, which is then applied to the real response including headers.
This does not make any sense in my opinion.
Unfortunately rfc 2616 is not very clear about what a 100 Continue response should look like. It says in section 10.1 that such a response can contain optional headers but does not specify exactly which ones are allowed.
However I think that a proxy should not add a Transfer-Encoding header to a 1XX header.

I can send you wireshark captures of all three scenarios if you want.
Klemens Schölhorn
24 March 2014, 23:45
I forgot to mention that the last scenario obviously breaks the .NET HTTPClient ("The server committed a protocol violation") and also curl (curl --header "Expect: 100-continue" -v -d "username=test@test.com&password=test" http://cloud.test.com/api2/auth-token/ -> "Problem (2) in the Chunked-Encoded data").
Hugo Leisink
25 March 2014, 10:26
Try the following. Add this code to the end of src/http.c:
bool empty_body_because_of_http_status(int status) {
return ((status >= 100) && (status < 200)) || (status == 204) || (status == 304);
}


Add to src/http.h:
#include <stdbool.h>

...
bool empty_body_because_of_http_status(int status);


Change line 1667 of src/target.c to:
} else if (empty_body_because_of_http_status(code)) {

and change line 1679 to:
} else if (session->keep_alive &&
(strncasestr(buffer, hs_conlen, header_length) == NULL) &&
(strncasestr(buffer, hs_chunked, header_length) == NULL) &&
(empty_body_because_of_http_status(code) == false)) {
Klemens Schölhorn
25 March 2014, 16:20
Thanks for your quick reply.
This fixes the problem and makes the conversation look like the one from 9.3. (including the timeout-problem)

I also had to include src/http.h into src/target.c.
This topic has been closed.