Skip to content

Commit 37ee680

Browse files
novalisgitster
authored andcommitted
http.postbuffer: allow full range of ssize_t values
Unfortunately, in order to push some large repos where a server does not support chunked encoding, the http postbuffer must sometimes exceed two gigabytes. On a 64-bit system, this is OK: we just malloc a larger buffer. This means that we need to use CURLOPT_POSTFIELDSIZE_LARGE to set the buffer size. Signed-off-by: David Turner <[email protected]> Reviewed-by: Jonathan Nieder <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent b14f27f commit 37ee680

File tree

5 files changed

+32
-6
lines changed

5 files changed

+32
-6
lines changed

cache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1901,6 +1901,7 @@ extern int git_parse_maybe_bool(const char *);
19011901
extern int git_config_int(const char *, const char *);
19021902
extern int64_t git_config_int64(const char *, const char *);
19031903
extern unsigned long git_config_ulong(const char *, const char *);
1904+
extern ssize_t git_config_ssize_t(const char *, const char *);
19041905
extern int git_config_bool_or_int(const char *, const char *, int *);
19051906
extern int git_config_bool(const char *, const char *);
19061907
extern int git_config_maybe_bool(const char *, const char *);

config.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,15 @@ int git_parse_ulong(const char *value, unsigned long *ret)
834834
return 1;
835835
}
836836

837+
static int git_parse_ssize_t(const char *value, ssize_t *ret)
838+
{
839+
intmax_t tmp;
840+
if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(ssize_t)))
841+
return 0;
842+
*ret = tmp;
843+
return 1;
844+
}
845+
837846
NORETURN
838847
static void die_bad_number(const char *name, const char *value)
839848
{
@@ -892,6 +901,14 @@ unsigned long git_config_ulong(const char *name, const char *value)
892901
return ret;
893902
}
894903

904+
ssize_t git_config_ssize_t(const char *name, const char *value)
905+
{
906+
ssize_t ret;
907+
if (!git_parse_ssize_t(value, &ret))
908+
die_bad_number(name, value);
909+
return ret;
910+
}
911+
895912
int git_parse_maybe_bool(const char *value)
896913
{
897914
if (!value)

http.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ long int git_curl_ipresolve;
1919
#endif
2020
int active_requests;
2121
int http_is_verbose;
22-
size_t http_post_buffer = 16 * LARGE_PACKET_MAX;
22+
ssize_t http_post_buffer = 16 * LARGE_PACKET_MAX;
2323

2424
#if LIBCURL_VERSION_NUM >= 0x070a06
2525
#define LIBCURL_CAN_HANDLE_AUTH_ANY
@@ -331,7 +331,9 @@ static int http_options(const char *var, const char *value, void *cb)
331331
}
332332

333333
if (!strcmp("http.postbuffer", var)) {
334-
http_post_buffer = git_config_int(var, value);
334+
http_post_buffer = git_config_ssize_t(var, value);
335+
if (http_post_buffer < 0)
336+
warning(_("negative value for http.postbuffer; defaulting to %d"), LARGE_PACKET_MAX);
335337
if (http_post_buffer < LARGE_PACKET_MAX)
336338
http_post_buffer = LARGE_PACKET_MAX;
337339
return 0;

http.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ extern struct curl_slist *http_copy_default_headers(void);
111111
extern long int git_curl_ipresolve;
112112
extern int active_requests;
113113
extern int http_is_verbose;
114-
extern size_t http_post_buffer;
114+
extern ssize_t http_post_buffer;
115115
extern struct credential http_auth;
116116

117117
extern char curl_errorstr[CURL_ERROR_SIZE];

remote-curl.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,12 @@ static int probe_rpc(struct rpc_state *rpc, struct slot_results *results)
531531
return err;
532532
}
533533

534+
static curl_off_t xcurl_off_t(ssize_t len) {
535+
if (len > maximum_signed_value_of_type(curl_off_t))
536+
die("cannot handle pushes this big");
537+
return (curl_off_t) len;
538+
}
539+
534540
static int post_rpc(struct rpc_state *rpc)
535541
{
536542
struct active_request_slot *slot;
@@ -614,7 +620,7 @@ static int post_rpc(struct rpc_state *rpc)
614620
* and we just need to send it.
615621
*/
616622
curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, gzip_body);
617-
curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, gzip_size);
623+
curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE_LARGE, xcurl_off_t(gzip_size));
618624

619625
} else if (use_gzip && 1024 < rpc->len) {
620626
/* The client backend isn't giving us compressed data so
@@ -645,7 +651,7 @@ static int post_rpc(struct rpc_state *rpc)
645651

646652
headers = curl_slist_append(headers, "Content-Encoding: gzip");
647653
curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, gzip_body);
648-
curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, gzip_size);
654+
curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE_LARGE, xcurl_off_t(gzip_size));
649655

650656
if (options.verbosity > 1) {
651657
fprintf(stderr, "POST %s (gzip %lu to %lu bytes)\n",
@@ -658,7 +664,7 @@ static int post_rpc(struct rpc_state *rpc)
658664
* more normal Content-Length approach.
659665
*/
660666
curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, rpc->buf);
661-
curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, rpc->len);
667+
curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE_LARGE, xcurl_off_t(rpc->len));
662668
if (options.verbosity > 1) {
663669
fprintf(stderr, "POST %s (%lu bytes)\n",
664670
rpc->service_name, (unsigned long)rpc->len);

0 commit comments

Comments
 (0)