git/http.c

#define USE_THE_REPOSITORY_VARIABLE

#include "git-compat-util.h"
#include "git-curl-compat.h"
#include "hex.h"
#include "http.h"
#include "config.h"
#include "pack.h"
#include "run-command.h"
#include "url.h"
#include "urlmatch.h"
#include "credential.h"
#include "version.h"
#include "pkt-line.h"
#include "gettext.h"
#include "trace.h"
#include "transport.h"
#include "packfile.h"
#include "string-list.h"
#include "object-file.h"
#include "object-store-ll.h"
#include "tempfile.h"

static struct trace_key trace_curl =;
static int trace_curl_data =;
static int trace_curl_redact =;
long int git_curl_ipresolve = CURL_IPRESOLVE_WHATEVER;
int active_requests;
int http_is_verbose;
ssize_t http_post_buffer =;

static int min_curl_sessions =;
static int curl_session_count;
static int max_requests =;
static CURLM *curlm;
static CURL *curl_default;

#define PREV_BUF_SIZE

char curl_errorstr[CURL_ERROR_SIZE];

static int curl_ssl_verify =;
static int curl_ssl_try;
static char *curl_http_version;
static char *ssl_cert;
static char *ssl_cert_type;
static char *ssl_cipherlist;
static char *ssl_version;
static struct {} sslversions[] = {
	{ "sslv2", CURL_SSLVERSION_SSLv2 },
	{ "sslv3", CURL_SSLVERSION_SSLv3 },
	{ "tlsv1", CURL_SSLVERSION_TLSv1 },
#ifdef GIT_CURL_HAVE_CURL_SSLVERSION_TLSv1_0
	{ "tlsv1.0", CURL_SSLVERSION_TLSv1_0 },
	{ "tlsv1.1", CURL_SSLVERSION_TLSv1_1 },
	{ "tlsv1.2", CURL_SSLVERSION_TLSv1_2 },
#endif
#ifdef GIT_CURL_HAVE_CURL_SSLVERSION_TLSv1_3
	{ "tlsv1.3", CURL_SSLVERSION_TLSv1_3 },
#endif
};
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 char *ssl_pinnedkey;
#endif
static char *ssl_cainfo;
static long curl_low_speed_limit =;
static long curl_low_speed_time =;
static int curl_ftp_no_epsv;
static char *curl_http_proxy;
static char *http_proxy_authmethod;

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 =;
static int proxy_ssl_cert_password_required;

static struct {} proxy_authmethods[] = {
	{ "basic", CURLAUTH_BASIC },
	{ "digest", CURLAUTH_DIGEST },
	{ "negotiate", CURLAUTH_GSSNEGOTIATE },
	{ "ntlm", CURLAUTH_NTLM },
	{ "anyauth", CURLAUTH_ANY },
	/*
	 * CURLAUTH_DIGEST_IE has no corresponding command-line option in
	 * curl(1) and is not included in CURLAUTH_ANY, so we leave it out
	 * here, too
	 */
};
#ifdef CURLGSSAPI_DELEGATION_FLAG
static char *curl_deleg;
static struct {
	const char *name;
	long curl_deleg_param;
} curl_deleg_levels[] = {
	{ "none", CURLGSSAPI_DELEGATION_NONE },
	{ "policy", CURLGSSAPI_DELEGATION_POLICY_FLAG },
	{ "always", CURLGSSAPI_DELEGATION_FLAG },
};
#endif

enum proactive_auth {};

static struct credential proxy_auth =;
static const char *curl_proxyuserpwd;
static char *curl_cookie_file;
static int curl_save_cookies;
struct credential http_auth =;
static enum proactive_auth http_proactive_auth;
static char *user_agent;
static int curl_empty_auth =;

enum http_follow_config http_follow_config =;

static struct credential cert_auth =;
static int ssl_cert_password_required;
static unsigned long http_auth_methods = CURLAUTH_ANY;
static int http_auth_methods_restricted;
/* Modes for which empty_auth cannot actually help us. */
static unsigned long empty_auth_useless =
	CURLAUTH_BASIC
	| CURLAUTH_DIGEST_IE
	| CURLAUTH_DIGEST;

static struct curl_slist *pragma_header;
static struct string_list extra_http_headers =;

static struct curl_slist *host_resolutions;

static struct active_request_slot *active_queue_head;

static char *cached_accept_language;

static char *http_ssl_backend;

static int http_schannel_check_revoke =;
/*
 * With the backend being set to `schannel`, setting sslCAinfo would override
 * the Certificate Store in cURL v7.60.0 and later, which is not what we want
 * by default.
 */
static int http_schannel_use_ssl_cainfo;

static int always_auth_proactively(void)
{}

size_t fread_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_)
{}

int seek_buffer(void *clientp, curl_off_t offset, int origin)
{}

size_t fwrite_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_)
{}

/*
 * 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)
{}

static size_t fwrite_wwwauth(char *ptr, size_t eltsize, size_t nmemb, void *p UNUSED)
{}

size_t fwrite_null(char *ptr UNUSED, size_t eltsize UNUSED, size_t nmemb,
		   void *data UNUSED)
{}

static struct curl_slist *object_request_headers(void)
{}

static void closedown_active_slot(struct active_request_slot *slot)
{}

static void finish_active_slot(struct active_request_slot *slot)
{}

static void xmulti_remove_handle(struct active_request_slot *slot)
{}

static void process_curl_messages(void)
{}

static int http_options(const char *var, const char *value,
			const struct config_context *ctx, void *data)
{}

static int curl_empty_auth_enabled(void)
{}

struct curl_slist *http_append_auth_header(const struct credential *c,
					   struct curl_slist *headers)
{}

static void init_curl_http_auth(CURL *result)
{}

/* *var must be free-able */
static void var_override(char **var, char *value)
{}

static void set_proxyauth_name_password(CURL *result)
{}

static void init_curl_proxy_auth(CURL *result)
{}

static int has_cert_password(void)
{}

#ifdef GIT_CURL_HAVE_CURLOPT_PROXY_KEYPASSWD
static int has_proxy_cert_password(void)
{
	if (http_proxy_ssl_cert == NULL || proxy_ssl_cert_password_required != 1)
		return 0;
	if (!proxy_cert_auth.password) {
		proxy_cert_auth.protocol = xstrdup("cert");
		proxy_cert_auth.host = xstrdup("");
		proxy_cert_auth.username = xstrdup("");
		proxy_cert_auth.path = xstrdup(http_proxy_ssl_cert);
		credential_fill(&proxy_cert_auth, 0);
	}
	return 1;
}
#endif

#ifdef GITCURL_HAVE_CURLOPT_TCP_KEEPALIVE
static void set_curl_keepalive(CURL *c)
{
	curl_easy_setopt(c, CURLOPT_TCP_KEEPALIVE, 1);
}

#else
static int sockopt_callback(void *client, curl_socket_t fd, curlsocktype type)
{}

static void set_curl_keepalive(CURL *c)
{}
#endif

/* Return 1 if redactions have been made, 0 otherwise. */
static int redact_sensitive_header(struct strbuf *header, size_t offset)
{}

static int match_curl_h2_trace(const char *line, const char **out)
{}

/* Redact headers in info */
static void redact_sensitive_info_header(struct strbuf *header)
{}

static void curl_dump_header(const char *text, unsigned char *ptr, size_t size, int hide_sensitive_header)
{}

static void curl_dump_data(const char *text, unsigned char *ptr, size_t size)
{}

static void curl_dump_info(char *data, size_t size)
{}

static int curl_trace(CURL *handle UNUSED, curl_infotype type,
		      char *data, size_t size,
		      void *userp UNUSED)
{}

void http_trace_curl_no_data(void)
{}

void setup_curl_trace(CURL *handle)
{}

static void proto_list_append(struct strbuf *list, const char *proto)
{}

static long get_curl_allowed_protocols(int from_user, struct strbuf *list)
{}

#ifdef GIT_CURL_HAVE_CURL_HTTP_VERSION_2
static int get_curl_http_version_opt(const char *version_string, long *opt)
{
	int i;
	static struct {
		const char *name;
		long opt_token;
	} choice[] = {
		{ "HTTP/1.1", CURL_HTTP_VERSION_1_1 },
		{ "HTTP/2", CURL_HTTP_VERSION_2 }
	};

	for (i = 0; i < ARRAY_SIZE(choice); i++) {
		if (!strcmp(version_string, choice[i].name)) {
			*opt = choice[i].opt_token;
			return 0;
		}
	}

	warning("unknown value given to http.version: '%s'", version_string);
	return -1; /* not found */
}

#endif

static CURL *get_curl_handle(void)
{}

static void set_from_env(char **var, const char *envname)
{}

void http_init(struct remote *remote, const char *url, int proactive_auth)
{}

void http_cleanup(void)
{}

struct active_request_slot *get_active_slot(void)
{}

int start_active_slot(struct active_request_slot *slot)
{}

struct fill_chain {};

static struct fill_chain *fill_cfg;

void add_fill_function(void *data, int (*fill)(void *))
{}

void fill_active_slots(void)
{}

void step_active_slots(void)
{}

void run_active_slot(struct active_request_slot *slot)
{}

static void release_active_slot(struct active_request_slot *slot)
{}

void finish_all_active_slots(void)
{}

/* Helpers for modifying and creating URLs */
static inline int needs_quote(int ch)
{}

static char *quote_ref_url(const char *base, const char *ref)
{}

void append_remote_object_url(struct strbuf *buf, const char *url,
			      const char *hex,
			      int only_two_digit_prefix)
{}

char *get_remote_object_url(const char *url, const char *hex,
			    int only_two_digit_prefix)
{}

void normalize_curl_result(CURLcode *result, long http_code,
			   char *errorstr, size_t errorlen)
{}

static int handle_curl_result(struct slot_results *results)
{}

int run_one_slot(struct active_request_slot *slot,
		 struct slot_results *results)
{}

struct curl_slist *http_copy_default_headers(void)
{}

static CURLcode curlinfo_strbuf(CURL *curl, CURLINFO info, struct strbuf *buf)
{}

/*
 * Check for and extract a content-type parameter. "raw"
 * should be positioned at the start of the potential
 * parameter, with any whitespace already removed.
 *
 * "name" is the name of the parameter. The value is appended
 * to "out".
 */
static int extract_param(const char *raw, const char *name,
			 struct strbuf *out)
{}

/*
 * Extract a normalized version of the content type, with any
 * spaces suppressed, all letters lowercased, and no trailing ";"
 * or parameters.
 *
 * Note that we will silently remove even invalid whitespace. For
 * example, "text / plain" is specifically forbidden by RFC 2616,
 * but "text/plain" is the only reasonable output, and this keeps
 * our code simple.
 *
 * If the "charset" argument is not NULL, store the value of any
 * charset parameter there.
 *
 * Example:
 *   "TEXT/PLAIN; charset=utf-8" -> "text/plain", "utf-8"
 *   "text / plain" -> "text/plain"
 */
static void extract_content_type(struct strbuf *raw, struct strbuf *type,
				 struct strbuf *charset)
{}

static void write_accept_language(struct strbuf *buf)
{}

/*
 * Get an Accept-Language header which indicates user's preferred languages.
 *
 * Examples:
 *   LANGUAGE= -> ""
 *   LANGUAGE=ko:en -> "Accept-Language: ko, en; q=0.9, *; q=0.1"
 *   LANGUAGE=ko_KR.UTF-8:sr@latin -> "Accept-Language: ko-KR, sr; q=0.9, *; q=0.1"
 *   LANGUAGE=ko LANG=en_US.UTF-8 -> "Accept-Language: ko, *; q=0.1"
 *   LANGUAGE= LANG=en_US.UTF-8 -> "Accept-Language: en-US, *; q=0.1"
 *   LANGUAGE= LANG=C -> ""
 */
const char *http_get_accept_language_header(void)
{}

static void http_opt_request_remainder(CURL *curl, off_t pos)
{}

/* http_request() targets */
#define HTTP_REQUEST_STRBUF
#define HTTP_REQUEST_FILE

static int http_request(const char *url,
			void *result, int target,
			const struct http_get_options *options)
{}

/*
 * Update the "base" url to a more appropriate value, as deduced by
 * redirects seen when requesting a URL starting with "url".
 *
 * The "asked" parameter is a URL that we asked curl to access, and must begin
 * with "base".
 *
 * The "got" parameter is the URL that curl reported to us as where we ended
 * up.
 *
 * Returns 1 if we updated the base url, 0 otherwise.
 *
 * Our basic strategy is to compare "base" and "asked" to find the bits
 * specific to our request. We then strip those bits off of "got" to yield the
 * new base. So for example, if our base is "http://example.com/foo.git",
 * and we ask for "http://example.com/foo.git/info/refs", we might end up
 * with "https://other.example.com/foo.git/info/refs". We would want the
 * new URL to become "https://other.example.com/foo.git".
 *
 * Note that this assumes a sane redirect scheme. It's entirely possible
 * in the example above to end up at a URL that does not even end in
 * "info/refs".  In such a case we die. There's not much we can do, such a
 * scheme is unlikely to represent a real git repository, and failing to
 * rewrite the base opens options for malicious redirects to do funny things.
 */
static int update_url_from_redirect(struct strbuf *base,
				    const char *asked,
				    const struct strbuf *got)
{}

static int http_request_reauth(const char *url,
			       void *result, int target,
			       struct http_get_options *options)
{}

int http_get_strbuf(const char *url,
		    struct strbuf *result,
		    struct http_get_options *options)
{}

/*
 * Downloads a URL and stores the result in the given file.
 *
 * If a previous interrupted download is detected (i.e. a previous temporary
 * file is still around) the download is resumed.
 */
int http_get_file(const char *url, const char *filename,
		  struct http_get_options *options)
{}

int http_fetch_ref(const char *base, struct ref *ref)
{}

/* Helpers for fetching packs */
static char *fetch_pack_index(unsigned char *hash, const char *base_url)
{}

static int fetch_and_setup_pack_index(struct packed_git **packs_head,
	unsigned char *sha1, const char *base_url)
{}

int http_get_info_packs(const char *base_url, struct packed_git **packs_head)
{}

void release_http_pack_request(struct http_pack_request *preq)
{}

static const char *default_index_pack_args[] =;

int finish_http_pack_request(struct http_pack_request *preq)
{}

void http_install_packfile(struct packed_git *p,
			   struct packed_git **list_to_remove_from)
{}

struct http_pack_request *new_http_pack_request(
	const unsigned char *packed_git_hash, const char *base_url) {}

struct http_pack_request *new_direct_http_pack_request(
	const unsigned char *packed_git_hash, char *url)
{}

/* Helpers for fetching objects (loose) */
static size_t fwrite_sha1_file(char *ptr, size_t eltsize, size_t nmemb,
			       void *data)
{}

struct http_object_request *new_http_object_request(const char *base_url,
						    const struct object_id *oid)
{}

void process_http_object_request(struct http_object_request *freq)
{}

int finish_http_object_request(struct http_object_request *freq)
{}

void abort_http_object_request(struct http_object_request **freq_p)
{}

void release_http_object_request(struct http_object_request **freq_p)
{}