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