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