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