Commit 53a8f4631ea695d8bd4aa2a5b762adc13c6a806d

Patrick Steinhardt 2020-06-03T07:40:59

Merge pull request #5536 from libgit2/ethomson/http httpclient: support googlesource

diff --git a/src/transports/httpclient.c b/src/transports/httpclient.c
index bde67ca..010baa6 100644
--- a/src/transports/httpclient.c
+++ b/src/transports/httpclient.c
@@ -1038,6 +1038,7 @@ on_error:
 
 GIT_INLINE(int) client_read(git_http_client *client)
 {
+	http_parser_context *parser_context = client->parser.data;
 	git_stream *stream;
 	char *buf = client->read_buf.ptr + client->read_buf.size;
 	size_t max_len;
@@ -1054,6 +1055,9 @@ GIT_INLINE(int) client_read(git_http_client *client)
 	max_len = client->read_buf.asize - client->read_buf.size;
 	max_len = min(max_len, INT_MAX);
 
+	if (parser_context->output_size)
+		max_len = min(max_len, parser_context->output_size);
+
 	if (max_len == 0) {
 		git_error_set(GIT_ERROR_HTTP, "no room in output buffer");
 		return -1;
@@ -1191,7 +1195,7 @@ static void complete_response_body(git_http_client *client)
 	/* If we're not keeping alive, don't bother. */
 	if (!client->keepalive) {
 		client->connected = 0;
-		return;
+		goto done;
 	}
 
 	parser_context.client = client;
@@ -1205,6 +1209,9 @@ static void complete_response_body(git_http_client *client)
 		git_error_clear();
 		client->connected = 0;
 	}
+
+done:
+	git_buf_clear(&client->read_buf);
 }
 
 int git_http_client_send_request(
@@ -1419,15 +1426,20 @@ int git_http_client_read_body(
 	client->parser.data = &parser_context;
 
 	/*
-	 * Clients expect to get a non-zero amount of data from us.
-	 * With a sufficiently small buffer, one might only read a chunk
-	 * length.  Loop until we actually have data to return.
+	 * Clients expect to get a non-zero amount of data from us,
+	 * so we either block until we have data to return, until we
+	 * hit EOF or there's an error.  Do this in a loop, since we
+	 * may end up reading only some stream metadata (like chunk
+	 * information).
 	 */
 	while (!parser_context.output_written) {
 		error = client_read_and_parse(client);
 
 		if (error <= 0)
 			goto done;
+
+		if (client->state == DONE)
+			break;
 	}
 
 	assert(parser_context.output_written <= INT_MAX);
diff --git a/tests/online/clone.c b/tests/online/clone.c
index 034d0c2..9107956 100644
--- a/tests/online/clone.c
+++ b/tests/online/clone.c
@@ -11,6 +11,7 @@
 #define BB_REPO_URL "https://libgit3@bitbucket.org/libgit2/testgitrepository.git"
 #define BB_REPO_URL_WITH_PASS "https://libgit3:libgit3@bitbucket.org/libgit2/testgitrepository.git"
 #define BB_REPO_URL_WITH_WRONG_PASS "https://libgit3:wrong@bitbucket.org/libgit2/testgitrepository.git"
+#define GOOGLESOURCE_REPO_URL "https://chromium.googlesource.com/external/github.com/sergi/go-diff"
 
 #define SSH_REPO_URL "ssh://github.com/libgit2/TestGitRepository"
 
@@ -463,6 +464,13 @@ void test_online_clone__bitbucket_falls_back_to_specified_creds(void)
 	cl_fixture_cleanup("./foo");
 }
 
+void test_online_clone__googlesource(void)
+{
+	cl_git_pass(git_clone(&g_repo, GOOGLESOURCE_REPO_URL, "./foo", &g_options));
+	git_repository_free(g_repo); g_repo = NULL;
+	cl_fixture_cleanup("./foo");
+}
+
 static int cancel_at_half(const git_indexer_progress *stats, void *payload)
 {
 	GIT_UNUSED(payload);