From df126e108b899da133a980e900df39dfe57fcd59 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 31 Oct 2012 07:20:15 -0400 Subject: remote-curl: hoist gzip buffer size to top of post_rpc When we gzip the post data for a smart-http rpc request, we compute the gzip body and its size inside the "use_gzip" conditional. We keep track of the body after the conditional ends, but not the size. Let's remember both, which will enable us to retry failed gzip requests in a future patch. Signed-off-by: Jeff King --- remote-curl.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'remote-curl.c') diff --git a/remote-curl.c b/remote-curl.c index aefafd33d..10cd47d38 100644 --- a/remote-curl.c +++ b/remote-curl.c @@ -413,6 +413,7 @@ static int post_rpc(struct rpc_state *rpc) struct curl_slist *headers = NULL; int use_gzip = rpc->gzip_request; char *gzip_body = NULL; + size_t gzip_size; int err, large_request = 0; /* Try to load the entire request, if we can fit it into the @@ -478,19 +479,18 @@ retry: * we can try to deflate it ourselves, this may save on. * the transfer time. */ - size_t size; git_zstream stream; int ret; memset(&stream, 0, sizeof(stream)); git_deflate_init_gzip(&stream, Z_BEST_COMPRESSION); - size = git_deflate_bound(&stream, rpc->len); - gzip_body = xmalloc(size); + gzip_size = git_deflate_bound(&stream, rpc->len); + gzip_body = xmalloc(gzip_size); stream.next_in = (unsigned char *)rpc->buf; stream.avail_in = rpc->len; stream.next_out = (unsigned char *)gzip_body; - stream.avail_out = size; + stream.avail_out = gzip_size; ret = git_deflate(&stream, Z_FINISH); if (ret != Z_STREAM_END) @@ -500,16 +500,16 @@ retry: if (ret != Z_OK) die("cannot deflate request; zlib end error %d", ret); - size = stream.total_out; + gzip_size = stream.total_out; headers = curl_slist_append(headers, "Content-Encoding: gzip"); curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, gzip_body); - curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, size); + curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, gzip_size); if (options.verbosity > 1) { fprintf(stderr, "POST %s (gzip %lu to %lu bytes)\n", rpc->service_name, - (unsigned long)rpc->len, (unsigned long)size); + (unsigned long)rpc->len, (unsigned long)gzip_size); fflush(stderr); } } else { -- cgit v1.2.1 From 2e736fd5e94c6fa44ba95d81a5b0ae407b968b78 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 31 Oct 2012 07:29:16 -0400 Subject: remote-curl: retry failed requests for auth even with gzip Commit b81401c taught the post_rpc function to retry the http request after prompting for credentials. However, it did not handle two cases: 1. If we have a large request, we do not retry. That's OK, since we would have sent a probe (with retry) already. 2. If we are gzipping the request, we do not retry. That was considered OK, because the intended use was for push (e.g., listing refs is OK, but actually pushing objects is not), and we never gzip on push. This patch teaches post_rpc to retry even a gzipped request. This has two advantages: 1. It is possible to configure a "half-auth" state for fetching, where the set of refs and their sha1s are advertised, but one cannot actually fetch objects. This is not a recommended configuration, as it leaks some information about what is in the repository (e.g., an attacker can try brute-forcing possible content in your repository and checking whether it matches your branch sha1). However, it can be slightly more convenient, since a no-op fetch will not require a password at all. 2. It future-proofs us should we decide to ever gzip more requests. Signed-off-by: Jeff King --- remote-curl.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'remote-curl.c') diff --git a/remote-curl.c b/remote-curl.c index 10cd47d38..fac2befd8 100644 --- a/remote-curl.c +++ b/remote-curl.c @@ -474,6 +474,15 @@ retry: fflush(stderr); } + } else if (gzip_body) { + /* + * If we are looping to retry authentication, then the previous + * run will have set up the headers and gzip buffer already, + * and we just need to send it. + */ + curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, gzip_body); + curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, gzip_size); + } else if (use_gzip && 1024 < rpc->len) { /* The client backend isn't giving us compressed data so * we can try to deflate it ourselves, this may save on. @@ -530,7 +539,7 @@ retry: curl_easy_setopt(slot->curl, CURLOPT_FILE, rpc); err = run_slot(slot); - if (err == HTTP_REAUTH && !large_request && !use_gzip) + if (err == HTTP_REAUTH && !large_request) goto retry; if (err != HTTP_OK) err = -1; -- cgit v1.2.1