blob: 88da5468e77f5a543edb7583e2846f19eb509653 [file] [log] [blame]
Daniel Barkalow6eb7ed52005-04-23 18:47:23 -07001#include "cache.h"
2#include "commit.h"
Daniel Barkalow30ae7642007-09-10 23:02:45 -04003#include "walker.h"
Nick Hengeveld29508e12005-11-18 11:02:58 -08004#include "http.h"
Johannes Schindelin7baa3e82005-10-15 11:10:46 -07005
Jonathan Nieder9cba13c2011-03-16 02:08:34 -05006struct alt_base {
Gerrit Pape2afea3b2007-03-28 09:46:15 +00007 char *base;
Daniel Barkalowb3661562005-09-14 23:26:08 -04008 int got_indices;
9 struct packed_git *packs;
10 struct alt_base *next;
11};
12
Nick Hengevelde388ab72005-11-18 11:03:04 -080013enum object_request_state {
Nick Hengeveld1d389ab2005-10-10 23:22:01 -070014 WAITING,
15 ABORTED,
16 ACTIVE,
Gary V. Vaughan4b055482010-05-14 09:31:35 +000017 COMPLETE
Nick Hengeveld1d389ab2005-10-10 23:22:01 -070018};
Daniel Barkalow6eb7ed52005-04-23 18:47:23 -070019
Jonathan Nieder9cba13c2011-03-16 02:08:34 -050020struct object_request {
Daniel Barkalow30ae7642007-09-10 23:02:45 -040021 struct walker *walker;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -070022 unsigned char sha1[20];
23 struct alt_base *repo;
Nick Hengevelde388ab72005-11-18 11:03:04 -080024 enum object_request_state state;
Tay Ray Chuan5424bc52009-06-06 16:44:02 +080025 struct http_object_request *req;
Nick Hengevelde388ab72005-11-18 11:03:04 -080026 struct object_request *next;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -070027};
28
Nick Hengevelde388ab72005-11-18 11:03:04 -080029struct alternates_request {
Daniel Barkalow30ae7642007-09-10 23:02:45 -040030 struct walker *walker;
Petr Baudis8e29f6a2006-07-27 23:56:22 +020031 const char *base;
Nick Hengeveldacc075a2005-11-12 09:11:32 -080032 char *url;
Mike Hommey028c2972007-12-09 20:30:59 +010033 struct strbuf *buffer;
Nick Hengeveldacc075a2005-11-12 09:11:32 -080034 struct active_request_slot *slot;
35 int http_specific;
36};
37
Daniel Barkalow30ae7642007-09-10 23:02:45 -040038struct walker_data {
39 const char *url;
40 int got_alternates;
41 struct alt_base *alt;
Daniel Barkalow30ae7642007-09-10 23:02:45 -040042};
43
David Rientjes96f1e582006-08-15 10:23:48 -070044static struct object_request *object_queue_head;
Sergey Vlasovbc8f2652005-10-13 10:49:53 -070045
Daniel Barkalow30ae7642007-09-10 23:02:45 -040046static void fetch_alternates(struct walker *walker, const char *base);
Nick Hengeveld1d389ab2005-10-10 23:22:01 -070047
Nick Hengeveld29508e12005-11-18 11:02:58 -080048static void process_object_response(void *callback_data);
Nick Hengeveld1d389ab2005-10-10 23:22:01 -070049
Daniel Barkalow30ae7642007-09-10 23:02:45 -040050static void start_object_request(struct walker *walker,
51 struct object_request *obj_req)
Nick Hengeveld1d389ab2005-10-10 23:22:01 -070052{
Nick Hengeveld1d389ab2005-10-10 23:22:01 -070053 struct active_request_slot *slot;
Tay Ray Chuan5424bc52009-06-06 16:44:02 +080054 struct http_object_request *req;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -070055
Tay Ray Chuan5424bc52009-06-06 16:44:02 +080056 req = new_http_object_request(obj_req->repo->base, obj_req->sha1);
57 if (req == NULL) {
Nick Hengevelde388ab72005-11-18 11:03:04 -080058 obj_req->state = ABORTED;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -070059 return;
60 }
Tay Ray Chuan5424bc52009-06-06 16:44:02 +080061 obj_req->req = req;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -070062
Tay Ray Chuan5424bc52009-06-06 16:44:02 +080063 slot = req->slot;
Nick Hengeveld29508e12005-11-18 11:02:58 -080064 slot->callback_func = process_object_response;
Nick Hengevelde388ab72005-11-18 11:03:04 -080065 slot->callback_data = obj_req;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -070066
Nick Hengevelda7a8d372005-10-10 23:22:01 -070067 /* Try to get the request started, abort the request on error */
Nick Hengevelde388ab72005-11-18 11:03:04 -080068 obj_req->state = ACTIVE;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -070069 if (!start_active_slot(slot)) {
Nick Hengevelde388ab72005-11-18 11:03:04 -080070 obj_req->state = ABORTED;
Tay Ray Chuan5424bc52009-06-06 16:44:02 +080071 release_http_object_request(req);
Nick Hengevelde388ab72005-11-18 11:03:04 -080072 return;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -070073 }
Nick Hengeveld1d389ab2005-10-10 23:22:01 -070074}
75
Nick Hengevelde388ab72005-11-18 11:03:04 -080076static void finish_object_request(struct object_request *obj_req)
Nick Hengeveld1d389ab2005-10-10 23:22:01 -070077{
Tay Ray Chuan5424bc52009-06-06 16:44:02 +080078 if (finish_http_object_request(obj_req->req))
Nick Hengeveld1d389ab2005-10-10 23:22:01 -070079 return;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -070080
Tay Ray Chuan5424bc52009-06-06 16:44:02 +080081 if (obj_req->req->rename == 0)
Daniel Barkalow30ae7642007-09-10 23:02:45 -040082 walker_say(obj_req->walker, "got %s\n", sha1_to_hex(obj_req->sha1));
Nick Hengeveld1d389ab2005-10-10 23:22:01 -070083}
84
Nick Hengeveld29508e12005-11-18 11:02:58 -080085static void process_object_response(void *callback_data)
86{
Nick Hengevelde388ab72005-11-18 11:03:04 -080087 struct object_request *obj_req =
88 (struct object_request *)callback_data;
Daniel Barkalow30ae7642007-09-10 23:02:45 -040089 struct walker *walker = obj_req->walker;
90 struct walker_data *data = walker->data;
91 struct alt_base *alt = data->alt;
Nick Hengeveld29508e12005-11-18 11:02:58 -080092
Tay Ray Chuan5424bc52009-06-06 16:44:02 +080093 process_http_object_request(obj_req->req);
Nick Hengevelde388ab72005-11-18 11:03:04 -080094 obj_req->state = COMPLETE;
Nick Hengeveld29508e12005-11-18 11:02:58 -080095
96 /* Use alternates if necessary */
Tay Ray Chuan5424bc52009-06-06 16:44:02 +080097 if (missing_target(obj_req->req)) {
Daniel Barkalow30ae7642007-09-10 23:02:45 -040098 fetch_alternates(walker, alt->base);
Nick Hengevelde388ab72005-11-18 11:03:04 -080099 if (obj_req->repo->next != NULL) {
100 obj_req->repo =
101 obj_req->repo->next;
Tay Ray Chuan5424bc52009-06-06 16:44:02 +0800102 release_http_object_request(obj_req->req);
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400103 start_object_request(walker, obj_req);
Nick Hengeveld29508e12005-11-18 11:02:58 -0800104 return;
105 }
106 }
107
Nick Hengevelde388ab72005-11-18 11:03:04 -0800108 finish_object_request(obj_req);
Nick Hengeveld29508e12005-11-18 11:02:58 -0800109}
110
Nick Hengevelde388ab72005-11-18 11:03:04 -0800111static void release_object_request(struct object_request *obj_req)
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700112{
Nick Hengevelde388ab72005-11-18 11:03:04 -0800113 struct object_request *entry = object_queue_head;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700114
Tay Ray Chuan5424bc52009-06-06 16:44:02 +0800115 if (obj_req->req !=NULL && obj_req->req->localfile != -1)
116 error("fd leakage in release: %d", obj_req->req->localfile);
Nick Hengevelde388ab72005-11-18 11:03:04 -0800117 if (obj_req == object_queue_head) {
118 object_queue_head = obj_req->next;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700119 } else {
Nick Hengevelde388ab72005-11-18 11:03:04 -0800120 while (entry->next != NULL && entry->next != obj_req)
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700121 entry = entry->next;
Nick Hengevelde388ab72005-11-18 11:03:04 -0800122 if (entry->next == obj_req)
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700123 entry->next = entry->next->next;
124 }
125
Nick Hengevelde388ab72005-11-18 11:03:04 -0800126 free(obj_req);
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700127}
128
Nick Hengevelda7a8d372005-10-10 23:22:01 -0700129#ifdef USE_CURL_MULTI
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400130static int fill_active_slot(struct walker *walker)
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700131{
Daniel Barkalow45c17412007-09-10 23:02:28 -0400132 struct object_request *obj_req;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700133
Daniel Barkalow45c17412007-09-10 23:02:28 -0400134 for (obj_req = object_queue_head; obj_req; obj_req = obj_req->next) {
Nick Hengevelde388ab72005-11-18 11:03:04 -0800135 if (obj_req->state == WAITING) {
136 if (has_sha1_file(obj_req->sha1))
Mark Wooding09db4442006-02-01 11:44:28 +0000137 obj_req->state = COMPLETE;
Daniel Barkalow45c17412007-09-10 23:02:28 -0400138 else {
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400139 start_object_request(walker, obj_req);
Daniel Barkalow45c17412007-09-10 23:02:28 -0400140 return 1;
141 }
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700142 }
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700143 }
Daniel Barkalow45c17412007-09-10 23:02:28 -0400144 return 0;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700145}
Nick Hengevelda7a8d372005-10-10 23:22:01 -0700146#endif
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700147
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400148static void prefetch(struct walker *walker, unsigned char *sha1)
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700149{
Nick Hengevelde388ab72005-11-18 11:03:04 -0800150 struct object_request *newreq;
151 struct object_request *tail;
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400152 struct walker_data *data = walker->data;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700153
154 newreq = xmalloc(sizeof(*newreq));
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400155 newreq->walker = walker;
Shawn Pearcee7024962006-08-23 02:49:00 -0400156 hashcpy(newreq->sha1, sha1);
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400157 newreq->repo = data->alt;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700158 newreq->state = WAITING;
Tay Ray Chuan5424bc52009-06-06 16:44:02 +0800159 newreq->req = NULL;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700160 newreq->next = NULL;
161
Tay Ray Chuane9176742009-06-06 16:43:41 +0800162 http_is_verbose = walker->get_verbosely;
163
Nick Hengevelde388ab72005-11-18 11:03:04 -0800164 if (object_queue_head == NULL) {
165 object_queue_head = newreq;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700166 } else {
Nick Hengevelde388ab72005-11-18 11:03:04 -0800167 tail = object_queue_head;
Tay Ray Chuan4c42aa12009-06-06 16:43:33 +0800168 while (tail->next != NULL)
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700169 tail = tail->next;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700170 tail->next = newreq;
171 }
Nick Hengeveld29508e12005-11-18 11:02:58 -0800172
Nick Hengevelda7a8d372005-10-10 23:22:01 -0700173#ifdef USE_CURL_MULTI
Nick Hengeveld29508e12005-11-18 11:02:58 -0800174 fill_active_slots();
175 step_active_slots();
Nick Hengevelda7a8d372005-10-10 23:22:01 -0700176#endif
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700177}
178
Nick Hengevelde388ab72005-11-18 11:03:04 -0800179static void process_alternates_response(void *callback_data)
Daniel Barkalowb3661562005-09-14 23:26:08 -0400180{
Nick Hengevelde388ab72005-11-18 11:03:04 -0800181 struct alternates_request *alt_req =
182 (struct alternates_request *)callback_data;
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400183 struct walker *walker = alt_req->walker;
184 struct walker_data *cdata = walker->data;
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800185 struct active_request_slot *slot = alt_req->slot;
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400186 struct alt_base *tail = cdata->alt;
Petr Baudis8e29f6a2006-07-27 23:56:22 +0200187 const char *base = alt_req->base;
Dan McGeea04ff3e2011-05-03 23:47:27 +0800188 const char null_byte = '\0';
Daniel Barkalowb3661562005-09-14 23:26:08 -0400189 char *data;
190 int i = 0;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700191
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800192 if (alt_req->http_specific) {
193 if (slot->curl_result != CURLE_OK ||
Mike Hommey028c2972007-12-09 20:30:59 +0100194 !alt_req->buffer->len) {
Junio C Hamanodc1b5ea2005-10-10 23:22:02 -0700195
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800196 /* Try reusing the slot to get non-http alternates */
197 alt_req->http_specific = 0;
198 sprintf(alt_req->url, "%s/objects/info/alternates",
199 base);
200 curl_easy_setopt(slot->curl, CURLOPT_URL,
201 alt_req->url);
202 active_requests++;
203 slot->in_use = 1;
Nick Hengeveldc9826472006-03-15 08:59:52 -0800204 if (slot->finished != NULL)
205 (*slot->finished) = 0;
Mark Woodinga3f583c2006-02-01 11:44:39 +0000206 if (!start_active_slot(slot)) {
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400207 cdata->got_alternates = -1;
Nick Hengeveld29508e12005-11-18 11:02:58 -0800208 slot->in_use = 0;
Nick Hengeveldc9826472006-03-15 08:59:52 -0800209 if (slot->finished != NULL)
210 (*slot->finished) = 1;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700211 }
Mark Woodinga3f583c2006-02-01 11:44:39 +0000212 return;
Daniel Barkalowb3661562005-09-14 23:26:08 -0400213 }
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800214 } else if (slot->curl_result != CURLE_OK) {
Junio C Hamanobe4a0152006-09-16 10:58:20 -0700215 if (!missing_target(slot)) {
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400216 cdata->got_alternates = -1;
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800217 return;
218 }
Daniel Barkalowb3661562005-09-14 23:26:08 -0400219 }
220
Dan McGeea04ff3e2011-05-03 23:47:27 +0800221 fwrite_buffer((char *)&null_byte, 1, 1, alt_req->buffer);
Mike Hommey028c2972007-12-09 20:30:59 +0100222 alt_req->buffer->len--;
223 data = alt_req->buffer->buf;
Daniel Barkalow1b0c1e62005-09-18 14:14:19 -0400224
Mike Hommey028c2972007-12-09 20:30:59 +0100225 while (i < alt_req->buffer->len) {
Daniel Barkalowb3661562005-09-14 23:26:08 -0400226 int posn = i;
Mike Hommey028c2972007-12-09 20:30:59 +0100227 while (posn < alt_req->buffer->len && data[posn] != '\n')
Daniel Barkalowb3661562005-09-14 23:26:08 -0400228 posn++;
229 if (data[posn] == '\n') {
Daniel Barkalow1b0c1e62005-09-18 14:14:19 -0400230 int okay = 0;
231 int serverlen = 0;
232 struct alt_base *newalt;
Daniel Barkalowb3661562005-09-14 23:26:08 -0400233 if (data[i] == '/') {
Tay Ray Chuan4c42aa12009-06-06 16:43:33 +0800234 /*
235 * This counts
Junio C Hamano5df1e0d2006-09-12 23:53:27 -0700236 * http://git.host/pub/scm/linux.git/
237 * -----------here^
238 * so memcpy(dst, base, serverlen) will
239 * copy up to "...git.host".
240 */
241 const char *colon_ss = strstr(base,"://");
242 if (colon_ss) {
243 serverlen = (strchr(colon_ss + 3, '/')
244 - base);
245 okay = 1;
246 }
Daniel Barkalow1b0c1e62005-09-18 14:14:19 -0400247 } else if (!memcmp(data + i, "../", 3)) {
Tay Ray Chuan4c42aa12009-06-06 16:43:33 +0800248 /*
249 * Relative URL; chop the corresponding
Junio C Hamano5df1e0d2006-09-12 23:53:27 -0700250 * number of subpath from base (and ../
251 * from data), and concatenate the result.
252 *
253 * The code first drops ../ from data, and
254 * then drops one ../ from data and one path
255 * from base. IOW, one extra ../ is dropped
256 * from data than path is dropped from base.
257 *
258 * This is not wrong. The alternate in
259 * http://git.host/pub/scm/linux.git/
260 * to borrow from
261 * http://git.host/pub/scm/linus.git/
262 * is ../../linus.git/objects/. You need
263 * two ../../ to borrow from your direct
264 * neighbour.
265 */
Daniel Barkalow1b0c1e62005-09-18 14:14:19 -0400266 i += 3;
267 serverlen = strlen(base);
Junio C Hamano8fcf7f92006-01-31 18:15:51 -0800268 while (i + 2 < posn &&
Daniel Barkalow1b0c1e62005-09-18 14:14:19 -0400269 !memcmp(data + i, "../", 3)) {
270 do {
271 serverlen--;
272 } while (serverlen &&
273 base[serverlen - 1] != '/');
274 i += 3;
275 }
Pavel Roskina9486b02006-07-10 02:57:51 -0400276 /* If the server got removed, give up. */
Junio C Hamano8fcf7f92006-01-31 18:15:51 -0800277 okay = strchr(base, ':') - base + 3 <
Tay Ray Chuan4c42aa12009-06-06 16:43:33 +0800278 serverlen;
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800279 } else if (alt_req->http_specific) {
Daniel Barkalow1b0c1e62005-09-18 14:14:19 -0400280 char *colon = strchr(data + i, ':');
281 char *slash = strchr(data + i, '/');
282 if (colon && slash && colon < data + posn &&
283 slash < data + posn && colon < slash) {
284 okay = 1;
285 }
286 }
Junio C Hamano5df1e0d2006-09-12 23:53:27 -0700287 /* skip "objects\n" at end */
Daniel Barkalow1b0c1e62005-09-18 14:14:19 -0400288 if (okay) {
René Scharfe59b82632014-08-30 17:55:45 +0200289 struct strbuf target = STRBUF_INIT;
290 strbuf_add(&target, base, serverlen);
291 strbuf_add(&target, data + i, posn - i - 7);
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400292 if (walker->get_verbosely)
René Scharfe59b82632014-08-30 17:55:45 +0200293 fprintf(stderr, "Also look at %s\n",
294 target.buf);
Daniel Barkalowb3661562005-09-14 23:26:08 -0400295 newalt = xmalloc(sizeof(*newalt));
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700296 newalt->next = NULL;
René Scharfe59b82632014-08-30 17:55:45 +0200297 newalt->base = strbuf_detach(&target, NULL);
Daniel Barkalowb3661562005-09-14 23:26:08 -0400298 newalt->got_indices = 0;
299 newalt->packs = NULL;
Nick Hengeveld8d9fbe52006-04-04 05:33:18 -0700300
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700301 while (tail->next != NULL)
302 tail = tail->next;
303 tail->next = newalt;
Daniel Barkalowb3661562005-09-14 23:26:08 -0400304 }
305 }
306 i = posn + 1;
307 }
Sergey Vlasovbc8f2652005-10-13 10:49:53 -0700308
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400309 cdata->got_alternates = 1;
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800310}
311
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400312static void fetch_alternates(struct walker *walker, const char *base)
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800313{
Mike Hommey028c2972007-12-09 20:30:59 +0100314 struct strbuf buffer = STRBUF_INIT;
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800315 char *url;
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800316 struct active_request_slot *slot;
Nick Hengeveldcb754fd2006-01-31 18:00:37 -0800317 struct alternates_request alt_req;
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400318 struct walker_data *cdata = walker->data;
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800319
Tay Ray Chuan4c42aa12009-06-06 16:43:33 +0800320 /*
321 * If another request has already started fetching alternates,
322 * wait for them to arrive and return to processing this request's
323 * curl message
324 */
Nick Hengeveld29508e12005-11-18 11:02:58 -0800325#ifdef USE_CURL_MULTI
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400326 while (cdata->got_alternates == 0) {
Nick Hengeveld29508e12005-11-18 11:02:58 -0800327 step_active_slots();
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800328 }
Nick Hengeveld29508e12005-11-18 11:02:58 -0800329#endif
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800330
331 /* Nothing to do if they've already been fetched */
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400332 if (cdata->got_alternates == 1)
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800333 return;
334
335 /* Start the fetch */
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400336 cdata->got_alternates = 0;
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800337
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400338 if (walker->get_verbosely)
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800339 fprintf(stderr, "Getting alternates list for %s\n", base);
Junio C Hamano8fcf7f92006-01-31 18:15:51 -0800340
Jeff King28310182014-06-19 17:24:33 -0400341 url = xstrfmt("%s/objects/info/http-alternates", base);
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800342
Tay Ray Chuan4c42aa12009-06-06 16:43:33 +0800343 /*
344 * Use a callback to process the result, since another request
345 * may fail and need to have alternates loaded before continuing
346 */
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800347 slot = get_active_slot();
Nick Hengevelde388ab72005-11-18 11:03:04 -0800348 slot->callback_func = process_alternates_response;
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400349 alt_req.walker = walker;
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800350 slot->callback_data = &alt_req;
351
352 curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
Nick Hengeveld29508e12005-11-18 11:02:58 -0800353 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800354 curl_easy_setopt(slot->curl, CURLOPT_URL, url);
355
356 alt_req.base = base;
357 alt_req.url = url;
358 alt_req.buffer = &buffer;
359 alt_req.http_specific = 1;
360 alt_req.slot = slot;
361
362 if (start_active_slot(slot))
363 run_active_slot(slot);
364 else
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400365 cdata->got_alternates = -1;
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800366
Mike Hommey028c2972007-12-09 20:30:59 +0100367 strbuf_release(&buffer);
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800368 free(url);
Daniel Barkalowb3661562005-09-14 23:26:08 -0400369}
370
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400371static int fetch_indices(struct walker *walker, struct alt_base *repo)
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400372{
Tay Ray Chuanb8caac22009-06-06 16:43:59 +0800373 int ret;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700374
Daniel Barkalowb3661562005-09-14 23:26:08 -0400375 if (repo->got_indices)
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400376 return 0;
377
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400378 if (walker->get_verbosely)
Petr Baudis6fd72e32005-11-12 01:49:59 +0100379 fprintf(stderr, "Getting pack list for %s\n", repo->base);
Junio C Hamano8fcf7f92006-01-31 18:15:51 -0800380
Tay Ray Chuanb8caac22009-06-06 16:43:59 +0800381 switch (http_get_info_packs(repo->base, &repo->packs)) {
382 case HTTP_OK:
383 case HTTP_MISSING_TARGET:
384 repo->got_indices = 1;
385 ret = 0;
386 break;
387 default:
Nick Hengeveld5e3a7692005-11-18 11:03:11 -0800388 repo->got_indices = 0;
Tay Ray Chuanb8caac22009-06-06 16:43:59 +0800389 ret = -1;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700390 }
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400391
Mike Hommey3a462bc2007-12-10 22:36:11 +0100392 return ret;
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400393}
394
Michael Haggerty07c19e72012-09-09 08:19:38 +0200395static int http_fetch_pack(struct walker *walker, struct alt_base *repo, unsigned char *sha1)
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400396{
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400397 struct packed_git *target;
Nick Hengeveld49a0f242005-09-28 10:14:04 -0700398 int ret;
Nick Hengeveldcb754fd2006-01-31 18:00:37 -0800399 struct slot_results results;
Tay Ray Chuan2264dfa2009-06-06 16:44:01 +0800400 struct http_pack_request *preq;
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400401
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400402 if (fetch_indices(walker, repo))
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400403 return -1;
Daniel Barkalowb3661562005-09-14 23:26:08 -0400404 target = find_sha1_pack(sha1, repo->packs);
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400405 if (!target)
Daniel Barkalowb3661562005-09-14 23:26:08 -0400406 return -1;
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400407
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400408 if (walker->get_verbosely) {
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400409 fprintf(stderr, "Getting pack %s\n",
410 sha1_to_hex(target->sha1));
411 fprintf(stderr, " which contains %s\n",
412 sha1_to_hex(sha1));
413 }
414
Tay Ray Chuan2264dfa2009-06-06 16:44:01 +0800415 preq = new_http_pack_request(target, repo->base);
416 if (preq == NULL)
417 goto abort;
418 preq->lst = &repo->packs;
419 preq->slot->results = &results;
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400420
Tay Ray Chuan2264dfa2009-06-06 16:44:01 +0800421 if (start_active_slot(preq->slot)) {
422 run_active_slot(preq->slot);
Nick Hengeveldc8568e12006-01-31 11:06:55 -0800423 if (results.curl_result != CURLE_OK) {
Tay Ray Chuan2264dfa2009-06-06 16:44:01 +0800424 error("Unable to get pack file %s\n%s", preq->url,
425 curl_errorstr);
426 goto abort;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700427 }
428 } else {
Tay Ray Chuan2264dfa2009-06-06 16:44:01 +0800429 error("Unable to start request");
430 goto abort;
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400431 }
432
Tay Ray Chuan2264dfa2009-06-06 16:44:01 +0800433 ret = finish_http_pack_request(preq);
434 release_http_pack_request(preq);
Nick Hengeveld49a0f242005-09-28 10:14:04 -0700435 if (ret)
Junio C Hamanob721e012005-10-10 23:22:01 -0700436 return ret;
Nick Hengeveld49a0f242005-09-28 10:14:04 -0700437
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400438 return 0;
Tay Ray Chuan2264dfa2009-06-06 16:44:01 +0800439
440abort:
441 return -1;
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400442}
443
Mark Wooding53f31382006-02-07 10:07:39 +0000444static void abort_object_request(struct object_request *obj_req)
445{
Mark Wooding53f31382006-02-07 10:07:39 +0000446 release_object_request(obj_req);
447}
448
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400449static int fetch_object(struct walker *walker, struct alt_base *repo, unsigned char *sha1)
Daniel Barkalow6eb7ed52005-04-23 18:47:23 -0700450{
451 char *hex = sha1_to_hex(sha1);
Nick Hengeveld29508e12005-11-18 11:02:58 -0800452 int ret = 0;
Nick Hengevelde388ab72005-11-18 11:03:04 -0800453 struct object_request *obj_req = object_queue_head;
Tay Ray Chuan5424bc52009-06-06 16:44:02 +0800454 struct http_object_request *req;
Daniel Barkalow6eb7ed52005-04-23 18:47:23 -0700455
David Rientjesa89fccd2006-08-17 11:54:57 -0700456 while (obj_req != NULL && hashcmp(obj_req->sha1, sha1))
Nick Hengevelde388ab72005-11-18 11:03:04 -0800457 obj_req = obj_req->next;
458 if (obj_req == NULL)
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700459 return error("Couldn't find request for %s in the queue", hex);
Junio C Hamano271421c2005-09-30 00:07:39 -0700460
Nick Hengevelde388ab72005-11-18 11:03:04 -0800461 if (has_sha1_file(obj_req->sha1)) {
Tay Ray Chuan5424bc52009-06-06 16:44:02 +0800462 if (obj_req->req != NULL)
463 abort_http_object_request(obj_req->req);
Mark Wooding53f31382006-02-07 10:07:39 +0000464 abort_object_request(obj_req);
Nick Hengeveld11f0daf2005-10-10 23:22:01 -0700465 return 0;
466 }
467
Nick Hengevelda7a8d372005-10-10 23:22:01 -0700468#ifdef USE_CURL_MULTI
Tay Ray Chuan4c42aa12009-06-06 16:43:33 +0800469 while (obj_req->state == WAITING)
Nick Hengeveld29508e12005-11-18 11:02:58 -0800470 step_active_slots();
Nick Hengevelda7a8d372005-10-10 23:22:01 -0700471#else
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400472 start_object_request(walker, obj_req);
Nick Hengevelda7a8d372005-10-10 23:22:01 -0700473#endif
Nick Hengeveld49a0f242005-09-28 10:14:04 -0700474
Tay Ray Chuan5424bc52009-06-06 16:44:02 +0800475 /*
476 * obj_req->req might change when fetching alternates in the callback
477 * process_object_response; therefore, the "shortcut" variable, req,
478 * is used only after we're done with slots.
479 */
Tay Ray Chuan4c42aa12009-06-06 16:43:33 +0800480 while (obj_req->state == ACTIVE)
Tay Ray Chuan5424bc52009-06-06 16:44:02 +0800481 run_active_slot(obj_req->req->slot);
Tay Ray Chuan4c42aa12009-06-06 16:43:33 +0800482
Tay Ray Chuan5424bc52009-06-06 16:44:02 +0800483 req = obj_req->req;
484
485 if (req->localfile != -1) {
486 close(req->localfile);
487 req->localfile = -1;
Petr Baudis313c4712005-11-12 00:55:16 +0100488 }
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700489
Nick Hengevelde388ab72005-11-18 11:03:04 -0800490 if (obj_req->state == ABORTED) {
Nick Hengeveld29508e12005-11-18 11:02:58 -0800491 ret = error("Request for %s aborted", hex);
Tay Ray Chuan5424bc52009-06-06 16:44:02 +0800492 } else if (req->curl_result != CURLE_OK &&
493 req->http_code != 416) {
494 if (missing_target(req))
Petr Baudise2029eb2005-10-21 18:18:46 +0200495 ret = -1; /* Be silent, it is probably in a pack. */
496 else
497 ret = error("%s (curl_result = %d, http_code = %ld, sha1 = %s)",
Tay Ray Chuan5424bc52009-06-06 16:44:02 +0800498 req->errorstr, req->curl_result,
499 req->http_code, hex);
500 } else if (req->zret != Z_STREAM_END) {
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400501 walker->corrupt_object_found++;
Tay Ray Chuan5424bc52009-06-06 16:44:02 +0800502 ret = error("File %s (%s) corrupt", hex, req->url);
503 } else if (hashcmp(obj_req->sha1, req->real_sha1)) {
Junio C Hamanobd2afde2006-02-22 17:47:10 -0800504 ret = error("File %s has bad hash", hex);
Tay Ray Chuan5424bc52009-06-06 16:44:02 +0800505 } else if (req->rename < 0) {
Mark Wooding7b934ec2006-02-01 11:44:35 +0000506 ret = error("unable to write sha1 filename %s",
Shawn O. Pearce0da8b2e2010-04-17 13:07:38 -0700507 sha1_file_name(req->sha1));
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700508 }
509
Tay Ray Chuan5424bc52009-06-06 16:44:02 +0800510 release_http_object_request(req);
Nick Hengevelde388ab72005-11-18 11:03:04 -0800511 release_object_request(obj_req);
Nick Hengeveld29508e12005-11-18 11:02:58 -0800512 return ret;
Daniel Barkalow6eb7ed52005-04-23 18:47:23 -0700513}
514
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400515static int fetch(struct walker *walker, unsigned char *sha1)
Daniel Barkalowb3661562005-09-14 23:26:08 -0400516{
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400517 struct walker_data *data = walker->data;
518 struct alt_base *altbase = data->alt;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700519
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400520 if (!fetch_object(walker, altbase, sha1))
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700521 return 0;
Daniel Barkalowb3661562005-09-14 23:26:08 -0400522 while (altbase) {
Michael Haggerty07c19e72012-09-09 08:19:38 +0200523 if (!http_fetch_pack(walker, altbase, sha1))
Daniel Barkalowb3661562005-09-14 23:26:08 -0400524 return 0;
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400525 fetch_alternates(walker, data->alt->base);
Daniel Barkalowb3661562005-09-14 23:26:08 -0400526 altbase = altbase->next;
527 }
Junio C Hamanobd2afde2006-02-22 17:47:10 -0800528 return error("Unable to find %s under %s", sha1_to_hex(sha1),
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400529 data->alt->base);
Daniel Barkalowb3661562005-09-14 23:26:08 -0400530}
531
Daniel Barkalowc13b2632008-04-26 15:53:09 -0400532static int fetch_ref(struct walker *walker, struct ref *ref)
Daniel Barkalowcd541a62005-06-06 16:38:26 -0400533{
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400534 struct walker_data *data = walker->data;
Daniel Barkalowc13b2632008-04-26 15:53:09 -0400535 return http_fetch_ref(data->alt->base, ref);
Daniel Barkalowcd541a62005-06-06 16:38:26 -0400536}
537
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400538static void cleanup(struct walker *walker)
Daniel Barkalow6eb7ed52005-04-23 18:47:23 -0700539{
Tay Ray Chuan09ae9ac2010-03-02 18:49:28 +0800540 struct walker_data *data = walker->data;
541 struct alt_base *alt, *alt_next;
542
543 if (data) {
544 alt = data->alt;
545 while (alt) {
546 alt_next = alt->next;
547
548 free(alt->base);
549 free(alt);
550
551 alt = alt_next;
552 }
553 free(data);
554 walker->data = NULL;
555 }
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400556}
557
Tay Ray Chuan888692b2010-03-02 18:49:29 +0800558struct walker *get_http_walker(const char *url)
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400559{
Gerrit Pape9c880b32007-03-28 09:47:35 +0000560 char *s;
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400561 struct walker_data *data = xmalloc(sizeof(struct walker_data));
562 struct walker *walker = xmalloc(sizeof(struct walker));
Daniel Barkalow6eb7ed52005-04-23 18:47:23 -0700563
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400564 data->alt = xmalloc(sizeof(*data->alt));
Jeff King95244ae2014-06-19 17:19:43 -0400565 data->alt->base = xstrdup(url);
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400566 for (s = data->alt->base + strlen(data->alt->base) - 1; *s == '/'; --s)
Gerrit Pape9c880b32007-03-28 09:47:35 +0000567 *s = 0;
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400568
569 data->alt->got_indices = 0;
570 data->alt->packs = NULL;
571 data->alt->next = NULL;
572 data->got_alternates = -1;
573
574 walker->corrupt_object_found = 0;
575 walker->fetch = fetch;
576 walker->fetch_ref = fetch_ref;
577 walker->prefetch = prefetch;
578 walker->cleanup = cleanup;
579 walker->data = data;
Daniel Barkalow6eb7ed52005-04-23 18:47:23 -0700580
Daniel Barkalowfc57b6a2007-09-10 23:02:34 -0400581#ifdef USE_CURL_MULTI
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400582 add_fill_function(walker, (int (*)(void *)) fill_active_slot);
Daniel Barkalowfc57b6a2007-09-10 23:02:34 -0400583#endif
584
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400585 return walker;
Daniel Barkalow6eb7ed52005-04-23 18:47:23 -0700586}