Merge branch 'sc/http-late-auth' into maint
authorJunio C Hamano <gitster@pobox.com>
Wed, 16 Jun 2010 23:32:15 +0000 (16:32 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 16 Jun 2010 23:32:15 +0000 (16:32 -0700)
* sc/http-late-auth:
Prompt for a username when an HTTP request 401s

1  2 
http.c
http.h
remote-curl.c
diff --combined http.c
index 901e5972970e672f2524d70d11d4c3bb74ce98c5,51253e15a160b8bade37d24308ac3de92e5abe89..1320c50e32eb7b8715b263bc2af089c3dbce39fa
--- 1/http.c
--- 2/http.c
+++ b/http.c
@@@ -1,7 -1,6 +1,7 @@@
  #include "http.h"
  #include "pack.h"
  #include "sideband.h"
 +#include "run-command.h"
  
  int data_received;
  int active_requests;
@@@ -721,7 -720,7 +721,7 @@@ static inline int hex(int v
                return 'A' + v - 10;
  }
  
 -static void end_url_with_slash(struct strbuf *buf, const char *url)
 +void end_url_with_slash(struct strbuf *buf, const char *url)
  {
        strbuf_addstr(buf, url);
        if (buf->len && buf->buf[buf->len - 1] != '/')
@@@ -816,7 -815,21 +816,21 @@@ static int http_request(const char *url
                        ret = HTTP_OK;
                else if (missing_target(&results))
                        ret = HTTP_MISSING_TARGET;
-               else
+               else if (results.http_code == 401) {
+                       if (user_name) {
+                               ret = HTTP_NOAUTH;
+                       } else {
+                               /*
+                                * git_getpass is needed here because its very likely stdin/stdout are
+                                * pipes to our parent process.  So we instead need to use /dev/tty,
+                                * but that is non-portable.  Using git_getpass() can at least be stubbed
+                                * on other platforms with a different implementation if/when necessary.
+                                */
+                               user_name = xstrdup(git_getpass("Username: "));
+                               init_curl_http_auth(slot->curl);
+                               ret = HTTP_REAUTH;
+                       }
+               } else
                        ret = HTTP_ERROR;
        } else {
                error("Unable to start HTTP request for %s", url);
  
  int http_get_strbuf(const char *url, struct strbuf *result, int options)
  {
-       return http_request(url, result, HTTP_REQUEST_STRBUF, options);
+       int http_ret = http_request(url, result, HTTP_REQUEST_STRBUF, options);
+       if (http_ret == HTTP_REAUTH) {
+               http_ret = http_request(url, result, HTTP_REQUEST_STRBUF, options);
+       }
+       return http_ret;
  }
  
  /*
@@@ -897,67 -914,47 +915,67 @@@ int http_fetch_ref(const char *base, st
  }
  
  /* Helpers for fetching packs */
 -static int fetch_pack_index(unsigned char *sha1, const char *base_url)
 +static char *fetch_pack_index(unsigned char *sha1, const char *base_url)
  {
 -      int ret = 0;
 -      char *hex = xstrdup(sha1_to_hex(sha1));
 -      char *filename;
 -      char *url = NULL;
 +      char *url, *tmp;
        struct strbuf buf = STRBUF_INIT;
  
 -      if (has_pack_index(sha1)) {
 -              ret = 0;
 -              goto cleanup;
 -      }
 -
        if (http_is_verbose)
 -              fprintf(stderr, "Getting index for pack %s\n", hex);
 +              fprintf(stderr, "Getting index for pack %s\n", sha1_to_hex(sha1));
  
        end_url_with_slash(&buf, base_url);
 -      strbuf_addf(&buf, "objects/pack/pack-%s.idx", hex);
 +      strbuf_addf(&buf, "objects/pack/pack-%s.idx", sha1_to_hex(sha1));
        url = strbuf_detach(&buf, NULL);
  
 -      filename = sha1_pack_index_name(sha1);
 -      if (http_get_file(url, filename, 0) != HTTP_OK)
 -              ret = error("Unable to get pack index %s\n", url);
 +      strbuf_addf(&buf, "%s.temp", sha1_pack_index_name(sha1));
 +      tmp = strbuf_detach(&buf, NULL);
 +
 +      if (http_get_file(url, tmp, 0) != HTTP_OK) {
 +              error("Unable to get pack index %s\n", url);
 +              free(tmp);
 +              tmp = NULL;
 +      }
  
 -cleanup:
 -      free(hex);
        free(url);
 -      return ret;
 +      return tmp;
  }
  
  static int fetch_and_setup_pack_index(struct packed_git **packs_head,
        unsigned char *sha1, const char *base_url)
  {
        struct packed_git *new_pack;
 +      char *tmp_idx = NULL;
 +      int ret;
  
 -      if (fetch_pack_index(sha1, base_url))
 +      if (has_pack_index(sha1)) {
 +              new_pack = parse_pack_index(sha1, NULL);
 +              if (!new_pack)
 +                      return -1; /* parse_pack_index() already issued error message */
 +              goto add_pack;
 +      }
 +
 +      tmp_idx = fetch_pack_index(sha1, base_url);
 +      if (!tmp_idx)
                return -1;
  
 -      new_pack = parse_pack_index(sha1);
 -      if (!new_pack)
 +      new_pack = parse_pack_index(sha1, tmp_idx);
 +      if (!new_pack) {
 +              unlink(tmp_idx);
 +              free(tmp_idx);
 +
                return -1; /* parse_pack_index() already issued error message */
 +      }
 +
 +      ret = verify_pack_index(new_pack);
 +      if (!ret) {
 +              close_pack_index(new_pack);
 +              ret = move_temp_to_file(tmp_idx, sha1_pack_index_name(sha1));
 +      }
 +      free(tmp_idx);
 +      if (ret)
 +              return -1;
 +
 +add_pack:
        new_pack->next = *packs_head;
        *packs_head = new_pack;
        return 0;
@@@ -1021,62 -1018,37 +1039,62 @@@ void release_http_pack_request(struct h
  
  int finish_http_pack_request(struct http_pack_request *preq)
  {
 -      int ret;
        struct packed_git **lst;
 +      struct packed_git *p = preq->target;
 +      char *tmp_idx;
 +      struct child_process ip;
 +      const char *ip_argv[8];
  
 -      preq->target->pack_size = ftell(preq->packfile);
 +      close_pack_index(p);
  
 -      if (preq->packfile != NULL) {
 -              fclose(preq->packfile);
 -              preq->packfile = NULL;
 -              preq->slot->local = NULL;
 -      }
 -
 -      ret = move_temp_to_file(preq->tmpfile, preq->filename);
 -      if (ret)
 -              return ret;
 +      fclose(preq->packfile);
 +      preq->packfile = NULL;
 +      preq->slot->local = NULL;
  
        lst = preq->lst;
 -      while (*lst != preq->target)
 +      while (*lst != p)
                lst = &((*lst)->next);
        *lst = (*lst)->next;
  
 -      if (verify_pack(preq->target))
 +      tmp_idx = xstrdup(preq->tmpfile);
 +      strcpy(tmp_idx + strlen(tmp_idx) - strlen(".pack.temp"),
 +             ".idx.temp");
 +
 +      ip_argv[0] = "index-pack";
 +      ip_argv[1] = "-o";
 +      ip_argv[2] = tmp_idx;
 +      ip_argv[3] = preq->tmpfile;
 +      ip_argv[4] = NULL;
 +
 +      memset(&ip, 0, sizeof(ip));
 +      ip.argv = ip_argv;
 +      ip.git_cmd = 1;
 +      ip.no_stdin = 1;
 +      ip.no_stdout = 1;
 +
 +      if (run_command(&ip)) {
 +              unlink(preq->tmpfile);
 +              unlink(tmp_idx);
 +              free(tmp_idx);
 +              return -1;
 +      }
 +
 +      unlink(sha1_pack_index_name(p->sha1));
 +
 +      if (move_temp_to_file(preq->tmpfile, sha1_pack_name(p->sha1))
 +       || move_temp_to_file(tmp_idx, sha1_pack_index_name(p->sha1))) {
 +              free(tmp_idx);
                return -1;
 -      install_packed_git(preq->target);
 +      }
  
 +      install_packed_git(p);
 +      free(tmp_idx);
        return 0;
  }
  
  struct http_pack_request *new_http_pack_request(
        struct packed_git *target, const char *base_url)
  {
 -      char *filename;
        long prev_posn = 0;
        char range[RANGE_HEADER_SIZE];
        struct strbuf buf = STRBUF_INIT;
                sha1_to_hex(target->sha1));
        preq->url = strbuf_detach(&buf, NULL);
  
 -      filename = sha1_pack_name(target->sha1);
 -      snprintf(preq->filename, sizeof(preq->filename), "%s", filename);
 -      snprintf(preq->tmpfile, sizeof(preq->tmpfile), "%s.temp", filename);
 +      snprintf(preq->tmpfile, sizeof(preq->tmpfile), "%s.temp",
 +              sha1_pack_name(target->sha1));
        preq->packfile = fopen(preq->tmpfile, "a");
        if (!preq->packfile) {
                error("Unable to open local file %s for pack",
        return preq;
  
  abort:
 -      free(filename);
        free(preq->url);
        free(preq);
        return NULL;
@@@ -1181,6 -1155,7 +1199,6 @@@ struct http_object_request *new_http_ob
        freq->localfile = -1;
  
        filename = sha1_file_name(sha1);
 -      snprintf(freq->filename, sizeof(freq->filename), "%s", filename);
        snprintf(freq->tmpfile, sizeof(freq->tmpfile),
                 "%s.temp", filename);
  
        }
  
        if (freq->localfile < 0) {
 -              error("Couldn't create temporary file %s for %s: %s",
 -                    freq->tmpfile, freq->filename, strerror(errno));
 +              error("Couldn't create temporary file %s: %s",
 +                    freq->tmpfile, strerror(errno));
                goto abort;
        }
  
                        prev_posn = 0;
                        lseek(freq->localfile, 0, SEEK_SET);
                        if (ftruncate(freq->localfile, 0) < 0) {
 -                              error("Couldn't truncate temporary file %s for %s: %s",
 -                                        freq->tmpfile, freq->filename, strerror(errno));
 +                              error("Couldn't truncate temporary file %s: %s",
 +                                        freq->tmpfile, strerror(errno));
                                goto abort;
                        }
                }
@@@ -1334,7 -1309,7 +1352,7 @@@ int finish_http_object_request(struct h
                return -1;
        }
        freq->rename =
 -              move_temp_to_file(freq->tmpfile, freq->filename);
 +              move_temp_to_file(freq->tmpfile, sha1_file_name(freq->sha1));
  
        return freq->rename;
  }
diff --combined http.h
index b431b8bd5b6d694dd01fc92b2ffcca41655d82bf,2dd03e88b75e2f4dd7b328e5baf5359adebc945e..a0b59015948c3b9736dd6c09fd9137f7ecd4f59a
--- 1/http.h
--- 2/http.h
+++ b/http.h
@@@ -117,7 -117,6 +117,7 @@@ extern void append_remote_object_url(st
                                     int only_two_digit_prefix);
  extern char *get_remote_object_url(const char *url, const char *hex,
                                   int only_two_digit_prefix);
 +extern void end_url_with_slash(struct strbuf *buf, const char *url);
  
  /* Options for http_request_*() */
  #define HTTP_NO_CACHE         1
  #define HTTP_MISSING_TARGET   1
  #define HTTP_ERROR            2
  #define HTTP_START_FAILED     3
+ #define HTTP_REAUTH   4
+ #define HTTP_NOAUTH   5
  
  /*
   * Requests an url and stores the result in a strbuf.
@@@ -153,6 -154,7 +155,6 @@@ struct http_pack_reques
        struct packed_git *target;
        struct packed_git **lst;
        FILE *packfile;
 -      char filename[PATH_MAX];
        char tmpfile[PATH_MAX];
        struct curl_slist *range_header;
        struct active_request_slot *slot;
@@@ -167,6 -169,7 +169,6 @@@ extern void release_http_pack_request(s
  struct http_object_request
  {
        char *url;
 -      char filename[PATH_MAX];
        char tmpfile[PATH_MAX];
        int localfile;
        CURLcode curl_result;
diff --combined remote-curl.c
index 9c7fcf29566caa3813bd91a22fc78a00cec05335,07827562b56e38be543201f80e77ea581f9428f3..24fbb9a9b972c1078b3688b2d0683c9704e09ee6
@@@ -9,7 -9,7 +9,7 @@@
  #include "sideband.h"
  
  static struct remote *remote;
 -static const char *url;
 +static const char *url; /* always ends with a trailing slash */
  
  struct options {
        int verbosity;
@@@ -101,7 -101,7 +101,7 @@@ static struct discovery* discover_refs(
                return last;
        free_discovery(last);
  
 -      strbuf_addf(&buffer, "%s/info/refs", url);
 +      strbuf_addf(&buffer, "%sinfo/refs", url);
        if (!prefixcmp(url, "http://") || !prefixcmp(url, "https://")) {
                is_http = 1;
                if (!strchr(url, '?'))
                strbuf_reset(&buffer);
  
                proto_git_candidate = 0;
 -              strbuf_addf(&buffer, "%s/info/refs", url);
 +              strbuf_addf(&buffer, "%sinfo/refs", url);
                refs_url = strbuf_detach(&buffer, NULL);
  
                http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE);
        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");
@@@ -509,7 -511,7 +511,7 @@@ static int rpc_service(struct rpc_stat
        rpc->out = client.out;
        strbuf_init(&rpc->result, 0);
  
 -      strbuf_addf(&buf, "%s/%s", url, svc);
 +      strbuf_addf(&buf, "%s%s", url, svc);
        rpc->service_url = strbuf_detach(&buf, NULL);
  
        strbuf_addf(&buf, "Content-Type: application/x-%s-request", svc);
@@@ -798,13 -800,11 +800,13 @@@ int main(int argc, const char **argv
        remote = remote_get(argv[1]);
  
        if (argc > 2) {
 -              url = argv[2];
 +              end_url_with_slash(&buf, argv[2]);
        } else {
 -              url = remote->url[0];
 +              end_url_with_slash(&buf, remote->url[0]);
        }
  
 +      url = strbuf_detach(&buf, NULL);
 +
        http_init(remote);
  
        do {