git

Форк
0
/
http.c 
2840 строк · 75.1 Кб
1
#define USE_THE_REPOSITORY_VARIABLE
2

3
#include "git-compat-util.h"
4
#include "git-curl-compat.h"
5
#include "hex.h"
6
#include "http.h"
7
#include "config.h"
8
#include "pack.h"
9
#include "run-command.h"
10
#include "url.h"
11
#include "urlmatch.h"
12
#include "credential.h"
13
#include "version.h"
14
#include "pkt-line.h"
15
#include "gettext.h"
16
#include "trace.h"
17
#include "transport.h"
18
#include "packfile.h"
19
#include "string-list.h"
20
#include "object-file.h"
21
#include "object-store-ll.h"
22

23
static struct trace_key trace_curl = TRACE_KEY_INIT(CURL);
24
static int trace_curl_data = 1;
25
static int trace_curl_redact = 1;
26
long int git_curl_ipresolve = CURL_IPRESOLVE_WHATEVER;
27
int active_requests;
28
int http_is_verbose;
29
ssize_t http_post_buffer = 16 * LARGE_PACKET_MAX;
30

31
static int min_curl_sessions = 1;
32
static int curl_session_count;
33
static int max_requests = -1;
34
static CURLM *curlm;
35
static CURL *curl_default;
36

37
#define PREV_BUF_SIZE 4096
38

39
char curl_errorstr[CURL_ERROR_SIZE];
40

41
static int curl_ssl_verify = -1;
42
static int curl_ssl_try;
43
static char *curl_http_version;
44
static char *ssl_cert;
45
static char *ssl_cert_type;
46
static char *ssl_cipherlist;
47
static char *ssl_version;
48
static struct {
49
	const char *name;
50
	long ssl_version;
51
} sslversions[] = {
52
	{ "sslv2", CURL_SSLVERSION_SSLv2 },
53
	{ "sslv3", CURL_SSLVERSION_SSLv3 },
54
	{ "tlsv1", CURL_SSLVERSION_TLSv1 },
55
#ifdef GIT_CURL_HAVE_CURL_SSLVERSION_TLSv1_0
56
	{ "tlsv1.0", CURL_SSLVERSION_TLSv1_0 },
57
	{ "tlsv1.1", CURL_SSLVERSION_TLSv1_1 },
58
	{ "tlsv1.2", CURL_SSLVERSION_TLSv1_2 },
59
#endif
60
#ifdef GIT_CURL_HAVE_CURL_SSLVERSION_TLSv1_3
61
	{ "tlsv1.3", CURL_SSLVERSION_TLSv1_3 },
62
#endif
63
};
64
static char *ssl_key;
65
static char *ssl_key_type;
66
static char *ssl_capath;
67
static char *curl_no_proxy;
68
#ifdef GIT_CURL_HAVE_CURLOPT_PINNEDPUBLICKEY
69
static char *ssl_pinnedkey;
70
#endif
71
static char *ssl_cainfo;
72
static long curl_low_speed_limit = -1;
73
static long curl_low_speed_time = -1;
74
static int curl_ftp_no_epsv;
75
static char *curl_http_proxy;
76
static char *http_proxy_authmethod;
77

78
static char *http_proxy_ssl_cert;
79
static char *http_proxy_ssl_key;
80
static char *http_proxy_ssl_ca_info;
81
static struct credential proxy_cert_auth = CREDENTIAL_INIT;
82
static int proxy_ssl_cert_password_required;
83

84
static struct {
85
	const char *name;
86
	long curlauth_param;
87
} proxy_authmethods[] = {
88
	{ "basic", CURLAUTH_BASIC },
89
	{ "digest", CURLAUTH_DIGEST },
90
	{ "negotiate", CURLAUTH_GSSNEGOTIATE },
91
	{ "ntlm", CURLAUTH_NTLM },
92
	{ "anyauth", CURLAUTH_ANY },
93
	/*
94
	 * CURLAUTH_DIGEST_IE has no corresponding command-line option in
95
	 * curl(1) and is not included in CURLAUTH_ANY, so we leave it out
96
	 * here, too
97
	 */
98
};
99
#ifdef CURLGSSAPI_DELEGATION_FLAG
100
static char *curl_deleg;
101
static struct {
102
	const char *name;
103
	long curl_deleg_param;
104
} curl_deleg_levels[] = {
105
	{ "none", CURLGSSAPI_DELEGATION_NONE },
106
	{ "policy", CURLGSSAPI_DELEGATION_POLICY_FLAG },
107
	{ "always", CURLGSSAPI_DELEGATION_FLAG },
108
};
109
#endif
110

111
enum proactive_auth {
112
	PROACTIVE_AUTH_NONE = 0,
113
	PROACTIVE_AUTH_IF_CREDENTIALS,
114
	PROACTIVE_AUTH_AUTO,
115
	PROACTIVE_AUTH_BASIC,
116
};
117

118
static struct credential proxy_auth = CREDENTIAL_INIT;
119
static const char *curl_proxyuserpwd;
120
static char *curl_cookie_file;
121
static int curl_save_cookies;
122
struct credential http_auth = CREDENTIAL_INIT;
123
static enum proactive_auth http_proactive_auth;
124
static char *user_agent;
125
static int curl_empty_auth = -1;
126

127
enum http_follow_config http_follow_config = HTTP_FOLLOW_INITIAL;
128

129
static struct credential cert_auth = CREDENTIAL_INIT;
130
static int ssl_cert_password_required;
131
static unsigned long http_auth_methods = CURLAUTH_ANY;
132
static int http_auth_methods_restricted;
133
/* Modes for which empty_auth cannot actually help us. */
134
static unsigned long empty_auth_useless =
135
	CURLAUTH_BASIC
136
	| CURLAUTH_DIGEST_IE
137
	| CURLAUTH_DIGEST;
138

139
static struct curl_slist *pragma_header;
140
static struct string_list extra_http_headers = STRING_LIST_INIT_DUP;
141

142
static struct curl_slist *host_resolutions;
143

144
static struct active_request_slot *active_queue_head;
145

146
static char *cached_accept_language;
147

148
static char *http_ssl_backend;
149

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

158
static int always_auth_proactively(void)
159
{
160
	return http_proactive_auth != PROACTIVE_AUTH_NONE &&
161
	       http_proactive_auth != PROACTIVE_AUTH_IF_CREDENTIALS;
162
}
163

164
size_t fread_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_)
165
{
166
	size_t size = eltsize * nmemb;
167
	struct buffer *buffer = buffer_;
168

169
	if (size > buffer->buf.len - buffer->posn)
170
		size = buffer->buf.len - buffer->posn;
171
	memcpy(ptr, buffer->buf.buf + buffer->posn, size);
172
	buffer->posn += size;
173

174
	return size / eltsize;
175
}
176

177
int seek_buffer(void *clientp, curl_off_t offset, int origin)
178
{
179
	struct buffer *buffer = clientp;
180

181
	if (origin != SEEK_SET)
182
		BUG("seek_buffer only handles SEEK_SET");
183
	if (offset < 0 || offset >= buffer->buf.len) {
184
		error("curl seek would be outside of buffer");
185
		return CURL_SEEKFUNC_FAIL;
186
	}
187

188
	buffer->posn = offset;
189
	return CURL_SEEKFUNC_OK;
190
}
191

192
size_t fwrite_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_)
193
{
194
	size_t size = eltsize * nmemb;
195
	struct strbuf *buffer = buffer_;
196

197
	strbuf_add(buffer, ptr, size);
198
	return nmemb;
199
}
200

201
/*
202
 * A folded header continuation line starts with any number of spaces or
203
 * horizontal tab characters (SP or HTAB) as per RFC 7230 section 3.2.
204
 * It is not a continuation line if the line starts with any other character.
205
 */
206
static inline int is_hdr_continuation(const char *ptr, const size_t size)
207
{
208
	return size && (*ptr == ' ' || *ptr == '\t');
209
}
210

211
static size_t fwrite_wwwauth(char *ptr, size_t eltsize, size_t nmemb, void *p UNUSED)
212
{
213
	size_t size = eltsize * nmemb;
214
	struct strvec *values = &http_auth.wwwauth_headers;
215
	struct strbuf buf = STRBUF_INIT;
216
	const char *val;
217
	size_t val_len;
218

219
	/*
220
	 * Header lines may not come NULL-terminated from libcurl so we must
221
	 * limit all scans to the maximum length of the header line, or leverage
222
	 * strbufs for all operations.
223
	 *
224
	 * In addition, it is possible that header values can be split over
225
	 * multiple lines as per RFC 7230. 'Line folding' has been deprecated
226
	 * but older servers may still emit them. A continuation header field
227
	 * value is identified as starting with a space or horizontal tab.
228
	 *
229
	 * The formal definition of a header field as given in RFC 7230 is:
230
	 *
231
	 * header-field   = field-name ":" OWS field-value OWS
232
	 *
233
	 * field-name     = token
234
	 * field-value    = *( field-content / obs-fold )
235
	 * field-content  = field-vchar [ 1*( SP / HTAB ) field-vchar ]
236
	 * field-vchar    = VCHAR / obs-text
237
	 *
238
	 * obs-fold       = CRLF 1*( SP / HTAB )
239
	 *                ; obsolete line folding
240
	 *                ; see Section 3.2.4
241
	 */
242

243
	/* Start of a new WWW-Authenticate header */
244
	if (skip_iprefix_mem(ptr, size, "www-authenticate:", &val, &val_len)) {
245
		strbuf_add(&buf, val, val_len);
246

247
		/*
248
		 * Strip the CRLF that should be present at the end of each
249
		 * field as well as any trailing or leading whitespace from the
250
		 * value.
251
		 */
252
		strbuf_trim(&buf);
253

254
		strvec_push(values, buf.buf);
255
		http_auth.header_is_last_match = 1;
256
		goto exit;
257
	}
258

259
	/*
260
	 * This line could be a continuation of the previously matched header
261
	 * field. If this is the case then we should append this value to the
262
	 * end of the previously consumed value.
263
	 */
264
	if (http_auth.header_is_last_match && is_hdr_continuation(ptr, size)) {
265
		/*
266
		 * Trim the CRLF and any leading or trailing from this line.
267
		 */
268
		strbuf_add(&buf, ptr, size);
269
		strbuf_trim(&buf);
270

271
		/*
272
		 * At this point we should always have at least one existing
273
		 * value, even if it is empty. Do not bother appending the new
274
		 * value if this continuation header is itself empty.
275
		 */
276
		if (!values->nr) {
277
			BUG("should have at least one existing header value");
278
		} else if (buf.len) {
279
			char *prev = xstrdup(values->v[values->nr - 1]);
280

281
			/* Join two non-empty values with a single space. */
282
			const char *const sp = *prev ? " " : "";
283

284
			strvec_pop(values);
285
			strvec_pushf(values, "%s%s%s", prev, sp, buf.buf);
286
			free(prev);
287
		}
288

289
		goto exit;
290
	}
291

292
	/* Not a continuation of a previously matched auth header line. */
293
	http_auth.header_is_last_match = 0;
294

295
	/*
296
	 * If this is a HTTP status line and not a header field, this signals
297
	 * a different HTTP response. libcurl writes all the output of all
298
	 * response headers of all responses, including redirects.
299
	 * We only care about the last HTTP request response's headers so clear
300
	 * the existing array.
301
	 */
302
	if (skip_iprefix_mem(ptr, size, "http/", &val, &val_len))
303
		strvec_clear(values);
304

305
exit:
306
	strbuf_release(&buf);
307
	return size;
308
}
309

310
size_t fwrite_null(char *ptr UNUSED, size_t eltsize UNUSED, size_t nmemb,
311
		   void *data UNUSED)
312
{
313
	return nmemb;
314
}
315

316
static struct curl_slist *object_request_headers(void)
317
{
318
	return curl_slist_append(http_copy_default_headers(), "Pragma:");
319
}
320

321
static void closedown_active_slot(struct active_request_slot *slot)
322
{
323
	active_requests--;
324
	slot->in_use = 0;
325
}
326

327
static void finish_active_slot(struct active_request_slot *slot)
328
{
329
	closedown_active_slot(slot);
330
	curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE, &slot->http_code);
331

332
	if (slot->finished)
333
		(*slot->finished) = 1;
334

335
	/* Store slot results so they can be read after the slot is reused */
336
	if (slot->results) {
337
		slot->results->curl_result = slot->curl_result;
338
		slot->results->http_code = slot->http_code;
339
		curl_easy_getinfo(slot->curl, CURLINFO_HTTPAUTH_AVAIL,
340
				  &slot->results->auth_avail);
341

342
		curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CONNECTCODE,
343
			&slot->results->http_connectcode);
344
	}
345

346
	/* Run callback if appropriate */
347
	if (slot->callback_func)
348
		slot->callback_func(slot->callback_data);
349
}
350

351
static void xmulti_remove_handle(struct active_request_slot *slot)
352
{
353
	curl_multi_remove_handle(curlm, slot->curl);
354
}
355

356
static void process_curl_messages(void)
357
{
358
	int num_messages;
359
	struct active_request_slot *slot;
360
	CURLMsg *curl_message = curl_multi_info_read(curlm, &num_messages);
361

362
	while (curl_message != NULL) {
363
		if (curl_message->msg == CURLMSG_DONE) {
364
			int curl_result = curl_message->data.result;
365
			slot = active_queue_head;
366
			while (slot != NULL &&
367
			       slot->curl != curl_message->easy_handle)
368
				slot = slot->next;
369
			if (slot) {
370
				xmulti_remove_handle(slot);
371
				slot->curl_result = curl_result;
372
				finish_active_slot(slot);
373
			} else {
374
				fprintf(stderr, "Received DONE message for unknown request!\n");
375
			}
376
		} else {
377
			fprintf(stderr, "Unknown CURL message received: %d\n",
378
				(int)curl_message->msg);
379
		}
380
		curl_message = curl_multi_info_read(curlm, &num_messages);
381
	}
382
}
383

384
static int http_options(const char *var, const char *value,
385
			const struct config_context *ctx, void *data)
386
{
387
	if (!strcmp("http.version", var)) {
388
		return git_config_string(&curl_http_version, var, value);
389
	}
390
	if (!strcmp("http.sslverify", var)) {
391
		curl_ssl_verify = git_config_bool(var, value);
392
		return 0;
393
	}
394
	if (!strcmp("http.sslcipherlist", var))
395
		return git_config_string(&ssl_cipherlist, var, value);
396
	if (!strcmp("http.sslversion", var))
397
		return git_config_string(&ssl_version, var, value);
398
	if (!strcmp("http.sslcert", var))
399
		return git_config_pathname(&ssl_cert, var, value);
400
	if (!strcmp("http.sslcerttype", var))
401
		return git_config_string(&ssl_cert_type, var, value);
402
	if (!strcmp("http.sslkey", var))
403
		return git_config_pathname(&ssl_key, var, value);
404
	if (!strcmp("http.sslkeytype", var))
405
		return git_config_string(&ssl_key_type, var, value);
406
	if (!strcmp("http.sslcapath", var))
407
		return git_config_pathname(&ssl_capath, var, value);
408
	if (!strcmp("http.sslcainfo", var))
409
		return git_config_pathname(&ssl_cainfo, var, value);
410
	if (!strcmp("http.sslcertpasswordprotected", var)) {
411
		ssl_cert_password_required = git_config_bool(var, value);
412
		return 0;
413
	}
414
	if (!strcmp("http.ssltry", var)) {
415
		curl_ssl_try = git_config_bool(var, value);
416
		return 0;
417
	}
418
	if (!strcmp("http.sslbackend", var)) {
419
		free(http_ssl_backend);
420
		http_ssl_backend = xstrdup_or_null(value);
421
		return 0;
422
	}
423

424
	if (!strcmp("http.schannelcheckrevoke", var)) {
425
		http_schannel_check_revoke = git_config_bool(var, value);
426
		return 0;
427
	}
428

429
	if (!strcmp("http.schannelusesslcainfo", var)) {
430
		http_schannel_use_ssl_cainfo = git_config_bool(var, value);
431
		return 0;
432
	}
433

434
	if (!strcmp("http.minsessions", var)) {
435
		min_curl_sessions = git_config_int(var, value, ctx->kvi);
436
		if (min_curl_sessions > 1)
437
			min_curl_sessions = 1;
438
		return 0;
439
	}
440
	if (!strcmp("http.maxrequests", var)) {
441
		max_requests = git_config_int(var, value, ctx->kvi);
442
		return 0;
443
	}
444
	if (!strcmp("http.lowspeedlimit", var)) {
445
		curl_low_speed_limit = (long)git_config_int(var, value, ctx->kvi);
446
		return 0;
447
	}
448
	if (!strcmp("http.lowspeedtime", var)) {
449
		curl_low_speed_time = (long)git_config_int(var, value, ctx->kvi);
450
		return 0;
451
	}
452

453
	if (!strcmp("http.noepsv", var)) {
454
		curl_ftp_no_epsv = git_config_bool(var, value);
455
		return 0;
456
	}
457
	if (!strcmp("http.proxy", var))
458
		return git_config_string(&curl_http_proxy, var, value);
459

460
	if (!strcmp("http.proxyauthmethod", var))
461
		return git_config_string(&http_proxy_authmethod, var, value);
462

463
	if (!strcmp("http.proxysslcert", var))
464
		return git_config_string(&http_proxy_ssl_cert, var, value);
465

466
	if (!strcmp("http.proxysslkey", var))
467
		return git_config_string(&http_proxy_ssl_key, var, value);
468

469
	if (!strcmp("http.proxysslcainfo", var))
470
		return git_config_string(&http_proxy_ssl_ca_info, var, value);
471

472
	if (!strcmp("http.proxysslcertpasswordprotected", var)) {
473
		proxy_ssl_cert_password_required = git_config_bool(var, value);
474
		return 0;
475
	}
476

477
	if (!strcmp("http.cookiefile", var))
478
		return git_config_pathname(&curl_cookie_file, var, value);
479
	if (!strcmp("http.savecookies", var)) {
480
		curl_save_cookies = git_config_bool(var, value);
481
		return 0;
482
	}
483

484
	if (!strcmp("http.postbuffer", var)) {
485
		http_post_buffer = git_config_ssize_t(var, value, ctx->kvi);
486
		if (http_post_buffer < 0)
487
			warning(_("negative value for http.postBuffer; defaulting to %d"), LARGE_PACKET_MAX);
488
		if (http_post_buffer < LARGE_PACKET_MAX)
489
			http_post_buffer = LARGE_PACKET_MAX;
490
		return 0;
491
	}
492

493
	if (!strcmp("http.useragent", var))
494
		return git_config_string(&user_agent, var, value);
495

496
	if (!strcmp("http.emptyauth", var)) {
497
		if (value && !strcmp("auto", value))
498
			curl_empty_auth = -1;
499
		else
500
			curl_empty_auth = git_config_bool(var, value);
501
		return 0;
502
	}
503

504
	if (!strcmp("http.delegation", var)) {
505
#ifdef CURLGSSAPI_DELEGATION_FLAG
506
		return git_config_string(&curl_deleg, var, value);
507
#else
508
		warning(_("Delegation control is not supported with cURL < 7.22.0"));
509
		return 0;
510
#endif
511
	}
512

513
	if (!strcmp("http.pinnedpubkey", var)) {
514
#ifdef GIT_CURL_HAVE_CURLOPT_PINNEDPUBLICKEY
515
		return git_config_pathname(&ssl_pinnedkey, var, value);
516
#else
517
		warning(_("Public key pinning not supported with cURL < 7.39.0"));
518
		return 0;
519
#endif
520
	}
521

522
	if (!strcmp("http.extraheader", var)) {
523
		if (!value) {
524
			return config_error_nonbool(var);
525
		} else if (!*value) {
526
			string_list_clear(&extra_http_headers, 0);
527
		} else {
528
			string_list_append(&extra_http_headers, value);
529
		}
530
		return 0;
531
	}
532

533
	if (!strcmp("http.curloptresolve", var)) {
534
		if (!value) {
535
			return config_error_nonbool(var);
536
		} else if (!*value) {
537
			curl_slist_free_all(host_resolutions);
538
			host_resolutions = NULL;
539
		} else {
540
			host_resolutions = curl_slist_append(host_resolutions, value);
541
		}
542
		return 0;
543
	}
544

545
	if (!strcmp("http.followredirects", var)) {
546
		if (value && !strcmp(value, "initial"))
547
			http_follow_config = HTTP_FOLLOW_INITIAL;
548
		else if (git_config_bool(var, value))
549
			http_follow_config = HTTP_FOLLOW_ALWAYS;
550
		else
551
			http_follow_config = HTTP_FOLLOW_NONE;
552
		return 0;
553
	}
554

555
	if (!strcmp("http.proactiveauth", var)) {
556
		if (!value)
557
			return config_error_nonbool(var);
558
		if (!strcmp(value, "auto"))
559
			http_proactive_auth = PROACTIVE_AUTH_AUTO;
560
		else if (!strcmp(value, "basic"))
561
			http_proactive_auth = PROACTIVE_AUTH_BASIC;
562
		else if (!strcmp(value, "none"))
563
			http_proactive_auth = PROACTIVE_AUTH_NONE;
564
		else
565
			warning(_("Unknown value for http.proactiveauth"));
566
		return 0;
567
	}
568

569
	/* Fall back on the default ones */
570
	return git_default_config(var, value, ctx, data);
571
}
572

573
static int curl_empty_auth_enabled(void)
574
{
575
	if (curl_empty_auth >= 0)
576
		return curl_empty_auth;
577

578
	/*
579
	 * In the automatic case, kick in the empty-auth
580
	 * hack as long as we would potentially try some
581
	 * method more exotic than "Basic" or "Digest".
582
	 *
583
	 * But only do this when this is our second or
584
	 * subsequent request, as by then we know what
585
	 * methods are available.
586
	 */
587
	if (http_auth_methods_restricted &&
588
	    (http_auth_methods & ~empty_auth_useless))
589
		return 1;
590
	return 0;
591
}
592

593
struct curl_slist *http_append_auth_header(const struct credential *c,
594
					   struct curl_slist *headers)
595
{
596
	if (c->authtype && c->credential) {
597
		struct strbuf auth = STRBUF_INIT;
598
		strbuf_addf(&auth, "Authorization: %s %s",
599
			    c->authtype, c->credential);
600
		headers = curl_slist_append(headers, auth.buf);
601
		strbuf_release(&auth);
602
	}
603
	return headers;
604
}
605

606
static void init_curl_http_auth(CURL *result)
607
{
608
	if ((!http_auth.username || !*http_auth.username) &&
609
	    (!http_auth.credential || !*http_auth.credential)) {
610
		int empty_auth = curl_empty_auth_enabled();
611
		if ((empty_auth != -1 && !always_auth_proactively()) || empty_auth == 1) {
612
			curl_easy_setopt(result, CURLOPT_USERPWD, ":");
613
			return;
614
		} else if (!always_auth_proactively()) {
615
			return;
616
		} else if (http_proactive_auth == PROACTIVE_AUTH_BASIC) {
617
			strvec_push(&http_auth.wwwauth_headers, "Basic");
618
		}
619
	}
620

621
	credential_fill(&http_auth, 1);
622

623
	if (http_auth.password) {
624
		if (always_auth_proactively()) {
625
			/*
626
			 * We got a credential without an authtype and we don't
627
			 * know what's available.  Since our only two options at
628
			 * the moment are auto (which defaults to basic) and
629
			 * basic, use basic for now.
630
			 */
631
			curl_easy_setopt(result, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
632
		}
633
		curl_easy_setopt(result, CURLOPT_USERNAME, http_auth.username);
634
		curl_easy_setopt(result, CURLOPT_PASSWORD, http_auth.password);
635
	}
636
}
637

638
/* *var must be free-able */
639
static void var_override(char **var, char *value)
640
{
641
	if (value) {
642
		free(*var);
643
		*var = xstrdup(value);
644
	}
645
}
646

647
static void set_proxyauth_name_password(CURL *result)
648
{
649
	if (proxy_auth.password) {
650
		curl_easy_setopt(result, CURLOPT_PROXYUSERNAME,
651
			proxy_auth.username);
652
		curl_easy_setopt(result, CURLOPT_PROXYPASSWORD,
653
			proxy_auth.password);
654
	} else if (proxy_auth.authtype && proxy_auth.credential) {
655
		curl_easy_setopt(result, CURLOPT_PROXYHEADER,
656
				 http_append_auth_header(&proxy_auth, NULL));
657
	}
658
}
659

660
static void init_curl_proxy_auth(CURL *result)
661
{
662
	if (proxy_auth.username) {
663
		if (!proxy_auth.password && !proxy_auth.credential)
664
			credential_fill(&proxy_auth, 1);
665
		set_proxyauth_name_password(result);
666
	}
667

668
	var_override(&http_proxy_authmethod, getenv("GIT_HTTP_PROXY_AUTHMETHOD"));
669

670
	if (http_proxy_authmethod) {
671
		int i;
672
		for (i = 0; i < ARRAY_SIZE(proxy_authmethods); i++) {
673
			if (!strcmp(http_proxy_authmethod, proxy_authmethods[i].name)) {
674
				curl_easy_setopt(result, CURLOPT_PROXYAUTH,
675
						proxy_authmethods[i].curlauth_param);
676
				break;
677
			}
678
		}
679
		if (i == ARRAY_SIZE(proxy_authmethods)) {
680
			warning("unsupported proxy authentication method %s: using anyauth",
681
					http_proxy_authmethod);
682
			curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
683
		}
684
	}
685
	else
686
		curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
687
}
688

689
static int has_cert_password(void)
690
{
691
	if (ssl_cert == NULL || ssl_cert_password_required != 1)
692
		return 0;
693
	if (!cert_auth.password) {
694
		cert_auth.protocol = xstrdup("cert");
695
		cert_auth.host = xstrdup("");
696
		cert_auth.username = xstrdup("");
697
		cert_auth.path = xstrdup(ssl_cert);
698
		credential_fill(&cert_auth, 0);
699
	}
700
	return 1;
701
}
702

703
#ifdef GIT_CURL_HAVE_CURLOPT_PROXY_KEYPASSWD
704
static int has_proxy_cert_password(void)
705
{
706
	if (http_proxy_ssl_cert == NULL || proxy_ssl_cert_password_required != 1)
707
		return 0;
708
	if (!proxy_cert_auth.password) {
709
		proxy_cert_auth.protocol = xstrdup("cert");
710
		proxy_cert_auth.host = xstrdup("");
711
		proxy_cert_auth.username = xstrdup("");
712
		proxy_cert_auth.path = xstrdup(http_proxy_ssl_cert);
713
		credential_fill(&proxy_cert_auth, 0);
714
	}
715
	return 1;
716
}
717
#endif
718

719
#ifdef GITCURL_HAVE_CURLOPT_TCP_KEEPALIVE
720
static void set_curl_keepalive(CURL *c)
721
{
722
	curl_easy_setopt(c, CURLOPT_TCP_KEEPALIVE, 1);
723
}
724

725
#else
726
static int sockopt_callback(void *client, curl_socket_t fd, curlsocktype type)
727
{
728
	int ka = 1;
729
	int rc;
730
	socklen_t len = (socklen_t)sizeof(ka);
731

732
	if (type != CURLSOCKTYPE_IPCXN)
733
		return 0;
734

735
	rc = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&ka, len);
736
	if (rc < 0)
737
		warning_errno("unable to set SO_KEEPALIVE on socket");
738

739
	return CURL_SOCKOPT_OK;
740
}
741

742
static void set_curl_keepalive(CURL *c)
743
{
744
	curl_easy_setopt(c, CURLOPT_SOCKOPTFUNCTION, sockopt_callback);
745
}
746
#endif
747

748
/* Return 1 if redactions have been made, 0 otherwise. */
749
static int redact_sensitive_header(struct strbuf *header, size_t offset)
750
{
751
	int ret = 0;
752
	const char *sensitive_header;
753

754
	if (trace_curl_redact &&
755
	    (skip_iprefix(header->buf + offset, "Authorization:", &sensitive_header) ||
756
	     skip_iprefix(header->buf + offset, "Proxy-Authorization:", &sensitive_header))) {
757
		/* The first token is the type, which is OK to log */
758
		while (isspace(*sensitive_header))
759
			sensitive_header++;
760
		while (*sensitive_header && !isspace(*sensitive_header))
761
			sensitive_header++;
762
		/* Everything else is opaque and possibly sensitive */
763
		strbuf_setlen(header,  sensitive_header - header->buf);
764
		strbuf_addstr(header, " <redacted>");
765
		ret = 1;
766
	} else if (trace_curl_redact &&
767
		   skip_iprefix(header->buf + offset, "Cookie:", &sensitive_header)) {
768
		struct strbuf redacted_header = STRBUF_INIT;
769
		const char *cookie;
770

771
		while (isspace(*sensitive_header))
772
			sensitive_header++;
773

774
		cookie = sensitive_header;
775

776
		while (cookie) {
777
			char *equals;
778
			char *semicolon = strstr(cookie, "; ");
779
			if (semicolon)
780
				*semicolon = 0;
781
			equals = strchrnul(cookie, '=');
782
			if (!equals) {
783
				/* invalid cookie, just append and continue */
784
				strbuf_addstr(&redacted_header, cookie);
785
				continue;
786
			}
787
			strbuf_add(&redacted_header, cookie, equals - cookie);
788
			strbuf_addstr(&redacted_header, "=<redacted>");
789
			if (semicolon) {
790
				/*
791
				 * There are more cookies. (Or, for some
792
				 * reason, the input string ends in "; ".)
793
				 */
794
				strbuf_addstr(&redacted_header, "; ");
795
				cookie = semicolon + strlen("; ");
796
			} else {
797
				cookie = NULL;
798
			}
799
		}
800

801
		strbuf_setlen(header, sensitive_header - header->buf);
802
		strbuf_addbuf(header, &redacted_header);
803
		ret = 1;
804
	}
805
	return ret;
806
}
807

808
static int match_curl_h2_trace(const char *line, const char **out)
809
{
810
	const char *p;
811

812
	/*
813
	 * curl prior to 8.1.0 gives us:
814
	 *
815
	 *     h2h3 [<header-name>: <header-val>]
816
	 *
817
	 * Starting in 8.1.0, the first token became just "h2".
818
	 */
819
	if (skip_iprefix(line, "h2h3 [", out) ||
820
	    skip_iprefix(line, "h2 [", out))
821
		return 1;
822

823
	/*
824
	 * curl 8.3.0 uses:
825
	 *   [HTTP/2] [<stream-id>] [<header-name>: <header-val>]
826
	 * where <stream-id> is numeric.
827
	 */
828
	if (skip_iprefix(line, "[HTTP/2] [", &p)) {
829
		while (isdigit(*p))
830
			p++;
831
		if (skip_prefix(p, "] [", out))
832
			return 1;
833
	}
834

835
	return 0;
836
}
837

838
/* Redact headers in info */
839
static void redact_sensitive_info_header(struct strbuf *header)
840
{
841
	const char *sensitive_header;
842

843
	if (trace_curl_redact &&
844
	    match_curl_h2_trace(header->buf, &sensitive_header)) {
845
		if (redact_sensitive_header(header, sensitive_header - header->buf)) {
846
			/* redaction ate our closing bracket */
847
			strbuf_addch(header, ']');
848
		}
849
	}
850
}
851

852
static void curl_dump_header(const char *text, unsigned char *ptr, size_t size, int hide_sensitive_header)
853
{
854
	struct strbuf out = STRBUF_INIT;
855
	struct strbuf **headers, **header;
856

857
	strbuf_addf(&out, "%s, %10.10ld bytes (0x%8.8lx)\n",
858
		text, (long)size, (long)size);
859
	trace_strbuf(&trace_curl, &out);
860
	strbuf_reset(&out);
861
	strbuf_add(&out, ptr, size);
862
	headers = strbuf_split_max(&out, '\n', 0);
863

864
	for (header = headers; *header; header++) {
865
		if (hide_sensitive_header)
866
			redact_sensitive_header(*header, 0);
867
		strbuf_insertstr((*header), 0, text);
868
		strbuf_insertstr((*header), strlen(text), ": ");
869
		strbuf_rtrim((*header));
870
		strbuf_addch((*header), '\n');
871
		trace_strbuf(&trace_curl, (*header));
872
	}
873
	strbuf_list_free(headers);
874
	strbuf_release(&out);
875
}
876

877
static void curl_dump_data(const char *text, unsigned char *ptr, size_t size)
878
{
879
	size_t i;
880
	struct strbuf out = STRBUF_INIT;
881
	unsigned int width = 60;
882

883
	strbuf_addf(&out, "%s, %10.10ld bytes (0x%8.8lx)\n",
884
		text, (long)size, (long)size);
885
	trace_strbuf(&trace_curl, &out);
886

887
	for (i = 0; i < size; i += width) {
888
		size_t w;
889

890
		strbuf_reset(&out);
891
		strbuf_addf(&out, "%s: ", text);
892
		for (w = 0; (w < width) && (i + w < size); w++) {
893
			unsigned char ch = ptr[i + w];
894

895
			strbuf_addch(&out,
896
				       (ch >= 0x20) && (ch < 0x80)
897
				       ? ch : '.');
898
		}
899
		strbuf_addch(&out, '\n');
900
		trace_strbuf(&trace_curl, &out);
901
	}
902
	strbuf_release(&out);
903
}
904

905
static void curl_dump_info(char *data, size_t size)
906
{
907
	struct strbuf buf = STRBUF_INIT;
908

909
	strbuf_add(&buf, data, size);
910

911
	redact_sensitive_info_header(&buf);
912
	trace_printf_key(&trace_curl, "== Info: %s", buf.buf);
913

914
	strbuf_release(&buf);
915
}
916

917
static int curl_trace(CURL *handle UNUSED, curl_infotype type,
918
		      char *data, size_t size,
919
		      void *userp UNUSED)
920
{
921
	const char *text;
922
	enum { NO_FILTER = 0, DO_FILTER = 1 };
923

924
	switch (type) {
925
	case CURLINFO_TEXT:
926
		curl_dump_info(data, size);
927
		break;
928
	case CURLINFO_HEADER_OUT:
929
		text = "=> Send header";
930
		curl_dump_header(text, (unsigned char *)data, size, DO_FILTER);
931
		break;
932
	case CURLINFO_DATA_OUT:
933
		if (trace_curl_data) {
934
			text = "=> Send data";
935
			curl_dump_data(text, (unsigned char *)data, size);
936
		}
937
		break;
938
	case CURLINFO_SSL_DATA_OUT:
939
		if (trace_curl_data) {
940
			text = "=> Send SSL data";
941
			curl_dump_data(text, (unsigned char *)data, size);
942
		}
943
		break;
944
	case CURLINFO_HEADER_IN:
945
		text = "<= Recv header";
946
		curl_dump_header(text, (unsigned char *)data, size, NO_FILTER);
947
		break;
948
	case CURLINFO_DATA_IN:
949
		if (trace_curl_data) {
950
			text = "<= Recv data";
951
			curl_dump_data(text, (unsigned char *)data, size);
952
		}
953
		break;
954
	case CURLINFO_SSL_DATA_IN:
955
		if (trace_curl_data) {
956
			text = "<= Recv SSL data";
957
			curl_dump_data(text, (unsigned char *)data, size);
958
		}
959
		break;
960

961
	default:		/* we ignore unknown types by default */
962
		return 0;
963
	}
964
	return 0;
965
}
966

967
void http_trace_curl_no_data(void)
968
{
969
	trace_override_envvar(&trace_curl, "1");
970
	trace_curl_data = 0;
971
}
972

973
void setup_curl_trace(CURL *handle)
974
{
975
	if (!trace_want(&trace_curl))
976
		return;
977
	curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L);
978
	curl_easy_setopt(handle, CURLOPT_DEBUGFUNCTION, curl_trace);
979
	curl_easy_setopt(handle, CURLOPT_DEBUGDATA, NULL);
980
}
981

982
static void proto_list_append(struct strbuf *list, const char *proto)
983
{
984
	if (!list)
985
		return;
986
	if (list->len)
987
		strbuf_addch(list, ',');
988
	strbuf_addstr(list, proto);
989
}
990

991
static long get_curl_allowed_protocols(int from_user, struct strbuf *list)
992
{
993
	long bits = 0;
994

995
	if (is_transport_allowed("http", from_user)) {
996
		bits |= CURLPROTO_HTTP;
997
		proto_list_append(list, "http");
998
	}
999
	if (is_transport_allowed("https", from_user)) {
1000
		bits |= CURLPROTO_HTTPS;
1001
		proto_list_append(list, "https");
1002
	}
1003
	if (is_transport_allowed("ftp", from_user)) {
1004
		bits |= CURLPROTO_FTP;
1005
		proto_list_append(list, "ftp");
1006
	}
1007
	if (is_transport_allowed("ftps", from_user)) {
1008
		bits |= CURLPROTO_FTPS;
1009
		proto_list_append(list, "ftps");
1010
	}
1011

1012
	return bits;
1013
}
1014

1015
#ifdef GIT_CURL_HAVE_CURL_HTTP_VERSION_2
1016
static int get_curl_http_version_opt(const char *version_string, long *opt)
1017
{
1018
	int i;
1019
	static struct {
1020
		const char *name;
1021
		long opt_token;
1022
	} choice[] = {
1023
		{ "HTTP/1.1", CURL_HTTP_VERSION_1_1 },
1024
		{ "HTTP/2", CURL_HTTP_VERSION_2 }
1025
	};
1026

1027
	for (i = 0; i < ARRAY_SIZE(choice); i++) {
1028
		if (!strcmp(version_string, choice[i].name)) {
1029
			*opt = choice[i].opt_token;
1030
			return 0;
1031
		}
1032
	}
1033

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

1038
#endif
1039

1040
static CURL *get_curl_handle(void)
1041
{
1042
	CURL *result = curl_easy_init();
1043

1044
	if (!result)
1045
		die("curl_easy_init failed");
1046

1047
	if (!curl_ssl_verify) {
1048
		curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, 0);
1049
		curl_easy_setopt(result, CURLOPT_SSL_VERIFYHOST, 0);
1050
	} else {
1051
		/* Verify authenticity of the peer's certificate */
1052
		curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, 1);
1053
		/* The name in the cert must match whom we tried to connect */
1054
		curl_easy_setopt(result, CURLOPT_SSL_VERIFYHOST, 2);
1055
	}
1056

1057
#ifdef GIT_CURL_HAVE_CURL_HTTP_VERSION_2
1058
    if (curl_http_version) {
1059
		long opt;
1060
		if (!get_curl_http_version_opt(curl_http_version, &opt)) {
1061
			/* Set request use http version */
1062
			curl_easy_setopt(result, CURLOPT_HTTP_VERSION, opt);
1063
		}
1064
    }
1065
#endif
1066

1067
	curl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
1068
	curl_easy_setopt(result, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
1069

1070
#ifdef CURLGSSAPI_DELEGATION_FLAG
1071
	if (curl_deleg) {
1072
		int i;
1073
		for (i = 0; i < ARRAY_SIZE(curl_deleg_levels); i++) {
1074
			if (!strcmp(curl_deleg, curl_deleg_levels[i].name)) {
1075
				curl_easy_setopt(result, CURLOPT_GSSAPI_DELEGATION,
1076
						curl_deleg_levels[i].curl_deleg_param);
1077
				break;
1078
			}
1079
		}
1080
		if (i == ARRAY_SIZE(curl_deleg_levels))
1081
			warning("Unknown delegation method '%s': using default",
1082
				curl_deleg);
1083
	}
1084
#endif
1085

1086
	if (http_ssl_backend && !strcmp("schannel", http_ssl_backend) &&
1087
	    !http_schannel_check_revoke) {
1088
#ifdef GIT_CURL_HAVE_CURLSSLOPT_NO_REVOKE
1089
		curl_easy_setopt(result, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE);
1090
#else
1091
		warning(_("CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0"));
1092
#endif
1093
	}
1094

1095
	if (http_proactive_auth != PROACTIVE_AUTH_NONE)
1096
		init_curl_http_auth(result);
1097

1098
	if (getenv("GIT_SSL_VERSION"))
1099
		ssl_version = getenv("GIT_SSL_VERSION");
1100
	if (ssl_version && *ssl_version) {
1101
		int i;
1102
		for (i = 0; i < ARRAY_SIZE(sslversions); i++) {
1103
			if (!strcmp(ssl_version, sslversions[i].name)) {
1104
				curl_easy_setopt(result, CURLOPT_SSLVERSION,
1105
						 sslversions[i].ssl_version);
1106
				break;
1107
			}
1108
		}
1109
		if (i == ARRAY_SIZE(sslversions))
1110
			warning("unsupported ssl version %s: using default",
1111
				ssl_version);
1112
	}
1113

1114
	if (getenv("GIT_SSL_CIPHER_LIST"))
1115
		ssl_cipherlist = getenv("GIT_SSL_CIPHER_LIST");
1116
	if (ssl_cipherlist != NULL && *ssl_cipherlist)
1117
		curl_easy_setopt(result, CURLOPT_SSL_CIPHER_LIST,
1118
				ssl_cipherlist);
1119

1120
	if (ssl_cert)
1121
		curl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert);
1122
	if (ssl_cert_type)
1123
		curl_easy_setopt(result, CURLOPT_SSLCERTTYPE, ssl_cert_type);
1124
	if (has_cert_password())
1125
		curl_easy_setopt(result, CURLOPT_KEYPASSWD, cert_auth.password);
1126
	if (ssl_key)
1127
		curl_easy_setopt(result, CURLOPT_SSLKEY, ssl_key);
1128
	if (ssl_key_type)
1129
		curl_easy_setopt(result, CURLOPT_SSLKEYTYPE, ssl_key_type);
1130
	if (ssl_capath)
1131
		curl_easy_setopt(result, CURLOPT_CAPATH, ssl_capath);
1132
#ifdef GIT_CURL_HAVE_CURLOPT_PINNEDPUBLICKEY
1133
	if (ssl_pinnedkey)
1134
		curl_easy_setopt(result, CURLOPT_PINNEDPUBLICKEY, ssl_pinnedkey);
1135
#endif
1136
	if (http_ssl_backend && !strcmp("schannel", http_ssl_backend) &&
1137
	    !http_schannel_use_ssl_cainfo) {
1138
		curl_easy_setopt(result, CURLOPT_CAINFO, NULL);
1139
#ifdef GIT_CURL_HAVE_CURLOPT_PROXY_CAINFO
1140
		curl_easy_setopt(result, CURLOPT_PROXY_CAINFO, NULL);
1141
#endif
1142
	} else if (ssl_cainfo != NULL || http_proxy_ssl_ca_info != NULL) {
1143
		if (ssl_cainfo)
1144
			curl_easy_setopt(result, CURLOPT_CAINFO, ssl_cainfo);
1145
#ifdef GIT_CURL_HAVE_CURLOPT_PROXY_CAINFO
1146
		if (http_proxy_ssl_ca_info)
1147
			curl_easy_setopt(result, CURLOPT_PROXY_CAINFO, http_proxy_ssl_ca_info);
1148
#endif
1149
	}
1150

1151
	if (curl_low_speed_limit > 0 && curl_low_speed_time > 0) {
1152
		curl_easy_setopt(result, CURLOPT_LOW_SPEED_LIMIT,
1153
				 curl_low_speed_limit);
1154
		curl_easy_setopt(result, CURLOPT_LOW_SPEED_TIME,
1155
				 curl_low_speed_time);
1156
	}
1157

1158
	curl_easy_setopt(result, CURLOPT_MAXREDIRS, 20);
1159
	curl_easy_setopt(result, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL);
1160

1161
#ifdef GIT_CURL_HAVE_CURLOPT_PROTOCOLS_STR
1162
	{
1163
		struct strbuf buf = STRBUF_INIT;
1164

1165
		get_curl_allowed_protocols(0, &buf);
1166
		curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS_STR, buf.buf);
1167
		strbuf_reset(&buf);
1168

1169
		get_curl_allowed_protocols(-1, &buf);
1170
		curl_easy_setopt(result, CURLOPT_PROTOCOLS_STR, buf.buf);
1171
		strbuf_release(&buf);
1172
	}
1173
#else
1174
	curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS,
1175
			 get_curl_allowed_protocols(0, NULL));
1176
	curl_easy_setopt(result, CURLOPT_PROTOCOLS,
1177
			 get_curl_allowed_protocols(-1, NULL));
1178
#endif
1179

1180
	if (getenv("GIT_CURL_VERBOSE"))
1181
		http_trace_curl_no_data();
1182
	setup_curl_trace(result);
1183
	if (getenv("GIT_TRACE_CURL_NO_DATA"))
1184
		trace_curl_data = 0;
1185
	if (!git_env_bool("GIT_TRACE_REDACT", 1))
1186
		trace_curl_redact = 0;
1187

1188
	curl_easy_setopt(result, CURLOPT_USERAGENT,
1189
		user_agent ? user_agent : git_user_agent());
1190

1191
	if (curl_ftp_no_epsv)
1192
		curl_easy_setopt(result, CURLOPT_FTP_USE_EPSV, 0);
1193

1194
	if (curl_ssl_try)
1195
		curl_easy_setopt(result, CURLOPT_USE_SSL, CURLUSESSL_TRY);
1196

1197
	/*
1198
	 * CURL also examines these variables as a fallback; but we need to query
1199
	 * them here in order to decide whether to prompt for missing password (cf.
1200
	 * init_curl_proxy_auth()).
1201
	 *
1202
	 * Unlike many other common environment variables, these are historically
1203
	 * lowercase only. It appears that CURL did not know this and implemented
1204
	 * only uppercase variants, which was later corrected to take both - with
1205
	 * the exception of http_proxy, which is lowercase only also in CURL. As
1206
	 * the lowercase versions are the historical quasi-standard, they take
1207
	 * precedence here, as in CURL.
1208
	 */
1209
	if (!curl_http_proxy) {
1210
		if (http_auth.protocol && !strcmp(http_auth.protocol, "https")) {
1211
			var_override(&curl_http_proxy, getenv("HTTPS_PROXY"));
1212
			var_override(&curl_http_proxy, getenv("https_proxy"));
1213
		} else {
1214
			var_override(&curl_http_proxy, getenv("http_proxy"));
1215
		}
1216
		if (!curl_http_proxy) {
1217
			var_override(&curl_http_proxy, getenv("ALL_PROXY"));
1218
			var_override(&curl_http_proxy, getenv("all_proxy"));
1219
		}
1220
	}
1221

1222
	if (curl_http_proxy && curl_http_proxy[0] == '\0') {
1223
		/*
1224
		 * Handle case with the empty http.proxy value here to keep
1225
		 * common code clean.
1226
		 * NB: empty option disables proxying at all.
1227
		 */
1228
		curl_easy_setopt(result, CURLOPT_PROXY, "");
1229
	} else if (curl_http_proxy) {
1230
		struct strbuf proxy = STRBUF_INIT;
1231

1232
		if (starts_with(curl_http_proxy, "socks5h"))
1233
			curl_easy_setopt(result,
1234
				CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5_HOSTNAME);
1235
		else if (starts_with(curl_http_proxy, "socks5"))
1236
			curl_easy_setopt(result,
1237
				CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
1238
		else if (starts_with(curl_http_proxy, "socks4a"))
1239
			curl_easy_setopt(result,
1240
				CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4A);
1241
		else if (starts_with(curl_http_proxy, "socks"))
1242
			curl_easy_setopt(result,
1243
				CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
1244
#ifdef GIT_CURL_HAVE_CURLOPT_PROXY_KEYPASSWD
1245
		else if (starts_with(curl_http_proxy, "https")) {
1246
			curl_easy_setopt(result, CURLOPT_PROXYTYPE, CURLPROXY_HTTPS);
1247

1248
			if (http_proxy_ssl_cert)
1249
				curl_easy_setopt(result, CURLOPT_PROXY_SSLCERT, http_proxy_ssl_cert);
1250

1251
			if (http_proxy_ssl_key)
1252
				curl_easy_setopt(result, CURLOPT_PROXY_SSLKEY, http_proxy_ssl_key);
1253

1254
			if (has_proxy_cert_password())
1255
				curl_easy_setopt(result, CURLOPT_PROXY_KEYPASSWD, proxy_cert_auth.password);
1256
		}
1257
#endif
1258
		if (strstr(curl_http_proxy, "://"))
1259
			credential_from_url(&proxy_auth, curl_http_proxy);
1260
		else {
1261
			struct strbuf url = STRBUF_INIT;
1262
			strbuf_addf(&url, "http://%s", curl_http_proxy);
1263
			credential_from_url(&proxy_auth, url.buf);
1264
			strbuf_release(&url);
1265
		}
1266

1267
		if (!proxy_auth.host)
1268
			die("Invalid proxy URL '%s'", curl_http_proxy);
1269

1270
		strbuf_addstr(&proxy, proxy_auth.host);
1271
		if (proxy_auth.path) {
1272
			curl_version_info_data *ver = curl_version_info(CURLVERSION_NOW);
1273

1274
			if (ver->version_num < 0x075400)
1275
				die("libcurl 7.84 or later is required to support paths in proxy URLs");
1276

1277
			if (!starts_with(proxy_auth.protocol, "socks"))
1278
				die("Invalid proxy URL '%s': only SOCKS proxies support paths",
1279
				    curl_http_proxy);
1280

1281
			if (strcasecmp(proxy_auth.host, "localhost"))
1282
				die("Invalid proxy URL '%s': host must be localhost if a path is present",
1283
				    curl_http_proxy);
1284

1285
			strbuf_addch(&proxy, '/');
1286
			strbuf_add_percentencode(&proxy, proxy_auth.path, 0);
1287
		}
1288
		curl_easy_setopt(result, CURLOPT_PROXY, proxy.buf);
1289
		strbuf_release(&proxy);
1290

1291
		var_override(&curl_no_proxy, getenv("NO_PROXY"));
1292
		var_override(&curl_no_proxy, getenv("no_proxy"));
1293
		curl_easy_setopt(result, CURLOPT_NOPROXY, curl_no_proxy);
1294
	}
1295
	init_curl_proxy_auth(result);
1296

1297
	set_curl_keepalive(result);
1298

1299
	return result;
1300
}
1301

1302
static void set_from_env(char **var, const char *envname)
1303
{
1304
	const char *val = getenv(envname);
1305
	if (val) {
1306
		FREE_AND_NULL(*var);
1307
		*var = xstrdup(val);
1308
	}
1309
}
1310

1311
void http_init(struct remote *remote, const char *url, int proactive_auth)
1312
{
1313
	char *low_speed_limit;
1314
	char *low_speed_time;
1315
	char *normalized_url;
1316
	struct urlmatch_config config = URLMATCH_CONFIG_INIT;
1317

1318
	config.section = "http";
1319
	config.key = NULL;
1320
	config.collect_fn = http_options;
1321
	config.cascade_fn = git_default_config;
1322
	config.cb = NULL;
1323

1324
	http_is_verbose = 0;
1325
	normalized_url = url_normalize(url, &config.url);
1326

1327
	git_config(urlmatch_config_entry, &config);
1328
	free(normalized_url);
1329
	string_list_clear(&config.vars, 1);
1330

1331
#ifdef GIT_CURL_HAVE_CURLSSLSET_NO_BACKENDS
1332
	if (http_ssl_backend) {
1333
		const curl_ssl_backend **backends;
1334
		struct strbuf buf = STRBUF_INIT;
1335
		int i;
1336

1337
		switch (curl_global_sslset(-1, http_ssl_backend, &backends)) {
1338
		case CURLSSLSET_UNKNOWN_BACKEND:
1339
			strbuf_addf(&buf, _("Unsupported SSL backend '%s'. "
1340
					    "Supported SSL backends:"),
1341
					    http_ssl_backend);
1342
			for (i = 0; backends[i]; i++)
1343
				strbuf_addf(&buf, "\n\t%s", backends[i]->name);
1344
			die("%s", buf.buf);
1345
		case CURLSSLSET_NO_BACKENDS:
1346
			die(_("Could not set SSL backend to '%s': "
1347
			      "cURL was built without SSL backends"),
1348
			    http_ssl_backend);
1349
		case CURLSSLSET_TOO_LATE:
1350
			die(_("Could not set SSL backend to '%s': already set"),
1351
			    http_ssl_backend);
1352
		case CURLSSLSET_OK:
1353
			break; /* Okay! */
1354
		}
1355
	}
1356
#endif
1357

1358
	if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)
1359
		die("curl_global_init failed");
1360

1361
	if (proactive_auth && http_proactive_auth == PROACTIVE_AUTH_NONE)
1362
		http_proactive_auth = PROACTIVE_AUTH_IF_CREDENTIALS;
1363

1364
	if (remote && remote->http_proxy)
1365
		curl_http_proxy = xstrdup(remote->http_proxy);
1366

1367
	if (remote)
1368
		var_override(&http_proxy_authmethod, remote->http_proxy_authmethod);
1369

1370
	pragma_header = curl_slist_append(http_copy_default_headers(),
1371
		"Pragma: no-cache");
1372

1373
	{
1374
		char *http_max_requests = getenv("GIT_HTTP_MAX_REQUESTS");
1375
		if (http_max_requests)
1376
			max_requests = atoi(http_max_requests);
1377
	}
1378

1379
	curlm = curl_multi_init();
1380
	if (!curlm)
1381
		die("curl_multi_init failed");
1382

1383
	if (getenv("GIT_SSL_NO_VERIFY"))
1384
		curl_ssl_verify = 0;
1385

1386
	set_from_env(&ssl_cert, "GIT_SSL_CERT");
1387
	set_from_env(&ssl_cert_type, "GIT_SSL_CERT_TYPE");
1388
	set_from_env(&ssl_key, "GIT_SSL_KEY");
1389
	set_from_env(&ssl_key_type, "GIT_SSL_KEY_TYPE");
1390
	set_from_env(&ssl_capath, "GIT_SSL_CAPATH");
1391
	set_from_env(&ssl_cainfo, "GIT_SSL_CAINFO");
1392

1393
	set_from_env(&user_agent, "GIT_HTTP_USER_AGENT");
1394

1395
	low_speed_limit = getenv("GIT_HTTP_LOW_SPEED_LIMIT");
1396
	if (low_speed_limit)
1397
		curl_low_speed_limit = strtol(low_speed_limit, NULL, 10);
1398
	low_speed_time = getenv("GIT_HTTP_LOW_SPEED_TIME");
1399
	if (low_speed_time)
1400
		curl_low_speed_time = strtol(low_speed_time, NULL, 10);
1401

1402
	if (curl_ssl_verify == -1)
1403
		curl_ssl_verify = 1;
1404

1405
	curl_session_count = 0;
1406
	if (max_requests < 1)
1407
		max_requests = DEFAULT_MAX_REQUESTS;
1408

1409
	set_from_env(&http_proxy_ssl_cert, "GIT_PROXY_SSL_CERT");
1410
	set_from_env(&http_proxy_ssl_key, "GIT_PROXY_SSL_KEY");
1411
	set_from_env(&http_proxy_ssl_ca_info, "GIT_PROXY_SSL_CAINFO");
1412

1413
	if (getenv("GIT_PROXY_SSL_CERT_PASSWORD_PROTECTED"))
1414
		proxy_ssl_cert_password_required = 1;
1415

1416
	if (getenv("GIT_CURL_FTP_NO_EPSV"))
1417
		curl_ftp_no_epsv = 1;
1418

1419
	if (url) {
1420
		credential_from_url(&http_auth, url);
1421
		if (!ssl_cert_password_required &&
1422
		    getenv("GIT_SSL_CERT_PASSWORD_PROTECTED") &&
1423
		    starts_with(url, "https://"))
1424
			ssl_cert_password_required = 1;
1425
	}
1426

1427
	curl_default = get_curl_handle();
1428
}
1429

1430
void http_cleanup(void)
1431
{
1432
	struct active_request_slot *slot = active_queue_head;
1433

1434
	while (slot != NULL) {
1435
		struct active_request_slot *next = slot->next;
1436
		if (slot->curl) {
1437
			xmulti_remove_handle(slot);
1438
			curl_easy_cleanup(slot->curl);
1439
		}
1440
		free(slot);
1441
		slot = next;
1442
	}
1443
	active_queue_head = NULL;
1444

1445
	curl_easy_cleanup(curl_default);
1446

1447
	curl_multi_cleanup(curlm);
1448
	curl_global_cleanup();
1449

1450
	string_list_clear(&extra_http_headers, 0);
1451

1452
	curl_slist_free_all(pragma_header);
1453
	pragma_header = NULL;
1454

1455
	curl_slist_free_all(host_resolutions);
1456
	host_resolutions = NULL;
1457

1458
	if (curl_http_proxy) {
1459
		free((void *)curl_http_proxy);
1460
		curl_http_proxy = NULL;
1461
	}
1462

1463
	if (proxy_auth.password) {
1464
		memset(proxy_auth.password, 0, strlen(proxy_auth.password));
1465
		FREE_AND_NULL(proxy_auth.password);
1466
	}
1467

1468
	free((void *)curl_proxyuserpwd);
1469
	curl_proxyuserpwd = NULL;
1470

1471
	free((void *)http_proxy_authmethod);
1472
	http_proxy_authmethod = NULL;
1473

1474
	if (cert_auth.password) {
1475
		memset(cert_auth.password, 0, strlen(cert_auth.password));
1476
		FREE_AND_NULL(cert_auth.password);
1477
	}
1478
	ssl_cert_password_required = 0;
1479

1480
	if (proxy_cert_auth.password) {
1481
		memset(proxy_cert_auth.password, 0, strlen(proxy_cert_auth.password));
1482
		FREE_AND_NULL(proxy_cert_auth.password);
1483
	}
1484
	proxy_ssl_cert_password_required = 0;
1485

1486
	FREE_AND_NULL(cached_accept_language);
1487
}
1488

1489
struct active_request_slot *get_active_slot(void)
1490
{
1491
	struct active_request_slot *slot = active_queue_head;
1492
	struct active_request_slot *newslot;
1493

1494
	int num_transfers;
1495

1496
	/* Wait for a slot to open up if the queue is full */
1497
	while (active_requests >= max_requests) {
1498
		curl_multi_perform(curlm, &num_transfers);
1499
		if (num_transfers < active_requests)
1500
			process_curl_messages();
1501
	}
1502

1503
	while (slot != NULL && slot->in_use)
1504
		slot = slot->next;
1505

1506
	if (!slot) {
1507
		newslot = xmalloc(sizeof(*newslot));
1508
		newslot->curl = NULL;
1509
		newslot->in_use = 0;
1510
		newslot->next = NULL;
1511

1512
		slot = active_queue_head;
1513
		if (!slot) {
1514
			active_queue_head = newslot;
1515
		} else {
1516
			while (slot->next != NULL)
1517
				slot = slot->next;
1518
			slot->next = newslot;
1519
		}
1520
		slot = newslot;
1521
	}
1522

1523
	if (!slot->curl) {
1524
		slot->curl = curl_easy_duphandle(curl_default);
1525
		curl_session_count++;
1526
	}
1527

1528
	active_requests++;
1529
	slot->in_use = 1;
1530
	slot->results = NULL;
1531
	slot->finished = NULL;
1532
	slot->callback_data = NULL;
1533
	slot->callback_func = NULL;
1534

1535
	if (curl_cookie_file && !strcmp(curl_cookie_file, "-")) {
1536
		warning(_("refusing to read cookies from http.cookiefile '-'"));
1537
		FREE_AND_NULL(curl_cookie_file);
1538
	}
1539
	curl_easy_setopt(slot->curl, CURLOPT_COOKIEFILE, curl_cookie_file);
1540
	if (curl_save_cookies && (!curl_cookie_file || !curl_cookie_file[0])) {
1541
		curl_save_cookies = 0;
1542
		warning(_("ignoring http.savecookies for empty http.cookiefile"));
1543
	}
1544
	if (curl_save_cookies)
1545
		curl_easy_setopt(slot->curl, CURLOPT_COOKIEJAR, curl_cookie_file);
1546
	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, pragma_header);
1547
	curl_easy_setopt(slot->curl, CURLOPT_RESOLVE, host_resolutions);
1548
	curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, curl_errorstr);
1549
	curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, NULL);
1550
	curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, NULL);
1551
	curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, NULL);
1552
	curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, NULL);
1553
	curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, -1L);
1554
	curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 0);
1555
	curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
1556
	curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 1);
1557
	curl_easy_setopt(slot->curl, CURLOPT_RANGE, NULL);
1558

1559
	/*
1560
	 * Default following to off unless "ALWAYS" is configured; this gives
1561
	 * callers a sane starting point, and they can tweak for individual
1562
	 * HTTP_FOLLOW_* cases themselves.
1563
	 */
1564
	if (http_follow_config == HTTP_FOLLOW_ALWAYS)
1565
		curl_easy_setopt(slot->curl, CURLOPT_FOLLOWLOCATION, 1);
1566
	else
1567
		curl_easy_setopt(slot->curl, CURLOPT_FOLLOWLOCATION, 0);
1568

1569
	curl_easy_setopt(slot->curl, CURLOPT_IPRESOLVE, git_curl_ipresolve);
1570
	curl_easy_setopt(slot->curl, CURLOPT_HTTPAUTH, http_auth_methods);
1571
	if (http_auth.password || http_auth.credential || curl_empty_auth_enabled())
1572
		init_curl_http_auth(slot->curl);
1573

1574
	return slot;
1575
}
1576

1577
int start_active_slot(struct active_request_slot *slot)
1578
{
1579
	CURLMcode curlm_result = curl_multi_add_handle(curlm, slot->curl);
1580
	int num_transfers;
1581

1582
	if (curlm_result != CURLM_OK &&
1583
	    curlm_result != CURLM_CALL_MULTI_PERFORM) {
1584
		warning("curl_multi_add_handle failed: %s",
1585
			curl_multi_strerror(curlm_result));
1586
		active_requests--;
1587
		slot->in_use = 0;
1588
		return 0;
1589
	}
1590

1591
	/*
1592
	 * We know there must be something to do, since we just added
1593
	 * something.
1594
	 */
1595
	curl_multi_perform(curlm, &num_transfers);
1596
	return 1;
1597
}
1598

1599
struct fill_chain {
1600
	void *data;
1601
	int (*fill)(void *);
1602
	struct fill_chain *next;
1603
};
1604

1605
static struct fill_chain *fill_cfg;
1606

1607
void add_fill_function(void *data, int (*fill)(void *))
1608
{
1609
	struct fill_chain *new_fill = xmalloc(sizeof(*new_fill));
1610
	struct fill_chain **linkp = &fill_cfg;
1611
	new_fill->data = data;
1612
	new_fill->fill = fill;
1613
	new_fill->next = NULL;
1614
	while (*linkp)
1615
		linkp = &(*linkp)->next;
1616
	*linkp = new_fill;
1617
}
1618

1619
void fill_active_slots(void)
1620
{
1621
	struct active_request_slot *slot = active_queue_head;
1622

1623
	while (active_requests < max_requests) {
1624
		struct fill_chain *fill;
1625
		for (fill = fill_cfg; fill; fill = fill->next)
1626
			if (fill->fill(fill->data))
1627
				break;
1628

1629
		if (!fill)
1630
			break;
1631
	}
1632

1633
	while (slot != NULL) {
1634
		if (!slot->in_use && slot->curl != NULL
1635
			&& curl_session_count > min_curl_sessions) {
1636
			curl_easy_cleanup(slot->curl);
1637
			slot->curl = NULL;
1638
			curl_session_count--;
1639
		}
1640
		slot = slot->next;
1641
	}
1642
}
1643

1644
void step_active_slots(void)
1645
{
1646
	int num_transfers;
1647
	CURLMcode curlm_result;
1648

1649
	do {
1650
		curlm_result = curl_multi_perform(curlm, &num_transfers);
1651
	} while (curlm_result == CURLM_CALL_MULTI_PERFORM);
1652
	if (num_transfers < active_requests) {
1653
		process_curl_messages();
1654
		fill_active_slots();
1655
	}
1656
}
1657

1658
void run_active_slot(struct active_request_slot *slot)
1659
{
1660
	fd_set readfds;
1661
	fd_set writefds;
1662
	fd_set excfds;
1663
	int max_fd;
1664
	struct timeval select_timeout;
1665
	int finished = 0;
1666

1667
	slot->finished = &finished;
1668
	while (!finished) {
1669
		step_active_slots();
1670

1671
		if (slot->in_use) {
1672
			long curl_timeout;
1673
			curl_multi_timeout(curlm, &curl_timeout);
1674
			if (curl_timeout == 0) {
1675
				continue;
1676
			} else if (curl_timeout == -1) {
1677
				select_timeout.tv_sec  = 0;
1678
				select_timeout.tv_usec = 50000;
1679
			} else {
1680
				select_timeout.tv_sec  =  curl_timeout / 1000;
1681
				select_timeout.tv_usec = (curl_timeout % 1000) * 1000;
1682
			}
1683

1684
			max_fd = -1;
1685
			FD_ZERO(&readfds);
1686
			FD_ZERO(&writefds);
1687
			FD_ZERO(&excfds);
1688
			curl_multi_fdset(curlm, &readfds, &writefds, &excfds, &max_fd);
1689

1690
			/*
1691
			 * It can happen that curl_multi_timeout returns a pathologically
1692
			 * long timeout when curl_multi_fdset returns no file descriptors
1693
			 * to read.  See commit message for more details.
1694
			 */
1695
			if (max_fd < 0 &&
1696
			    (select_timeout.tv_sec > 0 ||
1697
			     select_timeout.tv_usec > 50000)) {
1698
				select_timeout.tv_sec  = 0;
1699
				select_timeout.tv_usec = 50000;
1700
			}
1701

1702
			select(max_fd+1, &readfds, &writefds, &excfds, &select_timeout);
1703
		}
1704
	}
1705

1706
	/*
1707
	 * The value of slot->finished we set before the loop was used
1708
	 * to set our "finished" variable when our request completed.
1709
	 *
1710
	 * 1. The slot may not have been reused for another requst
1711
	 *    yet, in which case it still has &finished.
1712
	 *
1713
	 * 2. The slot may already be in-use to serve another request,
1714
	 *    which can further be divided into two cases:
1715
	 *
1716
	 * (a) If call run_active_slot() hasn't been called for that
1717
	 *     other request, slot->finished would have been cleared
1718
	 *     by get_active_slot() and has NULL.
1719
	 *
1720
	 * (b) If the request did call run_active_slot(), then the
1721
	 *     call would have updated slot->finished at the beginning
1722
	 *     of this function, and with the clearing of the member
1723
	 *     below, we would find that slot->finished is now NULL.
1724
	 *
1725
	 * In all cases, slot->finished has no useful information to
1726
	 * anybody at this point.  Some compilers warn us for
1727
	 * attempting to smuggle a pointer that is about to become
1728
	 * invalid, i.e. &finished.  We clear it here to assure them.
1729
	 */
1730
	slot->finished = NULL;
1731
}
1732

1733
static void release_active_slot(struct active_request_slot *slot)
1734
{
1735
	closedown_active_slot(slot);
1736
	if (slot->curl) {
1737
		xmulti_remove_handle(slot);
1738
		if (curl_session_count > min_curl_sessions) {
1739
			curl_easy_cleanup(slot->curl);
1740
			slot->curl = NULL;
1741
			curl_session_count--;
1742
		}
1743
	}
1744
	fill_active_slots();
1745
}
1746

1747
void finish_all_active_slots(void)
1748
{
1749
	struct active_request_slot *slot = active_queue_head;
1750

1751
	while (slot != NULL)
1752
		if (slot->in_use) {
1753
			run_active_slot(slot);
1754
			slot = active_queue_head;
1755
		} else {
1756
			slot = slot->next;
1757
		}
1758
}
1759

1760
/* Helpers for modifying and creating URLs */
1761
static inline int needs_quote(int ch)
1762
{
1763
	if (((ch >= 'A') && (ch <= 'Z'))
1764
			|| ((ch >= 'a') && (ch <= 'z'))
1765
			|| ((ch >= '0') && (ch <= '9'))
1766
			|| (ch == '/')
1767
			|| (ch == '-')
1768
			|| (ch == '.'))
1769
		return 0;
1770
	return 1;
1771
}
1772

1773
static char *quote_ref_url(const char *base, const char *ref)
1774
{
1775
	struct strbuf buf = STRBUF_INIT;
1776
	const char *cp;
1777
	int ch;
1778

1779
	end_url_with_slash(&buf, base);
1780

1781
	for (cp = ref; (ch = *cp) != 0; cp++)
1782
		if (needs_quote(ch))
1783
			strbuf_addf(&buf, "%%%02x", ch);
1784
		else
1785
			strbuf_addch(&buf, *cp);
1786

1787
	return strbuf_detach(&buf, NULL);
1788
}
1789

1790
void append_remote_object_url(struct strbuf *buf, const char *url,
1791
			      const char *hex,
1792
			      int only_two_digit_prefix)
1793
{
1794
	end_url_with_slash(buf, url);
1795

1796
	strbuf_addf(buf, "objects/%.*s/", 2, hex);
1797
	if (!only_two_digit_prefix)
1798
		strbuf_addstr(buf, hex + 2);
1799
}
1800

1801
char *get_remote_object_url(const char *url, const char *hex,
1802
			    int only_two_digit_prefix)
1803
{
1804
	struct strbuf buf = STRBUF_INIT;
1805
	append_remote_object_url(&buf, url, hex, only_two_digit_prefix);
1806
	return strbuf_detach(&buf, NULL);
1807
}
1808

1809
void normalize_curl_result(CURLcode *result, long http_code,
1810
			   char *errorstr, size_t errorlen)
1811
{
1812
	/*
1813
	 * If we see a failing http code with CURLE_OK, we have turned off
1814
	 * FAILONERROR (to keep the server's custom error response), and should
1815
	 * translate the code into failure here.
1816
	 *
1817
	 * Likewise, if we see a redirect (30x code), that means we turned off
1818
	 * redirect-following, and we should treat the result as an error.
1819
	 */
1820
	if (*result == CURLE_OK && http_code >= 300) {
1821
		*result = CURLE_HTTP_RETURNED_ERROR;
1822
		/*
1823
		 * Normally curl will already have put the "reason phrase"
1824
		 * from the server into curl_errorstr; unfortunately without
1825
		 * FAILONERROR it is lost, so we can give only the numeric
1826
		 * status code.
1827
		 */
1828
		xsnprintf(errorstr, errorlen,
1829
			  "The requested URL returned error: %ld",
1830
			  http_code);
1831
	}
1832
}
1833

1834
static int handle_curl_result(struct slot_results *results)
1835
{
1836
	normalize_curl_result(&results->curl_result, results->http_code,
1837
			      curl_errorstr, sizeof(curl_errorstr));
1838

1839
	if (results->curl_result == CURLE_OK) {
1840
		credential_approve(&http_auth);
1841
		credential_approve(&proxy_auth);
1842
		credential_approve(&cert_auth);
1843
		return HTTP_OK;
1844
	} else if (results->curl_result == CURLE_SSL_CERTPROBLEM) {
1845
		/*
1846
		 * We can't tell from here whether it's a bad path, bad
1847
		 * certificate, bad password, or something else wrong
1848
		 * with the certificate.  So we reject the credential to
1849
		 * avoid caching or saving a bad password.
1850
		 */
1851
		credential_reject(&cert_auth);
1852
		return HTTP_NOAUTH;
1853
#ifdef GIT_CURL_HAVE_CURLE_SSL_PINNEDPUBKEYNOTMATCH
1854
	} else if (results->curl_result == CURLE_SSL_PINNEDPUBKEYNOTMATCH) {
1855
		return HTTP_NOMATCHPUBLICKEY;
1856
#endif
1857
	} else if (missing_target(results))
1858
		return HTTP_MISSING_TARGET;
1859
	else if (results->http_code == 401) {
1860
		if ((http_auth.username && http_auth.password) ||\
1861
		    (http_auth.authtype && http_auth.credential)) {
1862
			if (http_auth.multistage) {
1863
				credential_clear_secrets(&http_auth);
1864
				return HTTP_REAUTH;
1865
			}
1866
			credential_reject(&http_auth);
1867
			if (always_auth_proactively())
1868
				http_proactive_auth = PROACTIVE_AUTH_NONE;
1869
			return HTTP_NOAUTH;
1870
		} else {
1871
			http_auth_methods &= ~CURLAUTH_GSSNEGOTIATE;
1872
			if (results->auth_avail) {
1873
				http_auth_methods &= results->auth_avail;
1874
				http_auth_methods_restricted = 1;
1875
			}
1876
			return HTTP_REAUTH;
1877
		}
1878
	} else {
1879
		if (results->http_connectcode == 407)
1880
			credential_reject(&proxy_auth);
1881
		if (!curl_errorstr[0])
1882
			strlcpy(curl_errorstr,
1883
				curl_easy_strerror(results->curl_result),
1884
				sizeof(curl_errorstr));
1885
		return HTTP_ERROR;
1886
	}
1887
}
1888

1889
int run_one_slot(struct active_request_slot *slot,
1890
		 struct slot_results *results)
1891
{
1892
	slot->results = results;
1893
	if (!start_active_slot(slot)) {
1894
		xsnprintf(curl_errorstr, sizeof(curl_errorstr),
1895
			  "failed to start HTTP request");
1896
		return HTTP_START_FAILED;
1897
	}
1898

1899
	run_active_slot(slot);
1900
	return handle_curl_result(results);
1901
}
1902

1903
struct curl_slist *http_copy_default_headers(void)
1904
{
1905
	struct curl_slist *headers = NULL;
1906
	const struct string_list_item *item;
1907

1908
	for_each_string_list_item(item, &extra_http_headers)
1909
		headers = curl_slist_append(headers, item->string);
1910

1911
	return headers;
1912
}
1913

1914
static CURLcode curlinfo_strbuf(CURL *curl, CURLINFO info, struct strbuf *buf)
1915
{
1916
	char *ptr;
1917
	CURLcode ret;
1918

1919
	strbuf_reset(buf);
1920
	ret = curl_easy_getinfo(curl, info, &ptr);
1921
	if (!ret && ptr)
1922
		strbuf_addstr(buf, ptr);
1923
	return ret;
1924
}
1925

1926
/*
1927
 * Check for and extract a content-type parameter. "raw"
1928
 * should be positioned at the start of the potential
1929
 * parameter, with any whitespace already removed.
1930
 *
1931
 * "name" is the name of the parameter. The value is appended
1932
 * to "out".
1933
 */
1934
static int extract_param(const char *raw, const char *name,
1935
			 struct strbuf *out)
1936
{
1937
	size_t len = strlen(name);
1938

1939
	if (strncasecmp(raw, name, len))
1940
		return -1;
1941
	raw += len;
1942

1943
	if (*raw != '=')
1944
		return -1;
1945
	raw++;
1946

1947
	while (*raw && !isspace(*raw) && *raw != ';')
1948
		strbuf_addch(out, *raw++);
1949
	return 0;
1950
}
1951

1952
/*
1953
 * Extract a normalized version of the content type, with any
1954
 * spaces suppressed, all letters lowercased, and no trailing ";"
1955
 * or parameters.
1956
 *
1957
 * Note that we will silently remove even invalid whitespace. For
1958
 * example, "text / plain" is specifically forbidden by RFC 2616,
1959
 * but "text/plain" is the only reasonable output, and this keeps
1960
 * our code simple.
1961
 *
1962
 * If the "charset" argument is not NULL, store the value of any
1963
 * charset parameter there.
1964
 *
1965
 * Example:
1966
 *   "TEXT/PLAIN; charset=utf-8" -> "text/plain", "utf-8"
1967
 *   "text / plain" -> "text/plain"
1968
 */
1969
static void extract_content_type(struct strbuf *raw, struct strbuf *type,
1970
				 struct strbuf *charset)
1971
{
1972
	const char *p;
1973

1974
	strbuf_reset(type);
1975
	strbuf_grow(type, raw->len);
1976
	for (p = raw->buf; *p; p++) {
1977
		if (isspace(*p))
1978
			continue;
1979
		if (*p == ';') {
1980
			p++;
1981
			break;
1982
		}
1983
		strbuf_addch(type, tolower(*p));
1984
	}
1985

1986
	if (!charset)
1987
		return;
1988

1989
	strbuf_reset(charset);
1990
	while (*p) {
1991
		while (isspace(*p) || *p == ';')
1992
			p++;
1993
		if (!extract_param(p, "charset", charset))
1994
			return;
1995
		while (*p && !isspace(*p))
1996
			p++;
1997
	}
1998

1999
	if (!charset->len && starts_with(type->buf, "text/"))
2000
		strbuf_addstr(charset, "ISO-8859-1");
2001
}
2002

2003
static void write_accept_language(struct strbuf *buf)
2004
{
2005
	/*
2006
	 * MAX_DECIMAL_PLACES must not be larger than 3. If it is larger than
2007
	 * that, q-value will be smaller than 0.001, the minimum q-value the
2008
	 * HTTP specification allows. See
2009
	 * https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.1 for q-value.
2010
	 */
2011
	const int MAX_DECIMAL_PLACES = 3;
2012
	const int MAX_LANGUAGE_TAGS = 1000;
2013
	const int MAX_ACCEPT_LANGUAGE_HEADER_SIZE = 4000;
2014
	char **language_tags = NULL;
2015
	int num_langs = 0;
2016
	const char *s = get_preferred_languages();
2017
	int i;
2018
	struct strbuf tag = STRBUF_INIT;
2019

2020
	/* Don't add Accept-Language header if no language is preferred. */
2021
	if (!s)
2022
		return;
2023

2024
	/*
2025
	 * Split the colon-separated string of preferred languages into
2026
	 * language_tags array.
2027
	 */
2028
	do {
2029
		/* collect language tag */
2030
		for (; *s && (isalnum(*s) || *s == '_'); s++)
2031
			strbuf_addch(&tag, *s == '_' ? '-' : *s);
2032

2033
		/* skip .codeset, @modifier and any other unnecessary parts */
2034
		while (*s && *s != ':')
2035
			s++;
2036

2037
		if (tag.len) {
2038
			num_langs++;
2039
			REALLOC_ARRAY(language_tags, num_langs);
2040
			language_tags[num_langs - 1] = strbuf_detach(&tag, NULL);
2041
			if (num_langs >= MAX_LANGUAGE_TAGS - 1) /* -1 for '*' */
2042
				break;
2043
		}
2044
	} while (*s++);
2045

2046
	/* write Accept-Language header into buf */
2047
	if (num_langs) {
2048
		int last_buf_len = 0;
2049
		int max_q;
2050
		int decimal_places;
2051
		char q_format[32];
2052

2053
		/* add '*' */
2054
		REALLOC_ARRAY(language_tags, num_langs + 1);
2055
		language_tags[num_langs++] = xstrdup("*");
2056

2057
		/* compute decimal_places */
2058
		for (max_q = 1, decimal_places = 0;
2059
		     max_q < num_langs && decimal_places <= MAX_DECIMAL_PLACES;
2060
		     decimal_places++, max_q *= 10)
2061
			;
2062

2063
		xsnprintf(q_format, sizeof(q_format), ";q=0.%%0%dd", decimal_places);
2064

2065
		strbuf_addstr(buf, "Accept-Language: ");
2066

2067
		for (i = 0; i < num_langs; i++) {
2068
			if (i > 0)
2069
				strbuf_addstr(buf, ", ");
2070

2071
			strbuf_addstr(buf, language_tags[i]);
2072

2073
			if (i > 0)
2074
				strbuf_addf(buf, q_format, max_q - i);
2075

2076
			if (buf->len > MAX_ACCEPT_LANGUAGE_HEADER_SIZE) {
2077
				strbuf_remove(buf, last_buf_len, buf->len - last_buf_len);
2078
				break;
2079
			}
2080

2081
			last_buf_len = buf->len;
2082
		}
2083
	}
2084

2085
	for (i = 0; i < num_langs; i++)
2086
		free(language_tags[i]);
2087
	free(language_tags);
2088
}
2089

2090
/*
2091
 * Get an Accept-Language header which indicates user's preferred languages.
2092
 *
2093
 * Examples:
2094
 *   LANGUAGE= -> ""
2095
 *   LANGUAGE=ko:en -> "Accept-Language: ko, en; q=0.9, *; q=0.1"
2096
 *   LANGUAGE=ko_KR.UTF-8:sr@latin -> "Accept-Language: ko-KR, sr; q=0.9, *; q=0.1"
2097
 *   LANGUAGE=ko LANG=en_US.UTF-8 -> "Accept-Language: ko, *; q=0.1"
2098
 *   LANGUAGE= LANG=en_US.UTF-8 -> "Accept-Language: en-US, *; q=0.1"
2099
 *   LANGUAGE= LANG=C -> ""
2100
 */
2101
const char *http_get_accept_language_header(void)
2102
{
2103
	if (!cached_accept_language) {
2104
		struct strbuf buf = STRBUF_INIT;
2105
		write_accept_language(&buf);
2106
		if (buf.len > 0)
2107
			cached_accept_language = strbuf_detach(&buf, NULL);
2108
	}
2109

2110
	return cached_accept_language;
2111
}
2112

2113
static void http_opt_request_remainder(CURL *curl, off_t pos)
2114
{
2115
	char buf[128];
2116
	xsnprintf(buf, sizeof(buf), "%"PRIuMAX"-", (uintmax_t)pos);
2117
	curl_easy_setopt(curl, CURLOPT_RANGE, buf);
2118
}
2119

2120
/* http_request() targets */
2121
#define HTTP_REQUEST_STRBUF	0
2122
#define HTTP_REQUEST_FILE	1
2123

2124
static int http_request(const char *url,
2125
			void *result, int target,
2126
			const struct http_get_options *options)
2127
{
2128
	struct active_request_slot *slot;
2129
	struct slot_results results;
2130
	struct curl_slist *headers = http_copy_default_headers();
2131
	struct strbuf buf = STRBUF_INIT;
2132
	const char *accept_language;
2133
	int ret;
2134

2135
	slot = get_active_slot();
2136
	curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
2137

2138
	if (!result) {
2139
		curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 1);
2140
	} else {
2141
		curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
2142
		curl_easy_setopt(slot->curl, CURLOPT_WRITEDATA, result);
2143

2144
		if (target == HTTP_REQUEST_FILE) {
2145
			off_t posn = ftello(result);
2146
			curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
2147
					 fwrite);
2148
			if (posn > 0)
2149
				http_opt_request_remainder(slot->curl, posn);
2150
		} else
2151
			curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
2152
					 fwrite_buffer);
2153
	}
2154

2155
	curl_easy_setopt(slot->curl, CURLOPT_HEADERFUNCTION, fwrite_wwwauth);
2156

2157
	accept_language = http_get_accept_language_header();
2158

2159
	if (accept_language)
2160
		headers = curl_slist_append(headers, accept_language);
2161

2162
	strbuf_addstr(&buf, "Pragma:");
2163
	if (options && options->no_cache)
2164
		strbuf_addstr(&buf, " no-cache");
2165
	if (options && options->initial_request &&
2166
	    http_follow_config == HTTP_FOLLOW_INITIAL)
2167
		curl_easy_setopt(slot->curl, CURLOPT_FOLLOWLOCATION, 1);
2168

2169
	headers = curl_slist_append(headers, buf.buf);
2170

2171
	/* Add additional headers here */
2172
	if (options && options->extra_headers) {
2173
		const struct string_list_item *item;
2174
		if (options && options->extra_headers) {
2175
			for_each_string_list_item(item, options->extra_headers) {
2176
				headers = curl_slist_append(headers, item->string);
2177
			}
2178
		}
2179
	}
2180

2181
	headers = http_append_auth_header(&http_auth, headers);
2182

2183
	curl_easy_setopt(slot->curl, CURLOPT_URL, url);
2184
	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, headers);
2185
	curl_easy_setopt(slot->curl, CURLOPT_ENCODING, "");
2186
	curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 0);
2187

2188
	ret = run_one_slot(slot, &results);
2189

2190
	if (options && options->content_type) {
2191
		struct strbuf raw = STRBUF_INIT;
2192
		curlinfo_strbuf(slot->curl, CURLINFO_CONTENT_TYPE, &raw);
2193
		extract_content_type(&raw, options->content_type,
2194
				     options->charset);
2195
		strbuf_release(&raw);
2196
	}
2197

2198
	if (options && options->effective_url)
2199
		curlinfo_strbuf(slot->curl, CURLINFO_EFFECTIVE_URL,
2200
				options->effective_url);
2201

2202
	curl_slist_free_all(headers);
2203
	strbuf_release(&buf);
2204

2205
	return ret;
2206
}
2207

2208
/*
2209
 * Update the "base" url to a more appropriate value, as deduced by
2210
 * redirects seen when requesting a URL starting with "url".
2211
 *
2212
 * The "asked" parameter is a URL that we asked curl to access, and must begin
2213
 * with "base".
2214
 *
2215
 * The "got" parameter is the URL that curl reported to us as where we ended
2216
 * up.
2217
 *
2218
 * Returns 1 if we updated the base url, 0 otherwise.
2219
 *
2220
 * Our basic strategy is to compare "base" and "asked" to find the bits
2221
 * specific to our request. We then strip those bits off of "got" to yield the
2222
 * new base. So for example, if our base is "http://example.com/foo.git",
2223
 * and we ask for "http://example.com/foo.git/info/refs", we might end up
2224
 * with "https://other.example.com/foo.git/info/refs". We would want the
2225
 * new URL to become "https://other.example.com/foo.git".
2226
 *
2227
 * Note that this assumes a sane redirect scheme. It's entirely possible
2228
 * in the example above to end up at a URL that does not even end in
2229
 * "info/refs".  In such a case we die. There's not much we can do, such a
2230
 * scheme is unlikely to represent a real git repository, and failing to
2231
 * rewrite the base opens options for malicious redirects to do funny things.
2232
 */
2233
static int update_url_from_redirect(struct strbuf *base,
2234
				    const char *asked,
2235
				    const struct strbuf *got)
2236
{
2237
	const char *tail;
2238
	size_t new_len;
2239

2240
	if (!strcmp(asked, got->buf))
2241
		return 0;
2242

2243
	if (!skip_prefix(asked, base->buf, &tail))
2244
		BUG("update_url_from_redirect: %s is not a superset of %s",
2245
		    asked, base->buf);
2246

2247
	new_len = got->len;
2248
	if (!strip_suffix_mem(got->buf, &new_len, tail))
2249
		die(_("unable to update url base from redirection:\n"
2250
		      "  asked for: %s\n"
2251
		      "   redirect: %s"),
2252
		    asked, got->buf);
2253

2254
	strbuf_reset(base);
2255
	strbuf_add(base, got->buf, new_len);
2256

2257
	return 1;
2258
}
2259

2260
static int http_request_reauth(const char *url,
2261
			       void *result, int target,
2262
			       struct http_get_options *options)
2263
{
2264
	int i = 3;
2265
	int ret;
2266

2267
	if (always_auth_proactively())
2268
		credential_fill(&http_auth, 1);
2269

2270
	ret = http_request(url, result, target, options);
2271

2272
	if (ret != HTTP_OK && ret != HTTP_REAUTH)
2273
		return ret;
2274

2275
	if (options && options->effective_url && options->base_url) {
2276
		if (update_url_from_redirect(options->base_url,
2277
					     url, options->effective_url)) {
2278
			credential_from_url(&http_auth, options->base_url->buf);
2279
			url = options->effective_url->buf;
2280
		}
2281
	}
2282

2283
	while (ret == HTTP_REAUTH && --i) {
2284
		/*
2285
		 * The previous request may have put cruft into our output stream; we
2286
		 * should clear it out before making our next request.
2287
		 */
2288
		switch (target) {
2289
		case HTTP_REQUEST_STRBUF:
2290
			strbuf_reset(result);
2291
			break;
2292
		case HTTP_REQUEST_FILE:
2293
			if (fflush(result)) {
2294
				error_errno("unable to flush a file");
2295
				return HTTP_START_FAILED;
2296
			}
2297
			rewind(result);
2298
			if (ftruncate(fileno(result), 0) < 0) {
2299
				error_errno("unable to truncate a file");
2300
				return HTTP_START_FAILED;
2301
			}
2302
			break;
2303
		default:
2304
			BUG("Unknown http_request target");
2305
		}
2306

2307
		credential_fill(&http_auth, 1);
2308

2309
		ret = http_request(url, result, target, options);
2310
	}
2311
	return ret;
2312
}
2313

2314
int http_get_strbuf(const char *url,
2315
		    struct strbuf *result,
2316
		    struct http_get_options *options)
2317
{
2318
	return http_request_reauth(url, result, HTTP_REQUEST_STRBUF, options);
2319
}
2320

2321
/*
2322
 * Downloads a URL and stores the result in the given file.
2323
 *
2324
 * If a previous interrupted download is detected (i.e. a previous temporary
2325
 * file is still around) the download is resumed.
2326
 */
2327
int http_get_file(const char *url, const char *filename,
2328
		  struct http_get_options *options)
2329
{
2330
	int ret;
2331
	struct strbuf tmpfile = STRBUF_INIT;
2332
	FILE *result;
2333

2334
	strbuf_addf(&tmpfile, "%s.temp", filename);
2335
	result = fopen(tmpfile.buf, "a");
2336
	if (!result) {
2337
		error("Unable to open local file %s", tmpfile.buf);
2338
		ret = HTTP_ERROR;
2339
		goto cleanup;
2340
	}
2341

2342
	ret = http_request_reauth(url, result, HTTP_REQUEST_FILE, options);
2343
	fclose(result);
2344

2345
	if (ret == HTTP_OK && finalize_object_file(tmpfile.buf, filename))
2346
		ret = HTTP_ERROR;
2347
cleanup:
2348
	strbuf_release(&tmpfile);
2349
	return ret;
2350
}
2351

2352
int http_fetch_ref(const char *base, struct ref *ref)
2353
{
2354
	struct http_get_options options = {0};
2355
	char *url;
2356
	struct strbuf buffer = STRBUF_INIT;
2357
	int ret = -1;
2358

2359
	options.no_cache = 1;
2360

2361
	url = quote_ref_url(base, ref->name);
2362
	if (http_get_strbuf(url, &buffer, &options) == HTTP_OK) {
2363
		strbuf_rtrim(&buffer);
2364
		if (buffer.len == the_hash_algo->hexsz)
2365
			ret = get_oid_hex(buffer.buf, &ref->old_oid);
2366
		else if (starts_with(buffer.buf, "ref: ")) {
2367
			ref->symref = xstrdup(buffer.buf + 5);
2368
			ret = 0;
2369
		}
2370
	}
2371

2372
	strbuf_release(&buffer);
2373
	free(url);
2374
	return ret;
2375
}
2376

2377
/* Helpers for fetching packs */
2378
static char *fetch_pack_index(unsigned char *hash, const char *base_url)
2379
{
2380
	char *url, *tmp;
2381
	struct strbuf buf = STRBUF_INIT;
2382

2383
	if (http_is_verbose)
2384
		fprintf(stderr, "Getting index for pack %s\n", hash_to_hex(hash));
2385

2386
	end_url_with_slash(&buf, base_url);
2387
	strbuf_addf(&buf, "objects/pack/pack-%s.idx", hash_to_hex(hash));
2388
	url = strbuf_detach(&buf, NULL);
2389

2390
	strbuf_addf(&buf, "%s.temp", sha1_pack_index_name(hash));
2391
	tmp = strbuf_detach(&buf, NULL);
2392

2393
	if (http_get_file(url, tmp, NULL) != HTTP_OK) {
2394
		error("Unable to get pack index %s", url);
2395
		FREE_AND_NULL(tmp);
2396
	}
2397

2398
	free(url);
2399
	return tmp;
2400
}
2401

2402
static int fetch_and_setup_pack_index(struct packed_git **packs_head,
2403
	unsigned char *sha1, const char *base_url)
2404
{
2405
	struct packed_git *new_pack;
2406
	char *tmp_idx = NULL;
2407
	int ret;
2408

2409
	if (has_pack_index(sha1)) {
2410
		new_pack = parse_pack_index(sha1, sha1_pack_index_name(sha1));
2411
		if (!new_pack)
2412
			return -1; /* parse_pack_index() already issued error message */
2413
		goto add_pack;
2414
	}
2415

2416
	tmp_idx = fetch_pack_index(sha1, base_url);
2417
	if (!tmp_idx)
2418
		return -1;
2419

2420
	new_pack = parse_pack_index(sha1, tmp_idx);
2421
	if (!new_pack) {
2422
		unlink(tmp_idx);
2423
		free(tmp_idx);
2424

2425
		return -1; /* parse_pack_index() already issued error message */
2426
	}
2427

2428
	ret = verify_pack_index(new_pack);
2429
	if (!ret) {
2430
		close_pack_index(new_pack);
2431
		ret = finalize_object_file(tmp_idx, sha1_pack_index_name(sha1));
2432
	}
2433
	free(tmp_idx);
2434
	if (ret)
2435
		return -1;
2436

2437
add_pack:
2438
	new_pack->next = *packs_head;
2439
	*packs_head = new_pack;
2440
	return 0;
2441
}
2442

2443
int http_get_info_packs(const char *base_url, struct packed_git **packs_head)
2444
{
2445
	struct http_get_options options = {0};
2446
	int ret = 0;
2447
	char *url;
2448
	const char *data;
2449
	struct strbuf buf = STRBUF_INIT;
2450
	struct object_id oid;
2451

2452
	end_url_with_slash(&buf, base_url);
2453
	strbuf_addstr(&buf, "objects/info/packs");
2454
	url = strbuf_detach(&buf, NULL);
2455

2456
	options.no_cache = 1;
2457
	ret = http_get_strbuf(url, &buf, &options);
2458
	if (ret != HTTP_OK)
2459
		goto cleanup;
2460

2461
	data = buf.buf;
2462
	while (*data) {
2463
		if (skip_prefix(data, "P pack-", &data) &&
2464
		    !parse_oid_hex(data, &oid, &data) &&
2465
		    skip_prefix(data, ".pack", &data) &&
2466
		    (*data == '\n' || *data == '\0')) {
2467
			fetch_and_setup_pack_index(packs_head, oid.hash, base_url);
2468
		} else {
2469
			data = strchrnul(data, '\n');
2470
		}
2471
		if (*data)
2472
			data++; /* skip past newline */
2473
	}
2474

2475
cleanup:
2476
	free(url);
2477
	return ret;
2478
}
2479

2480
void release_http_pack_request(struct http_pack_request *preq)
2481
{
2482
	if (preq->packfile) {
2483
		fclose(preq->packfile);
2484
		preq->packfile = NULL;
2485
	}
2486
	preq->slot = NULL;
2487
	strbuf_release(&preq->tmpfile);
2488
	curl_slist_free_all(preq->headers);
2489
	free(preq->url);
2490
	free(preq);
2491
}
2492

2493
static const char *default_index_pack_args[] =
2494
	{"index-pack", "--stdin", NULL};
2495

2496
int finish_http_pack_request(struct http_pack_request *preq)
2497
{
2498
	struct child_process ip = CHILD_PROCESS_INIT;
2499
	int tmpfile_fd;
2500
	int ret = 0;
2501

2502
	fclose(preq->packfile);
2503
	preq->packfile = NULL;
2504

2505
	tmpfile_fd = xopen(preq->tmpfile.buf, O_RDONLY);
2506

2507
	ip.git_cmd = 1;
2508
	ip.in = tmpfile_fd;
2509
	strvec_pushv(&ip.args, preq->index_pack_args ?
2510
		     preq->index_pack_args :
2511
		     default_index_pack_args);
2512

2513
	if (preq->preserve_index_pack_stdout)
2514
		ip.out = 0;
2515
	else
2516
		ip.no_stdout = 1;
2517

2518
	if (run_command(&ip)) {
2519
		ret = -1;
2520
		goto cleanup;
2521
	}
2522

2523
cleanup:
2524
	close(tmpfile_fd);
2525
	unlink(preq->tmpfile.buf);
2526
	return ret;
2527
}
2528

2529
void http_install_packfile(struct packed_git *p,
2530
			   struct packed_git **list_to_remove_from)
2531
{
2532
	struct packed_git **lst = list_to_remove_from;
2533

2534
	while (*lst != p)
2535
		lst = &((*lst)->next);
2536
	*lst = (*lst)->next;
2537

2538
	install_packed_git(the_repository, p);
2539
}
2540

2541
struct http_pack_request *new_http_pack_request(
2542
	const unsigned char *packed_git_hash, const char *base_url) {
2543

2544
	struct strbuf buf = STRBUF_INIT;
2545

2546
	end_url_with_slash(&buf, base_url);
2547
	strbuf_addf(&buf, "objects/pack/pack-%s.pack",
2548
		hash_to_hex(packed_git_hash));
2549
	return new_direct_http_pack_request(packed_git_hash,
2550
					    strbuf_detach(&buf, NULL));
2551
}
2552

2553
struct http_pack_request *new_direct_http_pack_request(
2554
	const unsigned char *packed_git_hash, char *url)
2555
{
2556
	off_t prev_posn = 0;
2557
	struct http_pack_request *preq;
2558

2559
	CALLOC_ARRAY(preq, 1);
2560
	strbuf_init(&preq->tmpfile, 0);
2561

2562
	preq->url = url;
2563

2564
	strbuf_addf(&preq->tmpfile, "%s.temp", sha1_pack_name(packed_git_hash));
2565
	preq->packfile = fopen(preq->tmpfile.buf, "a");
2566
	if (!preq->packfile) {
2567
		error("Unable to open local file %s for pack",
2568
		      preq->tmpfile.buf);
2569
		goto abort;
2570
	}
2571

2572
	preq->slot = get_active_slot();
2573
	preq->headers = object_request_headers();
2574
	curl_easy_setopt(preq->slot->curl, CURLOPT_WRITEDATA, preq->packfile);
2575
	curl_easy_setopt(preq->slot->curl, CURLOPT_WRITEFUNCTION, fwrite);
2576
	curl_easy_setopt(preq->slot->curl, CURLOPT_URL, preq->url);
2577
	curl_easy_setopt(preq->slot->curl, CURLOPT_HTTPHEADER, preq->headers);
2578

2579
	/*
2580
	 * If there is data present from a previous transfer attempt,
2581
	 * resume where it left off
2582
	 */
2583
	prev_posn = ftello(preq->packfile);
2584
	if (prev_posn>0) {
2585
		if (http_is_verbose)
2586
			fprintf(stderr,
2587
				"Resuming fetch of pack %s at byte %"PRIuMAX"\n",
2588
				hash_to_hex(packed_git_hash),
2589
				(uintmax_t)prev_posn);
2590
		http_opt_request_remainder(preq->slot->curl, prev_posn);
2591
	}
2592

2593
	return preq;
2594

2595
abort:
2596
	strbuf_release(&preq->tmpfile);
2597
	free(preq->url);
2598
	free(preq);
2599
	return NULL;
2600
}
2601

2602
/* Helpers for fetching objects (loose) */
2603
static size_t fwrite_sha1_file(char *ptr, size_t eltsize, size_t nmemb,
2604
			       void *data)
2605
{
2606
	unsigned char expn[4096];
2607
	size_t size = eltsize * nmemb;
2608
	int posn = 0;
2609
	struct http_object_request *freq = data;
2610
	struct active_request_slot *slot = freq->slot;
2611

2612
	if (slot) {
2613
		CURLcode c = curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE,
2614
						&slot->http_code);
2615
		if (c != CURLE_OK)
2616
			BUG("curl_easy_getinfo for HTTP code failed: %s",
2617
				curl_easy_strerror(c));
2618
		if (slot->http_code >= 300)
2619
			return nmemb;
2620
	}
2621

2622
	do {
2623
		ssize_t retval = xwrite(freq->localfile,
2624
					(char *) ptr + posn, size - posn);
2625
		if (retval < 0)
2626
			return posn / eltsize;
2627
		posn += retval;
2628
	} while (posn < size);
2629

2630
	freq->stream.avail_in = size;
2631
	freq->stream.next_in = (void *)ptr;
2632
	do {
2633
		freq->stream.next_out = expn;
2634
		freq->stream.avail_out = sizeof(expn);
2635
		freq->zret = git_inflate(&freq->stream, Z_SYNC_FLUSH);
2636
		the_hash_algo->update_fn(&freq->c, expn,
2637
					 sizeof(expn) - freq->stream.avail_out);
2638
	} while (freq->stream.avail_in && freq->zret == Z_OK);
2639
	return nmemb;
2640
}
2641

2642
struct http_object_request *new_http_object_request(const char *base_url,
2643
						    const struct object_id *oid)
2644
{
2645
	char *hex = oid_to_hex(oid);
2646
	struct strbuf filename = STRBUF_INIT;
2647
	struct strbuf prevfile = STRBUF_INIT;
2648
	int prevlocal;
2649
	char prev_buf[PREV_BUF_SIZE];
2650
	ssize_t prev_read = 0;
2651
	off_t prev_posn = 0;
2652
	struct http_object_request *freq;
2653

2654
	CALLOC_ARRAY(freq, 1);
2655
	strbuf_init(&freq->tmpfile, 0);
2656
	oidcpy(&freq->oid, oid);
2657
	freq->localfile = -1;
2658

2659
	loose_object_path(the_repository, &filename, oid);
2660
	strbuf_addf(&freq->tmpfile, "%s.temp", filename.buf);
2661

2662
	strbuf_addf(&prevfile, "%s.prev", filename.buf);
2663
	unlink_or_warn(prevfile.buf);
2664
	rename(freq->tmpfile.buf, prevfile.buf);
2665
	unlink_or_warn(freq->tmpfile.buf);
2666
	strbuf_release(&filename);
2667

2668
	if (freq->localfile != -1)
2669
		error("fd leakage in start: %d", freq->localfile);
2670
	freq->localfile = open(freq->tmpfile.buf,
2671
			       O_WRONLY | O_CREAT | O_EXCL, 0666);
2672
	/*
2673
	 * This could have failed due to the "lazy directory creation";
2674
	 * try to mkdir the last path component.
2675
	 */
2676
	if (freq->localfile < 0 && errno == ENOENT) {
2677
		char *dir = strrchr(freq->tmpfile.buf, '/');
2678
		if (dir) {
2679
			*dir = 0;
2680
			mkdir(freq->tmpfile.buf, 0777);
2681
			*dir = '/';
2682
		}
2683
		freq->localfile = open(freq->tmpfile.buf,
2684
				       O_WRONLY | O_CREAT | O_EXCL, 0666);
2685
	}
2686

2687
	if (freq->localfile < 0) {
2688
		error_errno("Couldn't create temporary file %s",
2689
			    freq->tmpfile.buf);
2690
		goto abort;
2691
	}
2692

2693
	git_inflate_init(&freq->stream);
2694

2695
	the_hash_algo->init_fn(&freq->c);
2696

2697
	freq->url = get_remote_object_url(base_url, hex, 0);
2698

2699
	/*
2700
	 * If a previous temp file is present, process what was already
2701
	 * fetched.
2702
	 */
2703
	prevlocal = open(prevfile.buf, O_RDONLY);
2704
	if (prevlocal != -1) {
2705
		do {
2706
			prev_read = xread(prevlocal, prev_buf, PREV_BUF_SIZE);
2707
			if (prev_read>0) {
2708
				if (fwrite_sha1_file(prev_buf,
2709
						     1,
2710
						     prev_read,
2711
						     freq) == prev_read) {
2712
					prev_posn += prev_read;
2713
				} else {
2714
					prev_read = -1;
2715
				}
2716
			}
2717
		} while (prev_read > 0);
2718
		close(prevlocal);
2719
	}
2720
	unlink_or_warn(prevfile.buf);
2721
	strbuf_release(&prevfile);
2722

2723
	/*
2724
	 * Reset inflate/SHA1 if there was an error reading the previous temp
2725
	 * file; also rewind to the beginning of the local file.
2726
	 */
2727
	if (prev_read == -1) {
2728
		memset(&freq->stream, 0, sizeof(freq->stream));
2729
		git_inflate_init(&freq->stream);
2730
		the_hash_algo->init_fn(&freq->c);
2731
		if (prev_posn>0) {
2732
			prev_posn = 0;
2733
			lseek(freq->localfile, 0, SEEK_SET);
2734
			if (ftruncate(freq->localfile, 0) < 0) {
2735
				error_errno("Couldn't truncate temporary file %s",
2736
					    freq->tmpfile.buf);
2737
				goto abort;
2738
			}
2739
		}
2740
	}
2741

2742
	freq->slot = get_active_slot();
2743
	freq->headers = object_request_headers();
2744

2745
	curl_easy_setopt(freq->slot->curl, CURLOPT_WRITEDATA, freq);
2746
	curl_easy_setopt(freq->slot->curl, CURLOPT_FAILONERROR, 0);
2747
	curl_easy_setopt(freq->slot->curl, CURLOPT_WRITEFUNCTION, fwrite_sha1_file);
2748
	curl_easy_setopt(freq->slot->curl, CURLOPT_ERRORBUFFER, freq->errorstr);
2749
	curl_easy_setopt(freq->slot->curl, CURLOPT_URL, freq->url);
2750
	curl_easy_setopt(freq->slot->curl, CURLOPT_HTTPHEADER, freq->headers);
2751

2752
	/*
2753
	 * If we have successfully processed data from a previous fetch
2754
	 * attempt, only fetch the data we don't already have.
2755
	 */
2756
	if (prev_posn>0) {
2757
		if (http_is_verbose)
2758
			fprintf(stderr,
2759
				"Resuming fetch of object %s at byte %"PRIuMAX"\n",
2760
				hex, (uintmax_t)prev_posn);
2761
		http_opt_request_remainder(freq->slot->curl, prev_posn);
2762
	}
2763

2764
	return freq;
2765

2766
abort:
2767
	strbuf_release(&prevfile);
2768
	free(freq->url);
2769
	free(freq);
2770
	return NULL;
2771
}
2772

2773
void process_http_object_request(struct http_object_request *freq)
2774
{
2775
	if (!freq->slot)
2776
		return;
2777
	freq->curl_result = freq->slot->curl_result;
2778
	freq->http_code = freq->slot->http_code;
2779
	freq->slot = NULL;
2780
}
2781

2782
int finish_http_object_request(struct http_object_request *freq)
2783
{
2784
	struct stat st;
2785
	struct strbuf filename = STRBUF_INIT;
2786

2787
	close(freq->localfile);
2788
	freq->localfile = -1;
2789

2790
	process_http_object_request(freq);
2791

2792
	if (freq->http_code == 416) {
2793
		warning("requested range invalid; we may already have all the data.");
2794
	} else if (freq->curl_result != CURLE_OK) {
2795
		if (stat(freq->tmpfile.buf, &st) == 0)
2796
			if (st.st_size == 0)
2797
				unlink_or_warn(freq->tmpfile.buf);
2798
		return -1;
2799
	}
2800

2801
	git_inflate_end(&freq->stream);
2802
	the_hash_algo->final_oid_fn(&freq->real_oid, &freq->c);
2803
	if (freq->zret != Z_STREAM_END) {
2804
		unlink_or_warn(freq->tmpfile.buf);
2805
		return -1;
2806
	}
2807
	if (!oideq(&freq->oid, &freq->real_oid)) {
2808
		unlink_or_warn(freq->tmpfile.buf);
2809
		return -1;
2810
	}
2811
	loose_object_path(the_repository, &filename, &freq->oid);
2812
	freq->rename = finalize_object_file(freq->tmpfile.buf, filename.buf);
2813
	strbuf_release(&filename);
2814

2815
	return freq->rename;
2816
}
2817

2818
void abort_http_object_request(struct http_object_request *freq)
2819
{
2820
	unlink_or_warn(freq->tmpfile.buf);
2821

2822
	release_http_object_request(freq);
2823
}
2824

2825
void release_http_object_request(struct http_object_request *freq)
2826
{
2827
	if (freq->localfile != -1) {
2828
		close(freq->localfile);
2829
		freq->localfile = -1;
2830
	}
2831
	FREE_AND_NULL(freq->url);
2832
	if (freq->slot) {
2833
		freq->slot->callback_func = NULL;
2834
		freq->slot->callback_data = NULL;
2835
		release_active_slot(freq->slot);
2836
		freq->slot = NULL;
2837
	}
2838
	curl_slist_free_all(freq->headers);
2839
	strbuf_release(&freq->tmpfile);
2840
}
2841

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.