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