perf-lib: fix ignored exit code inside loop
[git] / remote-curl.c
1 #include "cache.h"
2 #include "remote.h"
3 #include "strbuf.h"
4 #include "walker.h"
5 #include "http.h"
6 #include "exec_cmd.h"
7 #include "run-command.h"
8 #include "pkt-line.h"
9 #include "string-list.h"
10 #include "sideband.h"
11 #include "argv-array.h"
12 #include "credential.h"
13 #include "sha1-array.h"
14
15 static struct remote *remote;
16 /* always ends with a trailing slash */
17 static struct strbuf url = STRBUF_INIT;
18
19 struct options {
20         int verbosity;
21         unsigned long depth;
22         unsigned progress : 1,
23                 check_self_contained_and_connected : 1,
24                 cloning : 1,
25                 update_shallow : 1,
26                 followtags : 1,
27                 dry_run : 1,
28                 thin : 1,
29                 push_cert : 1;
30 };
31 static struct options options;
32 static struct string_list cas_options = STRING_LIST_INIT_DUP;
33
34 static int set_option(const char *name, const char *value)
35 {
36         if (!strcmp(name, "verbosity")) {
37                 char *end;
38                 int v = strtol(value, &end, 10);
39                 if (value == end || *end)
40                         return -1;
41                 options.verbosity = v;
42                 return 0;
43         }
44         else if (!strcmp(name, "progress")) {
45                 if (!strcmp(value, "true"))
46                         options.progress = 1;
47                 else if (!strcmp(value, "false"))
48                         options.progress = 0;
49                 else
50                         return -1;
51                 return 0;
52         }
53         else if (!strcmp(name, "depth")) {
54                 char *end;
55                 unsigned long v = strtoul(value, &end, 10);
56                 if (value == end || *end)
57                         return -1;
58                 options.depth = v;
59                 return 0;
60         }
61         else if (!strcmp(name, "followtags")) {
62                 if (!strcmp(value, "true"))
63                         options.followtags = 1;
64                 else if (!strcmp(value, "false"))
65                         options.followtags = 0;
66                 else
67                         return -1;
68                 return 0;
69         }
70         else if (!strcmp(name, "dry-run")) {
71                 if (!strcmp(value, "true"))
72                         options.dry_run = 1;
73                 else if (!strcmp(value, "false"))
74                         options.dry_run = 0;
75                 else
76                         return -1;
77                 return 0;
78         }
79         else if (!strcmp(name, "check-connectivity")) {
80                 if (!strcmp(value, "true"))
81                         options.check_self_contained_and_connected = 1;
82                 else if (!strcmp(value, "false"))
83                         options.check_self_contained_and_connected = 0;
84                 else
85                         return -1;
86                 return 0;
87         }
88         else if (!strcmp(name, "cas")) {
89                 struct strbuf val = STRBUF_INIT;
90                 strbuf_addf(&val, "--" CAS_OPT_NAME "=%s", value);
91                 string_list_append(&cas_options, val.buf);
92                 strbuf_release(&val);
93                 return 0;
94         } else if (!strcmp(name, "cloning")) {
95                 if (!strcmp(value, "true"))
96                         options.cloning = 1;
97                 else if (!strcmp(value, "false"))
98                         options.cloning = 0;
99                 else
100                         return -1;
101                 return 0;
102         } else if (!strcmp(name, "update-shallow")) {
103                 if (!strcmp(value, "true"))
104                         options.update_shallow = 1;
105                 else if (!strcmp(value, "false"))
106                         options.update_shallow = 0;
107                 else
108                         return -1;
109                 return 0;
110         } else if (!strcmp(name, "pushcert")) {
111                 if (!strcmp(value, "true"))
112                         options.push_cert = 1;
113                 else if (!strcmp(value, "false"))
114                         options.push_cert = 0;
115                 else
116                         return -1;
117                 return 0;
118         } else {
119                 return 1 /* unsupported */;
120         }
121 }
122
123 struct discovery {
124         const char *service;
125         char *buf_alloc;
126         char *buf;
127         size_t len;
128         struct ref *refs;
129         struct sha1_array shallow;
130         unsigned proto_git : 1;
131 };
132 static struct discovery *last_discovery;
133
134 static struct ref *parse_git_refs(struct discovery *heads, int for_push)
135 {
136         struct ref *list = NULL;
137         get_remote_heads(-1, heads->buf, heads->len, &list,
138                          for_push ? REF_NORMAL : 0, NULL, &heads->shallow);
139         return list;
140 }
141
142 static struct ref *parse_info_refs(struct discovery *heads)
143 {
144         char *data, *start, *mid;
145         char *ref_name;
146         int i = 0;
147
148         struct ref *refs = NULL;
149         struct ref *ref = NULL;
150         struct ref *last_ref = NULL;
151
152         data = heads->buf;
153         start = NULL;
154         mid = data;
155         while (i < heads->len) {
156                 if (!start) {
157                         start = &data[i];
158                 }
159                 if (data[i] == '\t')
160                         mid = &data[i];
161                 if (data[i] == '\n') {
162                         if (mid - start != 40)
163                                 die("%sinfo/refs not valid: is this a git repository?",
164                                     url.buf);
165                         data[i] = 0;
166                         ref_name = mid + 1;
167                         ref = xmalloc(sizeof(struct ref) +
168                                       strlen(ref_name) + 1);
169                         memset(ref, 0, sizeof(struct ref));
170                         strcpy(ref->name, ref_name);
171                         get_sha1_hex(start, ref->old_sha1);
172                         if (!refs)
173                                 refs = ref;
174                         if (last_ref)
175                                 last_ref->next = ref;
176                         last_ref = ref;
177                         start = NULL;
178                 }
179                 i++;
180         }
181
182         ref = alloc_ref("HEAD");
183         if (!http_fetch_ref(url.buf, ref) &&
184             !resolve_remote_symref(ref, refs)) {
185                 ref->next = refs;
186                 refs = ref;
187         } else {
188                 free(ref);
189         }
190
191         return refs;
192 }
193
194 static void free_discovery(struct discovery *d)
195 {
196         if (d) {
197                 if (d == last_discovery)
198                         last_discovery = NULL;
199                 free(d->shallow.sha1);
200                 free(d->buf_alloc);
201                 free_refs(d->refs);
202                 free(d);
203         }
204 }
205
206 static int show_http_message(struct strbuf *type, struct strbuf *charset,
207                              struct strbuf *msg)
208 {
209         const char *p, *eol;
210
211         /*
212          * We only show text/plain parts, as other types are likely
213          * to be ugly to look at on the user's terminal.
214          */
215         if (strcmp(type->buf, "text/plain"))
216                 return -1;
217         if (charset->len)
218                 strbuf_reencode(msg, charset->buf, get_log_output_encoding());
219
220         strbuf_trim(msg);
221         if (!msg->len)
222                 return -1;
223
224         p = msg->buf;
225         do {
226                 eol = strchrnul(p, '\n');
227                 fprintf(stderr, "remote: %.*s\n", (int)(eol - p), p);
228                 p = eol + 1;
229         } while(*eol);
230         return 0;
231 }
232
233 static struct discovery *discover_refs(const char *service, int for_push)
234 {
235         struct strbuf exp = STRBUF_INIT;
236         struct strbuf type = STRBUF_INIT;
237         struct strbuf charset = STRBUF_INIT;
238         struct strbuf buffer = STRBUF_INIT;
239         struct strbuf refs_url = STRBUF_INIT;
240         struct strbuf effective_url = STRBUF_INIT;
241         struct discovery *last = last_discovery;
242         int http_ret, maybe_smart = 0;
243         struct http_get_options options;
244
245         if (last && !strcmp(service, last->service))
246                 return last;
247         free_discovery(last);
248
249         strbuf_addf(&refs_url, "%sinfo/refs", url.buf);
250         if ((starts_with(url.buf, "http://") || starts_with(url.buf, "https://")) &&
251              git_env_bool("GIT_SMART_HTTP", 1)) {
252                 maybe_smart = 1;
253                 if (!strchr(url.buf, '?'))
254                         strbuf_addch(&refs_url, '?');
255                 else
256                         strbuf_addch(&refs_url, '&');
257                 strbuf_addf(&refs_url, "service=%s", service);
258         }
259
260         memset(&options, 0, sizeof(options));
261         options.content_type = &type;
262         options.charset = &charset;
263         options.effective_url = &effective_url;
264         options.base_url = &url;
265         options.no_cache = 1;
266         options.keep_error = 1;
267
268         http_ret = http_get_strbuf(refs_url.buf, &buffer, &options);
269         switch (http_ret) {
270         case HTTP_OK:
271                 break;
272         case HTTP_MISSING_TARGET:
273                 show_http_message(&type, &charset, &buffer);
274                 die("repository '%s' not found", url.buf);
275         case HTTP_NOAUTH:
276                 show_http_message(&type, &charset, &buffer);
277                 die("Authentication failed for '%s'", url.buf);
278         default:
279                 show_http_message(&type, &charset, &buffer);
280                 die("unable to access '%s': %s", url.buf, curl_errorstr);
281         }
282
283         last= xcalloc(1, sizeof(*last_discovery));
284         last->service = service;
285         last->buf_alloc = strbuf_detach(&buffer, &last->len);
286         last->buf = last->buf_alloc;
287
288         strbuf_addf(&exp, "application/x-%s-advertisement", service);
289         if (maybe_smart &&
290             (5 <= last->len && last->buf[4] == '#') &&
291             !strbuf_cmp(&exp, &type)) {
292                 char *line;
293
294                 /*
295                  * smart HTTP response; validate that the service
296                  * pkt-line matches our request.
297                  */
298                 line = packet_read_line_buf(&last->buf, &last->len, NULL);
299
300                 strbuf_reset(&exp);
301                 strbuf_addf(&exp, "# service=%s", service);
302                 if (strcmp(line, exp.buf))
303                         die("invalid server response; got '%s'", line);
304                 strbuf_release(&exp);
305
306                 /* The header can include additional metadata lines, up
307                  * until a packet flush marker.  Ignore these now, but
308                  * in the future we might start to scan them.
309                  */
310                 while (packet_read_line_buf(&last->buf, &last->len, NULL))
311                         ;
312
313                 last->proto_git = 1;
314         }
315
316         if (last->proto_git)
317                 last->refs = parse_git_refs(last, for_push);
318         else
319                 last->refs = parse_info_refs(last);
320
321         strbuf_release(&refs_url);
322         strbuf_release(&exp);
323         strbuf_release(&type);
324         strbuf_release(&charset);
325         strbuf_release(&effective_url);
326         strbuf_release(&buffer);
327         last_discovery = last;
328         return last;
329 }
330
331 static struct ref *get_refs(int for_push)
332 {
333         struct discovery *heads;
334
335         if (for_push)
336                 heads = discover_refs("git-receive-pack", for_push);
337         else
338                 heads = discover_refs("git-upload-pack", for_push);
339
340         return heads->refs;
341 }
342
343 static void output_refs(struct ref *refs)
344 {
345         struct ref *posn;
346         for (posn = refs; posn; posn = posn->next) {
347                 if (posn->symref)
348                         printf("@%s %s\n", posn->symref, posn->name);
349                 else
350                         printf("%s %s\n", sha1_to_hex(posn->old_sha1), posn->name);
351         }
352         printf("\n");
353         fflush(stdout);
354 }
355
356 struct rpc_state {
357         const char *service_name;
358         const char **argv;
359         struct strbuf *stdin_preamble;
360         char *service_url;
361         char *hdr_content_type;
362         char *hdr_accept;
363         char *buf;
364         size_t alloc;
365         size_t len;
366         size_t pos;
367         int in;
368         int out;
369         struct strbuf result;
370         unsigned gzip_request : 1;
371         unsigned initial_buffer : 1;
372 };
373
374 static size_t rpc_out(void *ptr, size_t eltsize,
375                 size_t nmemb, void *buffer_)
376 {
377         size_t max = eltsize * nmemb;
378         struct rpc_state *rpc = buffer_;
379         size_t avail = rpc->len - rpc->pos;
380
381         if (!avail) {
382                 rpc->initial_buffer = 0;
383                 avail = packet_read(rpc->out, NULL, NULL, rpc->buf, rpc->alloc, 0);
384                 if (!avail)
385                         return 0;
386                 rpc->pos = 0;
387                 rpc->len = avail;
388         }
389
390         if (max < avail)
391                 avail = max;
392         memcpy(ptr, rpc->buf + rpc->pos, avail);
393         rpc->pos += avail;
394         return avail;
395 }
396
397 #ifndef NO_CURL_IOCTL
398 static curlioerr rpc_ioctl(CURL *handle, int cmd, void *clientp)
399 {
400         struct rpc_state *rpc = clientp;
401
402         switch (cmd) {
403         case CURLIOCMD_NOP:
404                 return CURLIOE_OK;
405
406         case CURLIOCMD_RESTARTREAD:
407                 if (rpc->initial_buffer) {
408                         rpc->pos = 0;
409                         return CURLIOE_OK;
410                 }
411                 error("unable to rewind rpc post data - try increasing http.postBuffer");
412                 return CURLIOE_FAILRESTART;
413
414         default:
415                 return CURLIOE_UNKNOWNCMD;
416         }
417 }
418 #endif
419
420 static size_t rpc_in(char *ptr, size_t eltsize,
421                 size_t nmemb, void *buffer_)
422 {
423         size_t size = eltsize * nmemb;
424         struct rpc_state *rpc = buffer_;
425         write_or_die(rpc->in, ptr, size);
426         return size;
427 }
428
429 static int run_slot(struct active_request_slot *slot,
430                     struct slot_results *results)
431 {
432         int err;
433         struct slot_results results_buf;
434
435         if (!results)
436                 results = &results_buf;
437
438         err = run_one_slot(slot, results);
439
440         if (err != HTTP_OK && err != HTTP_REAUTH) {
441                 error("RPC failed; result=%d, HTTP code = %ld",
442                       results->curl_result, results->http_code);
443         }
444
445         return err;
446 }
447
448 static int probe_rpc(struct rpc_state *rpc, struct slot_results *results)
449 {
450         struct active_request_slot *slot;
451         struct curl_slist *headers = NULL;
452         struct strbuf buf = STRBUF_INIT;
453         int err;
454
455         slot = get_active_slot();
456
457         headers = curl_slist_append(headers, rpc->hdr_content_type);
458         headers = curl_slist_append(headers, rpc->hdr_accept);
459
460         curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
461         curl_easy_setopt(slot->curl, CURLOPT_POST, 1);
462         curl_easy_setopt(slot->curl, CURLOPT_URL, rpc->service_url);
463         curl_easy_setopt(slot->curl, CURLOPT_ENCODING, NULL);
464         curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, "0000");
465         curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, 4);
466         curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, headers);
467         curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
468         curl_easy_setopt(slot->curl, CURLOPT_FILE, &buf);
469
470         err = run_slot(slot, results);
471
472         curl_slist_free_all(headers);
473         strbuf_release(&buf);
474         return err;
475 }
476
477 static int post_rpc(struct rpc_state *rpc)
478 {
479         struct active_request_slot *slot;
480         struct curl_slist *headers = NULL;
481         int use_gzip = rpc->gzip_request;
482         char *gzip_body = NULL;
483         size_t gzip_size = 0;
484         int err, large_request = 0;
485         int needs_100_continue = 0;
486
487         /* Try to load the entire request, if we can fit it into the
488          * allocated buffer space we can use HTTP/1.0 and avoid the
489          * chunked encoding mess.
490          */
491         while (1) {
492                 size_t left = rpc->alloc - rpc->len;
493                 char *buf = rpc->buf + rpc->len;
494                 int n;
495
496                 if (left < LARGE_PACKET_MAX) {
497                         large_request = 1;
498                         use_gzip = 0;
499                         break;
500                 }
501
502                 n = packet_read(rpc->out, NULL, NULL, buf, left, 0);
503                 if (!n)
504                         break;
505                 rpc->len += n;
506         }
507
508         if (large_request) {
509                 struct slot_results results;
510
511                 do {
512                         err = probe_rpc(rpc, &results);
513                         if (err == HTTP_REAUTH)
514                                 credential_fill(&http_auth);
515                 } while (err == HTTP_REAUTH);
516                 if (err != HTTP_OK)
517                         return -1;
518
519                 if (results.auth_avail & CURLAUTH_GSSNEGOTIATE)
520                         needs_100_continue = 1;
521         }
522
523         headers = curl_slist_append(headers, rpc->hdr_content_type);
524         headers = curl_slist_append(headers, rpc->hdr_accept);
525         headers = curl_slist_append(headers, needs_100_continue ?
526                 "Expect: 100-continue" : "Expect:");
527
528 retry:
529         slot = get_active_slot();
530
531         curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
532         curl_easy_setopt(slot->curl, CURLOPT_POST, 1);
533         curl_easy_setopt(slot->curl, CURLOPT_URL, rpc->service_url);
534         curl_easy_setopt(slot->curl, CURLOPT_ENCODING, "gzip");
535
536         if (large_request) {
537                 /* The request body is large and the size cannot be predicted.
538                  * We must use chunked encoding to send it.
539                  */
540                 headers = curl_slist_append(headers, "Transfer-Encoding: chunked");
541                 rpc->initial_buffer = 1;
542                 curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, rpc_out);
543                 curl_easy_setopt(slot->curl, CURLOPT_INFILE, rpc);
544 #ifndef NO_CURL_IOCTL
545                 curl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, rpc_ioctl);
546                 curl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, rpc);
547 #endif
548                 if (options.verbosity > 1) {
549                         fprintf(stderr, "POST %s (chunked)\n", rpc->service_name);
550                         fflush(stderr);
551                 }
552
553         } else if (gzip_body) {
554                 /*
555                  * If we are looping to retry authentication, then the previous
556                  * run will have set up the headers and gzip buffer already,
557                  * and we just need to send it.
558                  */
559                 curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, gzip_body);
560                 curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, gzip_size);
561
562         } else if (use_gzip && 1024 < rpc->len) {
563                 /* The client backend isn't giving us compressed data so
564                  * we can try to deflate it ourselves, this may save on.
565                  * the transfer time.
566                  */
567                 git_zstream stream;
568                 int ret;
569
570                 git_deflate_init_gzip(&stream, Z_BEST_COMPRESSION);
571                 gzip_size = git_deflate_bound(&stream, rpc->len);
572                 gzip_body = xmalloc(gzip_size);
573
574                 stream.next_in = (unsigned char *)rpc->buf;
575                 stream.avail_in = rpc->len;
576                 stream.next_out = (unsigned char *)gzip_body;
577                 stream.avail_out = gzip_size;
578
579                 ret = git_deflate(&stream, Z_FINISH);
580                 if (ret != Z_STREAM_END)
581                         die("cannot deflate request; zlib deflate error %d", ret);
582
583                 ret = git_deflate_end_gently(&stream);
584                 if (ret != Z_OK)
585                         die("cannot deflate request; zlib end error %d", ret);
586
587                 gzip_size = stream.total_out;
588
589                 headers = curl_slist_append(headers, "Content-Encoding: gzip");
590                 curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, gzip_body);
591                 curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, gzip_size);
592
593                 if (options.verbosity > 1) {
594                         fprintf(stderr, "POST %s (gzip %lu to %lu bytes)\n",
595                                 rpc->service_name,
596                                 (unsigned long)rpc->len, (unsigned long)gzip_size);
597                         fflush(stderr);
598                 }
599         } else {
600                 /* We know the complete request size in advance, use the
601                  * more normal Content-Length approach.
602                  */
603                 curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, rpc->buf);
604                 curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, rpc->len);
605                 if (options.verbosity > 1) {
606                         fprintf(stderr, "POST %s (%lu bytes)\n",
607                                 rpc->service_name, (unsigned long)rpc->len);
608                         fflush(stderr);
609                 }
610         }
611
612         curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, headers);
613         curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, rpc_in);
614         curl_easy_setopt(slot->curl, CURLOPT_FILE, rpc);
615
616         err = run_slot(slot, NULL);
617         if (err == HTTP_REAUTH && !large_request) {
618                 credential_fill(&http_auth);
619                 goto retry;
620         }
621         if (err != HTTP_OK)
622                 err = -1;
623
624         curl_slist_free_all(headers);
625         free(gzip_body);
626         return err;
627 }
628
629 static int rpc_service(struct rpc_state *rpc, struct discovery *heads)
630 {
631         const char *svc = rpc->service_name;
632         struct strbuf buf = STRBUF_INIT;
633         struct strbuf *preamble = rpc->stdin_preamble;
634         struct child_process client = CHILD_PROCESS_INIT;
635         int err = 0;
636
637         client.in = -1;
638         client.out = -1;
639         client.git_cmd = 1;
640         client.argv = rpc->argv;
641         if (start_command(&client))
642                 exit(1);
643         if (preamble)
644                 write_or_die(client.in, preamble->buf, preamble->len);
645         if (heads)
646                 write_or_die(client.in, heads->buf, heads->len);
647
648         rpc->alloc = http_post_buffer;
649         rpc->buf = xmalloc(rpc->alloc);
650         rpc->in = client.in;
651         rpc->out = client.out;
652         strbuf_init(&rpc->result, 0);
653
654         strbuf_addf(&buf, "%s%s", url.buf, svc);
655         rpc->service_url = strbuf_detach(&buf, NULL);
656
657         strbuf_addf(&buf, "Content-Type: application/x-%s-request", svc);
658         rpc->hdr_content_type = strbuf_detach(&buf, NULL);
659
660         strbuf_addf(&buf, "Accept: application/x-%s-result", svc);
661         rpc->hdr_accept = strbuf_detach(&buf, NULL);
662
663         while (!err) {
664                 int n = packet_read(rpc->out, NULL, NULL, rpc->buf, rpc->alloc, 0);
665                 if (!n)
666                         break;
667                 rpc->pos = 0;
668                 rpc->len = n;
669                 err |= post_rpc(rpc);
670         }
671
672         close(client.in);
673         client.in = -1;
674         if (!err) {
675                 strbuf_read(&rpc->result, client.out, 0);
676         } else {
677                 char buf[4096];
678                 for (;;)
679                         if (xread(client.out, buf, sizeof(buf)) <= 0)
680                                 break;
681         }
682
683         close(client.out);
684         client.out = -1;
685
686         err |= finish_command(&client);
687         free(rpc->service_url);
688         free(rpc->hdr_content_type);
689         free(rpc->hdr_accept);
690         free(rpc->buf);
691         strbuf_release(&buf);
692         return err;
693 }
694
695 static int fetch_dumb(int nr_heads, struct ref **to_fetch)
696 {
697         struct walker *walker;
698         char **targets = xmalloc(nr_heads * sizeof(char*));
699         int ret, i;
700
701         if (options.depth)
702                 die("dumb http transport does not support --depth");
703         for (i = 0; i < nr_heads; i++)
704                 targets[i] = xstrdup(sha1_to_hex(to_fetch[i]->old_sha1));
705
706         walker = get_http_walker(url.buf);
707         walker->get_all = 1;
708         walker->get_tree = 1;
709         walker->get_history = 1;
710         walker->get_verbosely = options.verbosity >= 3;
711         walker->get_recover = 0;
712         ret = walker_fetch(walker, nr_heads, targets, NULL, NULL);
713         walker_free(walker);
714
715         for (i = 0; i < nr_heads; i++)
716                 free(targets[i]);
717         free(targets);
718
719         return ret ? error("fetch failed.") : 0;
720 }
721
722 static int fetch_git(struct discovery *heads,
723         int nr_heads, struct ref **to_fetch)
724 {
725         struct rpc_state rpc;
726         struct strbuf preamble = STRBUF_INIT;
727         char *depth_arg = NULL;
728         int argc = 0, i, err;
729         const char *argv[17];
730
731         argv[argc++] = "fetch-pack";
732         argv[argc++] = "--stateless-rpc";
733         argv[argc++] = "--stdin";
734         argv[argc++] = "--lock-pack";
735         if (options.followtags)
736                 argv[argc++] = "--include-tag";
737         if (options.thin)
738                 argv[argc++] = "--thin";
739         if (options.verbosity >= 3) {
740                 argv[argc++] = "-v";
741                 argv[argc++] = "-v";
742         }
743         if (options.check_self_contained_and_connected)
744                 argv[argc++] = "--check-self-contained-and-connected";
745         if (options.cloning)
746                 argv[argc++] = "--cloning";
747         if (options.update_shallow)
748                 argv[argc++] = "--update-shallow";
749         if (!options.progress)
750                 argv[argc++] = "--no-progress";
751         if (options.depth) {
752                 struct strbuf buf = STRBUF_INIT;
753                 strbuf_addf(&buf, "--depth=%lu", options.depth);
754                 depth_arg = strbuf_detach(&buf, NULL);
755                 argv[argc++] = depth_arg;
756         }
757         argv[argc++] = url.buf;
758         argv[argc++] = NULL;
759
760         for (i = 0; i < nr_heads; i++) {
761                 struct ref *ref = to_fetch[i];
762                 if (!*ref->name)
763                         die("cannot fetch by sha1 over smart http");
764                 packet_buf_write(&preamble, "%s %s\n",
765                                  sha1_to_hex(ref->old_sha1), ref->name);
766         }
767         packet_buf_flush(&preamble);
768
769         memset(&rpc, 0, sizeof(rpc));
770         rpc.service_name = "git-upload-pack",
771         rpc.argv = argv;
772         rpc.stdin_preamble = &preamble;
773         rpc.gzip_request = 1;
774
775         err = rpc_service(&rpc, heads);
776         if (rpc.result.len)
777                 write_or_die(1, rpc.result.buf, rpc.result.len);
778         strbuf_release(&rpc.result);
779         strbuf_release(&preamble);
780         free(depth_arg);
781         return err;
782 }
783
784 static int fetch(int nr_heads, struct ref **to_fetch)
785 {
786         struct discovery *d = discover_refs("git-upload-pack", 0);
787         if (d->proto_git)
788                 return fetch_git(d, nr_heads, to_fetch);
789         else
790                 return fetch_dumb(nr_heads, to_fetch);
791 }
792
793 static void parse_fetch(struct strbuf *buf)
794 {
795         struct ref **to_fetch = NULL;
796         struct ref *list_head = NULL;
797         struct ref **list = &list_head;
798         int alloc_heads = 0, nr_heads = 0;
799
800         do {
801                 const char *p;
802                 if (skip_prefix(buf->buf, "fetch ", &p)) {
803                         const char *name;
804                         struct ref *ref;
805                         unsigned char old_sha1[20];
806
807                         if (strlen(p) < 40 || get_sha1_hex(p, old_sha1))
808                                 die("protocol error: expected sha/ref, got %s'", p);
809                         if (p[40] == ' ')
810                                 name = p + 41;
811                         else if (!p[40])
812                                 name = "";
813                         else
814                                 die("protocol error: expected sha/ref, got %s'", p);
815
816                         ref = alloc_ref(name);
817                         hashcpy(ref->old_sha1, old_sha1);
818
819                         *list = ref;
820                         list = &ref->next;
821
822                         ALLOC_GROW(to_fetch, nr_heads + 1, alloc_heads);
823                         to_fetch[nr_heads++] = ref;
824                 }
825                 else
826                         die("http transport does not support %s", buf->buf);
827
828                 strbuf_reset(buf);
829                 if (strbuf_getline(buf, stdin, '\n') == EOF)
830                         return;
831                 if (!*buf->buf)
832                         break;
833         } while (1);
834
835         if (fetch(nr_heads, to_fetch))
836                 exit(128); /* error already reported */
837         free_refs(list_head);
838         free(to_fetch);
839
840         printf("\n");
841         fflush(stdout);
842         strbuf_reset(buf);
843 }
844
845 static int push_dav(int nr_spec, char **specs)
846 {
847         const char **argv = xmalloc((10 + nr_spec) * sizeof(char*));
848         int argc = 0, i;
849
850         argv[argc++] = "http-push";
851         argv[argc++] = "--helper-status";
852         if (options.dry_run)
853                 argv[argc++] = "--dry-run";
854         if (options.verbosity > 1)
855                 argv[argc++] = "--verbose";
856         argv[argc++] = url.buf;
857         for (i = 0; i < nr_spec; i++)
858                 argv[argc++] = specs[i];
859         argv[argc++] = NULL;
860
861         if (run_command_v_opt(argv, RUN_GIT_CMD))
862                 die("git-%s failed", argv[0]);
863         free(argv);
864         return 0;
865 }
866
867 static int push_git(struct discovery *heads, int nr_spec, char **specs)
868 {
869         struct rpc_state rpc;
870         int i, err;
871         struct argv_array args;
872         struct string_list_item *cas_option;
873         struct strbuf preamble = STRBUF_INIT;
874
875         argv_array_init(&args);
876         argv_array_pushl(&args, "send-pack", "--stateless-rpc", "--helper-status",
877                          NULL);
878
879         if (options.thin)
880                 argv_array_push(&args, "--thin");
881         if (options.dry_run)
882                 argv_array_push(&args, "--dry-run");
883         if (options.push_cert)
884                 argv_array_push(&args, "--signed");
885         if (options.verbosity == 0)
886                 argv_array_push(&args, "--quiet");
887         else if (options.verbosity > 1)
888                 argv_array_push(&args, "--verbose");
889         argv_array_push(&args, options.progress ? "--progress" : "--no-progress");
890         for_each_string_list_item(cas_option, &cas_options)
891                 argv_array_push(&args, cas_option->string);
892         argv_array_push(&args, url.buf);
893
894         argv_array_push(&args, "--stdin");
895         for (i = 0; i < nr_spec; i++)
896                 packet_buf_write(&preamble, "%s\n", specs[i]);
897         packet_buf_flush(&preamble);
898
899         memset(&rpc, 0, sizeof(rpc));
900         rpc.service_name = "git-receive-pack",
901         rpc.argv = args.argv;
902         rpc.stdin_preamble = &preamble;
903
904         err = rpc_service(&rpc, heads);
905         if (rpc.result.len)
906                 write_or_die(1, rpc.result.buf, rpc.result.len);
907         strbuf_release(&rpc.result);
908         strbuf_release(&preamble);
909         argv_array_clear(&args);
910         return err;
911 }
912
913 static int push(int nr_spec, char **specs)
914 {
915         struct discovery *heads = discover_refs("git-receive-pack", 1);
916         int ret;
917
918         if (heads->proto_git)
919                 ret = push_git(heads, nr_spec, specs);
920         else
921                 ret = push_dav(nr_spec, specs);
922         free_discovery(heads);
923         return ret;
924 }
925
926 static void parse_push(struct strbuf *buf)
927 {
928         char **specs = NULL;
929         int alloc_spec = 0, nr_spec = 0, i, ret;
930
931         do {
932                 if (starts_with(buf->buf, "push ")) {
933                         ALLOC_GROW(specs, nr_spec + 1, alloc_spec);
934                         specs[nr_spec++] = xstrdup(buf->buf + 5);
935                 }
936                 else
937                         die("http transport does not support %s", buf->buf);
938
939                 strbuf_reset(buf);
940                 if (strbuf_getline(buf, stdin, '\n') == EOF)
941                         goto free_specs;
942                 if (!*buf->buf)
943                         break;
944         } while (1);
945
946         ret = push(nr_spec, specs);
947         printf("\n");
948         fflush(stdout);
949
950         if (ret)
951                 exit(128); /* error already reported */
952
953  free_specs:
954         for (i = 0; i < nr_spec; i++)
955                 free(specs[i]);
956         free(specs);
957 }
958
959 int main(int argc, const char **argv)
960 {
961         struct strbuf buf = STRBUF_INIT;
962         int nongit;
963
964         git_setup_gettext();
965
966         git_extract_argv0_path(argv[0]);
967         setup_git_directory_gently(&nongit);
968         if (argc < 2) {
969                 error("remote-curl: usage: git remote-curl <remote> [<url>]");
970                 return 1;
971         }
972
973         options.verbosity = 1;
974         options.progress = !!isatty(2);
975         options.thin = 1;
976
977         remote = remote_get(argv[1]);
978
979         if (argc > 2) {
980                 end_url_with_slash(&url, argv[2]);
981         } else {
982                 end_url_with_slash(&url, remote->url[0]);
983         }
984
985         http_init(remote, url.buf, 0);
986
987         do {
988                 const char *arg;
989
990                 if (strbuf_getline(&buf, stdin, '\n') == EOF) {
991                         if (ferror(stdin))
992                                 error("remote-curl: error reading command stream from git");
993                         return 1;
994                 }
995                 if (buf.len == 0)
996                         break;
997                 if (starts_with(buf.buf, "fetch ")) {
998                         if (nongit)
999                                 die("remote-curl: fetch attempted without a local repo");
1000                         parse_fetch(&buf);
1001
1002                 } else if (!strcmp(buf.buf, "list") || starts_with(buf.buf, "list ")) {
1003                         int for_push = !!strstr(buf.buf + 4, "for-push");
1004                         output_refs(get_refs(for_push));
1005
1006                 } else if (starts_with(buf.buf, "push ")) {
1007                         parse_push(&buf);
1008
1009                 } else if (skip_prefix(buf.buf, "option ", &arg)) {
1010                         char *value = strchr(arg, ' ');
1011                         int result;
1012
1013                         if (value)
1014                                 *value++ = '\0';
1015                         else
1016                                 value = "true";
1017
1018                         result = set_option(arg, value);
1019                         if (!result)
1020                                 printf("ok\n");
1021                         else if (result < 0)
1022                                 printf("error invalid value\n");
1023                         else
1024                                 printf("unsupported\n");
1025                         fflush(stdout);
1026
1027                 } else if (!strcmp(buf.buf, "capabilities")) {
1028                         printf("fetch\n");
1029                         printf("option\n");
1030                         printf("push\n");
1031                         printf("check-connectivity\n");
1032                         printf("\n");
1033                         fflush(stdout);
1034                 } else {
1035                         error("remote-curl: unknown command '%s' from git", buf.buf);
1036                         return 1;
1037                 }
1038                 strbuf_reset(&buf);
1039         } while (1);
1040
1041         http_cleanup();
1042
1043         return 0;
1044 }