]> git.ipfire.org Git - thirdparty/git.git/blobdiff - remote-curl.c
The 19th batch
[thirdparty/git.git] / remote-curl.c
index 1161dc7fed689259141ae2eb5403d84b906027d3..4adcf25ed6eeb57136961235b10fc8c03a39f3ba 100644 (file)
@@ -1,4 +1,7 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
+#include "git-curl-compat.h"
 #include "config.h"
 #include "environment.h"
 #include "gettext.h"
@@ -57,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)
@@ -67,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"))
@@ -76,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)
@@ -84,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"))
@@ -101,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"))
@@ -110,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"))
@@ -119,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"))
@@ -128,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 != '"')
@@ -138,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"))
@@ -146,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"))
@@ -154,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"))
@@ -162,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"))
@@ -172,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"))
@@ -180,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 {
@@ -191,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"))
@@ -201,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 */;
@@ -270,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)
@@ -299,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;
@@ -893,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;
@@ -926,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);
@@ -948,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);
@@ -960,7 +978,9 @@ retry:
                /* The request body is large and the size cannot be predicted.
                 * We must use chunked encoding to send it.
                 */
+#ifdef GIT_CURL_NEED_TRANSFER_ENCODING_HEADER
                headers = curl_slist_append(headers, "Transfer-Encoding: chunked");
+#endif
                rpc->initial_buffer = 1;
                curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, rpc_out);
                curl_easy_setopt(slot->curl, CURLOPT_INFILE, rpc);
@@ -1043,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)
@@ -1555,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);
@@ -1586,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)