Ignore:
Timestamp:
Jun 23, 2014, 9:45:51 PM (11 years ago)
Author:
dmik
Message:

git: Merge version 2.0.0 from vendor to dmik branch.

Location:
git/branches/dmik
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • git/branches/dmik

  • TabularUnified git/branches/dmik/remote-curl.c

    r626 r782  
    77#include "run-command.h"
    88#include "pkt-line.h"
     9#include "string-list.h"
    910#include "sideband.h"
     11#include "argv-array.h"
     12#include "credential.h"
     13#include "sha1-array.h"
    1014
    1115static struct remote *remote;
    12 static const char *url; /* always ends with a trailing slash */
     16/* always ends with a trailing slash */
     17static struct strbuf url = STRBUF_INIT;
    1318
    1419struct options {
     
    1621        unsigned long depth;
    1722        unsigned progress : 1,
     23                check_self_contained_and_connected : 1,
     24                cloning : 1,
     25                update_shallow : 1,
    1826                followtags : 1,
    1927                dry_run : 1,
     
    2129};
    2230static struct options options;
     31static struct string_list cas_options = STRING_LIST_INIT_DUP;
    2332
    2433static int set_option(const char *name, const char *value)
     
    6776                return 0;
    6877        }
    69         else {
     78        else if (!strcmp(name, "check-connectivity")) {
     79                if (!strcmp(value, "true"))
     80                        options.check_self_contained_and_connected = 1;
     81                else if (!strcmp(value, "false"))
     82                        options.check_self_contained_and_connected = 0;
     83                else
     84                        return -1;
     85                return 0;
     86        }
     87        else if (!strcmp(name, "cas")) {
     88                struct strbuf val = STRBUF_INIT;
     89                strbuf_addf(&val, "--" CAS_OPT_NAME "=%s", value);
     90                string_list_append(&cas_options, val.buf);
     91                strbuf_release(&val);
     92                return 0;
     93        } else if (!strcmp(name, "cloning")) {
     94                if (!strcmp(value, "true"))
     95                        options.cloning = 1;
     96                else if (!strcmp(value, "false"))
     97                        options.cloning = 0;
     98                else
     99                        return -1;
     100                return 0;
     101        } else if (!strcmp(name, "update-shallow")) {
     102                if (!strcmp(value, "true"))
     103                        options.update_shallow = 1;
     104                else if (!strcmp(value, "false"))
     105                        options.update_shallow = 0;
     106                else
     107                        return -1;
     108                return 0;
     109        } else {
    70110                return 1 /* unsupported */;
    71111        }
     
    77117        char *buf;
    78118        size_t len;
     119        struct ref *refs;
     120        struct sha1_array shallow;
    79121        unsigned proto_git : 1;
    80122};
    81123static struct discovery *last_discovery;
    82124
    83 static void free_discovery(struct discovery *d)
    84 {
    85         if (d) {
    86                 if (d == last_discovery)
    87                         last_discovery = NULL;
    88                 free(d->buf_alloc);
    89                 free(d);
    90         }
    91 }
    92 
    93 static struct discovery* discover_refs(const char *service)
    94 {
    95         struct strbuf buffer = STRBUF_INIT;
    96         struct discovery *last = last_discovery;
    97         char *refs_url;
    98         int http_ret, is_http = 0, proto_git_candidate = 1;
    99 
    100         if (last && !strcmp(service, last->service))
    101                 return last;
    102         free_discovery(last);
    103 
    104         strbuf_addf(&buffer, "%sinfo/refs", url);
    105         if (!prefixcmp(url, "http://") || !prefixcmp(url, "https://")) {
    106                 is_http = 1;
    107                 if (!strchr(url, '?'))
    108                         strbuf_addch(&buffer, '?');
    109                 else
    110                         strbuf_addch(&buffer, '&');
    111                 strbuf_addf(&buffer, "service=%s", service);
    112         }
    113         refs_url = strbuf_detach(&buffer, NULL);
    114 
    115         http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE);
    116 
    117         /* try again with "plain" url (no ? or & appended) */
    118         if (http_ret != HTTP_OK && http_ret != HTTP_NOAUTH) {
    119                 free(refs_url);
    120                 strbuf_reset(&buffer);
    121 
    122                 proto_git_candidate = 0;
    123                 strbuf_addf(&buffer, "%sinfo/refs", url);
    124                 refs_url = strbuf_detach(&buffer, NULL);
    125 
    126                 http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE);
    127         }
    128 
    129         switch (http_ret) {
    130         case HTTP_OK:
    131                 break;
    132         case HTTP_MISSING_TARGET:
    133                 die("%s not found: did you run git update-server-info on the"
    134                     " server?", refs_url);
    135         case HTTP_NOAUTH:
    136                 die("Authentication failed");
    137         default:
    138                 http_error(refs_url, http_ret);
    139                 die("HTTP request failed");
    140         }
    141 
    142         last= xcalloc(1, sizeof(*last_discovery));
    143         last->service = service;
    144         last->buf_alloc = strbuf_detach(&buffer, &last->len);
    145         last->buf = last->buf_alloc;
    146 
    147         if (is_http && proto_git_candidate
    148                 && 5 <= last->len && last->buf[4] == '#') {
    149                 /* smart HTTP response; validate that the service
    150                  * pkt-line matches our request.
    151                  */
    152                 struct strbuf exp = STRBUF_INIT;
    153 
    154                 if (packet_get_line(&buffer, &last->buf, &last->len) <= 0)
    155                         die("%s has invalid packet header", refs_url);
    156                 if (buffer.len && buffer.buf[buffer.len - 1] == '\n')
    157                         strbuf_setlen(&buffer, buffer.len - 1);
    158 
    159                 strbuf_addf(&exp, "# service=%s", service);
    160                 if (strbuf_cmp(&exp, &buffer))
    161                         die("invalid server response; got '%s'", buffer.buf);
    162                 strbuf_release(&exp);
    163 
    164                 /* The header can include additional metadata lines, up
    165                  * until a packet flush marker.  Ignore these now, but
    166                  * in the future we might start to scan them.
    167                  */
    168                 strbuf_reset(&buffer);
    169                 while (packet_get_line(&buffer, &last->buf, &last->len) > 0)
    170                         strbuf_reset(&buffer);
    171 
    172                 last->proto_git = 1;
    173         }
    174 
    175         free(refs_url);
    176         strbuf_release(&buffer);
    177         last_discovery = last;
    178         return last;
    179 }
    180 
    181 static int write_discovery(int in, int out, void *data)
    182 {
    183         struct discovery *heads = data;
    184         int err = 0;
    185         if (write_in_full(out, heads->buf, heads->len) != heads->len)
    186                 err = 1;
    187         close(out);
    188         return err;
    189 }
    190 
    191125static struct ref *parse_git_refs(struct discovery *heads, int for_push)
    192126{
    193127        struct ref *list = NULL;
    194         struct async async;
    195 
    196         memset(&async, 0, sizeof(async));
    197         async.proc = write_discovery;
    198         async.data = heads;
    199         async.out = -1;
    200 
    201         if (start_async(&async))
    202                 die("cannot start thread to parse advertised refs");
    203         get_remote_heads(async.out, &list,
    204                         for_push ? REF_NORMAL : 0, NULL);
    205         close(async.out);
    206         if (finish_async(&async))
    207                 die("ref parsing thread failed");
     128        get_remote_heads(-1, heads->buf, heads->len, &list,
     129                         for_push ? REF_NORMAL : 0, NULL, &heads->shallow);
    208130        return list;
    209131}
     
    230152                if (data[i] == '\n') {
    231153                        if (mid - start != 40)
    232                                 die("%sinfo/refs not valid: is this a git repository?", url);
     154                                die("%sinfo/refs not valid: is this a git repository?",
     155                                    url.buf);
    233156                        data[i] = 0;
    234157                        ref_name = mid + 1;
     
    249172
    250173        ref = alloc_ref("HEAD");
    251         if (!http_fetch_ref(url, ref) &&
     174        if (!http_fetch_ref(url.buf, ref) &&
    252175            !resolve_remote_symref(ref, refs)) {
    253176                ref->next = refs;
     
    260183}
    261184
     185static void free_discovery(struct discovery *d)
     186{
     187        if (d) {
     188                if (d == last_discovery)
     189                        last_discovery = NULL;
     190                free(d->shallow.sha1);
     191                free(d->buf_alloc);
     192                free_refs(d->refs);
     193                free(d);
     194        }
     195}
     196
     197static int show_http_message(struct strbuf *type, struct strbuf *msg)
     198{
     199        const char *p, *eol;
     200
     201        /*
     202         * We only show text/plain parts, as other types are likely
     203         * to be ugly to look at on the user's terminal.
     204         *
     205         * TODO should handle "; charset=XXX", and re-encode into
     206         * logoutputencoding
     207         */
     208        if (strcasecmp(type->buf, "text/plain"))
     209                return -1;
     210
     211        strbuf_trim(msg);
     212        if (!msg->len)
     213                return -1;
     214
     215        p = msg->buf;
     216        do {
     217                eol = strchrnul(p, '\n');
     218                fprintf(stderr, "remote: %.*s\n", (int)(eol - p), p);
     219                p = eol + 1;
     220        } while(*eol);
     221        return 0;
     222}
     223
     224static struct discovery* discover_refs(const char *service, int for_push)
     225{
     226        struct strbuf exp = STRBUF_INIT;
     227        struct strbuf type = STRBUF_INIT;
     228        struct strbuf buffer = STRBUF_INIT;
     229        struct strbuf refs_url = STRBUF_INIT;
     230        struct strbuf effective_url = STRBUF_INIT;
     231        struct discovery *last = last_discovery;
     232        int http_ret, maybe_smart = 0;
     233        struct http_get_options options;
     234
     235        if (last && !strcmp(service, last->service))
     236                return last;
     237        free_discovery(last);
     238
     239        strbuf_addf(&refs_url, "%sinfo/refs", url.buf);
     240        if ((starts_with(url.buf, "http://") || starts_with(url.buf, "https://")) &&
     241             git_env_bool("GIT_SMART_HTTP", 1)) {
     242                maybe_smart = 1;
     243                if (!strchr(url.buf, '?'))
     244                        strbuf_addch(&refs_url, '?');
     245                else
     246                        strbuf_addch(&refs_url, '&');
     247                strbuf_addf(&refs_url, "service=%s", service);
     248        }
     249
     250        memset(&options, 0, sizeof(options));
     251        options.content_type = &type;
     252        options.effective_url = &effective_url;
     253        options.base_url = &url;
     254        options.no_cache = 1;
     255        options.keep_error = 1;
     256
     257        http_ret = http_get_strbuf(refs_url.buf, &buffer, &options);
     258        switch (http_ret) {
     259        case HTTP_OK:
     260                break;
     261        case HTTP_MISSING_TARGET:
     262                show_http_message(&type, &buffer);
     263                die("repository '%s' not found", url.buf);
     264        case HTTP_NOAUTH:
     265                show_http_message(&type, &buffer);
     266                die("Authentication failed for '%s'", url.buf);
     267        default:
     268                show_http_message(&type, &buffer);
     269                die("unable to access '%s': %s", url.buf, curl_errorstr);
     270        }
     271
     272        last= xcalloc(1, sizeof(*last_discovery));
     273        last->service = service;
     274        last->buf_alloc = strbuf_detach(&buffer, &last->len);
     275        last->buf = last->buf_alloc;
     276
     277        strbuf_addf(&exp, "application/x-%s-advertisement", service);
     278        if (maybe_smart &&
     279            (5 <= last->len && last->buf[4] == '#') &&
     280            !strbuf_cmp(&exp, &type)) {
     281                char *line;
     282
     283                /*
     284                 * smart HTTP response; validate that the service
     285                 * pkt-line matches our request.
     286                 */
     287                line = packet_read_line_buf(&last->buf, &last->len, NULL);
     288
     289                strbuf_reset(&exp);
     290                strbuf_addf(&exp, "# service=%s", service);
     291                if (strcmp(line, exp.buf))
     292                        die("invalid server response; got '%s'", line);
     293                strbuf_release(&exp);
     294
     295                /* The header can include additional metadata lines, up
     296                 * until a packet flush marker.  Ignore these now, but
     297                 * in the future we might start to scan them.
     298                 */
     299                while (packet_read_line_buf(&last->buf, &last->len, NULL))
     300                        ;
     301
     302                last->proto_git = 1;
     303        }
     304
     305        if (last->proto_git)
     306                last->refs = parse_git_refs(last, for_push);
     307        else
     308                last->refs = parse_info_refs(last);
     309
     310        strbuf_release(&refs_url);
     311        strbuf_release(&exp);
     312        strbuf_release(&type);
     313        strbuf_release(&effective_url);
     314        strbuf_release(&buffer);
     315        last_discovery = last;
     316        return last;
     317}
     318
    262319static struct ref *get_refs(int for_push)
    263320{
     
    265322
    266323        if (for_push)
    267                 heads = discover_refs("git-receive-pack");
     324                heads = discover_refs("git-receive-pack", for_push);
    268325        else
    269                 heads = discover_refs("git-upload-pack");
    270 
    271         if (heads->proto_git)
    272                 return parse_git_refs(heads, for_push);
    273         return parse_info_refs(heads);
     326                heads = discover_refs("git-upload-pack", for_push);
     327
     328        return heads->refs;
    274329}
    275330
     
    285340        printf("\n");
    286341        fflush(stdout);
    287         free_refs(refs);
    288342}
    289343
     
    291345        const char *service_name;
    292346        const char **argv;
     347        struct strbuf *stdin_preamble;
    293348        char *service_url;
    294349        char *hdr_content_type;
     
    314369        if (!avail) {
    315370                rpc->initial_buffer = 0;
    316                 avail = packet_read_line(rpc->out, rpc->buf, rpc->alloc);
     371                avail = packet_read(rpc->out, NULL, NULL, rpc->buf, rpc->alloc, 0);
    317372                if (!avail)
    318373                        return 0;
     
    360415}
    361416
    362 static int run_slot(struct active_request_slot *slot)
    363 {
    364         int err = 0;
    365         struct slot_results results;
    366 
    367         slot->results = &results;
    368         slot->curl_result = curl_easy_perform(slot->curl);
    369         finish_active_slot(slot);
    370 
    371         if (results.curl_result != CURLE_OK) {
    372                 err |= error("RPC failed; result=%d, HTTP code = %ld",
    373                         results.curl_result, results.http_code);
     417static int run_slot(struct active_request_slot *slot,
     418                    struct slot_results *results)
     419{
     420        int err;
     421        struct slot_results results_buf;
     422
     423        if (!results)
     424                results = &results_buf;
     425
     426        err = run_one_slot(slot, results);
     427
     428        if (err != HTTP_OK && err != HTTP_REAUTH) {
     429                error("RPC failed; result=%d, HTTP code = %ld",
     430                      results->curl_result, results->http_code);
    374431        }
    375432
     
    377434}
    378435
    379 static int probe_rpc(struct rpc_state *rpc)
     436static int probe_rpc(struct rpc_state *rpc, struct slot_results *results)
    380437{
    381438        struct active_request_slot *slot;
     
    392449        curl_easy_setopt(slot->curl, CURLOPT_POST, 1);
    393450        curl_easy_setopt(slot->curl, CURLOPT_URL, rpc->service_url);
    394         curl_easy_setopt(slot->curl, CURLOPT_ENCODING, "");
     451        curl_easy_setopt(slot->curl, CURLOPT_ENCODING, NULL);
    395452        curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, "0000");
    396453        curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, 4);
     
    399456        curl_easy_setopt(slot->curl, CURLOPT_FILE, &buf);
    400457
    401         err = run_slot(slot);
     458        err = run_slot(slot, results);
    402459
    403460        curl_slist_free_all(headers);
     
    412469        int use_gzip = rpc->gzip_request;
    413470        char *gzip_body = NULL;
     471        size_t gzip_size = 0;
    414472        int err, large_request = 0;
     473        int needs_100_continue = 0;
    415474
    416475        /* Try to load the entire request, if we can fit it into the
     
    429488                }
    430489
    431                 n = packet_read_line(rpc->out, buf, left);
     490                n = packet_read(rpc->out, NULL, NULL, buf, left, 0);
    432491                if (!n)
    433492                        break;
     
    436495
    437496        if (large_request) {
    438                 err = probe_rpc(rpc);
    439                 if (err)
    440                         return err;
    441         }
    442 
     497                struct slot_results results;
     498
     499                do {
     500                        err = probe_rpc(rpc, &results);
     501                        if (err == HTTP_REAUTH)
     502                                credential_fill(&http_auth);
     503                } while (err == HTTP_REAUTH);
     504                if (err != HTTP_OK)
     505                        return -1;
     506
     507                if (results.auth_avail & CURLAUTH_GSSNEGOTIATE)
     508                        needs_100_continue = 1;
     509        }
     510
     511        headers = curl_slist_append(headers, rpc->hdr_content_type);
     512        headers = curl_slist_append(headers, rpc->hdr_accept);
     513        headers = curl_slist_append(headers, needs_100_continue ?
     514                "Expect: 100-continue" : "Expect:");
     515
     516retry:
    443517        slot = get_active_slot();
    444518
     
    446520        curl_easy_setopt(slot->curl, CURLOPT_POST, 1);
    447521        curl_easy_setopt(slot->curl, CURLOPT_URL, rpc->service_url);
    448         curl_easy_setopt(slot->curl, CURLOPT_ENCODING, "");
    449 
    450         headers = curl_slist_append(headers, rpc->hdr_content_type);
    451         headers = curl_slist_append(headers, rpc->hdr_accept);
    452         headers = curl_slist_append(headers, "Expect:");
     522        curl_easy_setopt(slot->curl, CURLOPT_ENCODING, "gzip");
    453523
    454524        if (large_request) {
     
    469539                }
    470540
     541        } else if (gzip_body) {
     542                /*
     543                 * If we are looping to retry authentication, then the previous
     544                 * run will have set up the headers and gzip buffer already,
     545                 * and we just need to send it.
     546                 */
     547                curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, gzip_body);
     548                curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, gzip_size);
     549
    471550        } else if (use_gzip && 1024 < rpc->len) {
    472551                /* The client backend isn't giving us compressed data so
     
    474553                 * the transfer time.
    475554                 */
    476                 size_t size;
    477555                git_zstream stream;
    478556                int ret;
     
    480558                memset(&stream, 0, sizeof(stream));
    481559                git_deflate_init_gzip(&stream, Z_BEST_COMPRESSION);
    482                 size = git_deflate_bound(&stream, rpc->len);
    483                 gzip_body = xmalloc(size);
     560                gzip_size = git_deflate_bound(&stream, rpc->len);
     561                gzip_body = xmalloc(gzip_size);
    484562
    485563                stream.next_in = (unsigned char *)rpc->buf;
    486564                stream.avail_in = rpc->len;
    487565                stream.next_out = (unsigned char *)gzip_body;
    488                 stream.avail_out = size;
     566                stream.avail_out = gzip_size;
    489567
    490568                ret = git_deflate(&stream, Z_FINISH);
     
    496574                        die("cannot deflate request; zlib end error %d", ret);
    497575
    498                 size = stream.total_out;
     576                gzip_size = stream.total_out;
    499577
    500578                headers = curl_slist_append(headers, "Content-Encoding: gzip");
    501579                curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, gzip_body);
    502                 curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, size);
     580                curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, gzip_size);
    503581
    504582                if (options.verbosity > 1) {
    505583                        fprintf(stderr, "POST %s (gzip %lu to %lu bytes)\n",
    506584                                rpc->service_name,
    507                                 (unsigned long)rpc->len, (unsigned long)size);
     585                                (unsigned long)rpc->len, (unsigned long)gzip_size);
    508586                        fflush(stderr);
    509587                }
     
    525603        curl_easy_setopt(slot->curl, CURLOPT_FILE, rpc);
    526604
    527         err = run_slot(slot);
     605        err = run_slot(slot, NULL);
     606        if (err == HTTP_REAUTH && !large_request) {
     607                credential_fill(&http_auth);
     608                goto retry;
     609        }
     610        if (err != HTTP_OK)
     611                err = -1;
    528612
    529613        curl_slist_free_all(headers);
     
    536620        const char *svc = rpc->service_name;
    537621        struct strbuf buf = STRBUF_INIT;
     622        struct strbuf *preamble = rpc->stdin_preamble;
    538623        struct child_process client;
    539624        int err = 0;
     
    546631        if (start_command(&client))
    547632                exit(1);
     633        if (preamble)
     634                write_or_die(client.in, preamble->buf, preamble->len);
    548635        if (heads)
    549636                write_or_die(client.in, heads->buf, heads->len);
     
    555642        strbuf_init(&rpc->result, 0);
    556643
    557         strbuf_addf(&buf, "%s%s", url, svc);
     644        strbuf_addf(&buf, "%s%s", url.buf, svc);
    558645        rpc->service_url = strbuf_detach(&buf, NULL);
    559646
     
    565652
    566653        while (!err) {
    567                 int n = packet_read_line(rpc->out, rpc->buf, rpc->alloc);
     654                int n = packet_read(rpc->out, NULL, NULL, rpc->buf, rpc->alloc, 0);
    568655                if (!n)
    569656                        break;
     
    607694                targets[i] = xstrdup(sha1_to_hex(to_fetch[i]->old_sha1));
    608695
    609         walker = get_http_walker(url);
     696        walker = get_http_walker(url.buf);
    610697        walker->get_all = 1;
    611698        walker->get_tree = 1;
     
    627714{
    628715        struct rpc_state rpc;
     716        struct strbuf preamble = STRBUF_INIT;
    629717        char *depth_arg = NULL;
    630         const char **argv;
    631718        int argc = 0, i, err;
    632 
    633         argv = xmalloc((15 + nr_heads) * sizeof(char*));
     719        const char *argv[17];
     720
    634721        argv[argc++] = "fetch-pack";
    635722        argv[argc++] = "--stateless-rpc";
     723        argv[argc++] = "--stdin";
    636724        argv[argc++] = "--lock-pack";
    637725        if (options.followtags)
     
    643731                argv[argc++] = "-v";
    644732        }
     733        if (options.check_self_contained_and_connected)
     734                argv[argc++] = "--check-self-contained-and-connected";
     735        if (options.cloning)
     736                argv[argc++] = "--cloning";
     737        if (options.update_shallow)
     738                argv[argc++] = "--update-shallow";
    645739        if (!options.progress)
    646740                argv[argc++] = "--no-progress";
     
    651745                argv[argc++] = depth_arg;
    652746        }
    653         argv[argc++] = url;
     747        argv[argc++] = url.buf;
     748        argv[argc++] = NULL;
     749
    654750        for (i = 0; i < nr_heads; i++) {
    655751                struct ref *ref = to_fetch[i];
    656752                if (!ref->name || !*ref->name)
    657753                        die("cannot fetch by sha1 over smart http");
    658                 argv[argc++] = ref->name;
    659         }
    660         argv[argc++] = NULL;
     754                packet_buf_write(&preamble, "%s %s\n",
     755                                 sha1_to_hex(ref->old_sha1), ref->name);
     756        }
     757        packet_buf_flush(&preamble);
    661758
    662759        memset(&rpc, 0, sizeof(rpc));
    663760        rpc.service_name = "git-upload-pack",
    664761        rpc.argv = argv;
     762        rpc.stdin_preamble = &preamble;
    665763        rpc.gzip_request = 1;
    666764
    667765        err = rpc_service(&rpc, heads);
    668766        if (rpc.result.len)
    669                 safe_write(1, rpc.result.buf, rpc.result.len);
     767                write_or_die(1, rpc.result.buf, rpc.result.len);
    670768        strbuf_release(&rpc.result);
    671         free(argv);
     769        strbuf_release(&preamble);
    672770        free(depth_arg);
    673771        return err;
     
    676774static int fetch(int nr_heads, struct ref **to_fetch)
    677775{
    678         struct discovery *d = discover_refs("git-upload-pack");
     776        struct discovery *d = discover_refs("git-upload-pack", 0);
    679777        if (d->proto_git)
    680778                return fetch_git(d, nr_heads, to_fetch);
     
    691789
    692790        do {
    693                 if (!prefixcmp(buf->buf, "fetch ")) {
     791                if (starts_with(buf->buf, "fetch ")) {
    694792                        char *p = buf->buf + strlen("fetch ");
    695793                        char *name;
     
    746844        if (options.verbosity > 1)
    747845                argv[argc++] = "--verbose";
    748         argv[argc++] = url;
     846        argv[argc++] = url.buf;
    749847        for (i = 0; i < nr_spec; i++)
    750848                argv[argc++] = specs[i];
     
    760858{
    761859        struct rpc_state rpc;
    762         const char **argv;
    763         int argc = 0, i, err;
    764 
    765         argv = xmalloc((10 + nr_spec) * sizeof(char*));
    766         argv[argc++] = "send-pack";
    767         argv[argc++] = "--stateless-rpc";
    768         argv[argc++] = "--helper-status";
     860        int i, err;
     861        struct argv_array args;
     862        struct string_list_item *cas_option;
     863
     864        argv_array_init(&args);
     865        argv_array_pushl(&args, "send-pack", "--stateless-rpc", "--helper-status",
     866                         NULL);
     867
    769868        if (options.thin)
    770                 argv[argc++] = "--thin";
     869                argv_array_push(&args, "--thin");
    771870        if (options.dry_run)
    772                 argv[argc++] = "--dry-run";
     871                argv_array_push(&args, "--dry-run");
    773872        if (options.verbosity == 0)
    774                 argv[argc++] = "--quiet";
     873                argv_array_push(&args, "--quiet");
    775874        else if (options.verbosity > 1)
    776                 argv[argc++] = "--verbose";
    777         argv[argc++] = url;
     875                argv_array_push(&args, "--verbose");
     876        argv_array_push(&args, options.progress ? "--progress" : "--no-progress");
     877        for_each_string_list_item(cas_option, &cas_options)
     878                argv_array_push(&args, cas_option->string);
     879        argv_array_push(&args, url.buf);
    778880        for (i = 0; i < nr_spec; i++)
    779                 argv[argc++] = specs[i];
    780         argv[argc++] = NULL;
     881                argv_array_push(&args, specs[i]);
    781882
    782883        memset(&rpc, 0, sizeof(rpc));
    783884        rpc.service_name = "git-receive-pack",
    784         rpc.argv = argv;
     885        rpc.argv = args.argv;
    785886
    786887        err = rpc_service(&rpc, heads);
    787888        if (rpc.result.len)
    788                 safe_write(1, rpc.result.buf, rpc.result.len);
     889                write_or_die(1, rpc.result.buf, rpc.result.len);
    789890        strbuf_release(&rpc.result);
    790         free(argv);
     891        argv_array_clear(&args);
    791892        return err;
    792893}
     
    794895static int push(int nr_spec, char **specs)
    795896{
    796         struct discovery *heads = discover_refs("git-receive-pack");
     897        struct discovery *heads = discover_refs("git-receive-pack", 1);
    797898        int ret;
    798899
     
    811912
    812913        do {
    813                 if (!prefixcmp(buf->buf, "push ")) {
     914                if (starts_with(buf->buf, "push ")) {
    814915                        ALLOC_GROW(specs, nr_spec + 1, alloc_spec);
    815916                        specs[nr_spec++] = xstrdup(buf->buf + 5);
     
    857958
    858959        if (argc > 2) {
    859                 end_url_with_slash(&buf, argv[2]);
     960                end_url_with_slash(&url, argv[2]);
    860961        } else {
    861                 end_url_with_slash(&buf, remote->url[0]);
    862         }
    863 
    864         url = strbuf_detach(&buf, NULL);
    865 
    866         http_init(remote, url, 0);
     962                end_url_with_slash(&url, remote->url[0]);
     963        }
     964
     965        http_init(remote, url.buf, 0);
    867966
    868967        do {
     
    876975                if (buf.len == 0)
    877976                        break;
    878                 if (!prefixcmp(buf.buf, "fetch ")) {
     977                if (starts_with(buf.buf, "fetch ")) {
    879978                        if (nongit)
    880979                                die("Fetch attempted without a local repo");
    881980                        parse_fetch(&buf);
    882981
    883                 } else if (!strcmp(buf.buf, "list") || !prefixcmp(buf.buf, "list ")) {
     982                } else if (!strcmp(buf.buf, "list") || starts_with(buf.buf, "list ")) {
    884983                        int for_push = !!strstr(buf.buf + 4, "for-push");
    885984                        output_refs(get_refs(for_push));
    886985
    887                 } else if (!prefixcmp(buf.buf, "push ")) {
     986                } else if (starts_with(buf.buf, "push ")) {
    888987                        parse_push(&buf);
    889988
    890                 } else if (!prefixcmp(buf.buf, "option ")) {
     989                } else if (starts_with(buf.buf, "option ")) {
    891990                        char *name = buf.buf + strlen("option ");
    892991                        char *value = strchr(name, ' ');
     
    9111010                        printf("option\n");
    9121011                        printf("push\n");
     1012                        printf("check-connectivity\n");
    9131013                        printf("\n");
    9141014                        fflush(stdout);
Note: See TracChangeset for help on using the changeset viewer.