* [PATCH v4] http.c: use CURLOPT_RANGE for range requests
@ 2015-11-02 21:39 David Turner
2015-11-02 21:53 ` Jeff King
0 siblings, 1 reply; 2+ messages in thread
From: David Turner @ 2015-11-02 21:39 UTC (permalink / raw)
To: git, peff; +Cc: David Turner
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>
---
This one incorporates Jeff's suggestions about off_t. It also
simplifies by removing the possiblity of a missing low-end of a range;
the entire point of this function is to add a range HEADER and a
range of - is nugatory.
---
http.c | 33 ++++++++++++---------------------
http.h | 1 -
2 files changed, 12 insertions(+), 22 deletions(-)
diff --git a/http.c b/http.c
index 6b89dea..f9a0dc5 100644
--- a/http.c
+++ b/http.c
@@ -30,7 +30,6 @@ static CURL *curl_default;
#endif
#define PREV_BUF_SIZE 4096
-#define RANGE_HEADER_SIZE 30
char curl_errorstr[CURL_ERROR_SIZE];
@@ -692,6 +691,7 @@ struct active_request_slot *get_active_slot(void)
curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 0);
curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt(slot->curl, CURLOPT_RANGE, NULL);
#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
curl_easy_setopt(slot->curl, CURLOPT_HTTPAUTH, http_auth_methods);
#endif
@@ -1184,6 +1184,13 @@ static const char *get_accept_language(void)
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 */
#define HTTP_REQUEST_STRBUF 0
#define HTTP_REQUEST_FILE 1
@@ -1212,11 +1219,8 @@ static int http_request(const char *url,
long posn = ftell(result);
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
fwrite);
- if (posn > 0) {
- strbuf_addf(&buf, "Range: bytes=%ld-", posn);
- headers = curl_slist_append(headers, buf.buf);
- strbuf_reset(&buf);
- }
+ if (posn > 0)
+ http_opt_request_remainder(slot->curl, posn);
} else
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
fwrite_buffer);
@@ -1526,10 +1530,6 @@ void release_http_pack_request(struct http_pack_request *preq)
fclose(preq->packfile);
preq->packfile = NULL;
}
- if (preq->range_header != NULL) {
- curl_slist_free_all(preq->range_header);
- preq->range_header = NULL;
- }
preq->slot = NULL;
free(preq->url);
free(preq);
@@ -1593,7 +1593,6 @@ struct http_pack_request *new_http_pack_request(
struct packed_git *target, const char *base_url)
{
long prev_posn = 0;
- char range[RANGE_HEADER_SIZE];
struct strbuf buf = STRBUF_INIT;
struct http_pack_request *preq;
@@ -1631,10 +1630,7 @@ struct http_pack_request *new_http_pack_request(
fprintf(stderr,
"Resuming fetch of pack %s at byte %ld\n",
sha1_to_hex(target->sha1), prev_posn);
- xsnprintf(range, sizeof(range), "Range: bytes=%ld-", prev_posn);
- preq->range_header = curl_slist_append(NULL, range);
- curl_easy_setopt(preq->slot->curl, CURLOPT_HTTPHEADER,
- preq->range_header);
+ http_opt_request_remainder(preq->slot->curl, prev_posn);
}
return preq;
@@ -1684,8 +1680,6 @@ struct http_object_request *new_http_object_request(const char *base_url,
char prev_buf[PREV_BUF_SIZE];
ssize_t prev_read = 0;
long prev_posn = 0;
- char range[RANGE_HEADER_SIZE];
- struct curl_slist *range_header = NULL;
struct http_object_request *freq;
freq = xcalloc(1, sizeof(*freq));
@@ -1791,10 +1785,7 @@ struct http_object_request *new_http_object_request(const char *base_url,
fprintf(stderr,
"Resuming fetch of object %s at byte %ld\n",
hex, prev_posn);
- xsnprintf(range, sizeof(range), "Range: bytes=%ld-", prev_posn);
- range_header = curl_slist_append(range_header, range);
- curl_easy_setopt(freq->slot->curl,
- CURLOPT_HTTPHEADER, range_header);
+ http_opt_request_remainder(freq->slot->curl, prev_posn);
}
return freq;
diff --git a/http.h b/http.h
index 49afe39..4f97b60 100644
--- a/http.h
+++ b/http.h
@@ -190,7 +190,6 @@ struct http_pack_request {
struct packed_git **lst;
FILE *packfile;
char tmpfile[PATH_MAX];
- struct curl_slist *range_header;
struct active_request_slot *slot;
};
--
2.4.2.691.g714732c-twtrsrc
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH v4] http.c: use CURLOPT_RANGE for range requests
2015-11-02 21:39 [PATCH v4] http.c: use CURLOPT_RANGE for range requests David Turner
@ 2015-11-02 21:53 ` Jeff King
0 siblings, 0 replies; 2+ messages in thread
From: Jeff King @ 2015-11-02 21:53 UTC (permalink / raw)
To: David Turner; +Cc: git
On Mon, Nov 02, 2015 at 04:39:58PM -0500, David Turner wrote:
> 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>
> ---
>
> This one incorporates Jeff's suggestions about off_t. It also
> simplifies by removing the possiblity of a missing low-end of a range;
> the entire point of this function is to add a range HEADER and a
> range of - is nugatory.
Thanks, looks good to me. And I learned a new vocabulary word. :)
-Peff
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2015-11-02 21:53 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-11-02 21:39 [PATCH v4] http.c: use CURLOPT_RANGE for range requests David Turner
2015-11-02 21:53 ` Jeff King
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).