http.c: use CURLOPT_RANGE for range requests
A HTTP server is permitted to return a non-range response to a HTTP range request (and Apache httpd in fact does this in some cases). While libcurl knows how to correctly handle this (by skipping bytes before and after the requested range), it only turns on this handling if it is aware that a range request is being made. By manually setting the range header instead of using CURLOPT_RANGE, we were hiding the fact that this was a range request from libcurl. This could cause corruption. Signed-off-by: David Turner <dturner@twopensource.com> Reviewed-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
David Turner committed
Nov 2, 2015 at 16:39 UTC
835c4d3689972e616bd109cec3dd8cd4aa4d4c0d
2 files changed
+12
-22
http.c
+12
-21
@@ -30,7 +30,6 @@ static CURL *curl_default;
30
#endif
31
32
#define PREV_BUF_SIZE 4096
33
-#define RANGE_HEADER_SIZE 30
33
34
char curl_errorstr[CURL_ERROR_SIZE];
35
@@ -681,6 +680,7 @@ struct active_request_slot *get_active_slot(void)
680
curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 0);
681
curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
682
curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 1);
683
+ curl_easy_setopt(slot->curl, CURLOPT_RANGE, NULL);
684
#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
685
curl_easy_setopt(slot->curl, CURLOPT_HTTPAUTH, http_auth_methods);
686
#endif
@@ -1173,6 +1173,13 @@ static const char *get_accept_language(void)
1173
return cached_accept_language;
1174
}
1175
1176
+static void http_opt_request_remainder(CURL *curl, off_t pos)
1177
+{
1178
+ char buf[128];
1179
+ xsnprintf(buf, sizeof(buf), "%"PRIuMAX"-", (uintmax_t)pos);
1180
+ curl_easy_setopt(curl, CURLOPT_RANGE, buf);
1181
+}
1182
+
1183
/* http_request() targets */
1184
#define HTTP_REQUEST_STRBUF 0
1185
#define HTTP_REQUEST_FILE 1
@@ -1201,11 +1208,8 @@ static int http_request(const char *url,
1208
long posn = ftell(result);
1209
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
1210
fwrite);
1204
- if (posn > 0) {
1205
- strbuf_addf(&buf, "Range: bytes=%ld-", posn);
1206
- headers = curl_slist_append(headers, buf.buf);
1207
- strbuf_reset(&buf);
1208
- }
1211
+ if (posn > 0)
1212
+ http_opt_request_remainder(slot->curl, posn);
1213
} else
1214
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
1215
fwrite_buffer);
@@ -1515,10 +1519,6 @@ void release_http_pack_request(struct http_pack_request *preq)
1519
fclose(preq->packfile);
1520
preq->packfile = NULL;
1521
}
1518
- if (preq->range_header != NULL) {
1519
- curl_slist_free_all(preq->range_header);
1520
- preq->range_header = NULL;
1521
- }
1522
preq->slot = NULL;
1523
free(preq->url);
1524
free(preq);
@@ -1582,7 +1582,6 @@ struct http_pack_request *new_http_pack_request(
1582
struct packed_git *target, const char *base_url)
1583
{
1584
long prev_posn = 0;
1585
- char range[RANGE_HEADER_SIZE];
1585
struct strbuf buf = STRBUF_INIT;
1586
struct http_pack_request *preq;
1587
@@ -1620,10 +1619,7 @@ struct http_pack_request *new_http_pack_request(
1619
fprintf(stderr,
1620
"Resuming fetch of pack %s at byte %ld\n",
1621
sha1_to_hex(target->sha1), prev_posn);
1623
- xsnprintf(range, sizeof(range), "Range: bytes=%ld-", prev_posn);
1624
- preq->range_header = curl_slist_append(NULL, range);
1625
- curl_easy_setopt(preq->slot->curl, CURLOPT_HTTPHEADER,
1626
- preq->range_header);
1622
+ http_opt_request_remainder(preq->slot->curl, prev_posn);
1623
}
1624
1625
return preq;
@@ -1673,8 +1669,6 @@ struct http_object_request *new_http_object_request(const char *base_url,
1669
char prev_buf[PREV_BUF_SIZE];
1670
ssize_t prev_read = 0;
1671
long prev_posn = 0;
1676
- char range[RANGE_HEADER_SIZE];
1677
- struct curl_slist *range_header = NULL;
1672
struct http_object_request *freq;
1673
1674
freq = xcalloc(1, sizeof(*freq));
@@ -1780,10 +1774,7 @@ struct http_object_request *new_http_object_request(const char *base_url,
1774
fprintf(stderr,
1775
"Resuming fetch of object %s at byte %ld\n",
1776
hex, prev_posn);
1783
- xsnprintf(range, sizeof(range), "Range: bytes=%ld-", prev_posn);
1784
- range_header = curl_slist_append(range_header, range);
1785
- curl_easy_setopt(freq->slot->curl,
1786
- CURLOPT_HTTPHEADER, range_header);
1777
+ http_opt_request_remainder(freq->slot->curl, prev_posn);
1778
}
1779
1780
return freq;
http.h
-1
@@ -190,7 +190,6 @@ struct http_pack_request {
190
struct packed_git **lst;
191
FILE *packfile;
192
char tmpfile[PATH_MAX];
193
- struct curl_slist *range_header;
193
struct active_request_slot *slot;
194
};
195