http: update base URLs when we see redirects
[gitweb.git] / remote-curl.c
index 93a09a64c3b1689b0f29a26c6cdd601ef298b975..8ffd7ff7a7189ce2022a49ef808b43024b04dcc2 100644 (file)
@@ -7,6 +7,8 @@
 #include "run-command.h"
 #include "pkt-line.h"
 #include "sideband.h"
+#include "argv-array.h"
+#include "credential.h"
 
 static struct remote *remote;
 static const char *url; /* always ends with a trailing slash */
@@ -151,6 +153,33 @@ static void free_discovery(struct discovery *d)
        }
 }
 
+static int show_http_message(struct strbuf *type, struct strbuf *msg)
+{
+       const char *p, *eol;
+
+       /*
+        * We only show text/plain parts, as other types are likely
+        * to be ugly to look at on the user's terminal.
+        *
+        * TODO should handle "; charset=XXX", and re-encode into
+        * logoutputencoding
+        */
+       if (strcasecmp(type->buf, "text/plain"))
+               return -1;
+
+       strbuf_trim(msg);
+       if (!msg->len)
+               return -1;
+
+       p = msg->buf;
+       do {
+               eol = strchrnul(p, '\n');
+               fprintf(stderr, "remote: %.*s\n", (int)(eol - p), p);
+               p = eol + 1;
+       } while(*eol);
+       return 0;
+}
+
 static struct discovery* discover_refs(const char *service, int for_push)
 {
        struct strbuf exp = STRBUF_INIT;
@@ -159,6 +188,7 @@ static struct discovery* discover_refs(const char *service, int for_push)
        struct discovery *last = last_discovery;
        char *refs_url;
        int http_ret, maybe_smart = 0;
+       struct http_get_options options;
 
        if (last && !strcmp(service, last->service))
                return last;
@@ -176,18 +206,24 @@ static struct discovery* discover_refs(const char *service, int for_push)
        }
        refs_url = strbuf_detach(&buffer, NULL);
 
-       http_ret = http_get_strbuf(refs_url, &type, &buffer, HTTP_NO_CACHE);
+       memset(&options, 0, sizeof(options));
+       options.content_type = &type;
+       options.no_cache = 1;
+       options.keep_error = 1;
+
+       http_ret = http_get_strbuf(refs_url, &buffer, &options);
        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);
+               show_http_message(&type, &buffer);
+               die("repository '%s' not found", url);
        case HTTP_NOAUTH:
-               die("Authentication failed");
+               show_http_message(&type, &buffer);
+               die("Authentication failed for '%s'", url);
        default:
-               http_error(refs_url, http_ret);
-               die("HTTP request failed");
+               show_http_message(&type, &buffer);
+               die("unable to access '%s': %s", url, curl_errorstr);
        }
 
        last= xcalloc(1, sizeof(*last_discovery));
@@ -414,6 +450,8 @@ static int post_rpc(struct rpc_state *rpc)
        if (large_request) {
                do {
                        err = probe_rpc(rpc);
+                       if (err == HTTP_REAUTH)
+                               credential_fill(&http_auth);
                } while (err == HTTP_REAUTH);
                if (err != HTTP_OK)
                        return -1;
@@ -513,8 +551,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)
+       if (err == HTTP_REAUTH && !large_request) {
+               credential_fill(&http_auth);
                goto retry;
+       }
        if (err != HTTP_OK)
                err = -1;
 
@@ -758,36 +798,35 @@ static int push_dav(int nr_spec, char **specs)
 static int push_git(struct discovery *heads, int nr_spec, char **specs)
 {
        struct rpc_state rpc;
-       const char **argv;
-       int argc = 0, i, err;
+       int i, err;
+       struct argv_array args;
+
+       argv_array_init(&args);
+       argv_array_pushl(&args, "send-pack", "--stateless-rpc", "--helper-status",
+                        NULL);
 
-       argv = xmalloc((10 + nr_spec) * sizeof(char*));
-       argv[argc++] = "send-pack";
-       argv[argc++] = "--stateless-rpc";
-       argv[argc++] = "--helper-status";
        if (options.thin)
-               argv[argc++] = "--thin";
+               argv_array_push(&args, "--thin");
        if (options.dry_run)
-               argv[argc++] = "--dry-run";
+               argv_array_push(&args, "--dry-run");
        if (options.verbosity == 0)
-               argv[argc++] = "--quiet";
+               argv_array_push(&args, "--quiet");
        else if (options.verbosity > 1)
-               argv[argc++] = "--verbose";
-       argv[argc++] = options.progress ? "--progress" : "--no-progress";
-       argv[argc++] = url;
+               argv_array_push(&args, "--verbose");
+       argv_array_push(&args, options.progress ? "--progress" : "--no-progress");
+       argv_array_push(&args, url);
        for (i = 0; i < nr_spec; i++)
-               argv[argc++] = specs[i];
-       argv[argc++] = NULL;
+               argv_array_push(&args, specs[i]);
 
        memset(&rpc, 0, sizeof(rpc));
        rpc.service_name = "git-receive-pack",
-       rpc.argv = argv;
+       rpc.argv = args.argv;
 
        err = rpc_service(&rpc, heads);
        if (rpc.result.len)
                write_or_die(1, rpc.result.buf, rpc.result.len);
        strbuf_release(&rpc.result);
-       free(argv);
+       argv_array_clear(&args);
        return err;
 }