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