summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2019-12-12 13:53:43 +1000
committerEdward Thomson <ethomson@edwardthomson.com>2020-01-24 10:16:36 -0600
commit84b99a95bf7ce8b96db23f7402b205bc74202ae0 (patch)
treebeb77f873b98618e71ae5d821663f72835c44c8f
parenteacecebdcf12e72f692319eb0332f2e270ed359a (diff)
downloadlibgit2-84b99a95bf7ce8b96db23f7402b205bc74202ae0.tar.gz
httpclient: add chunk support to POST
Teach httpclient how to support chunking when POSTing request bodies.
-rw-r--r--src/transports/httpclient.c55
1 files changed, 44 insertions, 11 deletions
diff --git a/src/transports/httpclient.c b/src/transports/httpclient.c
index 5d432b3b3..1fb3b38f5 100644
--- a/src/transports/httpclient.c
+++ b/src/transports/httpclient.c
@@ -82,7 +82,8 @@ struct git_http_client {
unsigned request_count;
unsigned connected : 1,
- keepalive : 1;
+ keepalive : 1,
+ request_chunked : 1;
/* Temporary buffers to avoid extra mallocs */
git_buf request_msg;
@@ -587,6 +588,7 @@ int git_http_client_send_request(
client->state = SENDING_BODY;
client->request_body_len = request->content_length;
client->request_body_remain = request->content_length;
+ client->request_chunked = request->chunked;
} else {
client->state = SENT_REQUEST;
}
@@ -600,15 +602,49 @@ int git_http_client_send_body(
const char *buffer,
size_t buffer_len)
{
+ git_http_server *server;
+ git_buf hdr = GIT_BUF_INIT;
int error;
assert(client && client->state == SENDING_BODY);
- assert(buffer_len <= client->request_body_remain);
- error = stream_write(&client->server, buffer, buffer_len);
+ if (!buffer_len)
+ return 0;
+
+ server = &client->server;
+
+ if (client->request_body_len) {
+ assert(buffer_len <= client->request_body_remain);
+
+ if ((error = stream_write(server, buffer, buffer_len)) < 0)
+ goto done;
- if (error == 0)
client->request_body_remain -= buffer_len;
+ } else {
+ if ((error = git_buf_printf(&hdr, "%" PRIxZ "\r\n", buffer_len)) < 0 ||
+ (error = stream_write(server, hdr.ptr, hdr.size)) < 0 ||
+ (error = stream_write(server, buffer, buffer_len)) < 0 ||
+ (error = stream_write(server, "\r\n", 2)) < 0)
+ goto done;
+ }
+
+done:
+ git_buf_dispose(&hdr);
+ return error;
+}
+
+static int complete_request(git_http_client *client)
+{
+ int error = 0;
+
+ assert(client && client->state == SENDING_BODY);
+
+ if (client->request_body_len && client->request_body_remain) {
+ git_error_set(GIT_ERROR_NET, "truncated write");
+ error = -1;
+ } else if (client->request_chunked) {
+ error = stream_write(&client->server, "0\r\n\r\n", 5);
+ }
return error;
}
@@ -758,15 +794,12 @@ int git_http_client_read_response(
assert(response && client);
if (client->state == SENDING_BODY) {
- if (client->request_body_len && client->request_body_remain) {
- git_error_set(GIT_ERROR_NET, "truncated write");
- return -1;
- }
-
- client->state = SENT_REQUEST;
+ if ((error = complete_request(client)) < 0)
+ goto done;
} else if (client->state != SENT_REQUEST) {
git_error_set(GIT_ERROR_NET, "client is in invalid state");
- return -1;
+ error = -1;
+ goto done;
}
client->state = READING_RESPONSE;