Commit 6b2088363f6e6b4fea24939286eb108cfc999c77

Edward Thomson 2019-12-18T21:55:28

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.

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 {