diff options
Diffstat (limited to 'http.c')
| -rw-r--r-- | http.c | 434 |
1 files changed, 344 insertions, 90 deletions
@@ -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; @@ -39,6 +40,7 @@ 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_cert_type; static const char *ssl_cipherlist; static const char *ssl_version; static struct { @@ -58,6 +60,7 @@ static struct { #endif }; static const char *ssl_key; +static const char *ssl_key_type; static const char *ssl_capath; static const char *curl_no_proxy; #ifdef GIT_CURL_HAVE_CURLOPT_PINNEDPUBLICKEY @@ -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; @@ -157,21 +159,19 @@ size_t fread_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_) return size / eltsize; } -curlioerr ioctl_buffer(CURL *handle, int cmd, void *clientp) +int seek_buffer(void *clientp, curl_off_t offset, int origin) { struct buffer *buffer = clientp; - switch (cmd) { - case CURLIOCMD_NOP: - return CURLIOE_OK; - - case CURLIOCMD_RESTARTREAD: - buffer->posn = 0; - return CURLIOE_OK; - - default: - return CURLIOE_UNKNOWNCMD; + if (origin != SEEK_SET) + BUG("seek_buffer only handles SEEK_SET"); + if (offset < 0 || offset >= buffer->buf.len) { + error("curl seek would be outside of buffer"); + return CURL_SEEKFUNC_FAIL; } + + buffer->posn = offset; + return CURL_SEEKFUNC_OK; } size_t fwrite_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_) @@ -183,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--; @@ -251,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); @@ -266,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)) @@ -297,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; } @@ -347,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) @@ -418,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) @@ -441,18 +561,34 @@ 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 */ @@ -466,17 +602,22 @@ static void var_override(const char **var, char *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); } @@ -510,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; } @@ -525,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; } @@ -560,13 +701,15 @@ static void set_curl_keepalive(CURL *c) } #endif -static void redact_sensitive_header(struct strbuf *header) +/* Return 1 if redactions have been made, 0 otherwise. */ +static int redact_sensitive_header(struct strbuf *header, size_t offset) { + int ret = 0; const char *sensitive_header; if (trace_curl_redact && - (skip_iprefix(header->buf, "Authorization:", &sensitive_header) || - skip_iprefix(header->buf, "Proxy-Authorization:", &sensitive_header))) { + (skip_iprefix(header->buf + offset, "Authorization:", &sensitive_header) || + skip_iprefix(header->buf + offset, "Proxy-Authorization:", &sensitive_header))) { /* The first token is the type, which is OK to log */ while (isspace(*sensitive_header)) sensitive_header++; @@ -575,8 +718,9 @@ static void redact_sensitive_header(struct strbuf *header) /* Everything else is opaque and possibly sensitive */ strbuf_setlen(header, sensitive_header - header->buf); strbuf_addstr(header, " <redacted>"); + ret = 1; } else if (trace_curl_redact && - skip_iprefix(header->buf, "Cookie:", &sensitive_header)) { + skip_iprefix(header->buf + offset, "Cookie:", &sensitive_header)) { struct strbuf redacted_header = STRBUF_INIT; const char *cookie; @@ -612,6 +756,52 @@ static void redact_sensitive_header(struct strbuf *header) strbuf_setlen(header, sensitive_header - header->buf); strbuf_addbuf(header, &redacted_header); + ret = 1; + } + 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; + + if (trace_curl_redact && + 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, ']'); + } } } @@ -629,7 +819,7 @@ static void curl_dump_header(const char *text, unsigned char *ptr, size_t size, for (header = headers; *header; header++) { if (hide_sensitive_header) - redact_sensitive_header(*header); + redact_sensitive_header(*header, 0); strbuf_insertstr((*header), 0, text); strbuf_insertstr((*header), strlen(text), ": "); strbuf_rtrim((*header)); @@ -668,14 +858,28 @@ static void curl_dump_data(const char *text, unsigned char *ptr, size_t size) strbuf_release(&out); } -static int curl_trace(CURL *handle, curl_infotype type, char *data, size_t size, void *userp) +static void curl_dump_info(char *data, size_t size) +{ + struct strbuf buf = STRBUF_INIT; + + strbuf_add(&buf, data, size); + + redact_sensitive_info_header(&buf); + trace_printf_key(&trace_curl, "== Info: %s", buf.buf); + + strbuf_release(&buf); +} + +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 }; switch (type) { case CURLINFO_TEXT: - trace_printf_key(&trace_curl, "== Info: %s", data); + curl_dump_info(data, size); break; case CURLINFO_HEADER_OUT: text = "=> Send header"; @@ -731,20 +935,37 @@ void setup_curl_trace(CURL *handle) curl_easy_setopt(handle, CURLOPT_DEBUGDATA, NULL); } -static long get_curl_allowed_protocols(int from_user) +static void proto_list_append(struct strbuf *list, const char *proto) { - long allowed_protocols = 0; + if (!list) + return; + if (list->len) + strbuf_addch(list, ','); + strbuf_addstr(list, proto); +} - if (is_transport_allowed("http", from_user)) - allowed_protocols |= CURLPROTO_HTTP; - if (is_transport_allowed("https", from_user)) - allowed_protocols |= CURLPROTO_HTTPS; - if (is_transport_allowed("ftp", from_user)) - allowed_protocols |= CURLPROTO_FTP; - if (is_transport_allowed("ftps", from_user)) - allowed_protocols |= CURLPROTO_FTPS; +static long get_curl_allowed_protocols(int from_user, struct strbuf *list) +{ + long bits = 0; - return allowed_protocols; + if (is_transport_allowed("http", from_user)) { + bits |= CURLPROTO_HTTP; + proto_list_append(list, "http"); + } + if (is_transport_allowed("https", from_user)) { + bits |= CURLPROTO_HTTPS; + proto_list_append(list, "https"); + } + if (is_transport_allowed("ftp", from_user)) { + bits |= CURLPROTO_FTP; + proto_list_append(list, "ftp"); + } + if (is_transport_allowed("ftps", from_user)) { + bits |= CURLPROTO_FTPS; + proto_list_append(list, "ftps"); + } + + return bits; } #ifdef GIT_CURL_HAVE_CURL_HTTP_VERSION_2 @@ -854,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 @@ -888,10 +1113,26 @@ static CURL *get_curl_handle(void) curl_easy_setopt(result, CURLOPT_MAXREDIRS, 20); curl_easy_setopt(result, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL); + +#ifdef GIT_CURL_HAVE_CURLOPT_PROTOCOLS_STR + { + struct strbuf buf = STRBUF_INIT; + + get_curl_allowed_protocols(0, &buf); + curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS_STR, buf.buf); + strbuf_reset(&buf); + + get_curl_allowed_protocols(-1, &buf); + curl_easy_setopt(result, CURLOPT_PROTOCOLS_STR, buf.buf); + strbuf_release(&buf); + } +#else curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS, - get_curl_allowed_protocols(0)); + get_curl_allowed_protocols(0, NULL)); curl_easy_setopt(result, CURLOPT_PROTOCOLS, - get_curl_allowed_protocols(-1)); + get_curl_allowed_protocols(-1, NULL)); +#endif + if (getenv("GIT_CURL_VERBOSE")) http_trace_curl_no_data(); setup_curl_trace(result); @@ -1059,8 +1300,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"); @@ -1076,7 +1315,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"); @@ -1142,9 +1383,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; @@ -1234,6 +1472,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); @@ -1251,7 +1490,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; @@ -1540,7 +1779,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 { @@ -1682,7 +1926,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; @@ -1829,6 +2073,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) @@ -1846,11 +2092,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, ""); @@ -1932,6 +2182,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) @@ -1945,35 +2196,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, @@ -2150,6 +2401,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); } @@ -2234,11 +2486,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, @@ -2404,13 +2656,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 @@ -2498,5 +2751,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); } |
