diff options
Diffstat (limited to 'remote-curl.c')
-rw-r--r-- | remote-curl.c | 112 |
1 files changed, 64 insertions, 48 deletions
diff --git a/remote-curl.c b/remote-curl.c index 48c20b86f3..9a8b123507 100644 --- a/remote-curl.c +++ b/remote-curl.c @@ -95,15 +95,16 @@ static struct discovery* discover_refs(const char *service) struct strbuf buffer = STRBUF_INIT; struct discovery *last = last_discovery; char *refs_url; - int http_ret, is_http = 0, proto_git_candidate = 1; + int http_ret, maybe_smart = 0; if (last && !strcmp(service, last->service)) return last; free_discovery(last); strbuf_addf(&buffer, "%sinfo/refs", url); - if (!prefixcmp(url, "http://") || !prefixcmp(url, "https://")) { - is_http = 1; + if ((!prefixcmp(url, "http://") || !prefixcmp(url, "https://")) && + git_env_bool("GIT_SMART_HTTP", 1)) { + maybe_smart = 1; if (!strchr(url, '?')) strbuf_addch(&buffer, '?'); else @@ -113,19 +114,6 @@ static struct discovery* discover_refs(const char *service) refs_url = strbuf_detach(&buffer, NULL); http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE); - - /* try again with "plain" url (no ? or & appended) */ - if (http_ret != HTTP_OK && http_ret != HTTP_NOAUTH) { - free(refs_url); - strbuf_reset(&buffer); - - proto_git_candidate = 0; - strbuf_addf(&buffer, "%sinfo/refs", url); - refs_url = strbuf_detach(&buffer, NULL); - - http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE); - } - switch (http_ret) { case HTTP_OK: break; @@ -144,8 +132,7 @@ static struct discovery* discover_refs(const char *service) last->buf_alloc = strbuf_detach(&buffer, &last->len); last->buf = last->buf_alloc; - if (is_http && proto_git_candidate - && 5 <= last->len && last->buf[4] == '#') { + if (maybe_smart && 5 <= last->len && last->buf[4] == '#') { /* smart HTTP response; validate that the service * pkt-line matches our request. */ @@ -290,6 +277,7 @@ static void output_refs(struct ref *refs) struct rpc_state { const char *service_name; const char **argv; + struct strbuf *stdin_preamble; char *service_url; char *hdr_content_type; char *hdr_accept; @@ -361,16 +349,17 @@ static size_t rpc_in(char *ptr, size_t eltsize, static int run_slot(struct active_request_slot *slot) { - int err = 0; + int err; struct slot_results results; slot->results = &results; slot->curl_result = curl_easy_perform(slot->curl); finish_active_slot(slot); - if (results.curl_result != CURLE_OK) { - err |= error("RPC failed; result=%d, HTTP code = %ld", - results.curl_result, results.http_code); + err = handle_curl_result(&results); + if (err != HTTP_OK && err != HTTP_REAUTH) { + error("RPC failed; result=%d, HTTP code = %ld", + results.curl_result, results.http_code); } return err; @@ -391,7 +380,7 @@ static int probe_rpc(struct rpc_state *rpc) curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0); curl_easy_setopt(slot->curl, CURLOPT_POST, 1); curl_easy_setopt(slot->curl, CURLOPT_URL, rpc->service_url); - curl_easy_setopt(slot->curl, CURLOPT_ENCODING, ""); + curl_easy_setopt(slot->curl, CURLOPT_ENCODING, NULL); curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, "0000"); curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, 4); curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, headers); @@ -411,6 +400,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 = 0; int err, large_request = 0; /* Try to load the entire request, if we can fit it into the @@ -435,21 +425,24 @@ static int post_rpc(struct rpc_state *rpc) } if (large_request) { - err = probe_rpc(rpc); - if (err) - return err; + do { + err = probe_rpc(rpc); + } while (err == HTTP_REAUTH); + if (err != HTTP_OK) + return -1; } + headers = curl_slist_append(headers, rpc->hdr_content_type); + headers = curl_slist_append(headers, rpc->hdr_accept); + headers = curl_slist_append(headers, "Expect:"); + +retry: slot = get_active_slot(); curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0); curl_easy_setopt(slot->curl, CURLOPT_POST, 1); curl_easy_setopt(slot->curl, CURLOPT_URL, rpc->service_url); - curl_easy_setopt(slot->curl, CURLOPT_ENCODING, ""); - - headers = curl_slist_append(headers, rpc->hdr_content_type); - headers = curl_slist_append(headers, rpc->hdr_accept); - headers = curl_slist_append(headers, "Expect:"); + curl_easy_setopt(slot->curl, CURLOPT_ENCODING, "gzip"); if (large_request) { /* The request body is large and the size cannot be predicted. @@ -468,24 +461,32 @@ static int post_rpc(struct rpc_state *rpc) 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. * 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) @@ -495,16 +496,16 @@ static int post_rpc(struct rpc_state *rpc) 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 { @@ -525,6 +526,10 @@ static int post_rpc(struct rpc_state *rpc) curl_easy_setopt(slot->curl, CURLOPT_FILE, rpc); err = run_slot(slot); + if (err == HTTP_REAUTH && !large_request) + goto retry; + if (err != HTTP_OK) + err = -1; curl_slist_free_all(headers); free(gzip_body); @@ -535,6 +540,7 @@ static int rpc_service(struct rpc_state *rpc, struct discovery *heads) { const char *svc = rpc->service_name; struct strbuf buf = STRBUF_INIT; + struct strbuf *preamble = rpc->stdin_preamble; struct child_process client; int err = 0; @@ -545,6 +551,8 @@ static int rpc_service(struct rpc_state *rpc, struct discovery *heads) client.argv = rpc->argv; if (start_command(&client)) exit(1); + if (preamble) + write_or_die(client.in, preamble->buf, preamble->len); if (heads) write_or_die(client.in, heads->buf, heads->len); @@ -626,13 +634,14 @@ static int fetch_git(struct discovery *heads, int nr_heads, struct ref **to_fetch) { struct rpc_state rpc; + struct strbuf preamble = STRBUF_INIT; char *depth_arg = NULL; - const char **argv; int argc = 0, i, err; + const char *argv[15]; - argv = xmalloc((15 + nr_heads) * sizeof(char*)); argv[argc++] = "fetch-pack"; argv[argc++] = "--stateless-rpc"; + argv[argc++] = "--stdin"; argv[argc++] = "--lock-pack"; if (options.followtags) argv[argc++] = "--include-tag"; @@ -651,24 +660,27 @@ static int fetch_git(struct discovery *heads, argv[argc++] = depth_arg; } argv[argc++] = url; + argv[argc++] = NULL; + for (i = 0; i < nr_heads; i++) { struct ref *ref = to_fetch[i]; if (!ref->name || !*ref->name) die("cannot fetch by sha1 over smart http"); - argv[argc++] = ref->name; + packet_buf_write(&preamble, "%s\n", ref->name); } - argv[argc++] = NULL; + packet_buf_flush(&preamble); memset(&rpc, 0, sizeof(rpc)); rpc.service_name = "git-upload-pack", rpc.argv = argv; + rpc.stdin_preamble = &preamble; rpc.gzip_request = 1; err = rpc_service(&rpc, heads); if (rpc.result.len) safe_write(1, rpc.result.buf, rpc.result.len); strbuf_release(&rpc.result); - free(argv); + strbuf_release(&preamble); free(depth_arg); return err; } @@ -770,8 +782,11 @@ static int push_git(struct discovery *heads, int nr_spec, char **specs) argv[argc++] = "--thin"; if (options.dry_run) argv[argc++] = "--dry-run"; - if (options.verbosity > 1) + if (options.verbosity == 0) + argv[argc++] = "--quiet"; + else if (options.verbosity > 1) argv[argc++] = "--verbose"; + argv[argc++] = options.progress ? "--progress" : "--no-progress"; argv[argc++] = url; for (i = 0; i < nr_spec; i++) argv[argc++] = specs[i]; @@ -805,7 +820,7 @@ static int push(int nr_spec, char **specs) static void parse_push(struct strbuf *buf) { char **specs = NULL; - int alloc_spec = 0, nr_spec = 0, i; + int alloc_spec = 0, nr_spec = 0, i, ret; do { if (!prefixcmp(buf->buf, "push ")) { @@ -822,12 +837,13 @@ static void parse_push(struct strbuf *buf) break; } while (1); - if (push(nr_spec, specs)) - exit(128); /* error already reported */ - + ret = push(nr_spec, specs); printf("\n"); fflush(stdout); + if (ret) + exit(128); /* error already reported */ + free_specs: for (i = 0; i < nr_spec; i++) free(specs[i]); |