httpclient: handle chunked responses Detect responses that are sent with Transfer-Encoding: chunked, and record that information so that we can consume the entire message body.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
diff --git a/src/transports/httpclient.c b/src/transports/httpclient.c
index 54c4fc5..cfbe6c6 100644
--- a/src/transports/httpclient.c
+++ b/src/transports/httpclient.c
@@ -163,6 +163,9 @@ static int on_header_complete(http_parser *parser)
}
response->content_length = (size_t)len;
+ } else if (!strcasecmp("Transfer-Encoding", name->ptr) &&
+ !strcasecmp("chunked", value->ptr)) {
+ ctx->response->chunked = 1;
} else if (!strcasecmp("Proxy-Authenticate", git_buf_cstr(name))) {
char *dup = git__strndup(value->ptr, value->size);
GIT_ERROR_CHECK_ALLOC(dup);
@@ -351,7 +354,11 @@ static int on_headers_complete(http_parser *parser)
/* Stop parsing. */
http_parser_pause(parser, 1);
- ctx->client->state = READING_BODY;
+ if (ctx->response->content_type || ctx->response->chunked)
+ ctx->client->state = READING_BODY;
+ else
+ ctx->client->state = DONE;
+
return 0;
}
@@ -1003,11 +1010,11 @@ GIT_INLINE(int) client_read_and_parse(git_http_client *client)
/*
* See if we've consumed the entire response body. If the client was
* reading the body but did not consume it entirely, it's possible that
- * they knew that the stream had finished (in a git response, seeing a final
- * flush) and stopped reading. But if the response was chunked, we may have
- * not consumed the final chunk marker. Consume it to ensure that we don't
- * have it waiting in our socket. If there's more than just a chunk marker,
- * close the connection.
+ * they knew that the stream had finished (in a git response, seeing a
+ * final flush) and stopped reading. But if the response was chunked,
+ * we may have not consumed the final chunk marker. Consume it to
+ * ensure that we don't have it waiting in our socket. If there's
+ * more than just a chunk marker, close the connection.
*/
static void complete_response_body(git_http_client *client)
{
diff --git a/src/transports/httpclient.h b/src/transports/httpclient.h
index 5f3c2ca..e22ab4e 100644
--- a/src/transports/httpclient.h
+++ b/src/transports/httpclient.h
@@ -53,7 +53,8 @@ typedef struct {
unsigned proxy_auth_schemetypes; /**< Schemes requested by proxy */
unsigned proxy_auth_credtypes; /**< Supported cred types for proxy */
- unsigned resend_credentials : 1; /**< Resend with authentication */
+ unsigned chunked : 1, /**< Response body is chunked */
+ resend_credentials : 1; /**< Resend with authentication */
} git_http_response;
typedef struct {