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