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