diff options
Diffstat (limited to 'remote-curl.c')
-rw-r--r-- | remote-curl.c | 98 |
1 files changed, 53 insertions, 45 deletions
diff --git a/remote-curl.c b/remote-curl.c index 0e720ee8bb..278fecdd9b 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. */ @@ -188,7 +175,7 @@ static int write_discovery(int in, int out, void *data) return err; } -static struct ref *parse_git_refs(struct discovery *heads) +static struct ref *parse_git_refs(struct discovery *heads, int for_push) { struct ref *list = NULL; struct async async; @@ -200,7 +187,8 @@ static struct ref *parse_git_refs(struct discovery *heads) if (start_async(&async)) die("cannot start thread to parse advertised refs"); - get_remote_heads(async.out, &list, 0, NULL, 0, NULL); + get_remote_heads(async.out, &list, + for_push ? REF_NORMAL : 0, NULL); close(async.out); if (finish_async(&async)) die("ref parsing thread failed"); @@ -268,7 +256,7 @@ static struct ref *get_refs(int for_push) heads = discover_refs("git-upload-pack"); if (heads->proto_git) - return parse_git_refs(heads); + return parse_git_refs(heads, for_push); return parse_info_refs(heads); } @@ -289,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; @@ -360,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; @@ -390,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); @@ -434,21 +424,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. @@ -524,6 +517,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 && !use_gzip) + goto retry; + if (err != HTTP_OK) + err = -1; curl_slist_free_all(headers); free(gzip_body); @@ -534,6 +531,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; @@ -544,6 +542,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); @@ -625,13 +625,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"; @@ -650,24 +651,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; } @@ -769,8 +773,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]; @@ -804,7 +811,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 ")) { @@ -821,12 +828,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]); @@ -859,7 +867,7 @@ int main(int argc, const char **argv) url = strbuf_detach(&buf, NULL); - http_init(remote, url); + http_init(remote, url, 0); do { if (strbuf_getline(&buf, stdin, '\n') == EOF) { |