Merge branch 'dt/http-range'

A Range: request can be responded with a full response and when
asked properly libcurl knows how to strip the result down to the
requested range.  However, we were hand-crafting a range request
and it did not kick in.

* dt/http-range:
  http: use off_t to store partial file size
  http.c: use CURLOPT_RANGE for range requests
This commit is contained in:
Junio C Hamano 2015-11-05 15:24:27 -08:00
commit 848cdba579
2 changed files with 16 additions and 26 deletions

41
http.c
View file

@ -30,7 +30,6 @@ static CURL *curl_default;
#endif #endif
#define PREV_BUF_SIZE 4096 #define PREV_BUF_SIZE 4096
#define RANGE_HEADER_SIZE 30
char curl_errorstr[CURL_ERROR_SIZE]; char curl_errorstr[CURL_ERROR_SIZE];
@ -681,6 +680,7 @@ struct active_request_slot *get_active_slot(void)
curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 0); curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 0);
curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1); curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 1); curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 1);
curl_easy_setopt(slot->curl, CURLOPT_RANGE, NULL);
#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY #ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
curl_easy_setopt(slot->curl, CURLOPT_HTTPAUTH, http_auth_methods); curl_easy_setopt(slot->curl, CURLOPT_HTTPAUTH, http_auth_methods);
#endif #endif
@ -1173,6 +1173,13 @@ static const char *get_accept_language(void)
return cached_accept_language; return cached_accept_language;
} }
static void http_opt_request_remainder(CURL *curl, off_t pos)
{
char buf[128];
xsnprintf(buf, sizeof(buf), "%"PRIuMAX"-", (uintmax_t)pos);
curl_easy_setopt(curl, CURLOPT_RANGE, buf);
}
/* http_request() targets */ /* http_request() targets */
#define HTTP_REQUEST_STRBUF 0 #define HTTP_REQUEST_STRBUF 0
#define HTTP_REQUEST_FILE 1 #define HTTP_REQUEST_FILE 1
@ -1198,14 +1205,11 @@ static int http_request(const char *url,
curl_easy_setopt(slot->curl, CURLOPT_FILE, result); curl_easy_setopt(slot->curl, CURLOPT_FILE, result);
if (target == HTTP_REQUEST_FILE) { if (target == HTTP_REQUEST_FILE) {
long posn = ftell(result); off_t posn = ftello(result);
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
fwrite); fwrite);
if (posn > 0) { if (posn > 0)
strbuf_addf(&buf, "Range: bytes=%ld-", posn); http_opt_request_remainder(slot->curl, posn);
headers = curl_slist_append(headers, buf.buf);
strbuf_reset(&buf);
}
} else } else
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
fwrite_buffer); fwrite_buffer);
@ -1515,10 +1519,6 @@ void release_http_pack_request(struct http_pack_request *preq)
fclose(preq->packfile); fclose(preq->packfile);
preq->packfile = NULL; preq->packfile = NULL;
} }
if (preq->range_header != NULL) {
curl_slist_free_all(preq->range_header);
preq->range_header = NULL;
}
preq->slot = NULL; preq->slot = NULL;
free(preq->url); free(preq->url);
free(preq); free(preq);
@ -1581,8 +1581,7 @@ int finish_http_pack_request(struct http_pack_request *preq)
struct http_pack_request *new_http_pack_request( struct http_pack_request *new_http_pack_request(
struct packed_git *target, const char *base_url) struct packed_git *target, const char *base_url)
{ {
long prev_posn = 0; off_t prev_posn = 0;
char range[RANGE_HEADER_SIZE];
struct strbuf buf = STRBUF_INIT; struct strbuf buf = STRBUF_INIT;
struct http_pack_request *preq; struct http_pack_request *preq;
@ -1614,16 +1613,13 @@ struct http_pack_request *new_http_pack_request(
* If there is data present from a previous transfer attempt, * If there is data present from a previous transfer attempt,
* resume where it left off * resume where it left off
*/ */
prev_posn = ftell(preq->packfile); prev_posn = ftello(preq->packfile);
if (prev_posn>0) { if (prev_posn>0) {
if (http_is_verbose) if (http_is_verbose)
fprintf(stderr, fprintf(stderr,
"Resuming fetch of pack %s at byte %ld\n", "Resuming fetch of pack %s at byte %ld\n",
sha1_to_hex(target->sha1), prev_posn); sha1_to_hex(target->sha1), prev_posn);
xsnprintf(range, sizeof(range), "Range: bytes=%ld-", prev_posn); http_opt_request_remainder(preq->slot->curl, prev_posn);
preq->range_header = curl_slist_append(NULL, range);
curl_easy_setopt(preq->slot->curl, CURLOPT_HTTPHEADER,
preq->range_header);
} }
return preq; return preq;
@ -1672,9 +1668,7 @@ struct http_object_request *new_http_object_request(const char *base_url,
int prevlocal; int prevlocal;
char prev_buf[PREV_BUF_SIZE]; char prev_buf[PREV_BUF_SIZE];
ssize_t prev_read = 0; ssize_t prev_read = 0;
long prev_posn = 0; off_t prev_posn = 0;
char range[RANGE_HEADER_SIZE];
struct curl_slist *range_header = NULL;
struct http_object_request *freq; struct http_object_request *freq;
freq = xcalloc(1, sizeof(*freq)); freq = xcalloc(1, sizeof(*freq));
@ -1780,10 +1774,7 @@ struct http_object_request *new_http_object_request(const char *base_url,
fprintf(stderr, fprintf(stderr,
"Resuming fetch of object %s at byte %ld\n", "Resuming fetch of object %s at byte %ld\n",
hex, prev_posn); hex, prev_posn);
xsnprintf(range, sizeof(range), "Range: bytes=%ld-", prev_posn); http_opt_request_remainder(freq->slot->curl, prev_posn);
range_header = curl_slist_append(range_header, range);
curl_easy_setopt(freq->slot->curl,
CURLOPT_HTTPHEADER, range_header);
} }
return freq; return freq;

1
http.h
View file

@ -190,7 +190,6 @@ struct http_pack_request {
struct packed_git **lst; struct packed_git **lst;
FILE *packfile; FILE *packfile;
char tmpfile[PATH_MAX]; char tmpfile[PATH_MAX];
struct curl_slist *range_header;
struct active_request_slot *slot; struct active_request_slot *slot;
}; };