Refactor merge strategies into separate includable file.
[git] / http-push.c
1 #include "cache.h"
2 #include "commit.h"
3 #include "pack.h"
4 #include "fetch.h"
5 #include "tag.h"
6 #include "blob.h"
7
8 #include <curl/curl.h>
9 #include <curl/easy.h>
10 #include "expat.h"
11
12 static const char http_push_usage[] =
13 "git-http-push [--complete] [--force] [--verbose] <url> <ref> [<ref>...]\n";
14
15 #if LIBCURL_VERSION_NUM >= 0x070908
16 #define USE_CURL_MULTI
17 #define DEFAULT_MAX_REQUESTS 5
18 #endif
19
20 #if LIBCURL_VERSION_NUM < 0x070704
21 #define curl_global_cleanup() do { /* nothing */ } while(0)
22 #endif
23 #if LIBCURL_VERSION_NUM < 0x070800
24 #define curl_global_init(a) do { /* nothing */ } while(0)
25 #endif
26
27 #if LIBCURL_VERSION_NUM < 0x070c04
28 #define NO_CURL_EASY_DUPHANDLE
29 #endif
30
31 #define RANGE_HEADER_SIZE 30
32
33 /* DAV method names and request body templates */
34 #define DAV_LOCK "LOCK"
35 #define DAV_MKCOL "MKCOL"
36 #define DAV_MOVE "MOVE"
37 #define DAV_PROPFIND "PROPFIND"
38 #define DAV_PUT "PUT"
39 #define DAV_UNLOCK "UNLOCK"
40 #define PROPFIND_REQUEST "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<D:propfind xmlns:D=\"DAV:\">\n<D:prop xmlns:R=\"%s\">\n<D:supportedlock/>\n</D:prop>\n</D:propfind>"
41 #define LOCK_REQUEST "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<D:lockinfo xmlns:D=\"DAV:\">\n<D:lockscope><D:exclusive/></D:lockscope>\n<D:locktype><D:write/></D:locktype>\n<D:owner>\n<D:href>mailto:%s</D:href>\n</D:owner>\n</D:lockinfo>"
42
43 #define LOCK_TIME 600
44 #define LOCK_REFRESH 30
45
46 static int active_requests = 0;
47 static int data_received;
48 static int pushing = 0;
49 static int aborted = 0;
50
51 #ifdef USE_CURL_MULTI
52 static int max_requests = -1;
53 static CURLM *curlm;
54 #endif
55 #ifndef NO_CURL_EASY_DUPHANDLE
56 static CURL *curl_default;
57 #endif
58 static struct curl_slist *no_pragma_header;
59 static struct curl_slist *default_headers;
60 static char curl_errorstr[CURL_ERROR_SIZE];
61
62 static int push_verbosely = 0;
63 static int push_all = 0;
64 static int force_all = 0;
65
66 struct buffer
67 {
68         size_t posn;
69         size_t size;
70         void *buffer;
71 };
72
73 struct repo
74 {
75         char *url;
76         struct packed_git *packs;
77 };
78
79 static struct repo *remote = NULL;
80
81 enum transfer_state {
82         NEED_CHECK,
83         RUN_HEAD,
84         NEED_PUSH,
85         RUN_MKCOL,
86         RUN_PUT,
87         RUN_MOVE,
88         ABORTED,
89         COMPLETE,
90 };
91
92 struct transfer_request
93 {
94         unsigned char sha1[20];
95         char *url;
96         char *dest;
97         struct active_lock *lock;
98         struct curl_slist *headers;
99         struct buffer buffer;
100         char filename[PATH_MAX];
101         char tmpfile[PATH_MAX];
102         enum transfer_state state;
103         CURLcode curl_result;
104         char errorstr[CURL_ERROR_SIZE];
105         long http_code;
106         unsigned char real_sha1[20];
107         SHA_CTX c;
108         z_stream stream;
109         int zret;
110         int rename;
111         struct active_request_slot *slot;
112         struct transfer_request *next;
113 };
114
115 struct active_request_slot
116 {
117         CURL *curl;
118         FILE *local;
119         int in_use;
120         int done;
121         CURLcode curl_result;
122         long http_code;
123         struct active_request_slot *next;
124 };
125
126 static struct transfer_request *request_queue_head = NULL;
127 static struct active_request_slot *active_queue_head = NULL;
128
129 static int curl_ssl_verify = -1;
130 static char *ssl_cert = NULL;
131 #if LIBCURL_VERSION_NUM >= 0x070902
132 static char *ssl_key = NULL;
133 #endif
134 #if LIBCURL_VERSION_NUM >= 0x070908
135 static char *ssl_capath = NULL;
136 #endif
137 static char *ssl_cainfo = NULL;
138 static long curl_low_speed_limit = -1;
139 static long curl_low_speed_time = -1;
140
141 struct active_lock
142 {
143         int ctx_activelock;
144         int ctx_owner;
145         int ctx_owner_href;
146         int ctx_timeout;
147         int ctx_locktoken;
148         int ctx_locktoken_href;
149         char *url;
150         char *owner;
151         char *token;
152         time_t start_time;
153         long timeout;
154         int refreshing;
155 };
156
157 struct lockprop
158 {
159         int supported_lock;
160         int lock_entry;
161         int lock_scope;
162         int lock_type;
163         int lock_exclusive;
164         int lock_exclusive_write;
165 };
166
167 static int http_options(const char *var, const char *value)
168 {
169         if (!strcmp("http.sslverify", var)) {
170                 if (curl_ssl_verify == -1) {
171                         curl_ssl_verify = git_config_bool(var, value);
172                 }
173                 return 0;
174         }
175
176         if (!strcmp("http.sslcert", var)) {
177                 if (ssl_cert == NULL) {
178                         ssl_cert = xmalloc(strlen(value)+1);
179                         strcpy(ssl_cert, value);
180                 }
181                 return 0;
182         }
183 #if LIBCURL_VERSION_NUM >= 0x070902
184         if (!strcmp("http.sslkey", var)) {
185                 if (ssl_key == NULL) {
186                         ssl_key = xmalloc(strlen(value)+1);
187                         strcpy(ssl_key, value);
188                 }
189                 return 0;
190         }
191 #endif
192 #if LIBCURL_VERSION_NUM >= 0x070908
193         if (!strcmp("http.sslcapath", var)) {
194                 if (ssl_capath == NULL) {
195                         ssl_capath = xmalloc(strlen(value)+1);
196                         strcpy(ssl_capath, value);
197                 }
198                 return 0;
199         }
200 #endif
201         if (!strcmp("http.sslcainfo", var)) {
202                 if (ssl_cainfo == NULL) {
203                         ssl_cainfo = xmalloc(strlen(value)+1);
204                         strcpy(ssl_cainfo, value);
205                 }
206                 return 0;
207         }
208
209 #ifdef USE_CURL_MULTI   
210         if (!strcmp("http.maxrequests", var)) {
211                 if (max_requests == -1)
212                         max_requests = git_config_int(var, value);
213                 return 0;
214         }
215 #endif
216
217         if (!strcmp("http.lowspeedlimit", var)) {
218                 if (curl_low_speed_limit == -1)
219                         curl_low_speed_limit = (long)git_config_int(var, value);
220                 return 0;
221         }
222         if (!strcmp("http.lowspeedtime", var)) {
223                 if (curl_low_speed_time == -1)
224                         curl_low_speed_time = (long)git_config_int(var, value);
225                 return 0;
226         }
227
228         /* Fall back on the default ones */
229         return git_default_config(var, value);
230 }
231
232 static size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb,
233                            struct buffer *buffer)
234 {
235         size_t size = eltsize * nmemb;
236         if (size > buffer->size - buffer->posn)
237                 size = buffer->size - buffer->posn;
238         memcpy(ptr, buffer->buffer + buffer->posn, size);
239         buffer->posn += size;
240         return size;
241 }
242
243 static size_t fwrite_buffer_dynamic(const void *ptr, size_t eltsize,
244                                     size_t nmemb, struct buffer *buffer)
245 {
246         size_t size = eltsize * nmemb;
247         if (size > buffer->size - buffer->posn) {
248                 buffer->size = buffer->size * 3 / 2;
249                 if (buffer->size < buffer->posn + size)
250                         buffer->size = buffer->posn + size;
251                 buffer->buffer = xrealloc(buffer->buffer, buffer->size);
252         }
253         memcpy(buffer->buffer + buffer->posn, ptr, size);
254         buffer->posn += size;
255         data_received++;
256         return size;
257 }
258
259 static size_t fwrite_null(const void *ptr, size_t eltsize,
260                           size_t nmemb, struct buffer *buffer)
261 {
262         data_received++;
263         return eltsize * nmemb;
264 }
265
266 #ifdef USE_CURL_MULTI
267 static void process_curl_messages(void);
268 static void process_request_queue(void);
269 #endif
270
271 static CURL* get_curl_handle(void)
272 {
273         CURL* result = curl_easy_init();
274
275         curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, curl_ssl_verify);
276 #if LIBCURL_VERSION_NUM >= 0x070907
277         curl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
278 #endif
279
280         if (ssl_cert != NULL)
281                 curl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert);
282 #if LIBCURL_VERSION_NUM >= 0x070902
283         if (ssl_key != NULL)
284                 curl_easy_setopt(result, CURLOPT_SSLKEY, ssl_key);
285 #endif
286 #if LIBCURL_VERSION_NUM >= 0x070908
287         if (ssl_capath != NULL)
288                 curl_easy_setopt(result, CURLOPT_CAPATH, ssl_capath);
289 #endif
290         if (ssl_cainfo != NULL)
291                 curl_easy_setopt(result, CURLOPT_CAINFO, ssl_cainfo);
292         curl_easy_setopt(result, CURLOPT_FAILONERROR, 1);
293
294         if (curl_low_speed_limit > 0 && curl_low_speed_time > 0) {
295                 curl_easy_setopt(result, CURLOPT_LOW_SPEED_LIMIT,
296                                  curl_low_speed_limit);
297                 curl_easy_setopt(result, CURLOPT_LOW_SPEED_TIME,
298                                  curl_low_speed_time);
299         }
300
301         return result;
302 }
303
304 static struct active_request_slot *get_active_slot(void)
305 {
306         struct active_request_slot *slot = active_queue_head;
307         struct active_request_slot *newslot;
308
309 #ifdef USE_CURL_MULTI
310         int num_transfers;
311
312         /* Wait for a slot to open up if the queue is full */
313         while (active_requests >= max_requests) {
314                 curl_multi_perform(curlm, &num_transfers);
315                 if (num_transfers < active_requests) {
316                         process_curl_messages();
317                 }
318         }
319 #endif
320
321         while (slot != NULL && slot->in_use) {
322                 slot = slot->next;
323         }
324         if (slot == NULL) {
325                 newslot = xmalloc(sizeof(*newslot));
326                 newslot->curl = NULL;
327                 newslot->in_use = 0;
328                 newslot->next = NULL;
329
330                 slot = active_queue_head;
331                 if (slot == NULL) {
332                         active_queue_head = newslot;
333                 } else {
334                         while (slot->next != NULL) {
335                                 slot = slot->next;
336                         }
337                         slot->next = newslot;
338                 }
339                 slot = newslot;
340         }
341
342         if (slot->curl == NULL) {
343 #ifdef NO_CURL_EASY_DUPHANDLE
344                 slot->curl = get_curl_handle();
345 #else
346                 slot->curl = curl_easy_duphandle(curl_default);
347 #endif
348         }
349
350         active_requests++;
351         slot->in_use = 1;
352         slot->done = 0;
353         slot->local = NULL;
354         curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, default_headers);
355         curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, curl_errorstr);
356
357         return slot;
358 }
359
360 static int start_active_slot(struct active_request_slot *slot)
361 {
362 #ifdef USE_CURL_MULTI
363         CURLMcode curlm_result = curl_multi_add_handle(curlm, slot->curl);
364
365         if (curlm_result != CURLM_OK &&
366             curlm_result != CURLM_CALL_MULTI_PERFORM) {
367                 active_requests--;
368                 slot->in_use = 0;
369                 return 0;
370         }
371 #endif
372         return 1;
373 }
374
375 static void run_active_slot(struct active_request_slot *slot)
376 {
377 #ifdef USE_CURL_MULTI
378         int num_transfers;
379         long last_pos = 0;
380         long current_pos;
381         fd_set readfds;
382         fd_set writefds;
383         fd_set excfds;
384         int max_fd;
385         struct timeval select_timeout;
386         CURLMcode curlm_result;
387
388         while (!slot->done) {
389                 data_received = 0;
390                 do {
391                         curlm_result = curl_multi_perform(curlm,
392                                                           &num_transfers);
393                 } while (curlm_result == CURLM_CALL_MULTI_PERFORM);
394                 if (num_transfers < active_requests) {
395                         process_curl_messages();
396                         process_request_queue();
397                 }
398
399                 if (!data_received && slot->local != NULL) {
400                         current_pos = ftell(slot->local);
401                         if (current_pos > last_pos)
402                                 data_received++;
403                         last_pos = current_pos;
404                 }
405
406                 if (!slot->done && !data_received) {
407                         max_fd = 0;
408                         FD_ZERO(&readfds);
409                         FD_ZERO(&writefds);
410                         FD_ZERO(&excfds);
411                         select_timeout.tv_sec = 0;
412                         select_timeout.tv_usec = 50000;
413                         select(max_fd, &readfds, &writefds,
414                                &excfds, &select_timeout);
415                 }
416         }
417 #else
418         slot->curl_result = curl_easy_perform(slot->curl);
419         active_requests--;
420 #endif
421 }
422
423 static void start_check(struct transfer_request *request)
424 {
425         char *hex = sha1_to_hex(request->sha1);
426         struct active_request_slot *slot;
427         char *posn;
428
429         request->url = xmalloc(strlen(remote->url) + 55);
430         strcpy(request->url, remote->url);
431         posn = request->url + strlen(remote->url);
432         strcpy(posn, "objects/");
433         posn += 8;
434         memcpy(posn, hex, 2);
435         posn += 2;
436         *(posn++) = '/';
437         strcpy(posn, hex + 2);
438
439         slot = get_active_slot();
440         curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, request->errorstr);
441         curl_easy_setopt(slot->curl, CURLOPT_URL, request->url);
442         curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 1);
443
444         if (start_active_slot(slot)) {
445                 request->slot = slot;
446                 request->state = RUN_HEAD;
447         } else {
448                 request->state = ABORTED;
449                 free(request->url);
450         }
451 }
452
453 static void start_mkcol(struct transfer_request *request)
454 {
455         char *hex = sha1_to_hex(request->sha1);
456         struct active_request_slot *slot;
457         char *posn;
458
459         request->url = xmalloc(strlen(remote->url) + 13);
460         strcpy(request->url, remote->url);
461         posn = request->url + strlen(remote->url);
462         strcpy(posn, "objects/");
463         posn += 8;
464         memcpy(posn, hex, 2);
465         posn += 2;
466         strcpy(posn, "/");
467
468         slot = get_active_slot();
469         curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1); /* undo PUT setup */
470         curl_easy_setopt(slot->curl, CURLOPT_URL, request->url);
471         curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, request->errorstr);
472         curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_MKCOL);
473         curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
474
475         if (start_active_slot(slot)) {
476                 request->slot = slot;
477                 request->state = RUN_MKCOL;
478         } else {
479                 request->state = ABORTED;
480                 free(request->url);
481         }
482 }
483
484 static void start_put(struct transfer_request *request)
485 {
486         char *hex = sha1_to_hex(request->sha1);
487         struct active_request_slot *slot;
488         char *posn;
489         char type[20];
490         char hdr[50];
491         void *unpacked;
492         unsigned long len;
493         int hdrlen;
494         ssize_t size;
495         z_stream stream;
496
497         unpacked = read_sha1_file(request->sha1, type, &len);
498         hdrlen = sprintf(hdr, "%s %lu", type, len) + 1;
499
500         /* Set it up */
501         memset(&stream, 0, sizeof(stream));
502         deflateInit(&stream, Z_BEST_COMPRESSION);
503         size = deflateBound(&stream, len + hdrlen);
504         request->buffer.buffer = xmalloc(size);
505
506         /* Compress it */
507         stream.next_out = request->buffer.buffer;
508         stream.avail_out = size;
509
510         /* First header.. */
511         stream.next_in = (void *)hdr;
512         stream.avail_in = hdrlen;
513         while (deflate(&stream, 0) == Z_OK)
514                 /* nothing */;
515
516         /* Then the data itself.. */
517         stream.next_in = unpacked;
518         stream.avail_in = len;
519         while (deflate(&stream, Z_FINISH) == Z_OK)
520                 /* nothing */;
521         deflateEnd(&stream);
522         free(unpacked);
523
524         request->buffer.size = stream.total_out;
525         request->buffer.posn = 0;
526
527         if (request->url != NULL)
528                 free(request->url);
529         request->url = xmalloc(strlen(remote->url) + 
530                                strlen(request->lock->token) + 51);
531         strcpy(request->url, remote->url);
532         posn = request->url + strlen(remote->url);
533         strcpy(posn, "objects/");
534         posn += 8;
535         memcpy(posn, hex, 2);
536         posn += 2;
537         *(posn++) = '/';
538         strcpy(posn, hex + 2);
539         request->dest = xmalloc(strlen(request->url) + 14);
540         sprintf(request->dest, "Destination: %s", request->url);
541         posn += 38;
542         *(posn++) = '.';
543         strcpy(posn, request->lock->token);
544
545         slot = get_active_slot();
546         curl_easy_setopt(slot->curl, CURLOPT_INFILE, &request->buffer);
547         curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, request->buffer.size);
548         curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
549         curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
550         curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT);
551         curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);
552         curl_easy_setopt(slot->curl, CURLOPT_PUT, 1);
553         curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
554         curl_easy_setopt(slot->curl, CURLOPT_URL, request->url);
555
556         if (start_active_slot(slot)) {
557                 request->slot = slot;
558                 request->state = RUN_PUT;
559         } else {
560                 request->state = ABORTED;
561                 free(request->url);
562         }
563 }
564
565 static void start_move(struct transfer_request *request)
566 {
567         struct active_request_slot *slot;
568         struct curl_slist *dav_headers = NULL;
569
570         slot = get_active_slot();
571         curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1); /* undo PUT setup */
572         curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_MOVE);
573         dav_headers = curl_slist_append(dav_headers, request->dest);
574         dav_headers = curl_slist_append(dav_headers, "Overwrite: T");
575         curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
576         curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
577         curl_easy_setopt(slot->curl, CURLOPT_URL, request->url);
578
579         if (start_active_slot(slot)) {
580                 request->slot = slot;
581                 request->state = RUN_MOVE;
582         } else {
583                 request->state = ABORTED;
584                 free(request->url);
585         }
586 }
587
588 int refresh_lock(struct active_lock *lock)
589 {
590         struct active_request_slot *slot;
591         char *if_header;
592         char timeout_header[25];
593         struct curl_slist *dav_headers = NULL;
594         int rc = 0;
595
596         lock->refreshing = 1;
597
598         if_header = xmalloc(strlen(lock->token) + 25);
599         sprintf(if_header, "If: (<opaquelocktoken:%s>)", lock->token);
600         sprintf(timeout_header, "Timeout: Second-%ld", lock->timeout);
601         dav_headers = curl_slist_append(dav_headers, if_header);
602         dav_headers = curl_slist_append(dav_headers, timeout_header);
603
604         slot = get_active_slot();
605         curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
606         curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
607         curl_easy_setopt(slot->curl, CURLOPT_URL, lock->url);
608         curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_LOCK);
609         curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
610
611         if (start_active_slot(slot)) {
612                 run_active_slot(slot);
613                 if (slot->curl_result != CURLE_OK) {
614                         fprintf(stderr, "Got HTTP error %ld\n", slot->http_code);
615                 } else {
616                         lock->start_time = time(NULL);
617                         rc = 1;
618                 }
619         }
620
621         lock->refreshing = 0;
622         curl_slist_free_all(dav_headers);
623         free(if_header);
624
625         return rc;
626 }
627
628 static void finish_request(struct transfer_request *request)
629 {
630         time_t current_time = time(NULL);
631         int time_remaining;
632
633         request->curl_result =  request->slot->curl_result;
634         request->http_code = request->slot->http_code;
635         request->slot = NULL;
636
637         /* Refresh the lock if it is close to timing out */
638         time_remaining = request->lock->start_time + request->lock->timeout
639                 - current_time;
640         if (time_remaining < LOCK_REFRESH && !request->lock->refreshing) {
641                 if (!refresh_lock(request->lock)) {
642                         fprintf(stderr, "Unable to refresh remote lock\n");
643                         aborted = 1;
644                 }
645         }
646
647         if (request->headers != NULL)
648                 curl_slist_free_all(request->headers);
649         if (request->state == RUN_HEAD) {
650                 if (request->http_code == 404) {
651                         request->state = NEED_PUSH;
652                 } else if (request->curl_result == CURLE_OK) {
653                         request->state = COMPLETE;
654                 } else {
655                         fprintf(stderr, "HEAD %s failed, aborting (%d/%ld)\n",
656                                 sha1_to_hex(request->sha1),
657                                 request->curl_result, request->http_code);
658                         request->state = ABORTED;
659                         aborted = 1;
660                 }
661         } else if (request->state == RUN_MKCOL) {
662                 if (request->curl_result == CURLE_OK ||
663                     request->http_code == 405) {
664                         start_put(request);
665                 } else {
666                         fprintf(stderr, "MKCOL %s failed, aborting (%d/%ld)\n",
667                                 sha1_to_hex(request->sha1),
668                                 request->curl_result, request->http_code);
669                         request->state = ABORTED;
670                         aborted = 1;
671                 }
672         } else if (request->state == RUN_PUT) {
673                 if (request->curl_result == CURLE_OK) {
674                         start_move(request);
675                 } else {
676                         fprintf(stderr, "PUT %s failed, aborting (%d/%ld)\n",
677                                 sha1_to_hex(request->sha1),
678                                 request->curl_result, request->http_code);
679                         request->state = ABORTED;
680                         aborted = 1;
681                 }
682         } else if (request->state == RUN_MOVE) {
683                 if (request->curl_result == CURLE_OK) {
684                         if (push_verbosely)
685                                 fprintf(stderr,
686                                         "sent %s\n",
687                                         sha1_to_hex(request->sha1));
688                         request->state = COMPLETE;
689                 } else {
690                         fprintf(stderr, "MOVE %s failed, aborting (%d/%ld)\n",
691                                 sha1_to_hex(request->sha1),
692                                 request->curl_result, request->http_code);
693                         request->state = ABORTED;
694                         aborted = 1;
695                 }
696         }
697 }
698
699 static void release_request(struct transfer_request *request)
700 {
701         struct transfer_request *entry = request_queue_head;
702
703         if (request == request_queue_head) {
704                 request_queue_head = request->next;
705         } else {
706                 while (entry->next != NULL && entry->next != request)
707                         entry = entry->next;
708                 if (entry->next == request)
709                         entry->next = entry->next->next;
710         }
711
712         free(request->url);
713         free(request);
714 }
715
716 #ifdef USE_CURL_MULTI
717 void process_curl_messages(void)
718 {
719         int num_messages;
720         struct active_request_slot *slot;
721         struct transfer_request *request = NULL;
722         CURLMsg *curl_message = curl_multi_info_read(curlm, &num_messages);
723
724         while (curl_message != NULL) {
725                 if (curl_message->msg == CURLMSG_DONE) {
726                         slot = active_queue_head;
727                         while (slot != NULL &&
728                                slot->curl != curl_message->easy_handle)
729                                 slot = slot->next;
730                         if (slot != NULL) {
731                                 curl_multi_remove_handle(curlm, slot->curl);
732                                 active_requests--;
733                                 slot->done = 1;
734                                 slot->in_use = 0;
735                                 slot->curl_result = curl_message->data.result;
736                                 curl_easy_getinfo(slot->curl,
737                                                   CURLINFO_HTTP_CODE,
738                                                   &slot->http_code);
739                                 request = request_queue_head;
740                                 while (request != NULL &&
741                                        request->slot != slot)
742                                         request = request->next;
743                                 if (request != NULL)
744                                         finish_request(request);
745                         } else {
746                                 fprintf(stderr, "Received DONE message for unknown request!\n");
747                         }
748                 } else {
749                         fprintf(stderr, "Unknown CURL message received: %d\n",
750                                 (int)curl_message->msg);
751                 }
752                 curl_message = curl_multi_info_read(curlm, &num_messages);
753         }
754 }
755
756 void process_request_queue(void)
757 {
758         struct transfer_request *request = request_queue_head;
759         struct active_request_slot *slot = active_queue_head;
760         int num_transfers;
761
762         if (aborted)
763                 return;
764
765         while (active_requests < max_requests && request != NULL) {
766                 if (!pushing && request->state == NEED_CHECK) {
767                         start_check(request);
768                         curl_multi_perform(curlm, &num_transfers);
769                 } else if (pushing && request->state == NEED_PUSH) {
770                         start_mkcol(request);
771                         curl_multi_perform(curlm, &num_transfers);
772                 }
773                 request = request->next;
774         }
775
776         while (slot != NULL) {
777                 if (!slot->in_use && slot->curl != NULL) {
778                         curl_easy_cleanup(slot->curl);
779                         slot->curl = NULL;
780                 }
781                 slot = slot->next;
782         }                               
783 }
784 #endif
785
786 void process_waiting_requests(void)
787 {
788         struct active_request_slot *slot = active_queue_head;
789
790         while (slot != NULL)
791                 if (slot->in_use) {
792                         run_active_slot(slot);
793                         slot = active_queue_head;
794                 } else {
795                         slot = slot->next;
796                 }
797 }
798
799 void add_request(unsigned char *sha1, struct active_lock *lock)
800 {
801         struct transfer_request *request = request_queue_head;
802         struct packed_git *target;
803         
804         while (request != NULL && memcmp(request->sha1, sha1, 20))
805                 request = request->next;
806         if (request != NULL)
807                 return;
808
809         target = find_sha1_pack(sha1, remote->packs);
810         if (target)
811                 return;
812
813         request = xmalloc(sizeof(*request));
814         memcpy(request->sha1, sha1, 20);
815         request->url = NULL;
816         request->lock = lock;
817         request->headers = NULL;
818         request->state = NEED_CHECK;
819         request->next = request_queue_head;
820         request_queue_head = request;
821 #ifdef USE_CURL_MULTI
822         process_request_queue();
823         process_curl_messages();
824 #endif
825 }
826
827 static int fetch_index(unsigned char *sha1)
828 {
829         char *hex = sha1_to_hex(sha1);
830         char *filename;
831         char *url;
832         char tmpfile[PATH_MAX];
833         long prev_posn = 0;
834         char range[RANGE_HEADER_SIZE];
835         struct curl_slist *range_header = NULL;
836
837         FILE *indexfile;
838         struct active_request_slot *slot;
839
840         /* Don't use the index if the pack isn't there */
841         url = xmalloc(strlen(remote->url) + 65);
842         sprintf(url, "%s/objects/pack/pack-%s.pack", remote->url, hex);
843         slot = get_active_slot();
844         curl_easy_setopt(slot->curl, CURLOPT_URL, url);
845         curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 1);
846         if (start_active_slot(slot)) {
847                 run_active_slot(slot);
848                 if (slot->curl_result != CURLE_OK) {
849                         free(url);
850                         return error("Unable to verify pack %s is available",
851                                      hex);
852                 }
853         } else {
854                 return error("Unable to start request");
855         }
856
857         if (has_pack_index(sha1))
858                 return 0;
859
860         if (push_verbosely)
861                 fprintf(stderr, "Getting index for pack %s\n", hex);
862         
863         sprintf(url, "%s/objects/pack/pack-%s.idx", remote->url, hex);
864         
865         filename = sha1_pack_index_name(sha1);
866         snprintf(tmpfile, sizeof(tmpfile), "%s.temp", filename);
867         indexfile = fopen(tmpfile, "a");
868         if (!indexfile)
869                 return error("Unable to open local file %s for pack index",
870                              filename);
871
872         slot = get_active_slot();
873         curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
874         curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
875         curl_easy_setopt(slot->curl, CURLOPT_FILE, indexfile);
876         curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite);
877         curl_easy_setopt(slot->curl, CURLOPT_URL, url);
878         curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);
879         slot->local = indexfile;
880
881         /* If there is data present from a previous transfer attempt,
882            resume where it left off */
883         prev_posn = ftell(indexfile);
884         if (prev_posn>0) {
885                 if (push_verbosely)
886                         fprintf(stderr,
887                                 "Resuming fetch of index for pack %s at byte %ld\n",
888                                 hex, prev_posn);
889                 sprintf(range, "Range: bytes=%ld-", prev_posn);
890                 range_header = curl_slist_append(range_header, range);
891                 curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, range_header);
892         }
893
894         if (start_active_slot(slot)) {
895                 run_active_slot(slot);
896                 if (slot->curl_result != CURLE_OK) {
897                         free(url);
898                         fclose(indexfile);
899                         return error("Unable to get pack index %s\n%s", url,
900                                      curl_errorstr);
901                 }
902         } else {
903                 free(url);
904                 return error("Unable to start request");
905         }
906
907         free(url);
908         fclose(indexfile);
909
910         return move_temp_to_file(tmpfile, filename);
911 }
912
913 static int setup_index(unsigned char *sha1)
914 {
915         struct packed_git *new_pack;
916
917         if (fetch_index(sha1))
918                 return -1;
919
920         new_pack = parse_pack_index(sha1);
921         new_pack->next = remote->packs;
922         remote->packs = new_pack;
923         return 0;
924 }
925
926 static int fetch_indices()
927 {
928         unsigned char sha1[20];
929         char *url;
930         struct buffer buffer;
931         char *data;
932         int i = 0;
933
934         struct active_request_slot *slot;
935
936         data = xmalloc(4096);
937         memset(data, 0, 4096);
938         buffer.size = 4096;
939         buffer.posn = 0;
940         buffer.buffer = data;
941
942         if (push_verbosely)
943                 fprintf(stderr, "Getting pack list\n");
944         
945         url = xmalloc(strlen(remote->url) + 21);
946         sprintf(url, "%s/objects/info/packs", remote->url);
947
948         slot = get_active_slot();
949         curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
950         curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
951                          fwrite_buffer_dynamic);
952         curl_easy_setopt(slot->curl, CURLOPT_URL, url);
953         curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);
954         if (start_active_slot(slot)) {
955                 run_active_slot(slot);
956                 if (slot->curl_result != CURLE_OK) {
957                         free(buffer.buffer);
958                         free(url);
959                         if (slot->http_code == 404)
960                                 return 0;
961                         else
962                                 return error("%s", curl_errorstr);
963                 }
964         } else {
965                 free(buffer.buffer);
966                 free(url);
967                 return error("Unable to start request");
968         }
969         free(url);
970
971         data = buffer.buffer;
972         while (i < buffer.posn) {
973                 switch (data[i]) {
974                 case 'P':
975                         i++;
976                         if (i + 52 < buffer.posn &&
977                             !strncmp(data + i, " pack-", 6) &&
978                             !strncmp(data + i + 46, ".pack\n", 6)) {
979                                 get_sha1_hex(data + i + 6, sha1);
980                                 setup_index(sha1);
981                                 i += 51;
982                                 break;
983                         }
984                 default:
985                         while (data[i] != '\n')
986                                 i++;
987                 }
988                 i++;
989         }
990
991         free(buffer.buffer);
992         return 0;
993 }
994
995 static inline int needs_quote(int ch)
996 {
997         switch (ch) {
998         case '/': case '-': case '.':
999         case 'A'...'Z': case 'a'...'z': case '0'...'9':
1000                 return 0;
1001         default:
1002                 return 1;
1003         }
1004 }
1005
1006 static inline int hex(int v)
1007 {
1008         if (v < 10) return '0' + v;
1009         else return 'A' + v - 10;
1010 }
1011
1012 static char *quote_ref_url(const char *base, const char *ref)
1013 {
1014         const char *cp;
1015         char *dp, *qref;
1016         int len, baselen, ch;
1017
1018         baselen = strlen(base);
1019         len = baselen + 12; /* "refs/heads/" + NUL */
1020         for (cp = ref; (ch = *cp) != 0; cp++, len++)
1021                 if (needs_quote(ch))
1022                         len += 2; /* extra two hex plus replacement % */
1023         qref = xmalloc(len);
1024         memcpy(qref, base, baselen);
1025         memcpy(qref + baselen, "refs/heads/", 11);
1026         for (cp = ref, dp = qref + baselen + 11; (ch = *cp) != 0; cp++) {
1027                 if (needs_quote(ch)) {
1028                         *dp++ = '%';
1029                         *dp++ = hex((ch >> 4) & 0xF);
1030                         *dp++ = hex(ch & 0xF);
1031                 }
1032                 else
1033                         *dp++ = ch;
1034         }
1035         *dp = 0;
1036
1037         return qref;
1038 }
1039
1040 int fetch_ref(char *ref, unsigned char *sha1)
1041 {
1042         char *url;
1043         char hex[42];
1044         struct buffer buffer;
1045         char *base = remote->url;
1046         struct active_request_slot *slot;
1047         buffer.size = 41;
1048         buffer.posn = 0;
1049         buffer.buffer = hex;
1050         hex[41] = '\0';
1051         
1052         url = quote_ref_url(base, ref);
1053         slot = get_active_slot();
1054         curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
1055         curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
1056                          fwrite_buffer_dynamic);
1057         curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);
1058         curl_easy_setopt(slot->curl, CURLOPT_URL, url);
1059         if (start_active_slot(slot)) {
1060                 run_active_slot(slot);
1061                 if (slot->curl_result != CURLE_OK)
1062                         return error("Couldn't get %s for %s\n%s",
1063                                      url, ref, curl_errorstr);
1064         } else {
1065                 return error("Unable to start request");
1066         }
1067
1068         hex[40] = '\0';
1069         get_sha1_hex(hex, sha1);
1070         return 0;
1071 }
1072
1073 static void
1074 start_activelock_element(void *userData, const char *name, const char **atts)
1075 {
1076         struct active_lock *lock = (struct active_lock *)userData;
1077
1078         if (lock->ctx_activelock && !strcmp(name, "D:timeout"))
1079                 lock->ctx_timeout = 1;
1080         else if (lock->ctx_owner && strstr(name, "href"))
1081                 lock->ctx_owner_href = 1;
1082         else if (lock->ctx_activelock && strstr(name, "owner"))
1083                 lock->ctx_owner = 1;
1084         else if (lock->ctx_locktoken && !strcmp(name, "D:href"))
1085                 lock->ctx_locktoken_href = 1;
1086         else if (lock->ctx_activelock && !strcmp(name, "D:locktoken"))
1087                 lock->ctx_locktoken = 1;
1088         else if (!strcmp(name, "D:activelock"))
1089                 lock->ctx_activelock = 1;
1090 }
1091
1092 static void
1093 end_activelock_element(void *userData, const char *name)
1094 {
1095         struct active_lock *lock = (struct active_lock *)userData;
1096
1097         if (lock->ctx_timeout && !strcmp(name, "D:timeout")) {
1098                 lock->ctx_timeout = 0;
1099         } else if (lock->ctx_owner_href && strstr(name, "href")) {
1100                 lock->ctx_owner_href = 0;
1101         } else if (lock->ctx_owner && strstr(name, "owner")) {
1102                 lock->ctx_owner = 0;
1103         } else if (lock->ctx_locktoken_href && !strcmp(name, "D:href")) {
1104                 lock->ctx_locktoken_href = 0;
1105         } else if (lock->ctx_locktoken && !strcmp(name, "D:locktoken")) {
1106                 lock->ctx_locktoken = 0;
1107         } else if (lock->ctx_activelock && !strcmp(name, "D:activelock")) {
1108                 lock->ctx_activelock = 0;
1109         }
1110 }
1111
1112 static void
1113 activelock_cdata(void *userData, const XML_Char *s, int len)
1114 {
1115         struct active_lock *lock = (struct active_lock *)userData;
1116         char *this = malloc(len+1);
1117         strncpy(this, s, len);
1118
1119         if (lock->ctx_owner_href) {
1120                 lock->owner = malloc(len+1);
1121                 strcpy(lock->owner, this);
1122         } else if (lock->ctx_locktoken_href) {
1123                 if (!strncmp(this, "opaquelocktoken:", 16)) {
1124                         lock->token = malloc(len-15);
1125                         strcpy(lock->token, this+16);
1126                 }
1127         } else if (lock->ctx_timeout) {
1128                 if (!strncmp(this, "Second-", 7))
1129                         lock->timeout = strtol(this+7, NULL, 10);
1130         }
1131
1132         free(this);
1133 }
1134
1135 static void
1136 start_lockprop_element(void *userData, const char *name, const char **atts)
1137 {
1138         struct lockprop *prop = (struct lockprop *)userData;
1139
1140         if (prop->lock_type && !strcmp(name, "D:write")) {
1141                 if (prop->lock_exclusive) {
1142                         prop->lock_exclusive_write = 1;
1143                 }
1144         } else if (prop->lock_scope && !strcmp(name, "D:exclusive")) {
1145                 prop->lock_exclusive = 1;
1146         } else if (prop->lock_entry) {
1147                 if (!strcmp(name, "D:lockscope")) {
1148                         prop->lock_scope = 1;
1149                 } else if (!strcmp(name, "D:locktype")) {
1150                         prop->lock_type = 1;
1151                 }
1152         } else if (prop->supported_lock) {
1153                 if (!strcmp(name, "D:lockentry")) {
1154                         prop->lock_entry = 1;
1155                 }
1156         } else if (!strcmp(name, "D:supportedlock")) {
1157                 prop->supported_lock = 1;
1158         }
1159 }
1160
1161 static void
1162 end_lockprop_element(void *userData, const char *name)
1163 {
1164         struct lockprop *prop = (struct lockprop *)userData;
1165
1166         if (!strcmp(name, "D:lockentry")) {
1167                 prop->lock_entry = 0;
1168                 prop->lock_scope = 0;
1169                 prop->lock_type = 0;
1170                 prop->lock_exclusive = 0;
1171         } else if (!strcmp(name, "D:supportedlock")) {
1172                 prop->supported_lock = 0;
1173         }
1174 }
1175
1176 struct active_lock *lock_remote(char *file, long timeout)
1177 {
1178         struct active_request_slot *slot;
1179         struct buffer out_buffer;
1180         struct buffer in_buffer;
1181         char *out_data;
1182         char *in_data;
1183         char *url;
1184         char *ep;
1185         char timeout_header[25];
1186         struct active_lock *new_lock;
1187         XML_Parser parser = XML_ParserCreate(NULL);
1188         enum XML_Status result;
1189         struct curl_slist *dav_headers = NULL;
1190
1191         url = xmalloc(strlen(remote->url) + strlen(file) + 1);
1192         sprintf(url, "%s%s", remote->url, file);
1193
1194         /* Make sure leading directories exist for the remote ref */
1195         ep = strchr(url + strlen(remote->url) + 11, '/');
1196         while (ep) {
1197                 *ep = 0;
1198                 slot = get_active_slot();
1199                 curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
1200                 curl_easy_setopt(slot->curl, CURLOPT_URL, url);
1201                 curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_MKCOL);
1202                 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
1203                 if (start_active_slot(slot)) {
1204                         run_active_slot(slot);
1205                         if (slot->curl_result != CURLE_OK &&
1206                             slot->http_code != 405) {
1207                                 fprintf(stderr,
1208                                         "Unable to create branch path %s\n",
1209                                         url);
1210                                 free(url);
1211                                 return NULL;
1212                         }
1213                 } else {
1214                         fprintf(stderr, "Unable to start request\n");
1215                         free(url);
1216                         return NULL;
1217                 }
1218                 *ep = '/';
1219                 ep = strchr(ep + 1, '/');
1220         }
1221
1222         out_buffer.size = strlen(LOCK_REQUEST) + strlen(git_default_email) - 2;
1223         out_data = xmalloc(out_buffer.size + 1);
1224         snprintf(out_data, out_buffer.size + 1, LOCK_REQUEST, git_default_email);
1225         out_buffer.posn = 0;
1226         out_buffer.buffer = out_data;
1227
1228         in_buffer.size = 4096;
1229         in_data = xmalloc(in_buffer.size);
1230         in_buffer.posn = 0;
1231         in_buffer.buffer = in_data;
1232
1233         new_lock = xmalloc(sizeof(*new_lock));
1234         new_lock->owner = NULL;
1235         new_lock->token = NULL;
1236         new_lock->timeout = -1;
1237         new_lock->refreshing = 0;
1238
1239         sprintf(timeout_header, "Timeout: Second-%ld", timeout);
1240         dav_headers = curl_slist_append(dav_headers, timeout_header);
1241         dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml");
1242
1243         slot = get_active_slot();
1244         curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
1245         curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size);
1246         curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
1247         curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);
1248         curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
1249                          fwrite_buffer_dynamic);
1250         curl_easy_setopt(slot->curl, CURLOPT_URL, url);
1251         curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);
1252         curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_LOCK);
1253         curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
1254
1255         if (start_active_slot(slot)) {
1256                 run_active_slot(slot);
1257                 if (slot->curl_result != CURLE_OK) {
1258                         fprintf(stderr, "Got HTTP error %ld\n", slot->http_code);
1259                         free(new_lock);
1260                         free(url);
1261                         free(out_data);
1262                         free(in_data);
1263                         return NULL;
1264                 }
1265         } else {
1266                 free(new_lock);
1267                 free(url);
1268                 free(out_data);
1269                 free(in_data);
1270                 fprintf(stderr, "Unable to start request\n");
1271                 return NULL;
1272         }
1273
1274         free(out_data);
1275
1276         XML_SetUserData(parser, new_lock);
1277         XML_SetElementHandler(parser, start_activelock_element,
1278                                       end_activelock_element);
1279         XML_SetCharacterDataHandler(parser, activelock_cdata);
1280         result = XML_Parse(parser, in_buffer.buffer, in_buffer.posn, 1);
1281         free(in_data);
1282         if (result != XML_STATUS_OK) {
1283                 fprintf(stderr, "%s", XML_ErrorString(
1284                                 XML_GetErrorCode(parser)));
1285                 free(url);
1286                 free(new_lock);
1287                 return NULL;
1288         }
1289
1290         if (new_lock->token == NULL || new_lock->timeout <= 0) {
1291                 if (new_lock->token != NULL)
1292                         free(new_lock->token);
1293                 if (new_lock->owner != NULL)
1294                         free(new_lock->owner);
1295                 free(url);
1296                 free(new_lock);
1297                 return NULL;
1298         }
1299
1300         new_lock->url = url;
1301         new_lock->start_time = time(NULL);
1302         return new_lock;
1303 }
1304
1305 int unlock_remote(struct active_lock *lock)
1306 {
1307         struct active_request_slot *slot;
1308         char *lock_token_header;
1309         struct curl_slist *dav_headers = NULL;
1310         int rc = 0;
1311
1312         lock_token_header = xmalloc(strlen(lock->token) + 31);
1313         sprintf(lock_token_header, "Lock-Token: <opaquelocktoken:%s>",
1314                 lock->token);
1315         dav_headers = curl_slist_append(dav_headers, lock_token_header);
1316
1317         slot = get_active_slot();
1318         curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
1319         curl_easy_setopt(slot->curl, CURLOPT_URL, lock->url);
1320         curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_UNLOCK);
1321         curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
1322
1323         if (start_active_slot(slot)) {
1324                 run_active_slot(slot);
1325                 if (slot->curl_result == CURLE_OK)
1326                         rc = 1;
1327                 else
1328                         fprintf(stderr, "Got HTTP error %ld\n",
1329                                 slot->http_code);
1330         } else {
1331                 fprintf(stderr, "Unable to start request\n");
1332         }
1333
1334         curl_slist_free_all(dav_headers);
1335         free(lock_token_header);
1336
1337         if (lock->owner != NULL)
1338                 free(lock->owner);
1339         free(lock->url);
1340         free(lock->token);
1341         free(lock);
1342
1343         return rc;
1344 }
1345
1346 int check_locking()
1347 {
1348         struct active_request_slot *slot;
1349         struct buffer in_buffer;
1350         struct buffer out_buffer;
1351         char *in_data;
1352         char *out_data;
1353         XML_Parser parser = XML_ParserCreate(NULL);
1354         enum XML_Status result;
1355         struct lockprop supported_lock;
1356         struct curl_slist *dav_headers = NULL;
1357
1358         out_buffer.size = strlen(PROPFIND_REQUEST) + strlen(remote->url) - 2;
1359         out_data = xmalloc(out_buffer.size + 1);
1360         snprintf(out_data, out_buffer.size + 1, PROPFIND_REQUEST, remote->url);
1361         out_buffer.posn = 0;
1362         out_buffer.buffer = out_data;
1363
1364         in_buffer.size = 4096;
1365         in_data = xmalloc(in_buffer.size);
1366         in_buffer.posn = 0;
1367         in_buffer.buffer = in_data;
1368
1369         dav_headers = curl_slist_append(dav_headers, "Depth: 0");
1370         dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml");
1371         
1372         slot = get_active_slot();
1373         curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
1374         curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size);
1375         curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
1376         curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);
1377         curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
1378                          fwrite_buffer_dynamic);
1379         curl_easy_setopt(slot->curl, CURLOPT_URL, remote->url);
1380         curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);
1381         curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PROPFIND);
1382         curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
1383
1384         if (start_active_slot(slot)) {
1385                 run_active_slot(slot);
1386                 free(out_data);
1387                 if (slot->curl_result != CURLE_OK) {
1388                         free(in_buffer.buffer);
1389                         return -1;
1390                 }
1391
1392                 XML_SetUserData(parser, &supported_lock);
1393                 XML_SetElementHandler(parser, start_lockprop_element,
1394                                       end_lockprop_element);
1395                 result = XML_Parse(parser, in_buffer.buffer, in_buffer.posn, 1);
1396                 free(in_buffer.buffer);
1397                 if (result != XML_STATUS_OK)
1398                         return error("%s", XML_ErrorString(
1399                                              XML_GetErrorCode(parser)));
1400         } else {
1401                 free(out_data);
1402                 free(in_buffer.buffer);
1403                 return error("Unable to start request");
1404         }
1405
1406         if (supported_lock.lock_exclusive_write)
1407                 return 0;
1408         else
1409                 return 1;
1410 }
1411
1412 int is_ancestor(unsigned char *sha1, struct commit *commit)
1413 {
1414         struct commit_list *parents;
1415
1416         if (parse_commit(commit))
1417                 return 0;
1418         parents = commit->parents;
1419         for (; parents; parents = parents->next) {
1420                 if (!memcmp(sha1, parents->item->object.sha1, 20)) {
1421                         return 1;
1422                 } else if (parents->item->object.type == commit_type) {
1423                         if (is_ancestor(
1424                                     sha1,
1425                                     (struct commit *)&parents->item->object
1426                                     ))
1427                                 return 1;
1428                 }
1429         }
1430         return 0;
1431 }
1432
1433 void get_delta(unsigned char *sha1, struct object *obj,
1434                struct active_lock *lock)
1435 {
1436         struct commit *commit;
1437         struct commit_list *parents;
1438         struct tree *tree;
1439         struct tree_entry_list *entry;
1440
1441         if (sha1 && !memcmp(sha1, obj->sha1, 20))
1442                 return;
1443
1444         if (aborted)
1445                 return;
1446
1447         if (obj->type == commit_type) {
1448                 if (push_verbosely)
1449                         fprintf(stderr, "walk %s\n", sha1_to_hex(obj->sha1));
1450                 add_request(obj->sha1, lock);
1451                 commit = (struct commit *)obj;
1452                 if (parse_commit(commit)) {
1453                         fprintf(stderr, "Error parsing commit %s\n",
1454                                 sha1_to_hex(obj->sha1));
1455                         aborted = 1;
1456                         return;
1457                 }
1458                 parents = commit->parents;
1459                 for (; parents; parents = parents->next)
1460                         if (sha1 == NULL ||
1461                             memcmp(sha1, parents->item->object.sha1, 20))
1462                                 get_delta(sha1, &parents->item->object,
1463                                           lock);
1464                 get_delta(sha1, &commit->tree->object, lock);
1465         } else if (obj->type == tree_type) {
1466                 if (push_verbosely)
1467                         fprintf(stderr, "walk %s\n", sha1_to_hex(obj->sha1));
1468                 add_request(obj->sha1, lock);
1469                 tree = (struct tree *)obj;
1470                 if (parse_tree(tree)) {
1471                         fprintf(stderr, "Error parsing tree %s\n",
1472                                 sha1_to_hex(obj->sha1));
1473                         aborted = 1;
1474                         return;
1475                 }
1476                 entry = tree->entries;
1477                 tree->entries = NULL;
1478                 while (entry) {
1479                         struct tree_entry_list *next = entry->next;
1480                         get_delta(sha1, entry->item.any, lock);
1481                         free(entry->name);
1482                         free(entry);
1483                         entry = next;
1484                 }
1485         } else if (obj->type == blob_type || obj->type == tag_type) {
1486                 add_request(obj->sha1, lock);
1487         }
1488 }
1489
1490 int update_remote(unsigned char *sha1, struct active_lock *lock)
1491 {
1492         struct active_request_slot *slot;
1493         char *out_data;
1494         char *if_header;
1495         struct buffer out_buffer;
1496         struct curl_slist *dav_headers = NULL;
1497         int i;
1498
1499         if_header = xmalloc(strlen(lock->token) + 25);
1500         sprintf(if_header, "If: (<opaquelocktoken:%s>)", lock->token);
1501         dav_headers = curl_slist_append(dav_headers, if_header);
1502
1503         out_buffer.size = 41;
1504         out_data = xmalloc(out_buffer.size + 1);
1505         i = snprintf(out_data, out_buffer.size + 1, "%s\n", sha1_to_hex(sha1));
1506         if (i != out_buffer.size) {
1507                 fprintf(stderr, "Unable to initialize PUT request body\n");
1508                 return 0;
1509         }
1510         out_buffer.posn = 0;
1511         out_buffer.buffer = out_data;
1512
1513         slot = get_active_slot();
1514         curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
1515         curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size);
1516         curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
1517         curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
1518         curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT);
1519         curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
1520         curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);
1521         curl_easy_setopt(slot->curl, CURLOPT_PUT, 1);
1522         curl_easy_setopt(slot->curl, CURLOPT_URL, lock->url);
1523
1524         if (start_active_slot(slot)) {
1525                 run_active_slot(slot);
1526                 free(out_data);
1527                 free(if_header);
1528                 if (slot->curl_result != CURLE_OK) {
1529                         fprintf(stderr,
1530                                 "PUT error: curl result=%d, HTTP code=%ld\n",
1531                                 slot->curl_result, slot->http_code);
1532                         /* We should attempt recovery? */
1533                         return 0;
1534                 }
1535         } else {
1536                 free(out_data);
1537                 free(if_header);
1538                 fprintf(stderr, "Unable to start PUT request\n");
1539                 return 0;
1540         }
1541
1542         return 1;
1543 }
1544
1545 int main(int argc, char **argv)
1546 {
1547         struct active_request_slot *slot;
1548         struct active_request_slot *next_slot;
1549         struct transfer_request *request;
1550         struct transfer_request *next_request;
1551         int nr_refspec = 0;
1552         char **refspec = NULL;
1553         int do_remote_update;
1554         int new_branch;
1555         int force_this;
1556         char *local_ref;
1557         unsigned char local_sha1[20];
1558         struct object *local_object = NULL;
1559         char *remote_ref = NULL;
1560         unsigned char remote_sha1[20];
1561         struct active_lock *remote_lock;
1562         char *remote_path = NULL;
1563         char *low_speed_limit;
1564         char *low_speed_time;
1565         int rc = 0;
1566         int i;
1567
1568         setup_ident();
1569
1570         remote = xmalloc(sizeof(*remote));
1571         remote->url = NULL;
1572         remote->packs = NULL;
1573
1574         argv++;
1575         for (i = 1; i < argc; i++, argv++) {
1576                 char *arg = *argv;
1577
1578                 if (*arg == '-') {
1579                         if (!strcmp(arg, "--complete")) {
1580                                 push_all = 1;
1581                                 continue;
1582                         }
1583                         if (!strcmp(arg, "--force")) {
1584                                 force_all = 1;
1585                                 continue;
1586                         }
1587                         if (!strcmp(arg, "--verbose")) {
1588                                 push_verbosely = 1;
1589                                 continue;
1590                         }
1591                         usage(http_push_usage);
1592                 }
1593                 if (!remote->url) {
1594                         remote->url = arg;
1595                         continue;
1596                 }
1597                 refspec = argv;
1598                 nr_refspec = argc - i;
1599                 break;
1600         }
1601
1602         curl_global_init(CURL_GLOBAL_ALL);
1603
1604 #ifdef USE_CURL_MULTI
1605         {
1606                 char *http_max_requests = getenv("GIT_HTTP_MAX_REQUESTS");
1607                 if (http_max_requests != NULL)
1608                         max_requests = atoi(http_max_requests);
1609         }
1610
1611         curlm = curl_multi_init();
1612         if (curlm == NULL) {
1613                 fprintf(stderr, "Error creating curl multi handle.\n");
1614                 return 1;
1615         }
1616 #endif
1617
1618         if (getenv("GIT_SSL_NO_VERIFY"))
1619                 curl_ssl_verify = 0;
1620
1621         ssl_cert = getenv("GIT_SSL_CERT");
1622 #if LIBCURL_VERSION_NUM >= 0x070902
1623         ssl_key = getenv("GIT_SSL_KEY");
1624 #endif
1625 #if LIBCURL_VERSION_NUM >= 0x070908
1626         ssl_capath = getenv("GIT_SSL_CAPATH");
1627 #endif
1628         ssl_cainfo = getenv("GIT_SSL_CAINFO");
1629
1630         low_speed_limit = getenv("GIT_HTTP_LOW_SPEED_LIMIT");
1631         if (low_speed_limit != NULL)
1632                 curl_low_speed_limit = strtol(low_speed_limit, NULL, 10);
1633         low_speed_time = getenv("GIT_HTTP_LOW_SPEED_TIME");
1634         if (low_speed_time != NULL)
1635                 curl_low_speed_time = strtol(low_speed_time, NULL, 10);
1636
1637         git_config(http_options);
1638
1639         if (curl_ssl_verify == -1)
1640                 curl_ssl_verify = 1;
1641
1642 #ifdef USE_CURL_MULTI
1643         if (max_requests < 1)
1644                 max_requests = DEFAULT_MAX_REQUESTS;
1645 #endif
1646
1647         no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:");
1648         default_headers = curl_slist_append(default_headers, "Range:");
1649         default_headers = curl_slist_append(default_headers, "Destination:");
1650         default_headers = curl_slist_append(default_headers, "If:");
1651         default_headers = curl_slist_append(default_headers,
1652                                             "Pragma: no-cache");
1653
1654 #ifndef NO_CURL_EASY_DUPHANDLE
1655         curl_default = get_curl_handle();
1656 #endif
1657
1658         /* Verify DAV compliance/lock support */
1659         if (check_locking() != 0) {
1660                 fprintf(stderr, "Error: no DAV locking support on remote repo %s\n", remote->url);
1661                 rc = 1;
1662                 goto cleanup;
1663         }
1664
1665         /* Process each refspec */
1666         for (i = 0; i < nr_refspec; i++) {
1667                 char *ep;
1668                 force_this = 0;
1669                 do_remote_update = 0;
1670                 new_branch = 0;
1671                 local_ref = refspec[i];
1672                 if (*local_ref == '+') {
1673                         force_this = 1;
1674                         local_ref++;
1675                 }
1676                 ep = strchr(local_ref, ':');
1677                 if (ep) {
1678                         remote_ref = ep + 1;
1679                         *ep = 0;
1680                 }
1681                 else
1682                         remote_ref = local_ref;
1683
1684                 /* Lock remote branch ref */
1685                 if (remote_path)
1686                         free(remote_path);
1687                 remote_path = xmalloc(strlen(remote_ref) + 12);
1688                 sprintf(remote_path, "refs/heads/%s", remote_ref);
1689                 remote_lock = lock_remote(remote_path, LOCK_TIME);
1690                 if (remote_lock == NULL) {
1691                         fprintf(stderr, "Unable to lock remote branch %s\n",
1692                                 remote_ref);
1693                         rc = 1;
1694                         continue;
1695                 }
1696
1697                 /* Resolve local and remote refs */
1698                 if (fetch_ref(remote_ref, remote_sha1) != 0) {
1699                         fprintf(stderr,
1700                                 "Remote branch %s does not exist on %s\n",
1701                                 remote_ref, remote->url);
1702                         new_branch = 1;
1703                 }
1704                 if (get_sha1(local_ref, local_sha1) != 0) {
1705                         fprintf(stderr, "Error resolving local branch %s\n",
1706                                 local_ref);
1707                         rc = 1;
1708                         goto unlock;
1709                 }
1710         
1711                 /* Find relationship between local and remote */
1712                 local_object = parse_object(local_sha1);
1713                 if (!local_object) {
1714                         fprintf(stderr, "Unable to parse local object %s\n",
1715                                 sha1_to_hex(local_sha1));
1716                         rc = 1;
1717                         goto unlock;
1718                 } else if (new_branch) {
1719                         do_remote_update = 1;
1720                 } else {
1721                         if (!memcmp(local_sha1, remote_sha1, 20)) {
1722                                 fprintf(stderr,
1723                                         "* %s: same as branch '%s' of %s\n",
1724                                         local_ref, remote_ref, remote->url);
1725                         } else if (is_ancestor(remote_sha1,
1726                                                (struct commit *)local_object)) {
1727                                 fprintf(stderr,
1728                                         "Remote %s will fast-forward to local %s\n",
1729                                         remote_ref, local_ref);
1730                                 do_remote_update = 1;
1731                         } else if (force_all || force_this) {
1732                                 fprintf(stderr,
1733                                         "* %s on %s does not fast forward to local branch '%s', overwriting\n",
1734                                         remote_ref, remote->url, local_ref);
1735                                 do_remote_update = 1;
1736                         } else {
1737                                 fprintf(stderr,
1738                                         "* %s on %s does not fast forward to local branch '%s'\n",
1739                                         remote_ref, remote->url, local_ref);
1740                                 rc = 1;
1741                                 goto unlock;
1742                         }
1743                 }
1744
1745                 /* Generate and check list of required objects */
1746                 pushing = 0;
1747                 if (do_remote_update || push_all)
1748                         fetch_indices();
1749                 get_delta(push_all ? NULL : remote_sha1,
1750                           local_object, remote_lock);
1751                 process_waiting_requests();
1752
1753                 /* Push missing objects to remote, this would be a
1754                    convenient time to pack them first if appropriate. */
1755                 pushing = 1;
1756                 process_request_queue();
1757                 process_waiting_requests();
1758
1759                 /* Update the remote branch if all went well */
1760                 if (do_remote_update) {
1761                         if (!aborted && update_remote(local_sha1,
1762                                                       remote_lock)) {
1763                                 fprintf(stderr, "%s remote branch %s\n",
1764                                         new_branch ? "Created" : "Updated",
1765                                         remote_ref);
1766                         } else {
1767                                 fprintf(stderr,
1768                                         "Unable to %s remote branch %s\n",
1769                                         new_branch ? "create" : "update",
1770                                         remote_ref);
1771                                 rc = 1;
1772                                 goto unlock;
1773                         }
1774                 }
1775
1776         unlock:
1777                 unlock_remote(remote_lock);
1778                 free(remote_path);
1779         }
1780
1781  cleanup:
1782         free(remote);
1783
1784         curl_slist_free_all(no_pragma_header);
1785         curl_slist_free_all(default_headers);
1786
1787         slot = active_queue_head;
1788         while (slot != NULL) {
1789                 next_slot = slot->next;
1790                 if (slot->curl != NULL)
1791                         curl_easy_cleanup(slot->curl);
1792                 free(slot);
1793                 slot = next_slot;
1794         }
1795
1796         request = request_queue_head;
1797         while (request != NULL) {
1798                 next_request = request->next;
1799                 release_request(request);
1800                 request = next_request;
1801         }
1802
1803 #ifndef NO_CURL_EASY_DUPHANDLE
1804         curl_easy_cleanup(curl_default);
1805 #endif
1806 #ifdef USE_CURL_MULTI
1807         curl_multi_cleanup(curlm);
1808 #endif
1809         curl_global_cleanup();
1810         return rc;
1811 }