Skip to content

Commit 84b99a9

Browse files
committed
httpclient: add chunk support to POST
Teach httpclient how to support chunking when POSTing request bodies.
1 parent eaceceb commit 84b99a9

File tree

1 file changed

+44
-11
lines changed

1 file changed

+44
-11
lines changed

src/transports/httpclient.c

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ struct git_http_client {
8282

8383
unsigned request_count;
8484
unsigned connected : 1,
85-
keepalive : 1;
85+
keepalive : 1,
86+
request_chunked : 1;
8687

8788
/* Temporary buffers to avoid extra mallocs */
8889
git_buf request_msg;
@@ -587,6 +588,7 @@ int git_http_client_send_request(
587588
client->state = SENDING_BODY;
588589
client->request_body_len = request->content_length;
589590
client->request_body_remain = request->content_length;
591+
client->request_chunked = request->chunked;
590592
} else {
591593
client->state = SENT_REQUEST;
592594
}
@@ -600,15 +602,49 @@ int git_http_client_send_body(
600602
const char *buffer,
601603
size_t buffer_len)
602604
{
605+
git_http_server *server;
606+
git_buf hdr = GIT_BUF_INIT;
603607
int error;
604608

605609
assert(client && client->state == SENDING_BODY);
606-
assert(buffer_len <= client->request_body_remain);
607610

608-
error = stream_write(&client->server, buffer, buffer_len);
611+
if (!buffer_len)
612+
return 0;
613+
614+
server = &client->server;
615+
616+
if (client->request_body_len) {
617+
assert(buffer_len <= client->request_body_remain);
618+
619+
if ((error = stream_write(server, buffer, buffer_len)) < 0)
620+
goto done;
609621

610-
if (error == 0)
611622
client->request_body_remain -= buffer_len;
623+
} else {
624+
if ((error = git_buf_printf(&hdr, "%" PRIxZ "\r\n", buffer_len)) < 0 ||
625+
(error = stream_write(server, hdr.ptr, hdr.size)) < 0 ||
626+
(error = stream_write(server, buffer, buffer_len)) < 0 ||
627+
(error = stream_write(server, "\r\n", 2)) < 0)
628+
goto done;
629+
}
630+
631+
done:
632+
git_buf_dispose(&hdr);
633+
return error;
634+
}
635+
636+
static int complete_request(git_http_client *client)
637+
{
638+
int error = 0;
639+
640+
assert(client && client->state == SENDING_BODY);
641+
642+
if (client->request_body_len && client->request_body_remain) {
643+
git_error_set(GIT_ERROR_NET, "truncated write");
644+
error = -1;
645+
} else if (client->request_chunked) {
646+
error = stream_write(&client->server, "0\r\n\r\n", 5);
647+
}
612648

613649
return error;
614650
}
@@ -758,15 +794,12 @@ int git_http_client_read_response(
758794
assert(response && client);
759795

760796
if (client->state == SENDING_BODY) {
761-
if (client->request_body_len && client->request_body_remain) {
762-
git_error_set(GIT_ERROR_NET, "truncated write");
763-
return -1;
764-
}
765-
766-
client->state = SENT_REQUEST;
797+
if ((error = complete_request(client)) < 0)
798+
goto done;
767799
} else if (client->state != SENT_REQUEST) {
768800
git_error_set(GIT_ERROR_NET, "client is in invalid state");
769-
return -1;
801+
error = -1;
802+
goto done;
770803
}
771804

772805
client->state = READING_RESPONSE;

0 commit comments

Comments
 (0)