summaryrefslogtreecommitdiff
path: root/remote-curl.c
diff options
context:
space:
mode:
Diffstat (limited to 'remote-curl.c')
-rw-r--r--remote-curl.c125
1 files changed, 77 insertions, 48 deletions
diff --git a/remote-curl.c b/remote-curl.c
index dad241e89d..9a71e04301 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "git-curl-compat.h"
#include "config.h"
@@ -9,11 +11,9 @@
#include "strbuf.h"
#include "walker.h"
#include "http.h"
-#include "exec-cmd.h"
#include "run-command.h"
#include "pkt-line.h"
#include "string-list.h"
-#include "sideband.h"
#include "strvec.h"
#include "credential.h"
#include "oid-array.h"
@@ -23,6 +23,7 @@
#include "quote.h"
#include "trace2.h"
#include "transport.h"
+#include "url.h"
#include "write-or-die.h"
static struct remote *remote;
@@ -59,9 +60,9 @@ struct options {
static struct options options;
static struct string_list cas_options = STRING_LIST_INIT_DUP;
-static int set_option(const char *name, const char *value)
+static int set_option(const char *name, size_t namelen, const char *value)
{
- if (!strcmp(name, "verbosity")) {
+ if (!strncmp(name, "verbosity", namelen)) {
char *end;
int v = strtol(value, &end, 10);
if (value == end || *end)
@@ -69,7 +70,7 @@ static int set_option(const char *name, const char *value)
options.verbosity = v;
return 0;
}
- else if (!strcmp(name, "progress")) {
+ else if (!strncmp(name, "progress", namelen)) {
if (!strcmp(value, "true"))
options.progress = 1;
else if (!strcmp(value, "false"))
@@ -78,7 +79,7 @@ static int set_option(const char *name, const char *value)
return -1;
return 0;
}
- else if (!strcmp(name, "depth")) {
+ else if (!strncmp(name, "depth", namelen)) {
char *end;
unsigned long v = strtoul(value, &end, 10);
if (value == end || *end)
@@ -86,15 +87,15 @@ static int set_option(const char *name, const char *value)
options.depth = v;
return 0;
}
- else if (!strcmp(name, "deepen-since")) {
+ else if (!strncmp(name, "deepen-since", namelen)) {
options.deepen_since = xstrdup(value);
return 0;
}
- else if (!strcmp(name, "deepen-not")) {
+ else if (!strncmp(name, "deepen-not", namelen)) {
string_list_append(&options.deepen_not, value);
return 0;
}
- else if (!strcmp(name, "deepen-relative")) {
+ else if (!strncmp(name, "deepen-relative", namelen)) {
if (!strcmp(value, "true"))
options.deepen_relative = 1;
else if (!strcmp(value, "false"))
@@ -103,7 +104,7 @@ static int set_option(const char *name, const char *value)
return -1;
return 0;
}
- else if (!strcmp(name, "followtags")) {
+ else if (!strncmp(name, "followtags", namelen)) {
if (!strcmp(value, "true"))
options.followtags = 1;
else if (!strcmp(value, "false"))
@@ -112,7 +113,7 @@ static int set_option(const char *name, const char *value)
return -1;
return 0;
}
- else if (!strcmp(name, "dry-run")) {
+ else if (!strncmp(name, "dry-run", namelen)) {
if (!strcmp(value, "true"))
options.dry_run = 1;
else if (!strcmp(value, "false"))
@@ -121,7 +122,7 @@ static int set_option(const char *name, const char *value)
return -1;
return 0;
}
- else if (!strcmp(name, "check-connectivity")) {
+ else if (!strncmp(name, "check-connectivity", namelen)) {
if (!strcmp(value, "true"))
options.check_self_contained_and_connected = 1;
else if (!strcmp(value, "false"))
@@ -130,7 +131,7 @@ static int set_option(const char *name, const char *value)
return -1;
return 0;
}
- else if (!strcmp(name, "cas")) {
+ else if (!strncmp(name, "cas", namelen)) {
struct strbuf val = STRBUF_INIT;
strbuf_addstr(&val, "--force-with-lease=");
if (*value != '"')
@@ -140,7 +141,7 @@ static int set_option(const char *name, const char *value)
string_list_append(&cas_options, val.buf);
strbuf_release(&val);
return 0;
- } else if (!strcmp(name, TRANS_OPT_FORCE_IF_INCLUDES)) {
+ } else if (!strncmp(name, TRANS_OPT_FORCE_IF_INCLUDES, namelen)) {
if (!strcmp(value, "true"))
options.force_if_includes = 1;
else if (!strcmp(value, "false"))
@@ -148,7 +149,7 @@ static int set_option(const char *name, const char *value)
else
return -1;
return 0;
- } else if (!strcmp(name, "cloning")) {
+ } else if (!strncmp(name, "cloning", namelen)) {
if (!strcmp(value, "true"))
options.cloning = 1;
else if (!strcmp(value, "false"))
@@ -156,7 +157,7 @@ static int set_option(const char *name, const char *value)
else
return -1;
return 0;
- } else if (!strcmp(name, "update-shallow")) {
+ } else if (!strncmp(name, "update-shallow", namelen)) {
if (!strcmp(value, "true"))
options.update_shallow = 1;
else if (!strcmp(value, "false"))
@@ -164,7 +165,7 @@ static int set_option(const char *name, const char *value)
else
return -1;
return 0;
- } else if (!strcmp(name, "pushcert")) {
+ } else if (!strncmp(name, "pushcert", namelen)) {
if (!strcmp(value, "true"))
options.push_cert = SEND_PACK_PUSH_CERT_ALWAYS;
else if (!strcmp(value, "false"))
@@ -174,7 +175,7 @@ static int set_option(const char *name, const char *value)
else
return -1;
return 0;
- } else if (!strcmp(name, "atomic")) {
+ } else if (!strncmp(name, "atomic", namelen)) {
if (!strcmp(value, "true"))
options.atomic = 1;
else if (!strcmp(value, "false"))
@@ -182,7 +183,7 @@ static int set_option(const char *name, const char *value)
else
return -1;
return 0;
- } else if (!strcmp(name, "push-option")) {
+ } else if (!strncmp(name, "push-option", namelen)) {
if (*value != '"')
string_list_append(&options.push_options, value);
else {
@@ -193,7 +194,7 @@ static int set_option(const char *name, const char *value)
strbuf_detach(&unquoted, NULL));
}
return 0;
- } else if (!strcmp(name, "family")) {
+ } else if (!strncmp(name, "family", namelen)) {
if (!strcmp(value, "ipv4"))
git_curl_ipresolve = CURL_IPRESOLVE_V4;
else if (!strcmp(value, "ipv6"))
@@ -203,24 +204,19 @@ static int set_option(const char *name, const char *value)
else
return -1;
return 0;
- } else if (!strcmp(name, "from-promisor")) {
+ } else if (!strncmp(name, "from-promisor", namelen)) {
options.from_promisor = 1;
return 0;
- } else if (!strcmp(name, "refetch")) {
+ } else if (!strncmp(name, "refetch", namelen)) {
options.refetch = 1;
return 0;
- } else if (!strcmp(name, "filter")) {
+ } else if (!strncmp(name, "filter", namelen)) {
options.filter = xstrdup(value);
return 0;
- } else if (!strcmp(name, "object-format")) {
- int algo;
+ } else if (!strncmp(name, "object-format", namelen)) {
options.object_format = 1;
- if (strcmp(value, "true")) {
- algo = hash_algo_by_name(value);
- if (algo == GIT_HASH_UNKNOWN)
- die("unknown object format '%s'", value);
- options.hash_algo = &hash_algos[algo];
- }
+ if (strcmp(value, "true"))
+ die(_("unknown value for object-format: %s"), value);
return 0;
} else {
return 1 /* unsupported */;
@@ -272,12 +268,23 @@ static struct ref *parse_git_refs(struct discovery *heads, int for_push)
return list;
}
+/*
+ * Try to detect the hash algorithm used by the remote repository when using
+ * the dumb HTTP transport. As dumb transports cannot tell us the object hash
+ * directly have to derive it from the advertised ref lengths.
+ */
static const struct git_hash_algo *detect_hash_algo(struct discovery *heads)
{
const char *p = memchr(heads->buf, '\t', heads->len);
int algo;
+
+ /*
+ * In case the remote has no refs we have no way to reliably determine
+ * the object hash used by that repository. In that case we simply fall
+ * back to SHA1, which may or may not be correct.
+ */
if (!p)
- return the_hash_algo;
+ return &hash_algos[GIT_HASH_SHA1];
algo = hash_algo_by_length((p - heads->buf) / 2);
if (algo == GIT_HASH_UNKNOWN)
@@ -301,6 +308,12 @@ static struct ref *parse_info_refs(struct discovery *heads)
"is this a git repository?",
transport_anonymize_url(url.buf));
+ /*
+ * Set the repository's hash algo to whatever we have just detected.
+ * This ensures that we can correctly parse the remote references.
+ */
+ repo_set_hash_algo(the_repository, hash_algo_by_ptr(options.hash_algo));
+
data = heads->buf;
start = NULL;
mid = data;
@@ -334,7 +347,7 @@ static struct ref *parse_info_refs(struct discovery *heads)
ref->next = refs;
refs = ref;
} else {
- free(ref);
+ free_one_ref(ref);
}
return refs;
@@ -895,7 +908,7 @@ static curl_off_t xcurl_off_t(size_t len)
static int post_rpc(struct rpc_state *rpc, int stateless_connect, int flush_received)
{
struct active_request_slot *slot;
- struct curl_slist *headers = http_copy_default_headers();
+ struct curl_slist *headers = NULL;
int use_gzip = rpc->gzip_request;
char *gzip_body = NULL;
size_t gzip_size = 0;
@@ -928,20 +941,24 @@ static int post_rpc(struct rpc_state *rpc, int stateless_connect, int flush_rece
do {
err = probe_rpc(rpc, &results);
if (err == HTTP_REAUTH)
- credential_fill(&http_auth);
+ credential_fill(&http_auth, 0);
} while (err == HTTP_REAUTH);
if (err != HTTP_OK)
return -1;
- if (results.auth_avail & CURLAUTH_GSSNEGOTIATE)
+ if (results.auth_avail & CURLAUTH_GSSNEGOTIATE || http_auth.authtype)
needs_100_continue = 1;
}
+retry:
+ headers = http_copy_default_headers();
headers = curl_slist_append(headers, rpc->hdr_content_type);
headers = curl_slist_append(headers, rpc->hdr_accept);
headers = curl_slist_append(headers, needs_100_continue ?
"Expect: 100-continue" : "Expect:");
+ headers = http_append_auth_header(&http_auth, headers);
+
/* Add Accept-Language header */
if (rpc->hdr_accept_language)
headers = curl_slist_append(headers, rpc->hdr_accept_language);
@@ -950,7 +967,6 @@ static int post_rpc(struct rpc_state *rpc, int stateless_connect, int flush_rece
if (rpc->protocol_header)
headers = curl_slist_append(headers, rpc->protocol_header);
-retry:
slot = get_active_slot();
curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
@@ -1047,7 +1063,8 @@ retry:
rpc->any_written = 0;
err = run_slot(slot, NULL);
if (err == HTTP_REAUTH && !large_request) {
- credential_fill(&http_auth);
+ credential_fill(&http_auth, 0);
+ curl_slist_free_all(headers);
goto retry;
}
if (err != HTTP_OK)
@@ -1450,8 +1467,14 @@ static int stateless_connect(const char *service_name)
* establish a stateless connection, otherwise we need to tell the
* client to fallback to using other transport helper functions to
* complete their request.
+ *
+ * The "git-upload-archive" service is a read-only operation. Fallback
+ * to use "git-upload-pack" service to discover protocol version.
*/
- discover = discover_refs(service_name, 0);
+ if (!strcmp(service_name, "git-upload-archive"))
+ discover = discover_refs("git-upload-pack", 0);
+ else
+ discover = discover_refs(service_name, 0);
if (discover->version != protocol_v2) {
printf("fallback\n");
fflush(stdout);
@@ -1489,9 +1512,11 @@ static int stateless_connect(const char *service_name)
/*
* Dump the capability listing that we got from the server earlier
- * during the info/refs request.
+ * during the info/refs request. This does not work with the
+ * "git-upload-archive" service.
*/
- write_or_die(rpc.in, discover->buf, discover->len);
+ if (strcmp(service_name, "git-upload-archive"))
+ write_or_die(rpc.in, discover->buf, discover->len);
/* Until we see EOF keep sending POSTs */
while (1) {
@@ -1551,7 +1576,7 @@ int cmd_main(int argc, const char **argv)
if (argc > 2) {
end_url_with_slash(&url, argv[2]);
} else {
- end_url_with_slash(&url, remote->url[0]);
+ end_url_with_slash(&url, remote->url.v[0]);
}
http_init(remote, url.buf, 0);
@@ -1567,8 +1592,11 @@ int cmd_main(int argc, const char **argv)
if (buf.len == 0)
break;
if (starts_with(buf.buf, "fetch ")) {
- if (nongit)
- die(_("remote-curl: fetch attempted without a local repo"));
+ if (nongit) {
+ setup_git_directory_gently(&nongit);
+ if (nongit)
+ die(_("remote-curl: fetch attempted without a local repo"));
+ }
parse_fetch(&buf);
} else if (!strcmp(buf.buf, "list") || starts_with(buf.buf, "list ")) {
@@ -1579,15 +1607,16 @@ int cmd_main(int argc, const char **argv)
parse_push(&buf);
} else if (skip_prefix(buf.buf, "option ", &arg)) {
- char *value = strchr(arg, ' ');
+ const char *value = strchrnul(arg, ' ');
+ size_t arglen = value - arg;
int result;
- if (value)
- *value++ = '\0';
+ if (*value)
+ value++; /* skip over SP */
else
value = "true";
- result = set_option(arg, value);
+ result = set_option(arg, arglen, value);
if (!result)
printf("ok\n");
else if (result < 0)