blob: 2c721f0c30d786e043dec819dc421788311c7e4b [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;
Jeff King54ba4c52015-09-24 17:07:31 -040032 struct strbuf *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;
Jeff King54ba4c52015-09-24 17:07:31 -0400198 strbuf_reset(alt_req->url);
199 strbuf_addf(alt_req->url, "%s/objects/info/alternates",
200 base);
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800201 curl_easy_setopt(slot->curl, CURLOPT_URL,
Jeff King54ba4c52015-09-24 17:07:31 -0400202 alt_req->url->buf);
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800203 active_requests++;
204 slot->in_use = 1;
Nick Hengeveldc9826472006-03-15 08:59:52 -0800205 if (slot->finished != NULL)
206 (*slot->finished) = 0;
Mark Woodinga3f583c2006-02-01 11:44:39 +0000207 if (!start_active_slot(slot)) {
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400208 cdata->got_alternates = -1;
Nick Hengeveld29508e12005-11-18 11:02:58 -0800209 slot->in_use = 0;
Nick Hengeveldc9826472006-03-15 08:59:52 -0800210 if (slot->finished != NULL)
211 (*slot->finished) = 1;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700212 }
Mark Woodinga3f583c2006-02-01 11:44:39 +0000213 return;
Daniel Barkalowb3661562005-09-14 23:26:08 -0400214 }
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800215 } else if (slot->curl_result != CURLE_OK) {
Junio C Hamanobe4a0152006-09-16 10:58:20 -0700216 if (!missing_target(slot)) {
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400217 cdata->got_alternates = -1;
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800218 return;
219 }
Daniel Barkalowb3661562005-09-14 23:26:08 -0400220 }
221
Dan McGeea04ff3e2011-05-03 23:47:27 +0800222 fwrite_buffer((char *)&null_byte, 1, 1, alt_req->buffer);
Mike Hommey028c2972007-12-09 20:30:59 +0100223 alt_req->buffer->len--;
224 data = alt_req->buffer->buf;
Daniel Barkalow1b0c1e62005-09-18 14:14:19 -0400225
Mike Hommey028c2972007-12-09 20:30:59 +0100226 while (i < alt_req->buffer->len) {
Daniel Barkalowb3661562005-09-14 23:26:08 -0400227 int posn = i;
Mike Hommey028c2972007-12-09 20:30:59 +0100228 while (posn < alt_req->buffer->len && data[posn] != '\n')
Daniel Barkalowb3661562005-09-14 23:26:08 -0400229 posn++;
230 if (data[posn] == '\n') {
Daniel Barkalow1b0c1e62005-09-18 14:14:19 -0400231 int okay = 0;
232 int serverlen = 0;
233 struct alt_base *newalt;
Daniel Barkalowb3661562005-09-14 23:26:08 -0400234 if (data[i] == '/') {
Tay Ray Chuan4c42aa12009-06-06 16:43:33 +0800235 /*
236 * This counts
Junio C Hamano5df1e0d2006-09-12 23:53:27 -0700237 * http://git.host/pub/scm/linux.git/
238 * -----------here^
239 * so memcpy(dst, base, serverlen) will
240 * copy up to "...git.host".
241 */
242 const char *colon_ss = strstr(base,"://");
243 if (colon_ss) {
244 serverlen = (strchr(colon_ss + 3, '/')
245 - base);
246 okay = 1;
247 }
Daniel Barkalow1b0c1e62005-09-18 14:14:19 -0400248 } else if (!memcmp(data + i, "../", 3)) {
Tay Ray Chuan4c42aa12009-06-06 16:43:33 +0800249 /*
250 * Relative URL; chop the corresponding
Junio C Hamano5df1e0d2006-09-12 23:53:27 -0700251 * number of subpath from base (and ../
252 * from data), and concatenate the result.
253 *
254 * The code first drops ../ from data, and
255 * then drops one ../ from data and one path
256 * from base. IOW, one extra ../ is dropped
257 * from data than path is dropped from base.
258 *
259 * This is not wrong. The alternate in
260 * http://git.host/pub/scm/linux.git/
261 * to borrow from
262 * http://git.host/pub/scm/linus.git/
263 * is ../../linus.git/objects/. You need
264 * two ../../ to borrow from your direct
265 * neighbour.
266 */
Daniel Barkalow1b0c1e62005-09-18 14:14:19 -0400267 i += 3;
268 serverlen = strlen(base);
Junio C Hamano8fcf7f92006-01-31 18:15:51 -0800269 while (i + 2 < posn &&
Daniel Barkalow1b0c1e62005-09-18 14:14:19 -0400270 !memcmp(data + i, "../", 3)) {
271 do {
272 serverlen--;
273 } while (serverlen &&
274 base[serverlen - 1] != '/');
275 i += 3;
276 }
Pavel Roskina9486b02006-07-10 02:57:51 -0400277 /* If the server got removed, give up. */
Junio C Hamano8fcf7f92006-01-31 18:15:51 -0800278 okay = strchr(base, ':') - base + 3 <
Tay Ray Chuan4c42aa12009-06-06 16:43:33 +0800279 serverlen;
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800280 } else if (alt_req->http_specific) {
Daniel Barkalow1b0c1e62005-09-18 14:14:19 -0400281 char *colon = strchr(data + i, ':');
282 char *slash = strchr(data + i, '/');
283 if (colon && slash && colon < data + posn &&
284 slash < data + posn && colon < slash) {
285 okay = 1;
286 }
287 }
Junio C Hamano5df1e0d2006-09-12 23:53:27 -0700288 /* skip "objects\n" at end */
Daniel Barkalow1b0c1e62005-09-18 14:14:19 -0400289 if (okay) {
René Scharfe59b82632014-08-30 17:55:45 +0200290 struct strbuf target = STRBUF_INIT;
291 strbuf_add(&target, base, serverlen);
292 strbuf_add(&target, data + i, posn - i - 7);
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400293 if (walker->get_verbosely)
René Scharfe59b82632014-08-30 17:55:45 +0200294 fprintf(stderr, "Also look at %s\n",
295 target.buf);
Daniel Barkalowb3661562005-09-14 23:26:08 -0400296 newalt = xmalloc(sizeof(*newalt));
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700297 newalt->next = NULL;
René Scharfe59b82632014-08-30 17:55:45 +0200298 newalt->base = strbuf_detach(&target, NULL);
Daniel Barkalowb3661562005-09-14 23:26:08 -0400299 newalt->got_indices = 0;
300 newalt->packs = NULL;
Nick Hengeveld8d9fbe52006-04-04 05:33:18 -0700301
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700302 while (tail->next != NULL)
303 tail = tail->next;
304 tail->next = newalt;
Daniel Barkalowb3661562005-09-14 23:26:08 -0400305 }
306 }
307 i = posn + 1;
308 }
Sergey Vlasovbc8f2652005-10-13 10:49:53 -0700309
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400310 cdata->got_alternates = 1;
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800311}
312
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400313static void fetch_alternates(struct walker *walker, const char *base)
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800314{
Mike Hommey028c2972007-12-09 20:30:59 +0100315 struct strbuf buffer = STRBUF_INIT;
Jeff King54ba4c52015-09-24 17:07:31 -0400316 struct strbuf url = STRBUF_INIT;
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800317 struct active_request_slot *slot;
Nick Hengeveldcb754fd2006-01-31 18:00:37 -0800318 struct alternates_request alt_req;
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400319 struct walker_data *cdata = walker->data;
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800320
Tay Ray Chuan4c42aa12009-06-06 16:43:33 +0800321 /*
322 * If another request has already started fetching alternates,
323 * wait for them to arrive and return to processing this request's
324 * curl message
325 */
Nick Hengeveld29508e12005-11-18 11:02:58 -0800326#ifdef USE_CURL_MULTI
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400327 while (cdata->got_alternates == 0) {
Nick Hengeveld29508e12005-11-18 11:02:58 -0800328 step_active_slots();
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800329 }
Nick Hengeveld29508e12005-11-18 11:02:58 -0800330#endif
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800331
332 /* Nothing to do if they've already been fetched */
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400333 if (cdata->got_alternates == 1)
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800334 return;
335
336 /* Start the fetch */
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400337 cdata->got_alternates = 0;
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800338
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400339 if (walker->get_verbosely)
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800340 fprintf(stderr, "Getting alternates list for %s\n", base);
Junio C Hamano8fcf7f92006-01-31 18:15:51 -0800341
Jeff King54ba4c52015-09-24 17:07:31 -0400342 strbuf_addf(&url, "%s/objects/info/http-alternates", base);
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800343
Tay Ray Chuan4c42aa12009-06-06 16:43:33 +0800344 /*
345 * Use a callback to process the result, since another request
346 * may fail and need to have alternates loaded before continuing
347 */
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800348 slot = get_active_slot();
Nick Hengevelde388ab72005-11-18 11:03:04 -0800349 slot->callback_func = process_alternates_response;
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400350 alt_req.walker = walker;
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800351 slot->callback_data = &alt_req;
352
353 curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
Nick Hengeveld29508e12005-11-18 11:02:58 -0800354 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
Jeff King54ba4c52015-09-24 17:07:31 -0400355 curl_easy_setopt(slot->curl, CURLOPT_URL, url.buf);
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800356
357 alt_req.base = base;
Jeff King54ba4c52015-09-24 17:07:31 -0400358 alt_req.url = &url;
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800359 alt_req.buffer = &buffer;
360 alt_req.http_specific = 1;
361 alt_req.slot = slot;
362
363 if (start_active_slot(slot))
364 run_active_slot(slot);
365 else
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400366 cdata->got_alternates = -1;
Nick Hengeveldacc075a2005-11-12 09:11:32 -0800367
Mike Hommey028c2972007-12-09 20:30:59 +0100368 strbuf_release(&buffer);
Jeff King54ba4c52015-09-24 17:07:31 -0400369 strbuf_release(&url);
Daniel Barkalowb3661562005-09-14 23:26:08 -0400370}
371
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400372static int fetch_indices(struct walker *walker, struct alt_base *repo)
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400373{
Tay Ray Chuanb8caac22009-06-06 16:43:59 +0800374 int ret;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700375
Daniel Barkalowb3661562005-09-14 23:26:08 -0400376 if (repo->got_indices)
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400377 return 0;
378
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400379 if (walker->get_verbosely)
Petr Baudis6fd72e32005-11-12 01:49:59 +0100380 fprintf(stderr, "Getting pack list for %s\n", repo->base);
Junio C Hamano8fcf7f92006-01-31 18:15:51 -0800381
Tay Ray Chuanb8caac22009-06-06 16:43:59 +0800382 switch (http_get_info_packs(repo->base, &repo->packs)) {
383 case HTTP_OK:
384 case HTTP_MISSING_TARGET:
385 repo->got_indices = 1;
386 ret = 0;
387 break;
388 default:
Nick Hengeveld5e3a7692005-11-18 11:03:11 -0800389 repo->got_indices = 0;
Tay Ray Chuanb8caac22009-06-06 16:43:59 +0800390 ret = -1;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700391 }
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400392
Mike Hommey3a462bc2007-12-10 22:36:11 +0100393 return ret;
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400394}
395
Michael Haggerty07c19e72012-09-09 08:19:38 +0200396static int http_fetch_pack(struct walker *walker, struct alt_base *repo, unsigned char *sha1)
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400397{
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400398 struct packed_git *target;
Nick Hengeveld49a0f242005-09-28 10:14:04 -0700399 int ret;
Nick Hengeveldcb754fd2006-01-31 18:00:37 -0800400 struct slot_results results;
Tay Ray Chuan2264dfa2009-06-06 16:44:01 +0800401 struct http_pack_request *preq;
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400402
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400403 if (fetch_indices(walker, repo))
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400404 return -1;
Daniel Barkalowb3661562005-09-14 23:26:08 -0400405 target = find_sha1_pack(sha1, repo->packs);
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400406 if (!target)
Daniel Barkalowb3661562005-09-14 23:26:08 -0400407 return -1;
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400408
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400409 if (walker->get_verbosely) {
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400410 fprintf(stderr, "Getting pack %s\n",
411 sha1_to_hex(target->sha1));
412 fprintf(stderr, " which contains %s\n",
413 sha1_to_hex(sha1));
414 }
415
Tay Ray Chuan2264dfa2009-06-06 16:44:01 +0800416 preq = new_http_pack_request(target, repo->base);
417 if (preq == NULL)
418 goto abort;
419 preq->lst = &repo->packs;
420 preq->slot->results = &results;
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400421
Tay Ray Chuan2264dfa2009-06-06 16:44:01 +0800422 if (start_active_slot(preq->slot)) {
423 run_active_slot(preq->slot);
Nick Hengeveldc8568e12006-01-31 11:06:55 -0800424 if (results.curl_result != CURLE_OK) {
Tay Ray Chuan2264dfa2009-06-06 16:44:01 +0800425 error("Unable to get pack file %s\n%s", preq->url,
426 curl_errorstr);
427 goto abort;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700428 }
429 } else {
Tay Ray Chuan2264dfa2009-06-06 16:44:01 +0800430 error("Unable to start request");
431 goto abort;
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400432 }
433
Tay Ray Chuan2264dfa2009-06-06 16:44:01 +0800434 ret = finish_http_pack_request(preq);
435 release_http_pack_request(preq);
Nick Hengeveld49a0f242005-09-28 10:14:04 -0700436 if (ret)
Junio C Hamanob721e012005-10-10 23:22:01 -0700437 return ret;
Nick Hengeveld49a0f242005-09-28 10:14:04 -0700438
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400439 return 0;
Tay Ray Chuan2264dfa2009-06-06 16:44:01 +0800440
441abort:
442 return -1;
barkalow@iabervon.org182005b2005-07-31 20:54:17 -0400443}
444
Mark Wooding53f31382006-02-07 10:07:39 +0000445static void abort_object_request(struct object_request *obj_req)
446{
Mark Wooding53f31382006-02-07 10:07:39 +0000447 release_object_request(obj_req);
448}
449
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400450static int fetch_object(struct walker *walker, struct alt_base *repo, unsigned char *sha1)
Daniel Barkalow6eb7ed52005-04-23 18:47:23 -0700451{
452 char *hex = sha1_to_hex(sha1);
Nick Hengeveld29508e12005-11-18 11:02:58 -0800453 int ret = 0;
Nick Hengevelde388ab72005-11-18 11:03:04 -0800454 struct object_request *obj_req = object_queue_head;
Tay Ray Chuan5424bc52009-06-06 16:44:02 +0800455 struct http_object_request *req;
Daniel Barkalow6eb7ed52005-04-23 18:47:23 -0700456
David Rientjesa89fccd2006-08-17 11:54:57 -0700457 while (obj_req != NULL && hashcmp(obj_req->sha1, sha1))
Nick Hengevelde388ab72005-11-18 11:03:04 -0800458 obj_req = obj_req->next;
459 if (obj_req == NULL)
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700460 return error("Couldn't find request for %s in the queue", hex);
Junio C Hamano271421c2005-09-30 00:07:39 -0700461
Nick Hengevelde388ab72005-11-18 11:03:04 -0800462 if (has_sha1_file(obj_req->sha1)) {
Tay Ray Chuan5424bc52009-06-06 16:44:02 +0800463 if (obj_req->req != NULL)
464 abort_http_object_request(obj_req->req);
Mark Wooding53f31382006-02-07 10:07:39 +0000465 abort_object_request(obj_req);
Nick Hengeveld11f0daf2005-10-10 23:22:01 -0700466 return 0;
467 }
468
Nick Hengevelda7a8d372005-10-10 23:22:01 -0700469#ifdef USE_CURL_MULTI
Tay Ray Chuan4c42aa12009-06-06 16:43:33 +0800470 while (obj_req->state == WAITING)
Nick Hengeveld29508e12005-11-18 11:02:58 -0800471 step_active_slots();
Nick Hengevelda7a8d372005-10-10 23:22:01 -0700472#else
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400473 start_object_request(walker, obj_req);
Nick Hengevelda7a8d372005-10-10 23:22:01 -0700474#endif
Nick Hengeveld49a0f242005-09-28 10:14:04 -0700475
Tay Ray Chuan5424bc52009-06-06 16:44:02 +0800476 /*
477 * obj_req->req might change when fetching alternates in the callback
478 * process_object_response; therefore, the "shortcut" variable, req,
479 * is used only after we're done with slots.
480 */
Tay Ray Chuan4c42aa12009-06-06 16:43:33 +0800481 while (obj_req->state == ACTIVE)
Tay Ray Chuan5424bc52009-06-06 16:44:02 +0800482 run_active_slot(obj_req->req->slot);
Tay Ray Chuan4c42aa12009-06-06 16:43:33 +0800483
Tay Ray Chuan5424bc52009-06-06 16:44:02 +0800484 req = obj_req->req;
485
486 if (req->localfile != -1) {
487 close(req->localfile);
488 req->localfile = -1;
Petr Baudis313c4712005-11-12 00:55:16 +0100489 }
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700490
Nick Hengevelde388ab72005-11-18 11:03:04 -0800491 if (obj_req->state == ABORTED) {
Nick Hengeveld29508e12005-11-18 11:02:58 -0800492 ret = error("Request for %s aborted", hex);
Tay Ray Chuan5424bc52009-06-06 16:44:02 +0800493 } else if (req->curl_result != CURLE_OK &&
494 req->http_code != 416) {
495 if (missing_target(req))
Petr Baudise2029eb2005-10-21 18:18:46 +0200496 ret = -1; /* Be silent, it is probably in a pack. */
497 else
498 ret = error("%s (curl_result = %d, http_code = %ld, sha1 = %s)",
Tay Ray Chuan5424bc52009-06-06 16:44:02 +0800499 req->errorstr, req->curl_result,
500 req->http_code, hex);
501 } else if (req->zret != Z_STREAM_END) {
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400502 walker->corrupt_object_found++;
Tay Ray Chuan5424bc52009-06-06 16:44:02 +0800503 ret = error("File %s (%s) corrupt", hex, req->url);
504 } else if (hashcmp(obj_req->sha1, req->real_sha1)) {
Junio C Hamanobd2afde2006-02-22 17:47:10 -0800505 ret = error("File %s has bad hash", hex);
Tay Ray Chuan5424bc52009-06-06 16:44:02 +0800506 } else if (req->rename < 0) {
Mark Wooding7b934ec2006-02-01 11:44:35 +0000507 ret = error("unable to write sha1 filename %s",
Shawn O. Pearce0da8b2e2010-04-17 13:07:38 -0700508 sha1_file_name(req->sha1));
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700509 }
510
Tay Ray Chuan5424bc52009-06-06 16:44:02 +0800511 release_http_object_request(req);
Nick Hengevelde388ab72005-11-18 11:03:04 -0800512 release_object_request(obj_req);
Nick Hengeveld29508e12005-11-18 11:02:58 -0800513 return ret;
Daniel Barkalow6eb7ed52005-04-23 18:47:23 -0700514}
515
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400516static int fetch(struct walker *walker, unsigned char *sha1)
Daniel Barkalowb3661562005-09-14 23:26:08 -0400517{
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400518 struct walker_data *data = walker->data;
519 struct alt_base *altbase = data->alt;
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700520
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400521 if (!fetch_object(walker, altbase, sha1))
Nick Hengeveld1d389ab2005-10-10 23:22:01 -0700522 return 0;
Daniel Barkalowb3661562005-09-14 23:26:08 -0400523 while (altbase) {
Michael Haggerty07c19e72012-09-09 08:19:38 +0200524 if (!http_fetch_pack(walker, altbase, sha1))
Daniel Barkalowb3661562005-09-14 23:26:08 -0400525 return 0;
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400526 fetch_alternates(walker, data->alt->base);
Daniel Barkalowb3661562005-09-14 23:26:08 -0400527 altbase = altbase->next;
528 }
Junio C Hamanobd2afde2006-02-22 17:47:10 -0800529 return error("Unable to find %s under %s", sha1_to_hex(sha1),
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400530 data->alt->base);
Daniel Barkalowb3661562005-09-14 23:26:08 -0400531}
532
Daniel Barkalowc13b2632008-04-26 15:53:09 -0400533static int fetch_ref(struct walker *walker, struct ref *ref)
Daniel Barkalowcd541a62005-06-06 16:38:26 -0400534{
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400535 struct walker_data *data = walker->data;
Daniel Barkalowc13b2632008-04-26 15:53:09 -0400536 return http_fetch_ref(data->alt->base, ref);
Daniel Barkalowcd541a62005-06-06 16:38:26 -0400537}
538
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400539static void cleanup(struct walker *walker)
Daniel Barkalow6eb7ed52005-04-23 18:47:23 -0700540{
Tay Ray Chuan09ae9ac2010-03-02 18:49:28 +0800541 struct walker_data *data = walker->data;
542 struct alt_base *alt, *alt_next;
543
544 if (data) {
545 alt = data->alt;
546 while (alt) {
547 alt_next = alt->next;
548
549 free(alt->base);
550 free(alt);
551
552 alt = alt_next;
553 }
554 free(data);
555 walker->data = NULL;
556 }
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400557}
558
Tay Ray Chuan888692b2010-03-02 18:49:29 +0800559struct walker *get_http_walker(const char *url)
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400560{
Gerrit Pape9c880b32007-03-28 09:47:35 +0000561 char *s;
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400562 struct walker_data *data = xmalloc(sizeof(struct walker_data));
563 struct walker *walker = xmalloc(sizeof(struct walker));
Daniel Barkalow6eb7ed52005-04-23 18:47:23 -0700564
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400565 data->alt = xmalloc(sizeof(*data->alt));
Jeff King95244ae2014-06-19 17:19:43 -0400566 data->alt->base = xstrdup(url);
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400567 for (s = data->alt->base + strlen(data->alt->base) - 1; *s == '/'; --s)
Gerrit Pape9c880b32007-03-28 09:47:35 +0000568 *s = 0;
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400569
570 data->alt->got_indices = 0;
571 data->alt->packs = NULL;
572 data->alt->next = NULL;
573 data->got_alternates = -1;
574
575 walker->corrupt_object_found = 0;
576 walker->fetch = fetch;
577 walker->fetch_ref = fetch_ref;
578 walker->prefetch = prefetch;
579 walker->cleanup = cleanup;
580 walker->data = data;
Daniel Barkalow6eb7ed52005-04-23 18:47:23 -0700581
Daniel Barkalowfc57b6a2007-09-10 23:02:34 -0400582#ifdef USE_CURL_MULTI
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400583 add_fill_function(walker, (int (*)(void *)) fill_active_slot);
Daniel Barkalowfc57b6a2007-09-10 23:02:34 -0400584#endif
585
Daniel Barkalow30ae7642007-09-10 23:02:45 -0400586 return walker;
Daniel Barkalow6eb7ed52005-04-23 18:47:23 -0700587}