transport-helper: do not request symbolic refs to remote helpers
[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                 memset(&stream, 0, sizeof(stream));
571                 git_deflate_init_gzip(&stream, Z_BEST_COMPRESSION);
572                 gzip_size = git_deflate_bound(&stream, rpc->len);
573                 gzip_body = xmalloc(gzip_size);
574
575                 stream.next_in = (unsigned char *)rpc->buf;
576                 stream.avail_in = rpc->len;
577                 stream.next_out = (unsigned char *)gzip_body;
578                 stream.avail_out = gzip_size;
579
580                 ret = git_deflate(&stream, Z_FINISH);
581                 if (ret != Z_STREAM_END)
582                         die("cannot deflate request; zlib deflate error %d", ret);
583
584                 ret = git_deflate_end_gently(&stream);
585                 if (ret != Z_OK)
586                         die("cannot deflate request; zlib end error %d", ret);
587
588                 gzip_size = stream.total_out;
589
590                 headers = curl_slist_append(headers, "Content-Encoding: gzip");
591                 curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, gzip_body);
592                 curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, gzip_size);
593
594                 if (options.verbosity > 1) {
595                         fprintf(stderr, "POST %s (gzip %lu to %lu bytes)\n",
596                                 rpc->service_name,
597                                 (unsigned long)rpc->len, (unsigned long)gzip_size);
598                         fflush(stderr);
599                 }
600         } else {
601                 /* We know the complete request size in advance, use the
602                  * more normal Content-Length approach.
603                  */
604                 curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, rpc->buf);
605                 curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, rpc->len);
606                 if (options.verbosity > 1) {
607                         fprintf(stderr, "POST %s (%lu bytes)\n",
608                                 rpc->service_name, (unsigned long)rpc->len);
609                         fflush(stderr);
610                 }
611         }
612
613         curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, headers);
614         curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, rpc_in);
615         curl_easy_setopt(slot->curl, CURLOPT_FILE, rpc);
616
617         err = run_slot(slot, NULL);
618         if (err == HTTP_REAUTH && !large_request) {
619                 credential_fill(&http_auth);
620                 goto retry;
621         }
622         if (err != HTTP_OK)
623                 err = -1;
624
625         curl_slist_free_all(headers);
626         free(gzip_body);
627         return err;
628 }
629
630 static int rpc_service(struct rpc_state *rpc, struct discovery *heads)
631 {
632         const char *svc = rpc->service_name;
633         struct strbuf buf = STRBUF_INIT;
634         struct strbuf *preamble = rpc->stdin_preamble;
635         struct child_process client = CHILD_PROCESS_INIT;
636         int err = 0;
637
638         client.in = -1;
639         client.out = -1;
640         client.git_cmd = 1;
641         client.argv = rpc->argv;
642         if (start_command(&client))
643                 exit(1);
644         if (preamble)
645                 write_or_die(client.in, preamble->buf, preamble->len);
646         if (heads)
647                 write_or_die(client.in, heads->buf, heads->len);
648
649         rpc->alloc = http_post_buffer;
650         rpc->buf = xmalloc(rpc->alloc);
651         rpc->in = client.in;
652         rpc->out = client.out;
653         strbuf_init(&rpc->result, 0);
654
655         strbuf_addf(&buf, "%s%s", url.buf, svc);
656         rpc->service_url = strbuf_detach(&buf, NULL);
657
658         strbuf_addf(&buf, "Content-Type: application/x-%s-request", svc);
659         rpc->hdr_content_type = strbuf_detach(&buf, NULL);
660
661         strbuf_addf(&buf, "Accept: application/x-%s-result", svc);
662         rpc->hdr_accept = strbuf_detach(&buf, NULL);
663
664         while (!err) {
665                 int n = packet_read(rpc->out, NULL, NULL, rpc->buf, rpc->alloc, 0);
666                 if (!n)
667                         break;
668                 rpc->pos = 0;
669                 rpc->len = n;
670                 err |= post_rpc(rpc);
671         }
672
673         close(client.in);
674         client.in = -1;
675         if (!err) {
676                 strbuf_read(&rpc->result, client.out, 0);
677         } else {
678                 char buf[4096];
679                 for (;;)
680                         if (xread(client.out, buf, sizeof(buf)) <= 0)
681                                 break;
682         }
683
684         close(client.out);
685         client.out = -1;
686
687         err |= finish_command(&client);
688         free(rpc->service_url);
689         free(rpc->hdr_content_type);
690         free(rpc->hdr_accept);
691         free(rpc->buf);
692         strbuf_release(&buf);
693         return err;
694 }
695
696 static int fetch_dumb(int nr_heads, struct ref **to_fetch)
697 {
698         struct walker *walker;
699         char **targets = xmalloc(nr_heads * sizeof(char*));
700         int ret, i;
701
702         if (options.depth)
703                 die("dumb http transport does not support --depth");
704         for (i = 0; i < nr_heads; i++)
705                 targets[i] = xstrdup(sha1_to_hex(to_fetch[i]->old_sha1));
706
707         walker = get_http_walker(url.buf);
708         walker->get_all = 1;
709         walker->get_tree = 1;
710         walker->get_history = 1;
711         walker->get_verbosely = options.verbosity >= 3;
712         walker->get_recover = 0;
713         ret = walker_fetch(walker, nr_heads, targets, NULL, NULL);
714         walker_free(walker);
715
716         for (i = 0; i < nr_heads; i++)
717                 free(targets[i]);
718         free(targets);
719
720         return ret ? error("fetch failed.") : 0;
721 }
722
723 static int fetch_git(struct discovery *heads,
724         int nr_heads, struct ref **to_fetch)
725 {
726         struct rpc_state rpc;
727         struct strbuf preamble = STRBUF_INIT;
728         char *depth_arg = NULL;
729         int argc = 0, i, err;
730         const char *argv[17];
731
732         argv[argc++] = "fetch-pack";
733         argv[argc++] = "--stateless-rpc";
734         argv[argc++] = "--stdin";
735         argv[argc++] = "--lock-pack";
736         if (options.followtags)
737                 argv[argc++] = "--include-tag";
738         if (options.thin)
739                 argv[argc++] = "--thin";
740         if (options.verbosity >= 3) {
741                 argv[argc++] = "-v";
742                 argv[argc++] = "-v";
743         }
744         if (options.check_self_contained_and_connected)
745                 argv[argc++] = "--check-self-contained-and-connected";
746         if (options.cloning)
747                 argv[argc++] = "--cloning";
748         if (options.update_shallow)
749                 argv[argc++] = "--update-shallow";
750         if (!options.progress)
751                 argv[argc++] = "--no-progress";
752         if (options.depth) {
753                 struct strbuf buf = STRBUF_INIT;
754                 strbuf_addf(&buf, "--depth=%lu", options.depth);
755                 depth_arg = strbuf_detach(&buf, NULL);
756                 argv[argc++] = depth_arg;
757         }
758         argv[argc++] = url.buf;
759         argv[argc++] = NULL;
760
761         for (i = 0; i < nr_heads; i++) {
762                 struct ref *ref = to_fetch[i];
763                 if (!ref->name || !*ref->name)
764                         die("cannot fetch by sha1 over smart http");
765                 packet_buf_write(&preamble, "%s %s\n",
766                                  sha1_to_hex(ref->old_sha1), ref->name);
767         }
768         packet_buf_flush(&preamble);
769
770         memset(&rpc, 0, sizeof(rpc));
771         rpc.service_name = "git-upload-pack",
772         rpc.argv = argv;
773         rpc.stdin_preamble = &preamble;
774         rpc.gzip_request = 1;
775
776         err = rpc_service(&rpc, heads);
777         if (rpc.result.len)
778                 write_or_die(1, rpc.result.buf, rpc.result.len);
779         strbuf_release(&rpc.result);
780         strbuf_release(&preamble);
781         free(depth_arg);
782         return err;
783 }
784
785 static int fetch(int nr_heads, struct ref **to_fetch)
786 {
787         struct discovery *d = discover_refs("git-upload-pack", 0);
788         if (d->proto_git)
789                 return fetch_git(d, nr_heads, to_fetch);
790         else
791                 return fetch_dumb(nr_heads, to_fetch);
792 }
793
794 static void parse_fetch(struct strbuf *buf)
795 {
796         struct ref **to_fetch = NULL;
797         struct ref *list_head = NULL;
798         struct ref **list = &list_head;
799         int alloc_heads = 0, nr_heads = 0;
800
801         do {
802                 const char *p;
803                 if (skip_prefix(buf->buf, "fetch ", &p)) {
804                         const char *name;
805                         struct ref *ref;
806                         unsigned char old_sha1[20];
807
808                         if (strlen(p) < 40 || get_sha1_hex(p, old_sha1))
809                                 die("protocol error: expected sha/ref, got %s'", p);
810                         if (p[40] == ' ')
811                                 name = p + 41;
812                         else if (!p[40])
813                                 name = "";
814                         else
815                                 die("protocol error: expected sha/ref, got %s'", p);
816
817                         ref = alloc_ref(name);
818                         hashcpy(ref->old_sha1, old_sha1);
819
820                         *list = ref;
821                         list = &ref->next;
822
823                         ALLOC_GROW(to_fetch, nr_heads + 1, alloc_heads);
824                         to_fetch[nr_heads++] = ref;
825                 }
826                 else
827                         die("http transport does not support %s", buf->buf);
828
829                 strbuf_reset(buf);
830                 if (strbuf_getline(buf, stdin, '\n') == EOF)
831                         return;
832                 if (!*buf->buf)
833                         break;
834         } while (1);
835
836         if (fetch(nr_heads, to_fetch))
837                 exit(128); /* error already reported */
838         free_refs(list_head);
839         free(to_fetch);
840
841         printf("\n");
842         fflush(stdout);
843         strbuf_reset(buf);
844 }
845
846 static int push_dav(int nr_spec, char **specs)
847 {
848         const char **argv = xmalloc((10 + nr_spec) * sizeof(char*));
849         int argc = 0, i;
850
851         argv[argc++] = "http-push";
852         argv[argc++] = "--helper-status";
853         if (options.dry_run)
854                 argv[argc++] = "--dry-run";
855         if (options.verbosity > 1)
856                 argv[argc++] = "--verbose";
857         argv[argc++] = url.buf;
858         for (i = 0; i < nr_spec; i++)
859                 argv[argc++] = specs[i];
860         argv[argc++] = NULL;
861
862         if (run_command_v_opt(argv, RUN_GIT_CMD))
863                 die("git-%s failed", argv[0]);
864         free(argv);
865         return 0;
866 }
867
868 static int push_git(struct discovery *heads, int nr_spec, char **specs)
869 {
870         struct rpc_state rpc;
871         int i, err;
872         struct argv_array args;
873         struct string_list_item *cas_option;
874         struct strbuf preamble = STRBUF_INIT;
875
876         argv_array_init(&args);
877         argv_array_pushl(&args, "send-pack", "--stateless-rpc", "--helper-status",
878                          NULL);
879
880         if (options.thin)
881                 argv_array_push(&args, "--thin");
882         if (options.dry_run)
883                 argv_array_push(&args, "--dry-run");
884         if (options.push_cert)
885                 argv_array_push(&args, "--signed");
886         if (options.verbosity == 0)
887                 argv_array_push(&args, "--quiet");
888         else if (options.verbosity > 1)
889                 argv_array_push(&args, "--verbose");
890         argv_array_push(&args, options.progress ? "--progress" : "--no-progress");
891         for_each_string_list_item(cas_option, &cas_options)
892                 argv_array_push(&args, cas_option->string);
893         argv_array_push(&args, url.buf);
894
895         argv_array_push(&args, "--stdin");
896         for (i = 0; i < nr_spec; i++)
897                 packet_buf_write(&preamble, "%s\n", specs[i]);
898         packet_buf_flush(&preamble);
899
900         memset(&rpc, 0, sizeof(rpc));
901         rpc.service_name = "git-receive-pack",
902         rpc.argv = args.argv;
903         rpc.stdin_preamble = &preamble;
904
905         err = rpc_service(&rpc, heads);
906         if (rpc.result.len)
907                 write_or_die(1, rpc.result.buf, rpc.result.len);
908         strbuf_release(&rpc.result);
909         strbuf_release(&preamble);
910         argv_array_clear(&args);
911         return err;
912 }
913
914 static int push(int nr_spec, char **specs)
915 {
916         struct discovery *heads = discover_refs("git-receive-pack", 1);
917         int ret;
918
919         if (heads->proto_git)
920                 ret = push_git(heads, nr_spec, specs);
921         else
922                 ret = push_dav(nr_spec, specs);
923         free_discovery(heads);
924         return ret;
925 }
926
927 static void parse_push(struct strbuf *buf)
928 {
929         char **specs = NULL;
930         int alloc_spec = 0, nr_spec = 0, i, ret;
931
932         do {
933                 if (starts_with(buf->buf, "push ")) {
934                         ALLOC_GROW(specs, nr_spec + 1, alloc_spec);
935                         specs[nr_spec++] = xstrdup(buf->buf + 5);
936                 }
937                 else
938                         die("http transport does not support %s", buf->buf);
939
940                 strbuf_reset(buf);
941                 if (strbuf_getline(buf, stdin, '\n') == EOF)
942                         goto free_specs;
943                 if (!*buf->buf)
944                         break;
945         } while (1);
946
947         ret = push(nr_spec, specs);
948         printf("\n");
949         fflush(stdout);
950
951         if (ret)
952                 exit(128); /* error already reported */
953
954  free_specs:
955         for (i = 0; i < nr_spec; i++)
956                 free(specs[i]);
957         free(specs);
958 }
959
960 int main(int argc, const char **argv)
961 {
962         struct strbuf buf = STRBUF_INIT;
963         int nongit;
964
965         git_extract_argv0_path(argv[0]);
966         setup_git_directory_gently(&nongit);
967         if (argc < 2) {
968                 error("remote-curl: usage: git remote-curl <remote> [<url>]");
969                 return 1;
970         }
971
972         options.verbosity = 1;
973         options.progress = !!isatty(2);
974         options.thin = 1;
975
976         remote = remote_get(argv[1]);
977
978         if (argc > 2) {
979                 end_url_with_slash(&url, argv[2]);
980         } else {
981                 end_url_with_slash(&url, remote->url[0]);
982         }
983
984         http_init(remote, url.buf, 0);
985
986         do {
987                 const char *arg;
988
989                 if (strbuf_getline(&buf, stdin, '\n') == EOF) {
990                         if (ferror(stdin))
991                                 error("remote-curl: error reading command stream from git");
992                         return 1;
993                 }
994                 if (buf.len == 0)
995                         break;
996                 if (starts_with(buf.buf, "fetch ")) {
997                         if (nongit)
998                                 die("remote-curl: fetch attempted without a local repo");
999                         parse_fetch(&buf);
1000
1001                 } else if (!strcmp(buf.buf, "list") || starts_with(buf.buf, "list ")) {
1002                         int for_push = !!strstr(buf.buf + 4, "for-push");
1003                         output_refs(get_refs(for_push));
1004
1005                 } else if (starts_with(buf.buf, "push ")) {
1006                         parse_push(&buf);
1007
1008                 } else if (skip_prefix(buf.buf, "option ", &arg)) {
1009                         char *value = strchr(arg, ' ');
1010                         int result;
1011
1012                         if (value)
1013                                 *value++ = '\0';
1014                         else
1015                                 value = "true";
1016
1017                         result = set_option(arg, value);
1018                         if (!result)
1019                                 printf("ok\n");
1020                         else if (result < 0)
1021                                 printf("error invalid value\n");
1022                         else
1023                                 printf("unsupported\n");
1024                         fflush(stdout);
1025
1026                 } else if (!strcmp(buf.buf, "capabilities")) {
1027                         printf("fetch\n");
1028                         printf("option\n");
1029                         printf("push\n");
1030                         printf("check-connectivity\n");
1031                         printf("\n");
1032                         fflush(stdout);
1033                 } else {
1034                         error("remote-curl: unknown command '%s' from git", buf.buf);
1035                         return 1;
1036                 }
1037                 strbuf_reset(&buf);
1038         } while (1);
1039
1040         http_cleanup();
1041
1042         return 0;
1043 }