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