#define PREV_BUF_SIZE 4096
#define RANGE_HEADER_SIZE 30
+static int got_alternates = 0;
static int active_requests = 0;
static int data_received;
int in_use;
int done;
CURLcode curl_result;
+ long http_code;
struct active_request_slot *next;
};
static char *ssl_capath = NULL;
#endif
static char *ssl_cainfo = NULL;
+static long curl_low_speed_limit = -1;
+static long curl_low_speed_time = -1;
struct buffer
{
}
#endif
+ if (!strcmp("http.lowspeedlimit", var)) {
+ if (curl_low_speed_limit == -1)
+ curl_low_speed_limit = (long)git_config_int(var, value);
+ return 0;
+ }
+ if (!strcmp("http.lowspeedtime", var)) {
+ if (curl_low_speed_time == -1)
+ curl_low_speed_time = (long)git_config_int(var, value);
+ return 0;
+ }
+
/* Fall back on the default ones */
return git_default_config(var, value);
}
}
#ifdef USE_CURL_MULTI
-void process_curl_messages();
-void process_request_queue();
+static void process_curl_messages(void);
+static void process_request_queue(void);
#endif
+static int fetch_alternates(char *base);
-static CURL* get_curl_handle()
+static CURL* get_curl_handle(void)
{
CURL* result = curl_easy_init();
curl_easy_setopt(result, CURLOPT_CAINFO, ssl_cainfo);
curl_easy_setopt(result, CURLOPT_FAILONERROR, 1);
+ if (curl_low_speed_limit > 0 && curl_low_speed_time > 0) {
+ curl_easy_setopt(result, CURLOPT_LOW_SPEED_LIMIT,
+ curl_low_speed_limit);
+ curl_easy_setopt(result, CURLOPT_LOW_SPEED_TIME,
+ curl_low_speed_time);
+ }
+
+ curl_easy_setopt(result, CURLOPT_FOLLOWLOCATION, 1);
+
return result;
}
-struct active_request_slot *get_active_slot()
+static struct active_request_slot *get_active_slot(void)
{
struct active_request_slot *slot = active_queue_head;
struct active_request_slot *newslot;
}
if (slot == NULL) {
newslot = xmalloc(sizeof(*newslot));
-#ifdef NO_CURL_EASY_DUPHANDLE
- newslot->curl = get_curl_handle();
-#else
- newslot->curl = curl_easy_duphandle(curl_default);
-#endif
+ newslot->curl = NULL;
newslot->in_use = 0;
newslot->next = NULL;
slot = newslot;
}
+ if (slot->curl == NULL) {
+#ifdef NO_CURL_EASY_DUPHANDLE
+ slot->curl = get_curl_handle();
+#else
+ slot->curl = curl_easy_duphandle(curl_default);
+#endif
+ }
+
active_requests++;
slot->in_use = 1;
slot->done = 0;
return slot;
}
-int start_active_slot(struct active_request_slot *slot)
+static int start_active_slot(struct active_request_slot *slot)
{
#ifdef USE_CURL_MULTI
CURLMcode curlm_result = curl_multi_add_handle(curlm, slot->curl);
return 1;
}
-void run_active_slot(struct active_request_slot *slot)
+static void run_active_slot(struct active_request_slot *slot)
{
#ifdef USE_CURL_MULTI
int num_transfers;
#endif
}
-void start_request(struct transfer_request *request)
+static void start_request(struct transfer_request *request)
{
char *hex = sha1_to_hex(request->sha1);
char prevfile[PATH_MAX];
request->state = ACTIVE;
}
-void finish_request(struct transfer_request *request)
+static void finish_request(struct transfer_request *request)
{
+ struct stat st;
+
fchmod(request->local, 0444);
close(request->local);
if (request->http_code == 416) {
fprintf(stderr, "Warning: requested range invalid; we may already have all the data.\n");
} else if (request->curl_result != CURLE_OK) {
+ if (stat(request->tmpfile, &st) == 0)
+ if (st.st_size == 0)
+ unlink(request->tmpfile);
return;
}
pull_say("got %s\n", sha1_to_hex(request->sha1));
}
-void release_request(struct transfer_request *request)
+static void release_request(struct transfer_request *request)
{
struct transfer_request *entry = request_queue_head;
}
#ifdef USE_CURL_MULTI
-void process_curl_messages()
+static void process_curl_messages(void)
{
int num_messages;
struct active_request_slot *slot;
while (curl_message != NULL) {
if (curl_message->msg == CURLMSG_DONE) {
+ int curl_result = curl_message->data.result;
slot = active_queue_head;
while (slot != NULL &&
slot->curl != curl_message->easy_handle)
active_requests--;
slot->done = 1;
slot->in_use = 0;
- slot->curl_result = curl_message->data.result;
+ slot->curl_result = curl_result;
+ curl_easy_getinfo(slot->curl,
+ CURLINFO_HTTP_CODE,
+ &slot->http_code);
request = request_queue_head;
while (request != NULL &&
request->slot != slot)
fprintf(stderr, "Received DONE message for unknown request!\n");
}
if (request != NULL) {
- request->curl_result =
- curl_message->data.result;
- curl_easy_getinfo(slot->curl,
- CURLINFO_HTTP_CODE,
- &request->http_code);
+ request->curl_result = curl_result;
+ request->http_code = slot->http_code;
request->slot = NULL;
+ request->state = COMPLETE;
/* Use alternates if necessary */
- if (request->http_code == 404 &&
- request->repo->next != NULL) {
- request->repo = request->repo->next;
- start_request(request);
+ if (request->http_code == 404) {
+ fetch_alternates(alt->base);
+ if (request->repo->next != NULL) {
+ request->repo =
+ request->repo->next;
+ start_request(request);
+ }
} else {
finish_request(request);
- request->state = COMPLETE;
}
}
} else {
}
}
-void process_request_queue()
+static void process_request_queue(void)
{
struct transfer_request *request = request_queue_head;
+ struct active_request_slot *slot = active_queue_head;
int num_transfers;
while (active_requests < max_requests && request != NULL) {
}
request = request->next;
}
+
+ while (slot != NULL) {
+ if (!slot->in_use && slot->curl != NULL) {
+ curl_easy_cleanup(slot->curl);
+ slot->curl = NULL;
+ }
+ slot = slot->next;
+ }
}
#endif
struct active_request_slot *slot;
+ if (got_alternates)
+ return 0;
+
data = xmalloc(4096);
buffer.size = 4096;
buffer.posn = 0;
run_active_slot(slot);
if (slot->curl_result != CURLE_OK) {
free(buffer.buffer);
+ if (slot->http_code == 404)
+ got_alternates = 1;
return 0;
}
}
i = posn + 1;
}
+ got_alternates = 1;
free(buffer.buffer);
return ret;
}
}
#ifdef USE_CURL_MULTI
- int num_transfers;
while (request->state == WAITING) {
+ int num_transfers;
curl_multi_perform(curlm, &num_transfers);
if (num_transfers < active_requests) {
process_curl_messages();
run_active_slot(request->slot);
#ifndef USE_CURL_MULTI
request->curl_result = request->slot->curl_result;
- curl_easy_getinfo(request->slot->curl,
- CURLINFO_HTTP_CODE,
- &request->http_code);
+ request->http_code = request->slot->http_code;
request->slot = NULL;
/* Use alternates if necessary */
- if (request->http_code == 404 &&
- request->repo->next != NULL) {
- request->repo = request->repo->next;
- start_request(request);
+ if (request->http_code == 404) {
+ fetch_alternates(alt->base);
+ if (request->repo->next != NULL) {
+ request->repo = request->repo->next;
+ start_request(request);
+ }
} else {
finish_request(request);
request->state = COMPLETE;
}
if (request->curl_result != CURLE_OK && request->http_code != 416) {
- ret = error("%s (curl_result = %d, http_code = %ld, sha1 = %s)",
- request->errorstr, request->curl_result,
- request->http_code, hex);
+ if (request->http_code == 404)
+ ret = -1; /* Be silent, it is probably in a pack. */
+ else
+ ret = error("%s (curl_result = %d, http_code = %ld, sha1 = %s)",
+ request->errorstr, request->curl_result,
+ request->http_code, hex);
release_request(request);
return ret;
}
while (altbase) {
if (!fetch_pack(altbase, sha1))
return 0;
+ fetch_alternates(alt->base);
altbase = altbase->next;
}
return error("Unable to find %s under %s\n", sha1_to_hex(sha1),
char *url;
int arg = 1;
struct active_request_slot *slot;
+ char *low_speed_limit;
+ char *low_speed_time;
+ char *wait_url;
+ int rc = 0;
while (arg < argc && argv[arg][0] == '-') {
if (argv[arg][1] == 't') {
curl_global_init(CURL_GLOBAL_ALL);
#ifdef USE_CURL_MULTI
- char *http_max_requests = getenv("GIT_HTTP_MAX_REQUESTS");
- if (http_max_requests != NULL)
- max_requests = atoi(http_max_requests);
+ {
+ char *http_max_requests = getenv("GIT_HTTP_MAX_REQUESTS");
+ if (http_max_requests != NULL)
+ max_requests = atoi(http_max_requests);
+ }
curlm = curl_multi_init();
if (curlm == NULL) {
#endif
ssl_cainfo = getenv("GIT_SSL_CAINFO");
+ low_speed_limit = getenv("GIT_HTTP_LOW_SPEED_LIMIT");
+ if (low_speed_limit != NULL)
+ curl_low_speed_limit = strtol(low_speed_limit, NULL, 10);
+ low_speed_time = getenv("GIT_HTTP_LOW_SPEED_TIME");
+ if (low_speed_time != NULL)
+ curl_low_speed_time = strtol(low_speed_time, NULL, 10);
+
git_config(http_options);
if (curl_ssl_verify == -1)
alt->got_indices = 0;
alt->packs = NULL;
alt->next = NULL;
- fetch_alternates(alt->base);
if (pull(commit_id))
- return 1;
+ rc = 1;
curl_slist_free_all(pragma_header);
curl_slist_free_all(no_pragma_header);
#endif
slot = active_queue_head;
while (slot != NULL) {
- curl_easy_cleanup(slot->curl);
+ if (slot->in_use) {
+ if (get_verbosely) {
+ curl_easy_getinfo(slot->curl,
+ CURLINFO_EFFECTIVE_URL,
+ &wait_url);
+ fprintf(stderr, "Waiting for %s\n", wait_url);
+ }
+ run_active_slot(slot);
+ }
+ if (slot->curl != NULL)
+ curl_easy_cleanup(slot->curl);
slot = slot->next;
}
#ifdef USE_CURL_MULTI
curl_multi_cleanup(curlm);
#endif
curl_global_cleanup();
- return 0;
+ return rc;
}