static int push(int nr_spec, char **specs) { struct discovery *heads = discover_refs("git-receive-pack"); int ret; if (heads->proto_git) ret = push_git(heads, nr_spec, specs); else ret = push_dav(nr_spec, specs); free_discovery(heads); return ret; }
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; 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 (!strchr(url, '?')) strbuf_addch(&buffer, '?'); else strbuf_addch(&buffer, '&'); strbuf_addf(&buffer, "service=%s", 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; case HTTP_MISSING_TARGET: die("%s not found: did you run git update-server-info on the" " server?", refs_url); case HTTP_NOAUTH: die("Authentication failed"); default: http_error(refs_url, http_ret); die("HTTP request failed"); } last= xcalloc(1, sizeof(*last_discovery)); last->service = 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] == '#') { /* smart HTTP response; validate that the service * pkt-line matches our request. */ struct strbuf exp = STRBUF_INIT; if (packet_get_line(&buffer, &last->buf, &last->len) <= 0) die("%s has invalid packet header", refs_url); if (buffer.len && buffer.buf[buffer.len - 1] == '\n') strbuf_setlen(&buffer, buffer.len - 1); strbuf_addf(&exp, "# service=%s", service); if (strbuf_cmp(&exp, &buffer)) die("invalid server response; got '%s'", buffer.buf); strbuf_release(&exp); /* The header can include additional metadata lines, up * until a packet flush marker. Ignore these now, but * in the future we might start to scan them. */ strbuf_reset(&buffer); while (packet_get_line(&buffer, &last->buf, &last->len) > 0) strbuf_reset(&buffer); last->proto_git = 1; } free(refs_url); strbuf_release(&buffer); last_discovery = last; return last; }
static struct discovery *discover_refs(const char *service, int for_push) { struct strbuf exp = STRBUF_INIT; struct strbuf type = STRBUF_INIT; struct strbuf charset = STRBUF_INIT; struct strbuf buffer = STRBUF_INIT; struct strbuf refs_url = STRBUF_INIT; struct strbuf effective_url = STRBUF_INIT; struct discovery *last = last_discovery; int http_ret, maybe_smart = 0; struct http_get_options options; if (last && !strcmp(service, last->service)) return last; free_discovery(last); strbuf_addf(&refs_url, "%sinfo/refs", url.buf); if ((starts_with(url.buf, "http://") || starts_with(url.buf, "https://")) && git_env_bool("GIT_SMART_HTTP", 1)) { maybe_smart = 1; if (!strchr(url.buf, '?')) strbuf_addch(&refs_url, '?'); else strbuf_addch(&refs_url, '&'); strbuf_addf(&refs_url, "service=%s", service); } memset(&options, 0, sizeof(options)); options.content_type = &type; options.charset = &charset; options.effective_url = &effective_url; options.base_url = &url; options.no_cache = 1; options.keep_error = 1; http_ret = http_get_strbuf(refs_url.buf, &buffer, &options); switch (http_ret) { case HTTP_OK: break; case HTTP_MISSING_TARGET: show_http_message(&type, &charset, &buffer); die("repository '%s' not found", url.buf); case HTTP_NOAUTH: show_http_message(&type, &charset, &buffer); die("Authentication failed for '%s'", url.buf); default: show_http_message(&type, &charset, &buffer); die("unable to access '%s': %s", url.buf, curl_errorstr); } last= xcalloc(1, sizeof(*last_discovery)); last->service = service; last->buf_alloc = strbuf_detach(&buffer, &last->len); last->buf = last->buf_alloc; strbuf_addf(&exp, "application/x-%s-advertisement", service); if (maybe_smart && (5 <= last->len && last->buf[4] == '#') && !strbuf_cmp(&exp, &type)) { char *line; /* * smart HTTP response; validate that the service * pkt-line matches our request. */ line = packet_read_line_buf(&last->buf, &last->len, NULL); strbuf_reset(&exp); strbuf_addf(&exp, "# service=%s", service); if (strcmp(line, exp.buf)) die("invalid server response; got '%s'", line); strbuf_release(&exp); /* The header can include additional metadata lines, up * until a packet flush marker. Ignore these now, but * in the future we might start to scan them. */ while (packet_read_line_buf(&last->buf, &last->len, NULL)) ; last->proto_git = 1; } if (last->proto_git) last->refs = parse_git_refs(last, for_push); else last->refs = parse_info_refs(last); strbuf_release(&refs_url); strbuf_release(&exp); strbuf_release(&type); strbuf_release(&charset); strbuf_release(&effective_url); strbuf_release(&buffer); last_discovery = last; return last; }
static struct discovery *discover_refs(const char *service, int for_push) { struct strbuf exp = STRBUF_INIT; struct strbuf type = STRBUF_INIT; struct strbuf charset = STRBUF_INIT; struct strbuf buffer = STRBUF_INIT; struct strbuf refs_url = STRBUF_INIT; struct strbuf effective_url = STRBUF_INIT; struct strbuf protocol_header = STRBUF_INIT; struct string_list extra_headers = STRING_LIST_INIT_DUP; struct discovery *last = last_discovery; int http_ret, maybe_smart = 0; struct http_get_options http_options; enum protocol_version version = get_protocol_version_config(); if (last && !strcmp(service, last->service)) return last; free_discovery(last); strbuf_addf(&refs_url, "%sinfo/refs", url.buf); if ((starts_with(url.buf, "http://") || starts_with(url.buf, "https://")) && git_env_bool("GIT_SMART_HTTP", 1)) { maybe_smart = 1; if (!strchr(url.buf, '?')) strbuf_addch(&refs_url, '?'); else strbuf_addch(&refs_url, '&'); strbuf_addf(&refs_url, "service=%s", service); } /* * NEEDSWORK: If we are trying to use protocol v2 and we are planning * to perform a push, then fallback to v0 since the client doesn't know * how to push yet using v2. */ if (version == protocol_v2 && !strcmp("git-receive-pack", service)) version = protocol_v0; /* Add the extra Git-Protocol header */ if (get_protocol_http_header(version, &protocol_header)) string_list_append(&extra_headers, protocol_header.buf); memset(&http_options, 0, sizeof(http_options)); http_options.content_type = &type; http_options.charset = &charset; http_options.effective_url = &effective_url; http_options.base_url = &url; http_options.extra_headers = &extra_headers; http_options.initial_request = 1; http_options.no_cache = 1; http_options.keep_error = 1; http_ret = http_get_strbuf(refs_url.buf, &buffer, &http_options); switch (http_ret) { case HTTP_OK: break; case HTTP_MISSING_TARGET: show_http_message(&type, &charset, &buffer); die("repository '%s' not found", url.buf); case HTTP_NOAUTH: show_http_message(&type, &charset, &buffer); die("Authentication failed for '%s'", url.buf); default: show_http_message(&type, &charset, &buffer); die("unable to access '%s': %s", url.buf, curl_errorstr); } if (options.verbosity && !starts_with(refs_url.buf, url.buf)) warning(_("redirecting to %s"), url.buf); last= xcalloc(1, sizeof(*last_discovery)); last->service = xstrdup(service); last->buf_alloc = strbuf_detach(&buffer, &last->len); last->buf = last->buf_alloc; strbuf_addf(&exp, "application/x-%s-advertisement", service); if (maybe_smart && (5 <= last->len && last->buf[4] == '#') && !strbuf_cmp(&exp, &type)) { char *line; /* * smart HTTP response; validate that the service * pkt-line matches our request. */ line = packet_read_line_buf(&last->buf, &last->len, NULL); if (!line) die("invalid server response; expected service, got flush packet"); strbuf_reset(&exp); strbuf_addf(&exp, "# service=%s", service); if (strcmp(line, exp.buf)) die("invalid server response; got '%s'", line); strbuf_release(&exp); /* The header can include additional metadata lines, up * until a packet flush marker. Ignore these now, but * in the future we might start to scan them. */ while (packet_read_line_buf(&last->buf, &last->len, NULL)) ; last->proto_git = 1; } else if (maybe_smart && last->len > 5 && starts_with(last->buf + 4, "version 2")) { last->proto_git = 1; } if (last->proto_git) last->refs = parse_git_refs(last, for_push); else last->refs = parse_info_refs(last); strbuf_release(&refs_url); strbuf_release(&exp); strbuf_release(&type); strbuf_release(&charset); strbuf_release(&effective_url); strbuf_release(&buffer); strbuf_release(&protocol_header); string_list_clear(&extra_headers, 0); last_discovery = last; return last; }