aboutsummaryrefslogtreecommitdiffstats
path: root/http.c
diff options
context:
space:
mode:
Diffstat (limited to 'http.c')
-rw-r--r--http.c369
1 files changed, 279 insertions, 90 deletions
diff --git a/http.c b/http.c
index c4b6ddef28..2dea2d03da 100644
--- a/http.c
+++ b/http.c
@@ -1,9 +1,9 @@
#include "git-compat-util.h"
#include "git-curl-compat.h"
+#include "hex.h"
#include "http.h"
#include "config.h"
#include "pack.h"
-#include "sideband.h"
#include "run-command.h"
#include "url.h"
#include "urlmatch.h"
@@ -11,11 +11,12 @@
#include "version.h"
#include "pkt-line.h"
#include "gettext.h"
+#include "trace.h"
#include "transport.h"
#include "packfile.h"
-#include "protocol.h"
#include "string-list.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
static struct trace_key trace_curl = TRACE_KEY_INIT(CURL);
static int trace_curl_data = 1;
@@ -37,10 +38,11 @@ char curl_errorstr[CURL_ERROR_SIZE];
static int curl_ssl_verify = -1;
static int curl_ssl_try;
-static const char *curl_http_version = NULL;
-static const char *ssl_cert;
-static const char *ssl_cipherlist;
-static const char *ssl_version;
+static char *curl_http_version;
+static char *ssl_cert;
+static char *ssl_cert_type;
+static char *ssl_cipherlist;
+static char *ssl_version;
static struct {
const char *name;
long ssl_version;
@@ -57,22 +59,23 @@ static struct {
{ "tlsv1.3", CURL_SSLVERSION_TLSv1_3 },
#endif
};
-static const char *ssl_key;
-static const char *ssl_capath;
-static const char *curl_no_proxy;
+static char *ssl_key;
+static char *ssl_key_type;
+static char *ssl_capath;
+static char *curl_no_proxy;
#ifdef GIT_CURL_HAVE_CURLOPT_PINNEDPUBLICKEY
-static const char *ssl_pinnedkey;
+static char *ssl_pinnedkey;
#endif
-static const char *ssl_cainfo;
+static char *ssl_cainfo;
static long curl_low_speed_limit = -1;
static long curl_low_speed_time = -1;
static int curl_ftp_no_epsv;
-static const char *curl_http_proxy;
-static const char *http_proxy_authmethod;
+static char *curl_http_proxy;
+static char *http_proxy_authmethod;
-static const char *http_proxy_ssl_cert;
-static const char *http_proxy_ssl_key;
-static const char *http_proxy_ssl_ca_info;
+static char *http_proxy_ssl_cert;
+static char *http_proxy_ssl_key;
+static char *http_proxy_ssl_ca_info;
static struct credential proxy_cert_auth = CREDENTIAL_INIT;
static int proxy_ssl_cert_password_required;
@@ -92,7 +95,7 @@ static struct {
*/
};
#ifdef CURLGSSAPI_DELEGATION_FLAG
-static const char *curl_deleg;
+static char *curl_deleg;
static struct {
const char *name;
long curl_deleg_param;
@@ -105,11 +108,11 @@ static struct {
static struct credential proxy_auth = CREDENTIAL_INIT;
static const char *curl_proxyuserpwd;
-static const char *curl_cookie_file;
+static char *curl_cookie_file;
static int curl_save_cookies;
struct credential http_auth = CREDENTIAL_INIT;
static int http_proactive_auth;
-static const char *user_agent;
+static char *user_agent;
static int curl_empty_auth = -1;
enum http_follow_config http_follow_config = HTTP_FOLLOW_INITIAL;
@@ -125,7 +128,6 @@ static unsigned long empty_auth_useless =
| CURLAUTH_DIGEST;
static struct curl_slist *pragma_header;
-static struct curl_slist *no_pragma_header;
static struct string_list extra_http_headers = STRING_LIST_INIT_DUP;
static struct curl_slist *host_resolutions;
@@ -181,11 +183,126 @@ size_t fwrite_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_)
return nmemb;
}
-size_t fwrite_null(char *ptr, size_t eltsize, size_t nmemb, void *strbuf)
+/*
+ * A folded header continuation line starts with any number of spaces or
+ * horizontal tab characters (SP or HTAB) as per RFC 7230 section 3.2.
+ * It is not a continuation line if the line starts with any other character.
+ */
+static inline int is_hdr_continuation(const char *ptr, const size_t size)
+{
+ return size && (*ptr == ' ' || *ptr == '\t');
+}
+
+static size_t fwrite_wwwauth(char *ptr, size_t eltsize, size_t nmemb, void *p UNUSED)
+{
+ size_t size = eltsize * nmemb;
+ struct strvec *values = &http_auth.wwwauth_headers;
+ struct strbuf buf = STRBUF_INIT;
+ const char *val;
+ size_t val_len;
+
+ /*
+ * Header lines may not come NULL-terminated from libcurl so we must
+ * limit all scans to the maximum length of the header line, or leverage
+ * strbufs for all operations.
+ *
+ * In addition, it is possible that header values can be split over
+ * multiple lines as per RFC 7230. 'Line folding' has been deprecated
+ * but older servers may still emit them. A continuation header field
+ * value is identified as starting with a space or horizontal tab.
+ *
+ * The formal definition of a header field as given in RFC 7230 is:
+ *
+ * header-field = field-name ":" OWS field-value OWS
+ *
+ * field-name = token
+ * field-value = *( field-content / obs-fold )
+ * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
+ * field-vchar = VCHAR / obs-text
+ *
+ * obs-fold = CRLF 1*( SP / HTAB )
+ * ; obsolete line folding
+ * ; see Section 3.2.4
+ */
+
+ /* Start of a new WWW-Authenticate header */
+ if (skip_iprefix_mem(ptr, size, "www-authenticate:", &val, &val_len)) {
+ strbuf_add(&buf, val, val_len);
+
+ /*
+ * Strip the CRLF that should be present at the end of each
+ * field as well as any trailing or leading whitespace from the
+ * value.
+ */
+ strbuf_trim(&buf);
+
+ strvec_push(values, buf.buf);
+ http_auth.header_is_last_match = 1;
+ goto exit;
+ }
+
+ /*
+ * This line could be a continuation of the previously matched header
+ * field. If this is the case then we should append this value to the
+ * end of the previously consumed value.
+ */
+ if (http_auth.header_is_last_match && is_hdr_continuation(ptr, size)) {
+ /*
+ * Trim the CRLF and any leading or trailing from this line.
+ */
+ strbuf_add(&buf, ptr, size);
+ strbuf_trim(&buf);
+
+ /*
+ * At this point we should always have at least one existing
+ * value, even if it is empty. Do not bother appending the new
+ * value if this continuation header is itself empty.
+ */
+ if (!values->nr) {
+ BUG("should have at least one existing header value");
+ } else if (buf.len) {
+ char *prev = xstrdup(values->v[values->nr - 1]);
+
+ /* Join two non-empty values with a single space. */
+ const char *const sp = *prev ? " " : "";
+
+ strvec_pop(values);
+ strvec_pushf(values, "%s%s%s", prev, sp, buf.buf);
+ free(prev);
+ }
+
+ goto exit;
+ }
+
+ /* Not a continuation of a previously matched auth header line. */
+ http_auth.header_is_last_match = 0;
+
+ /*
+ * If this is a HTTP status line and not a header field, this signals
+ * a different HTTP response. libcurl writes all the output of all
+ * response headers of all responses, including redirects.
+ * We only care about the last HTTP request response's headers so clear
+ * the existing array.
+ */
+ if (skip_iprefix_mem(ptr, size, "http/", &val, &val_len))
+ strvec_clear(values);
+
+exit:
+ strbuf_release(&buf);
+ return size;
+}
+
+size_t fwrite_null(char *ptr UNUSED, size_t eltsize UNUSED, size_t nmemb,
+ void *data UNUSED)
{
return nmemb;
}
+static struct curl_slist *object_request_headers(void)
+{
+ return curl_slist_append(http_copy_default_headers(), "Pragma:");
+}
+
static void closedown_active_slot(struct active_request_slot *slot)
{
active_requests--;
@@ -249,7 +366,8 @@ static void process_curl_messages(void)
}
}
-static int http_options(const char *var, const char *value, void *cb)
+static int http_options(const char *var, const char *value,
+ const struct config_context *ctx, void *data)
{
if (!strcmp("http.version", var)) {
return git_config_string(&curl_http_version, var, value);
@@ -264,8 +382,12 @@ static int http_options(const char *var, const char *value, void *cb)
return git_config_string(&ssl_version, var, value);
if (!strcmp("http.sslcert", var))
return git_config_pathname(&ssl_cert, var, value);
+ if (!strcmp("http.sslcerttype", var))
+ return git_config_string(&ssl_cert_type, var, value);
if (!strcmp("http.sslkey", var))
return git_config_pathname(&ssl_key, var, value);
+ if (!strcmp("http.sslkeytype", var))
+ return git_config_string(&ssl_key_type, var, value);
if (!strcmp("http.sslcapath", var))
return git_config_pathname(&ssl_capath, var, value);
if (!strcmp("http.sslcainfo", var))
@@ -295,21 +417,21 @@ static int http_options(const char *var, const char *value, void *cb)
}
if (!strcmp("http.minsessions", var)) {
- min_curl_sessions = git_config_int(var, value);
+ min_curl_sessions = git_config_int(var, value, ctx->kvi);
if (min_curl_sessions > 1)
min_curl_sessions = 1;
return 0;
}
if (!strcmp("http.maxrequests", var)) {
- max_requests = git_config_int(var, value);
+ max_requests = git_config_int(var, value, ctx->kvi);
return 0;
}
if (!strcmp("http.lowspeedlimit", var)) {
- curl_low_speed_limit = (long)git_config_int(var, value);
+ curl_low_speed_limit = (long)git_config_int(var, value, ctx->kvi);
return 0;
}
if (!strcmp("http.lowspeedtime", var)) {
- curl_low_speed_time = (long)git_config_int(var, value);
+ curl_low_speed_time = (long)git_config_int(var, value, ctx->kvi);
return 0;
}
@@ -345,7 +467,7 @@ static int http_options(const char *var, const char *value, void *cb)
}
if (!strcmp("http.postbuffer", var)) {
- http_post_buffer = git_config_ssize_t(var, value);
+ http_post_buffer = git_config_ssize_t(var, value, ctx->kvi);
if (http_post_buffer < 0)
warning(_("negative value for http.postBuffer; defaulting to %d"), LARGE_PACKET_MAX);
if (http_post_buffer < LARGE_PACKET_MAX)
@@ -416,7 +538,7 @@ static int http_options(const char *var, const char *value, void *cb)
}
/* Fall back on the default ones */
- return git_default_config(var, value, cb);
+ return git_default_config(var, value, ctx, data);
}
static int curl_empty_auth_enabled(void)
@@ -439,42 +561,63 @@ static int curl_empty_auth_enabled(void)
return 0;
}
+struct curl_slist *http_append_auth_header(const struct credential *c,
+ struct curl_slist *headers)
+{
+ if (c->authtype && c->credential) {
+ struct strbuf auth = STRBUF_INIT;
+ strbuf_addf(&auth, "Authorization: %s %s",
+ c->authtype, c->credential);
+ headers = curl_slist_append(headers, auth.buf);
+ strbuf_release(&auth);
+ }
+ return headers;
+}
+
static void init_curl_http_auth(CURL *result)
{
- if (!http_auth.username || !*http_auth.username) {
+ if ((!http_auth.username || !*http_auth.username) &&
+ (!http_auth.credential || !*http_auth.credential)) {
if (curl_empty_auth_enabled())
curl_easy_setopt(result, CURLOPT_USERPWD, ":");
return;
}
- credential_fill(&http_auth);
+ credential_fill(&http_auth, 1);
- curl_easy_setopt(result, CURLOPT_USERNAME, http_auth.username);
- curl_easy_setopt(result, CURLOPT_PASSWORD, http_auth.password);
+ if (http_auth.password) {
+ curl_easy_setopt(result, CURLOPT_USERNAME, http_auth.username);
+ curl_easy_setopt(result, CURLOPT_PASSWORD, http_auth.password);
+ }
}
/* *var must be free-able */
-static void var_override(const char **var, char *value)
+static void var_override(char **var, char *value)
{
if (value) {
- free((void *)*var);
+ free(*var);
*var = xstrdup(value);
}
}
static void set_proxyauth_name_password(CURL *result)
{
+ if (proxy_auth.password) {
curl_easy_setopt(result, CURLOPT_PROXYUSERNAME,
proxy_auth.username);
curl_easy_setopt(result, CURLOPT_PROXYPASSWORD,
proxy_auth.password);
+ } else if (proxy_auth.authtype && proxy_auth.credential) {
+ curl_easy_setopt(result, CURLOPT_PROXYHEADER,
+ http_append_auth_header(&proxy_auth, NULL));
+ }
}
static void init_curl_proxy_auth(CURL *result)
{
if (proxy_auth.username) {
- if (!proxy_auth.password)
- credential_fill(&proxy_auth);
+ if (!proxy_auth.password && !proxy_auth.credential)
+ credential_fill(&proxy_auth, 1);
set_proxyauth_name_password(result);
}
@@ -508,7 +651,7 @@ static int has_cert_password(void)
cert_auth.host = xstrdup("");
cert_auth.username = xstrdup("");
cert_auth.path = xstrdup(ssl_cert);
- credential_fill(&cert_auth);
+ credential_fill(&cert_auth, 0);
}
return 1;
}
@@ -523,7 +666,7 @@ static int has_proxy_cert_password(void)
proxy_cert_auth.host = xstrdup("");
proxy_cert_auth.username = xstrdup("");
proxy_cert_auth.path = xstrdup(http_proxy_ssl_cert);
- credential_fill(&proxy_cert_auth);
+ credential_fill(&proxy_cert_auth, 0);
}
return 1;
}
@@ -618,17 +761,43 @@ static int redact_sensitive_header(struct strbuf *header, size_t offset)
return ret;
}
+static int match_curl_h2_trace(const char *line, const char **out)
+{
+ const char *p;
+
+ /*
+ * curl prior to 8.1.0 gives us:
+ *
+ * h2h3 [<header-name>: <header-val>]
+ *
+ * Starting in 8.1.0, the first token became just "h2".
+ */
+ if (skip_iprefix(line, "h2h3 [", out) ||
+ skip_iprefix(line, "h2 [", out))
+ return 1;
+
+ /*
+ * curl 8.3.0 uses:
+ * [HTTP/2] [<stream-id>] [<header-name>: <header-val>]
+ * where <stream-id> is numeric.
+ */
+ if (skip_iprefix(line, "[HTTP/2] [", &p)) {
+ while (isdigit(*p))
+ p++;
+ if (skip_prefix(p, "] [", out))
+ return 1;
+ }
+
+ return 0;
+}
+
/* Redact headers in info */
static void redact_sensitive_info_header(struct strbuf *header)
{
const char *sensitive_header;
- /*
- * curl's h2h3 prints headers in info, e.g.:
- * h2h3 [<header-name>: <header-val>]
- */
if (trace_curl_redact &&
- skip_iprefix(header->buf, "h2h3 [", &sensitive_header)) {
+ match_curl_h2_trace(header->buf, &sensitive_header)) {
if (redact_sensitive_header(header, sensitive_header - header->buf)) {
/* redaction ate our closing bracket */
strbuf_addch(header, ']');
@@ -701,7 +870,9 @@ static void curl_dump_info(char *data, size_t size)
strbuf_release(&buf);
}
-static int curl_trace(CURL *handle, curl_infotype type, char *data, size_t size, void *userp)
+static int curl_trace(CURL *handle UNUSED, curl_infotype type,
+ char *data, size_t size,
+ void *userp UNUSED)
{
const char *text;
enum { NO_FILTER = 0, DO_FILTER = 1 };
@@ -904,10 +1075,14 @@ static CURL *get_curl_handle(void)
if (ssl_cert)
curl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert);
+ if (ssl_cert_type)
+ curl_easy_setopt(result, CURLOPT_SSLCERTTYPE, ssl_cert_type);
if (has_cert_password())
curl_easy_setopt(result, CURLOPT_KEYPASSWD, cert_auth.password);
if (ssl_key)
curl_easy_setopt(result, CURLOPT_SSLKEY, ssl_key);
+ if (ssl_key_type)
+ curl_easy_setopt(result, CURLOPT_SSLKEYTYPE, ssl_key_type);
if (ssl_capath)
curl_easy_setopt(result, CURLOPT_CAPATH, ssl_capath);
#ifdef GIT_CURL_HAVE_CURLOPT_PINNEDPUBLICKEY
@@ -1058,11 +1233,13 @@ static CURL *get_curl_handle(void)
return result;
}
-static void set_from_env(const char **var, const char *envname)
+static void set_from_env(char **var, const char *envname)
{
const char *val = getenv(envname);
- if (val)
- *var = val;
+ if (val) {
+ FREE_AND_NULL(*var);
+ *var = xstrdup(val);
+ }
}
void http_init(struct remote *remote, const char *url, int proactive_auth)
@@ -1125,8 +1302,6 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
pragma_header = curl_slist_append(http_copy_default_headers(),
"Pragma: no-cache");
- no_pragma_header = curl_slist_append(http_copy_default_headers(),
- "Pragma:");
{
char *http_max_requests = getenv("GIT_HTTP_MAX_REQUESTS");
@@ -1142,7 +1317,9 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
curl_ssl_verify = 0;
set_from_env(&ssl_cert, "GIT_SSL_CERT");
+ set_from_env(&ssl_cert_type, "GIT_SSL_CERT_TYPE");
set_from_env(&ssl_key, "GIT_SSL_KEY");
+ set_from_env(&ssl_key_type, "GIT_SSL_KEY_TYPE");
set_from_env(&ssl_capath, "GIT_SSL_CAPATH");
set_from_env(&ssl_cainfo, "GIT_SSL_CAINFO");
@@ -1208,9 +1385,6 @@ void http_cleanup(void)
curl_slist_free_all(pragma_header);
pragma_header = NULL;
- curl_slist_free_all(no_pragma_header);
- no_pragma_header = NULL;
-
curl_slist_free_all(host_resolutions);
host_resolutions = NULL;
@@ -1300,6 +1474,7 @@ struct active_request_slot *get_active_slot(void)
curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, NULL);
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, NULL);
curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, NULL);
+ curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, -1L);
curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 0);
curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 1);
@@ -1317,7 +1492,7 @@ struct active_request_slot *get_active_slot(void)
curl_easy_setopt(slot->curl, CURLOPT_IPRESOLVE, git_curl_ipresolve);
curl_easy_setopt(slot->curl, CURLOPT_HTTPAUTH, http_auth_methods);
- if (http_auth.password || curl_empty_auth_enabled())
+ if (http_auth.password || http_auth.credential || curl_empty_auth_enabled())
init_curl_http_auth(slot->curl);
return slot;
@@ -1606,7 +1781,12 @@ static int handle_curl_result(struct slot_results *results)
} else if (missing_target(results))
return HTTP_MISSING_TARGET;
else if (results->http_code == 401) {
- if (http_auth.username && http_auth.password) {
+ if ((http_auth.username && http_auth.password) ||\
+ (http_auth.authtype && http_auth.credential)) {
+ if (http_auth.multistage) {
+ credential_clear_secrets(&http_auth);
+ return HTTP_REAUTH;
+ }
credential_reject(&http_auth);
return HTTP_NOAUTH;
} else {
@@ -1748,7 +1928,7 @@ static void write_accept_language(struct strbuf *buf)
* MAX_DECIMAL_PLACES must not be larger than 3. If it is larger than
* that, q-value will be smaller than 0.001, the minimum q-value the
* HTTP specification allows. See
- * http://tools.ietf.org/html/rfc7231#section-5.3.1 for q-value.
+ * https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.1 for q-value.
*/
const int MAX_DECIMAL_PLACES = 3;
const int MAX_LANGUAGE_TAGS = 1000;
@@ -1794,7 +1974,7 @@ static void write_accept_language(struct strbuf *buf)
/* add '*' */
REALLOC_ARRAY(language_tags, num_langs + 1);
- language_tags[num_langs++] = "*"; /* it's OK; this won't be freed */
+ language_tags[num_langs++] = xstrdup("*");
/* compute decimal_places */
for (max_q = 1, decimal_places = 0;
@@ -1824,8 +2004,7 @@ static void write_accept_language(struct strbuf *buf)
}
}
- /* free language tags -- last one is a static '*' */
- for (i = 0; i < num_langs - 1; i++)
+ for (i = 0; i < num_langs; i++)
free(language_tags[i]);
free(language_tags);
}
@@ -1895,6 +2074,8 @@ static int http_request(const char *url,
fwrite_buffer);
}
+ curl_easy_setopt(slot->curl, CURLOPT_HEADERFUNCTION, fwrite_wwwauth);
+
accept_language = http_get_accept_language_header();
if (accept_language)
@@ -1912,11 +2093,15 @@ static int http_request(const char *url,
/* Add additional headers here */
if (options && options->extra_headers) {
const struct string_list_item *item;
- for_each_string_list_item(item, options->extra_headers) {
- headers = curl_slist_append(headers, item->string);
+ if (options && options->extra_headers) {
+ for_each_string_list_item(item, options->extra_headers) {
+ headers = curl_slist_append(headers, item->string);
+ }
}
}
+ headers = http_append_auth_header(&http_auth, headers);
+
curl_easy_setopt(slot->curl, CURLOPT_URL, url);
curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(slot->curl, CURLOPT_ENCODING, "");
@@ -1998,6 +2183,7 @@ static int http_request_reauth(const char *url,
void *result, int target,
struct http_get_options *options)
{
+ int i = 3;
int ret = http_request(url, result, target, options);
if (ret != HTTP_OK && ret != HTTP_REAUTH)
@@ -2011,35 +2197,35 @@ static int http_request_reauth(const char *url,
}
}
- if (ret != HTTP_REAUTH)
- return ret;
-
- /*
- * The previous request may have put cruft into our output stream; we
- * should clear it out before making our next request.
- */
- switch (target) {
- case HTTP_REQUEST_STRBUF:
- strbuf_reset(result);
- break;
- case HTTP_REQUEST_FILE:
- if (fflush(result)) {
- error_errno("unable to flush a file");
- return HTTP_START_FAILED;
- }
- rewind(result);
- if (ftruncate(fileno(result), 0) < 0) {
- error_errno("unable to truncate a file");
- return HTTP_START_FAILED;
+ while (ret == HTTP_REAUTH && --i) {
+ /*
+ * The previous request may have put cruft into our output stream; we
+ * should clear it out before making our next request.
+ */
+ switch (target) {
+ case HTTP_REQUEST_STRBUF:
+ strbuf_reset(result);
+ break;
+ case HTTP_REQUEST_FILE:
+ if (fflush(result)) {
+ error_errno("unable to flush a file");
+ return HTTP_START_FAILED;
+ }
+ rewind(result);
+ if (ftruncate(fileno(result), 0) < 0) {
+ error_errno("unable to truncate a file");
+ return HTTP_START_FAILED;
+ }
+ break;
+ default:
+ BUG("Unknown http_request target");
}
- break;
- default:
- BUG("Unknown http_request target");
- }
- credential_fill(&http_auth);
+ credential_fill(&http_auth, 1);
- return http_request(url, result, target, options);
+ ret = http_request(url, result, target, options);
+ }
+ return ret;
}
int http_get_strbuf(const char *url,
@@ -2216,6 +2402,7 @@ void release_http_pack_request(struct http_pack_request *preq)
}
preq->slot = NULL;
strbuf_release(&preq->tmpfile);
+ curl_slist_free_all(preq->headers);
free(preq->url);
free(preq);
}
@@ -2300,11 +2487,11 @@ struct http_pack_request *new_direct_http_pack_request(
}
preq->slot = get_active_slot();
+ preq->headers = object_request_headers();
curl_easy_setopt(preq->slot->curl, CURLOPT_WRITEDATA, preq->packfile);
curl_easy_setopt(preq->slot->curl, CURLOPT_WRITEFUNCTION, fwrite);
curl_easy_setopt(preq->slot->curl, CURLOPT_URL, preq->url);
- curl_easy_setopt(preq->slot->curl, CURLOPT_HTTPHEADER,
- no_pragma_header);
+ curl_easy_setopt(preq->slot->curl, CURLOPT_HTTPHEADER, preq->headers);
/*
* If there is data present from a previous transfer attempt,
@@ -2470,13 +2657,14 @@ struct http_object_request *new_http_object_request(const char *base_url,
}
freq->slot = get_active_slot();
+ freq->headers = object_request_headers();
curl_easy_setopt(freq->slot->curl, CURLOPT_WRITEDATA, freq);
curl_easy_setopt(freq->slot->curl, CURLOPT_FAILONERROR, 0);
curl_easy_setopt(freq->slot->curl, CURLOPT_WRITEFUNCTION, fwrite_sha1_file);
curl_easy_setopt(freq->slot->curl, CURLOPT_ERRORBUFFER, freq->errorstr);
curl_easy_setopt(freq->slot->curl, CURLOPT_URL, freq->url);
- curl_easy_setopt(freq->slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);
+ curl_easy_setopt(freq->slot->curl, CURLOPT_HTTPHEADER, freq->headers);
/*
* If we have successfully processed data from a previous fetch
@@ -2564,5 +2752,6 @@ void release_http_object_request(struct http_object_request *freq)
release_active_slot(freq->slot);
freq->slot = NULL;
}
+ curl_slist_free_all(freq->headers);
strbuf_release(&freq->tmpfile);
}