]> git.ipfire.org Git - thirdparty/git.git/blame - http.c
Merge branch 'bc/http-empty-auth'
[thirdparty/git.git] / http.c
CommitLineData
1c4b6604 1#include "git-compat-util.h"
29508e1e 2#include "http.h"
2264dfa5 3#include "pack.h"
de1a2fdd 4#include "sideband.h"
fe72d420 5#include "run-command.h"
f39f72d8 6#include "url.h"
6a56993b 7#include "urlmatch.h"
148bb6a7 8#include "credential.h"
745c7c8e 9#include "version.h"
047ec602 10#include "pkt-line.h"
93f7d910 11#include "gettext.h"
f4113cac 12#include "transport.h"
29508e1e 13
c915f11e
EW
14#if LIBCURL_VERSION_NUM >= 0x070a08
15long int git_curl_ipresolve = CURL_IPRESOLVE_WHATEVER;
16#else
17long int git_curl_ipresolve;
18#endif
4251ccbd 19int active_requests;
e9176745 20int http_is_verbose;
de1a2fdd 21size_t http_post_buffer = 16 * LARGE_PACKET_MAX;
29508e1e 22
b8ac9230
MS
23#if LIBCURL_VERSION_NUM >= 0x070a06
24#define LIBCURL_CAN_HANDLE_AUTH_ANY
25#endif
26
ad75ebe5
TRC
27static int min_curl_sessions = 1;
28static int curl_session_count;
29508e1e 29#ifdef USE_CURL_MULTI
cc3530e8
MH
30static int max_requests = -1;
31static CURLM *curlm;
29508e1e
NH
32#endif
33#ifndef NO_CURL_EASY_DUPHANDLE
cc3530e8 34static CURL *curl_default;
29508e1e 35#endif
5424bc55
TRC
36
37#define PREV_BUF_SIZE 4096
5424bc55 38
29508e1e
NH
39char curl_errorstr[CURL_ERROR_SIZE];
40
cc3530e8 41static int curl_ssl_verify = -1;
4bc444eb 42static int curl_ssl_try;
4251ccbd 43static const char *ssl_cert;
f6f2a9e4 44static const char *ssl_cipherlist;
01861cb7
EP
45static const char *ssl_version;
46static struct {
47 const char *name;
48 long ssl_version;
49} sslversions[] = {
50 { "sslv2", CURL_SSLVERSION_SSLv2 },
51 { "sslv3", CURL_SSLVERSION_SSLv3 },
52 { "tlsv1", CURL_SSLVERSION_TLSv1 },
53#if LIBCURL_VERSION_NUM >= 0x072200
54 { "tlsv1.0", CURL_SSLVERSION_TLSv1_0 },
55 { "tlsv1.1", CURL_SSLVERSION_TLSv1_1 },
56 { "tlsv1.2", CURL_SSLVERSION_TLSv1_2 },
57#endif
58};
ef52aafa 59#if LIBCURL_VERSION_NUM >= 0x070903
4251ccbd 60static const char *ssl_key;
29508e1e
NH
61#endif
62#if LIBCURL_VERSION_NUM >= 0x070908
4251ccbd 63static const char *ssl_capath;
29508e1e 64#endif
4251ccbd 65static const char *ssl_cainfo;
cc3530e8
MH
66static long curl_low_speed_limit = -1;
67static long curl_low_speed_time = -1;
4251ccbd
JH
68static int curl_ftp_no_epsv;
69static const char *curl_http_proxy;
ef976395
KF
70static const char *http_proxy_authmethod;
71static struct {
72 const char *name;
73 long curlauth_param;
74} proxy_authmethods[] = {
75 { "basic", CURLAUTH_BASIC },
76 { "digest", CURLAUTH_DIGEST },
77 { "negotiate", CURLAUTH_GSSNEGOTIATE },
78 { "ntlm", CURLAUTH_NTLM },
79#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
80 { "anyauth", CURLAUTH_ANY },
81#endif
82 /*
83 * CURLAUTH_DIGEST_IE has no corresponding command-line option in
84 * curl(1) and is not included in CURLAUTH_ANY, so we leave it out
85 * here, too
86 */
87};
372370f1
KF
88static struct credential proxy_auth = CREDENTIAL_INIT;
89static const char *curl_proxyuserpwd;
bcfb95dd 90static const char *curl_cookie_file;
912b2acf 91static int curl_save_cookies;
2501aff8 92struct credential http_auth = CREDENTIAL_INIT;
a4ddbc33 93static int http_proactive_auth;
b1d1058c 94static const char *user_agent;
121061f6 95static int curl_empty_auth;
29508e1e 96
30dd9163
ML
97#if LIBCURL_VERSION_NUM >= 0x071700
98/* Use CURLOPT_KEYPASSWD as is */
99#elif LIBCURL_VERSION_NUM >= 0x070903
100#define CURLOPT_KEYPASSWD CURLOPT_SSLKEYPASSWD
101#else
102#define CURLOPT_KEYPASSWD CURLOPT_SSLCERTPASSWD
103#endif
104
148bb6a7 105static struct credential cert_auth = CREDENTIAL_INIT;
30dd9163 106static int ssl_cert_password_required;
4dbe6646 107#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
108static unsigned long http_auth_methods = CURLAUTH_ANY;
109#endif
30dd9163 110
cc3530e8 111static struct curl_slist *pragma_header;
5424bc55 112static struct curl_slist *no_pragma_header;
e9176745 113
4251ccbd 114static struct active_request_slot *active_queue_head;
29508e1e 115
f18604bb
YE
116static char *cached_accept_language;
117
a04ff3ec 118size_t fread_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_)
29508e1e
NH
119{
120 size_t size = eltsize * nmemb;
f444e528
JH
121 struct buffer *buffer = buffer_;
122
028c2976
MH
123 if (size > buffer->buf.len - buffer->posn)
124 size = buffer->buf.len - buffer->posn;
125 memcpy(ptr, buffer->buf.buf + buffer->posn, size);
29508e1e 126 buffer->posn += size;
028c2976 127
29508e1e
NH
128 return size;
129}
130
3944ba0c
MS
131#ifndef NO_CURL_IOCTL
132curlioerr ioctl_buffer(CURL *handle, int cmd, void *clientp)
133{
134 struct buffer *buffer = clientp;
135
136 switch (cmd) {
137 case CURLIOCMD_NOP:
138 return CURLIOE_OK;
139
140 case CURLIOCMD_RESTARTREAD:
141 buffer->posn = 0;
142 return CURLIOE_OK;
143
144 default:
145 return CURLIOE_UNKNOWNCMD;
146 }
147}
148#endif
149
a04ff3ec 150size_t fwrite_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_)
29508e1e
NH
151{
152 size_t size = eltsize * nmemb;
f444e528
JH
153 struct strbuf *buffer = buffer_;
154
028c2976 155 strbuf_add(buffer, ptr, size);
29508e1e
NH
156 return size;
157}
158
a04ff3ec 159size_t fwrite_null(char *ptr, size_t eltsize, size_t nmemb, void *strbuf)
29508e1e 160{
29508e1e
NH
161 return eltsize * nmemb;
162}
163
b90a3d7b
JH
164static void closedown_active_slot(struct active_request_slot *slot)
165{
166 active_requests--;
167 slot->in_use = 0;
168}
169
170static void finish_active_slot(struct active_request_slot *slot)
171{
172 closedown_active_slot(slot);
173 curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE, &slot->http_code);
174
175 if (slot->finished != NULL)
176 (*slot->finished) = 1;
177
178 /* Store slot results so they can be read after the slot is reused */
179 if (slot->results != NULL) {
180 slot->results->curl_result = slot->curl_result;
181 slot->results->http_code = slot->http_code;
182#if LIBCURL_VERSION_NUM >= 0x070a08
183 curl_easy_getinfo(slot->curl, CURLINFO_HTTPAUTH_AVAIL,
184 &slot->results->auth_avail);
185#else
186 slot->results->auth_avail = 0;
187#endif
372370f1
KF
188
189 curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CONNECTCODE,
190 &slot->results->http_connectcode);
b90a3d7b
JH
191 }
192
193 /* Run callback if appropriate */
194 if (slot->callback_func != NULL)
195 slot->callback_func(slot->callback_data);
196}
197
29508e1e
NH
198#ifdef USE_CURL_MULTI
199static void process_curl_messages(void)
200{
201 int num_messages;
202 struct active_request_slot *slot;
203 CURLMsg *curl_message = curl_multi_info_read(curlm, &num_messages);
204
205 while (curl_message != NULL) {
206 if (curl_message->msg == CURLMSG_DONE) {
207 int curl_result = curl_message->data.result;
208 slot = active_queue_head;
209 while (slot != NULL &&
210 slot->curl != curl_message->easy_handle)
211 slot = slot->next;
212 if (slot != NULL) {
213 curl_multi_remove_handle(curlm, slot->curl);
214 slot->curl_result = curl_result;
215 finish_active_slot(slot);
216 } else {
217 fprintf(stderr, "Received DONE message for unknown request!\n");
218 }
219 } else {
220 fprintf(stderr, "Unknown CURL message received: %d\n",
221 (int)curl_message->msg);
222 }
223 curl_message = curl_multi_info_read(curlm, &num_messages);
224 }
225}
226#endif
227
ef90d6d4 228static int http_options(const char *var, const char *value, void *cb)
29508e1e
NH
229{
230 if (!strcmp("http.sslverify", var)) {
7059cd99 231 curl_ssl_verify = git_config_bool(var, value);
29508e1e
NH
232 return 0;
233 }
f6f2a9e4
LKS
234 if (!strcmp("http.sslcipherlist", var))
235 return git_config_string(&ssl_cipherlist, var, value);
01861cb7
EP
236 if (!strcmp("http.sslversion", var))
237 return git_config_string(&ssl_version, var, value);
7059cd99
JH
238 if (!strcmp("http.sslcert", var))
239 return git_config_string(&ssl_cert, var, value);
ef52aafa 240#if LIBCURL_VERSION_NUM >= 0x070903
7059cd99
JH
241 if (!strcmp("http.sslkey", var))
242 return git_config_string(&ssl_key, var, value);
29508e1e
NH
243#endif
244#if LIBCURL_VERSION_NUM >= 0x070908
7059cd99 245 if (!strcmp("http.sslcapath", var))
bf9acba2 246 return git_config_pathname(&ssl_capath, var, value);
29508e1e 247#endif
7059cd99 248 if (!strcmp("http.sslcainfo", var))
bf9acba2 249 return git_config_pathname(&ssl_cainfo, var, value);
754ae192 250 if (!strcmp("http.sslcertpasswordprotected", var)) {
3f4ccd2b 251 ssl_cert_password_required = git_config_bool(var, value);
754ae192
ML
252 return 0;
253 }
4bc444eb
MV
254 if (!strcmp("http.ssltry", var)) {
255 curl_ssl_try = git_config_bool(var, value);
256 return 0;
257 }
ad75ebe5
TRC
258 if (!strcmp("http.minsessions", var)) {
259 min_curl_sessions = git_config_int(var, value);
260#ifndef USE_CURL_MULTI
261 if (min_curl_sessions > 1)
262 min_curl_sessions = 1;
263#endif
264 return 0;
265 }
a6080a0a 266#ifdef USE_CURL_MULTI
29508e1e 267 if (!strcmp("http.maxrequests", var)) {
7059cd99 268 max_requests = git_config_int(var, value);
29508e1e
NH
269 return 0;
270 }
271#endif
29508e1e 272 if (!strcmp("http.lowspeedlimit", var)) {
7059cd99 273 curl_low_speed_limit = (long)git_config_int(var, value);
29508e1e
NH
274 return 0;
275 }
276 if (!strcmp("http.lowspeedtime", var)) {
7059cd99 277 curl_low_speed_time = (long)git_config_int(var, value);
29508e1e
NH
278 return 0;
279 }
280
3ea099d4
SK
281 if (!strcmp("http.noepsv", var)) {
282 curl_ftp_no_epsv = git_config_bool(var, value);
283 return 0;
284 }
7059cd99
JH
285 if (!strcmp("http.proxy", var))
286 return git_config_string(&curl_http_proxy, var, value);
3ea099d4 287
ef976395
KF
288 if (!strcmp("http.proxyauthmethod", var))
289 return git_config_string(&http_proxy_authmethod, var, value);
290
bcfb95dd
DB
291 if (!strcmp("http.cookiefile", var))
292 return git_config_string(&curl_cookie_file, var, value);
912b2acf
DB
293 if (!strcmp("http.savecookies", var)) {
294 curl_save_cookies = git_config_bool(var, value);
295 return 0;
296 }
bcfb95dd 297
de1a2fdd
SP
298 if (!strcmp("http.postbuffer", var)) {
299 http_post_buffer = git_config_int(var, value);
300 if (http_post_buffer < LARGE_PACKET_MAX)
301 http_post_buffer = LARGE_PACKET_MAX;
302 return 0;
303 }
304
b1d1058c
SO
305 if (!strcmp("http.useragent", var))
306 return git_config_string(&user_agent, var, value);
307
121061f6 308 if (!strcmp("http.emptyauth", var)) {
309 curl_empty_auth = git_config_bool(var, value);
310 return 0;
311 }
312
29508e1e 313 /* Fall back on the default ones */
ef90d6d4 314 return git_default_config(var, value, cb);
29508e1e
NH
315}
316
c33976cb
JH
317static void init_curl_http_auth(CURL *result)
318{
121061f6 319 if (!http_auth.username) {
320 if (curl_empty_auth)
321 curl_easy_setopt(result, CURLOPT_USERPWD, ":");
6f4c347c 322 return;
121061f6 323 }
6f4c347c
JK
324
325 credential_fill(&http_auth);
326
327#if LIBCURL_VERSION_NUM >= 0x071301
328 curl_easy_setopt(result, CURLOPT_USERNAME, http_auth.username);
329 curl_easy_setopt(result, CURLOPT_PASSWORD, http_auth.password);
330#else
331 {
aa0834a0 332 static struct strbuf up = STRBUF_INIT;
a94cf2cb
BC
333 /*
334 * Note that we assume we only ever have a single set of
335 * credentials in a given program run, so we do not have
336 * to worry about updating this buffer, only setting its
337 * initial value.
338 */
339 if (!up.len)
340 strbuf_addf(&up, "%s:%s",
341 http_auth.username, http_auth.password);
aa0834a0 342 curl_easy_setopt(result, CURLOPT_USERPWD, up.buf);
c33976cb 343 }
6f4c347c 344#endif
c33976cb
JH
345}
346
ef976395
KF
347/* *var must be free-able */
348static void var_override(const char **var, char *value)
349{
350 if (value) {
351 free((void *)*var);
352 *var = xstrdup(value);
353 }
354}
355
372370f1
KF
356static void set_proxyauth_name_password(CURL *result)
357{
358#if LIBCURL_VERSION_NUM >= 0x071301
359 curl_easy_setopt(result, CURLOPT_PROXYUSERNAME,
360 proxy_auth.username);
361 curl_easy_setopt(result, CURLOPT_PROXYPASSWORD,
362 proxy_auth.password);
363#else
364 struct strbuf s = STRBUF_INIT;
365
366 strbuf_addstr_urlencode(&s, proxy_auth.username, 1);
367 strbuf_addch(&s, ':');
368 strbuf_addstr_urlencode(&s, proxy_auth.password, 1);
369 curl_proxyuserpwd = strbuf_detach(&s, NULL);
370 curl_easy_setopt(result, CURLOPT_PROXYUSERPWD, curl_proxyuserpwd);
371#endif
372}
373
ef976395
KF
374static void init_curl_proxy_auth(CURL *result)
375{
372370f1
KF
376 if (proxy_auth.username) {
377 if (!proxy_auth.password)
378 credential_fill(&proxy_auth);
379 set_proxyauth_name_password(result);
380 }
381
ef976395
KF
382 var_override(&http_proxy_authmethod, getenv("GIT_HTTP_PROXY_AUTHMETHOD"));
383
384#if LIBCURL_VERSION_NUM >= 0x070a07 /* CURLOPT_PROXYAUTH and CURLAUTH_ANY */
385 if (http_proxy_authmethod) {
386 int i;
387 for (i = 0; i < ARRAY_SIZE(proxy_authmethods); i++) {
388 if (!strcmp(http_proxy_authmethod, proxy_authmethods[i].name)) {
389 curl_easy_setopt(result, CURLOPT_PROXYAUTH,
390 proxy_authmethods[i].curlauth_param);
391 break;
392 }
393 }
394 if (i == ARRAY_SIZE(proxy_authmethods)) {
395 warning("unsupported proxy authentication method %s: using anyauth",
396 http_proxy_authmethod);
397 curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
398 }
399 }
400 else
401 curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
402#endif
403}
404
30dd9163
ML
405static int has_cert_password(void)
406{
30dd9163
ML
407 if (ssl_cert == NULL || ssl_cert_password_required != 1)
408 return 0;
148bb6a7
JK
409 if (!cert_auth.password) {
410 cert_auth.protocol = xstrdup("cert");
75e9a405 411 cert_auth.username = xstrdup("");
148bb6a7
JK
412 cert_auth.path = xstrdup(ssl_cert);
413 credential_fill(&cert_auth);
414 }
415 return 1;
30dd9163
ML
416}
417
47ce1153
JK
418#if LIBCURL_VERSION_NUM >= 0x071900
419static void set_curl_keepalive(CURL *c)
420{
421 curl_easy_setopt(c, CURLOPT_TCP_KEEPALIVE, 1);
422}
423
424#elif LIBCURL_VERSION_NUM >= 0x071000
a15d069a
EW
425static int sockopt_callback(void *client, curl_socket_t fd, curlsocktype type)
426{
427 int ka = 1;
428 int rc;
429 socklen_t len = (socklen_t)sizeof(ka);
430
431 if (type != CURLSOCKTYPE_IPCXN)
432 return 0;
433
434 rc = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&ka, len);
435 if (rc < 0)
436 warning("unable to set SO_KEEPALIVE on socket %s",
437 strerror(errno));
438
439 return 0; /* CURL_SOCKOPT_OK only exists since curl 7.21.5 */
440}
441
47ce1153
JK
442static void set_curl_keepalive(CURL *c)
443{
444 curl_easy_setopt(c, CURLOPT_SOCKOPTFUNCTION, sockopt_callback);
445}
446
447#else
448static void set_curl_keepalive(CURL *c)
449{
450 /* not supported on older curl versions */
451}
452#endif
453
4251ccbd 454static CURL *get_curl_handle(void)
11979b98 455{
4251ccbd 456 CURL *result = curl_easy_init();
f4113cac 457 long allowed_protocols = 0;
11979b98 458
faa3807c
BR
459 if (!result)
460 die("curl_easy_init failed");
461
a5ccc597
JH
462 if (!curl_ssl_verify) {
463 curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, 0);
464 curl_easy_setopt(result, CURLOPT_SSL_VERIFYHOST, 0);
465 } else {
466 /* Verify authenticity of the peer's certificate */
467 curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, 1);
468 /* The name in the cert must match whom we tried to connect */
469 curl_easy_setopt(result, CURLOPT_SSL_VERIFYHOST, 2);
470 }
471
11979b98
JH
472#if LIBCURL_VERSION_NUM >= 0x070907
473 curl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
474#endif
b8ac9230 475#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
525ecd26 476 curl_easy_setopt(result, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
b8ac9230 477#endif
11979b98 478
a4ddbc33
JK
479 if (http_proactive_auth)
480 init_curl_http_auth(result);
481
01861cb7
EP
482 if (getenv("GIT_SSL_VERSION"))
483 ssl_version = getenv("GIT_SSL_VERSION");
484 if (ssl_version && *ssl_version) {
485 int i;
486 for (i = 0; i < ARRAY_SIZE(sslversions); i++) {
487 if (!strcmp(ssl_version, sslversions[i].name)) {
488 curl_easy_setopt(result, CURLOPT_SSLVERSION,
489 sslversions[i].ssl_version);
490 break;
491 }
492 }
493 if (i == ARRAY_SIZE(sslversions))
494 warning("unsupported ssl version %s: using default",
495 ssl_version);
496 }
497
f6f2a9e4
LKS
498 if (getenv("GIT_SSL_CIPHER_LIST"))
499 ssl_cipherlist = getenv("GIT_SSL_CIPHER_LIST");
f6f2a9e4
LKS
500 if (ssl_cipherlist != NULL && *ssl_cipherlist)
501 curl_easy_setopt(result, CURLOPT_SSL_CIPHER_LIST,
502 ssl_cipherlist);
503
11979b98
JH
504 if (ssl_cert != NULL)
505 curl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert);
30dd9163 506 if (has_cert_password())
148bb6a7 507 curl_easy_setopt(result, CURLOPT_KEYPASSWD, cert_auth.password);
ef52aafa 508#if LIBCURL_VERSION_NUM >= 0x070903
11979b98
JH
509 if (ssl_key != NULL)
510 curl_easy_setopt(result, CURLOPT_SSLKEY, ssl_key);
511#endif
512#if LIBCURL_VERSION_NUM >= 0x070908
513 if (ssl_capath != NULL)
514 curl_easy_setopt(result, CURLOPT_CAPATH, ssl_capath);
515#endif
516 if (ssl_cainfo != NULL)
517 curl_easy_setopt(result, CURLOPT_CAINFO, ssl_cainfo);
11979b98
JH
518
519 if (curl_low_speed_limit > 0 && curl_low_speed_time > 0) {
520 curl_easy_setopt(result, CURLOPT_LOW_SPEED_LIMIT,
521 curl_low_speed_limit);
522 curl_easy_setopt(result, CURLOPT_LOW_SPEED_TIME,
523 curl_low_speed_time);
524 }
525
526 curl_easy_setopt(result, CURLOPT_FOLLOWLOCATION, 1);
b2581164 527 curl_easy_setopt(result, CURLOPT_MAXREDIRS, 20);
311e2ea0
TRC
528#if LIBCURL_VERSION_NUM >= 0x071301
529 curl_easy_setopt(result, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL);
530#elif LIBCURL_VERSION_NUM >= 0x071101
531 curl_easy_setopt(result, CURLOPT_POST301, 1);
532#endif
f4113cac
BB
533#if LIBCURL_VERSION_NUM >= 0x071304
534 if (is_transport_allowed("http"))
535 allowed_protocols |= CURLPROTO_HTTP;
536 if (is_transport_allowed("https"))
537 allowed_protocols |= CURLPROTO_HTTPS;
538 if (is_transport_allowed("ftp"))
539 allowed_protocols |= CURLPROTO_FTP;
540 if (is_transport_allowed("ftps"))
541 allowed_protocols |= CURLPROTO_FTPS;
542 curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS, allowed_protocols);
543#else
544 if (transport_restrict_protocols())
545 warning("protocol restrictions not applied to curl redirects because\n"
546 "your curl version is too old (>= 7.19.4)");
547#endif
11979b98 548
7982d74e
MW
549 if (getenv("GIT_CURL_VERBOSE"))
550 curl_easy_setopt(result, CURLOPT_VERBOSE, 1);
551
b1d1058c 552 curl_easy_setopt(result, CURLOPT_USERAGENT,
745c7c8e 553 user_agent ? user_agent : git_user_agent());
20fc9bc5 554
3ea099d4
SK
555 if (curl_ftp_no_epsv)
556 curl_easy_setopt(result, CURLOPT_FTP_USE_EPSV, 0);
557
4bc444eb
MV
558#ifdef CURLOPT_USE_SSL
559 if (curl_ssl_try)
560 curl_easy_setopt(result, CURLOPT_USE_SSL, CURLUSESSL_TRY);
561#endif
562
372370f1
KF
563 /*
564 * CURL also examines these variables as a fallback; but we need to query
565 * them here in order to decide whether to prompt for missing password (cf.
566 * init_curl_proxy_auth()).
567 *
568 * Unlike many other common environment variables, these are historically
569 * lowercase only. It appears that CURL did not know this and implemented
570 * only uppercase variants, which was later corrected to take both - with
571 * the exception of http_proxy, which is lowercase only also in CURL. As
572 * the lowercase versions are the historical quasi-standard, they take
573 * precedence here, as in CURL.
574 */
575 if (!curl_http_proxy) {
576 if (!strcmp(http_auth.protocol, "https")) {
577 var_override(&curl_http_proxy, getenv("HTTPS_PROXY"));
578 var_override(&curl_http_proxy, getenv("https_proxy"));
579 } else {
580 var_override(&curl_http_proxy, getenv("http_proxy"));
581 }
582 if (!curl_http_proxy) {
583 var_override(&curl_http_proxy, getenv("ALL_PROXY"));
584 var_override(&curl_http_proxy, getenv("all_proxy"));
585 }
586 }
587
dd613997 588 if (curl_http_proxy) {
9c5665aa 589 curl_easy_setopt(result, CURLOPT_PROXY, curl_http_proxy);
6d7afe07
PT
590#if LIBCURL_VERSION_NUM >= 0x071800
591 if (starts_with(curl_http_proxy, "socks5"))
592 curl_easy_setopt(result,
593 CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
594 else if (starts_with(curl_http_proxy, "socks4a"))
595 curl_easy_setopt(result,
596 CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4A);
597 else if (starts_with(curl_http_proxy, "socks"))
598 curl_easy_setopt(result,
599 CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
600#endif
372370f1
KF
601 if (strstr(curl_http_proxy, "://"))
602 credential_from_url(&proxy_auth, curl_http_proxy);
603 else {
604 struct strbuf url = STRBUF_INIT;
605 strbuf_addf(&url, "http://%s", curl_http_proxy);
606 credential_from_url(&proxy_auth, url.buf);
607 strbuf_release(&url);
608 }
609
610 curl_easy_setopt(result, CURLOPT_PROXY, proxy_auth.host);
5841520b 611 }
ef976395 612 init_curl_proxy_auth(result);
9c5665aa 613
47ce1153 614 set_curl_keepalive(result);
a15d069a 615
11979b98
JH
616 return result;
617}
618
7059cd99
JH
619static void set_from_env(const char **var, const char *envname)
620{
621 const char *val = getenv(envname);
622 if (val)
623 *var = val;
624}
625
a4ddbc33 626void http_init(struct remote *remote, const char *url, int proactive_auth)
29508e1e
NH
627{
628 char *low_speed_limit;
629 char *low_speed_time;
6a56993b
KM
630 char *normalized_url;
631 struct urlmatch_config config = { STRING_LIST_INIT_DUP };
632
633 config.section = "http";
634 config.key = NULL;
635 config.collect_fn = http_options;
636 config.cascade_fn = git_default_config;
637 config.cb = NULL;
29508e1e 638
e9176745 639 http_is_verbose = 0;
6a56993b 640 normalized_url = url_normalize(url, &config.url);
e9176745 641
6a56993b
KM
642 git_config(urlmatch_config_entry, &config);
643 free(normalized_url);
7059cd99 644
faa3807c
BR
645 if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)
646 die("curl_global_init failed");
29508e1e 647
a4ddbc33
JK
648 http_proactive_auth = proactive_auth;
649
9fc6440d
MH
650 if (remote && remote->http_proxy)
651 curl_http_proxy = xstrdup(remote->http_proxy);
652
ef976395
KF
653 if (remote)
654 var_override(&http_proxy_authmethod, remote->http_proxy_authmethod);
655
29508e1e 656 pragma_header = curl_slist_append(pragma_header, "Pragma: no-cache");
e9176745 657 no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:");
29508e1e
NH
658
659#ifdef USE_CURL_MULTI
660 {
661 char *http_max_requests = getenv("GIT_HTTP_MAX_REQUESTS");
662 if (http_max_requests != NULL)
663 max_requests = atoi(http_max_requests);
664 }
665
666 curlm = curl_multi_init();
8837eb47
JK
667 if (!curlm)
668 die("curl_multi_init failed");
29508e1e
NH
669#endif
670
671 if (getenv("GIT_SSL_NO_VERIFY"))
672 curl_ssl_verify = 0;
673
7059cd99 674 set_from_env(&ssl_cert, "GIT_SSL_CERT");
ef52aafa 675#if LIBCURL_VERSION_NUM >= 0x070903
7059cd99 676 set_from_env(&ssl_key, "GIT_SSL_KEY");
29508e1e
NH
677#endif
678#if LIBCURL_VERSION_NUM >= 0x070908
7059cd99 679 set_from_env(&ssl_capath, "GIT_SSL_CAPATH");
29508e1e 680#endif
7059cd99 681 set_from_env(&ssl_cainfo, "GIT_SSL_CAINFO");
29508e1e 682
b1d1058c
SO
683 set_from_env(&user_agent, "GIT_HTTP_USER_AGENT");
684
29508e1e
NH
685 low_speed_limit = getenv("GIT_HTTP_LOW_SPEED_LIMIT");
686 if (low_speed_limit != NULL)
687 curl_low_speed_limit = strtol(low_speed_limit, NULL, 10);
688 low_speed_time = getenv("GIT_HTTP_LOW_SPEED_TIME");
689 if (low_speed_time != NULL)
690 curl_low_speed_time = strtol(low_speed_time, NULL, 10);
691
29508e1e
NH
692 if (curl_ssl_verify == -1)
693 curl_ssl_verify = 1;
694
ad75ebe5 695 curl_session_count = 0;
29508e1e
NH
696#ifdef USE_CURL_MULTI
697 if (max_requests < 1)
698 max_requests = DEFAULT_MAX_REQUESTS;
699#endif
700
3ea099d4
SK
701 if (getenv("GIT_CURL_FTP_NO_EPSV"))
702 curl_ftp_no_epsv = 1;
703
deba4937 704 if (url) {
148bb6a7 705 credential_from_url(&http_auth, url);
754ae192
ML
706 if (!ssl_cert_password_required &&
707 getenv("GIT_SSL_CERT_PASSWORD_PROTECTED") &&
59556548 708 starts_with(url, "https://"))
30dd9163
ML
709 ssl_cert_password_required = 1;
710 }
c33976cb 711
29508e1e
NH
712#ifndef NO_CURL_EASY_DUPHANDLE
713 curl_default = get_curl_handle();
714#endif
715}
716
717void http_cleanup(void)
718{
719 struct active_request_slot *slot = active_queue_head;
29508e1e
NH
720
721 while (slot != NULL) {
3278cd0a 722 struct active_request_slot *next = slot->next;
f23d1f76 723 if (slot->curl != NULL) {
29508e1e 724#ifdef USE_CURL_MULTI
f23d1f76 725 curl_multi_remove_handle(curlm, slot->curl);
29508e1e 726#endif
29508e1e 727 curl_easy_cleanup(slot->curl);
f23d1f76 728 }
3278cd0a
SP
729 free(slot);
730 slot = next;
29508e1e 731 }
3278cd0a 732 active_queue_head = NULL;
29508e1e
NH
733
734#ifndef NO_CURL_EASY_DUPHANDLE
735 curl_easy_cleanup(curl_default);
736#endif
737
738#ifdef USE_CURL_MULTI
739 curl_multi_cleanup(curlm);
740#endif
741 curl_global_cleanup();
b3ca4e4e
NH
742
743 curl_slist_free_all(pragma_header);
3278cd0a 744 pragma_header = NULL;
9fc6440d 745
e9176745
TRC
746 curl_slist_free_all(no_pragma_header);
747 no_pragma_header = NULL;
748
9fc6440d 749 if (curl_http_proxy) {
e4a80ecf 750 free((void *)curl_http_proxy);
9fc6440d
MH
751 curl_http_proxy = NULL;
752 }
30dd9163 753
372370f1
KF
754 if (proxy_auth.password) {
755 memset(proxy_auth.password, 0, strlen(proxy_auth.password));
756 free(proxy_auth.password);
757 proxy_auth.password = NULL;
758 }
759
760 free((void *)curl_proxyuserpwd);
761 curl_proxyuserpwd = NULL;
762
ef976395
KF
763 free((void *)http_proxy_authmethod);
764 http_proxy_authmethod = NULL;
765
148bb6a7
JK
766 if (cert_auth.password != NULL) {
767 memset(cert_auth.password, 0, strlen(cert_auth.password));
768 free(cert_auth.password);
769 cert_auth.password = NULL;
30dd9163
ML
770 }
771 ssl_cert_password_required = 0;
f18604bb
YE
772
773 free(cached_accept_language);
774 cached_accept_language = NULL;
29508e1e
NH
775}
776
29508e1e
NH
777struct active_request_slot *get_active_slot(void)
778{
779 struct active_request_slot *slot = active_queue_head;
780 struct active_request_slot *newslot;
781
782#ifdef USE_CURL_MULTI
783 int num_transfers;
784
785 /* Wait for a slot to open up if the queue is full */
786 while (active_requests >= max_requests) {
787 curl_multi_perform(curlm, &num_transfers);
4251ccbd 788 if (num_transfers < active_requests)
29508e1e 789 process_curl_messages();
29508e1e
NH
790 }
791#endif
792
4251ccbd 793 while (slot != NULL && slot->in_use)
29508e1e 794 slot = slot->next;
4251ccbd 795
29508e1e
NH
796 if (slot == NULL) {
797 newslot = xmalloc(sizeof(*newslot));
798 newslot->curl = NULL;
799 newslot->in_use = 0;
800 newslot->next = NULL;
801
802 slot = active_queue_head;
803 if (slot == NULL) {
804 active_queue_head = newslot;
805 } else {
4251ccbd 806 while (slot->next != NULL)
29508e1e 807 slot = slot->next;
29508e1e
NH
808 slot->next = newslot;
809 }
810 slot = newslot;
811 }
812
813 if (slot->curl == NULL) {
814#ifdef NO_CURL_EASY_DUPHANDLE
815 slot->curl = get_curl_handle();
816#else
817 slot->curl = curl_easy_duphandle(curl_default);
818#endif
ad75ebe5 819 curl_session_count++;
29508e1e
NH
820 }
821
822 active_requests++;
823 slot->in_use = 1;
c8568e13 824 slot->results = NULL;
baa7b67d 825 slot->finished = NULL;
29508e1e
NH
826 slot->callback_data = NULL;
827 slot->callback_func = NULL;
bcfb95dd 828 curl_easy_setopt(slot->curl, CURLOPT_COOKIEFILE, curl_cookie_file);
912b2acf
DB
829 if (curl_save_cookies)
830 curl_easy_setopt(slot->curl, CURLOPT_COOKIEJAR, curl_cookie_file);
29508e1e 831 curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, pragma_header);
29508e1e 832 curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, curl_errorstr);
9094950d
NH
833 curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, NULL);
834 curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, NULL);
835 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, NULL);
1e41827d 836 curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, NULL);
9094950d
NH
837 curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 0);
838 curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
b793acf1 839 curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 1);
835c4d36 840 curl_easy_setopt(slot->curl, CURLOPT_RANGE, NULL);
c915f11e
EW
841
842#if LIBCURL_VERSION_NUM >= 0x070a08
843 curl_easy_setopt(slot->curl, CURLOPT_IPRESOLVE, git_curl_ipresolve);
844#endif
4dbe6646 845#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
846 curl_easy_setopt(slot->curl, CURLOPT_HTTPAUTH, http_auth_methods);
847#endif
121061f6 848 if (http_auth.password || curl_empty_auth)
dfa1725a 849 init_curl_http_auth(slot->curl);
29508e1e
NH
850
851 return slot;
852}
853
854int start_active_slot(struct active_request_slot *slot)
855{
856#ifdef USE_CURL_MULTI
857 CURLMcode curlm_result = curl_multi_add_handle(curlm, slot->curl);
45c17412 858 int num_transfers;
29508e1e
NH
859
860 if (curlm_result != CURLM_OK &&
861 curlm_result != CURLM_CALL_MULTI_PERFORM) {
862 active_requests--;
863 slot->in_use = 0;
864 return 0;
865 }
45c17412
DB
866
867 /*
868 * We know there must be something to do, since we just added
869 * something.
870 */
871 curl_multi_perform(curlm, &num_transfers);
29508e1e
NH
872#endif
873 return 1;
874}
875
876#ifdef USE_CURL_MULTI
fc57b6aa
DB
877struct fill_chain {
878 void *data;
879 int (*fill)(void *);
880 struct fill_chain *next;
881};
882
4251ccbd 883static struct fill_chain *fill_cfg;
fc57b6aa
DB
884
885void add_fill_function(void *data, int (*fill)(void *))
886{
e8eec71d 887 struct fill_chain *new = xmalloc(sizeof(*new));
fc57b6aa
DB
888 struct fill_chain **linkp = &fill_cfg;
889 new->data = data;
890 new->fill = fill;
891 new->next = NULL;
892 while (*linkp)
893 linkp = &(*linkp)->next;
894 *linkp = new;
895}
896
45c17412
DB
897void fill_active_slots(void)
898{
899 struct active_request_slot *slot = active_queue_head;
900
fc57b6aa
DB
901 while (active_requests < max_requests) {
902 struct fill_chain *fill;
903 for (fill = fill_cfg; fill; fill = fill->next)
904 if (fill->fill(fill->data))
905 break;
906
907 if (!fill)
45c17412 908 break;
fc57b6aa 909 }
45c17412
DB
910
911 while (slot != NULL) {
ad75ebe5
TRC
912 if (!slot->in_use && slot->curl != NULL
913 && curl_session_count > min_curl_sessions) {
45c17412
DB
914 curl_easy_cleanup(slot->curl);
915 slot->curl = NULL;
ad75ebe5 916 curl_session_count--;
45c17412
DB
917 }
918 slot = slot->next;
919 }
920}
921
29508e1e
NH
922void step_active_slots(void)
923{
924 int num_transfers;
925 CURLMcode curlm_result;
926
927 do {
928 curlm_result = curl_multi_perform(curlm, &num_transfers);
929 } while (curlm_result == CURLM_CALL_MULTI_PERFORM);
930 if (num_transfers < active_requests) {
931 process_curl_messages();
932 fill_active_slots();
933 }
934}
935#endif
936
937void run_active_slot(struct active_request_slot *slot)
938{
939#ifdef USE_CURL_MULTI
29508e1e
NH
940 fd_set readfds;
941 fd_set writefds;
942 fd_set excfds;
943 int max_fd;
944 struct timeval select_timeout;
baa7b67d 945 int finished = 0;
29508e1e 946
baa7b67d
NH
947 slot->finished = &finished;
948 while (!finished) {
29508e1e
NH
949 step_active_slots();
950
df26c471 951 if (slot->in_use) {
eb56c821
MF
952#if LIBCURL_VERSION_NUM >= 0x070f04
953 long curl_timeout;
954 curl_multi_timeout(curlm, &curl_timeout);
955 if (curl_timeout == 0) {
956 continue;
957 } else if (curl_timeout == -1) {
958 select_timeout.tv_sec = 0;
959 select_timeout.tv_usec = 50000;
960 } else {
961 select_timeout.tv_sec = curl_timeout / 1000;
962 select_timeout.tv_usec = (curl_timeout % 1000) * 1000;
963 }
964#else
965 select_timeout.tv_sec = 0;
966 select_timeout.tv_usec = 50000;
967#endif
29508e1e 968
6f9dd67f 969 max_fd = -1;
29508e1e
NH
970 FD_ZERO(&readfds);
971 FD_ZERO(&writefds);
972 FD_ZERO(&excfds);
6f9dd67f 973 curl_multi_fdset(curlm, &readfds, &writefds, &excfds, &max_fd);
eb56c821 974
7202b81f
SZ
975 /*
976 * It can happen that curl_multi_timeout returns a pathologically
977 * long timeout when curl_multi_fdset returns no file descriptors
978 * to read. See commit message for more details.
979 */
980 if (max_fd < 0 &&
981 (select_timeout.tv_sec > 0 ||
982 select_timeout.tv_usec > 50000)) {
983 select_timeout.tv_sec = 0;
984 select_timeout.tv_usec = 50000;
985 }
986
6f9dd67f 987 select(max_fd+1, &readfds, &writefds, &excfds, &select_timeout);
29508e1e
NH
988 }
989 }
990#else
991 while (slot->in_use) {
992 slot->curl_result = curl_easy_perform(slot->curl);
993 finish_active_slot(slot);
994 }
995#endif
996}
997
83e41e2e 998static void release_active_slot(struct active_request_slot *slot)
53f31389
MW
999{
1000 closedown_active_slot(slot);
ad75ebe5 1001 if (slot->curl && curl_session_count > min_curl_sessions) {
b3ca4e4e 1002#ifdef USE_CURL_MULTI
53f31389 1003 curl_multi_remove_handle(curlm, slot->curl);
b3ca4e4e 1004#endif
53f31389
MW
1005 curl_easy_cleanup(slot->curl);
1006 slot->curl = NULL;
ad75ebe5 1007 curl_session_count--;
53f31389 1008 }
b3ca4e4e 1009#ifdef USE_CURL_MULTI
53f31389 1010 fill_active_slots();
b3ca4e4e 1011#endif
53f31389
MW
1012}
1013
29508e1e
NH
1014void finish_all_active_slots(void)
1015{
1016 struct active_request_slot *slot = active_queue_head;
1017
1018 while (slot != NULL)
1019 if (slot->in_use) {
1020 run_active_slot(slot);
1021 slot = active_queue_head;
1022 } else {
1023 slot = slot->next;
1024 }
1025}
d7e92806 1026
5ace994f 1027/* Helpers for modifying and creating URLs */
d7e92806
MH
1028static inline int needs_quote(int ch)
1029{
1030 if (((ch >= 'A') && (ch <= 'Z'))
1031 || ((ch >= 'a') && (ch <= 'z'))
1032 || ((ch >= '0') && (ch <= '9'))
1033 || (ch == '/')
1034 || (ch == '-')
1035 || (ch == '.'))
1036 return 0;
1037 return 1;
1038}
1039
d7e92806
MH
1040static char *quote_ref_url(const char *base, const char *ref)
1041{
113106e0 1042 struct strbuf buf = STRBUF_INIT;
d7e92806 1043 const char *cp;
113106e0 1044 int ch;
d7e92806 1045
5ace994f 1046 end_url_with_slash(&buf, base);
113106e0
TRC
1047
1048 for (cp = ref; (ch = *cp) != 0; cp++)
d7e92806 1049 if (needs_quote(ch))
113106e0 1050 strbuf_addf(&buf, "%%%02x", ch);
d7e92806 1051 else
113106e0 1052 strbuf_addch(&buf, *cp);
d7e92806 1053
113106e0 1054 return strbuf_detach(&buf, NULL);
d7e92806
MH
1055}
1056
5424bc55
TRC
1057void append_remote_object_url(struct strbuf *buf, const char *url,
1058 const char *hex,
1059 int only_two_digit_prefix)
1060{
800324c3
TRC
1061 end_url_with_slash(buf, url);
1062
1063 strbuf_addf(buf, "objects/%.*s/", 2, hex);
5424bc55
TRC
1064 if (!only_two_digit_prefix)
1065 strbuf_addf(buf, "%s", hex+2);
1066}
1067
1068char *get_remote_object_url(const char *url, const char *hex,
1069 int only_two_digit_prefix)
1070{
1071 struct strbuf buf = STRBUF_INIT;
1072 append_remote_object_url(&buf, url, hex, only_two_digit_prefix);
1073 return strbuf_detach(&buf, NULL);
1074}
1075
b90a3d7b 1076static int handle_curl_result(struct slot_results *results)
88097030 1077{
6d052d78
JK
1078 /*
1079 * If we see a failing http code with CURLE_OK, we have turned off
1080 * FAILONERROR (to keep the server's custom error response), and should
1081 * translate the code into failure here.
1082 */
1083 if (results->curl_result == CURLE_OK &&
1084 results->http_code >= 400) {
1085 results->curl_result = CURLE_HTTP_RETURNED_ERROR;
1086 /*
1087 * Normally curl will already have put the "reason phrase"
1088 * from the server into curl_errorstr; unfortunately without
1089 * FAILONERROR it is lost, so we can give only the numeric
1090 * status code.
1091 */
1092 snprintf(curl_errorstr, sizeof(curl_errorstr),
1093 "The requested URL returned error: %ld",
1094 results->http_code);
1095 }
1096
88097030
JK
1097 if (results->curl_result == CURLE_OK) {
1098 credential_approve(&http_auth);
372370f1
KF
1099 if (proxy_auth.password)
1100 credential_approve(&proxy_auth);
88097030
JK
1101 return HTTP_OK;
1102 } else if (missing_target(results))
1103 return HTTP_MISSING_TARGET;
1104 else if (results->http_code == 401) {
1105 if (http_auth.username && http_auth.password) {
1106 credential_reject(&http_auth);
1107 return HTTP_NOAUTH;
1108 } else {
4dbe6646 1109#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
1110 http_auth_methods &= ~CURLAUTH_GSSNEGOTIATE;
1111#endif
88097030
JK
1112 return HTTP_REAUTH;
1113 }
1114 } else {
372370f1
KF
1115 if (results->http_connectcode == 407)
1116 credential_reject(&proxy_auth);
3503e9ab 1117#if LIBCURL_VERSION_NUM >= 0x070c00
88097030
JK
1118 if (!curl_errorstr[0])
1119 strlcpy(curl_errorstr,
1120 curl_easy_strerror(results->curl_result),
1121 sizeof(curl_errorstr));
3503e9ab 1122#endif
88097030
JK
1123 return HTTP_ERROR;
1124 }
1125}
1126
beed336c
JK
1127int run_one_slot(struct active_request_slot *slot,
1128 struct slot_results *results)
1129{
1130 slot->results = results;
1131 if (!start_active_slot(slot)) {
1132 snprintf(curl_errorstr, sizeof(curl_errorstr),
1133 "failed to start HTTP request");
1134 return HTTP_START_FAILED;
1135 }
1136
1137 run_active_slot(slot);
1138 return handle_curl_result(results);
1139}
1140
132b70a2
JK
1141static CURLcode curlinfo_strbuf(CURL *curl, CURLINFO info, struct strbuf *buf)
1142{
1143 char *ptr;
1144 CURLcode ret;
1145
1146 strbuf_reset(buf);
1147 ret = curl_easy_getinfo(curl, info, &ptr);
1148 if (!ret && ptr)
1149 strbuf_addstr(buf, ptr);
1150 return ret;
1151}
1152
e3131626
JK
1153/*
1154 * Check for and extract a content-type parameter. "raw"
1155 * should be positioned at the start of the potential
1156 * parameter, with any whitespace already removed.
1157 *
1158 * "name" is the name of the parameter. The value is appended
1159 * to "out".
1160 */
1161static int extract_param(const char *raw, const char *name,
1162 struct strbuf *out)
1163{
1164 size_t len = strlen(name);
1165
1166 if (strncasecmp(raw, name, len))
1167 return -1;
1168 raw += len;
1169
1170 if (*raw != '=')
1171 return -1;
1172 raw++;
1173
f34a655d 1174 while (*raw && !isspace(*raw) && *raw != ';')
e3131626
JK
1175 strbuf_addch(out, *raw++);
1176 return 0;
1177}
1178
bf197fd7
JK
1179/*
1180 * Extract a normalized version of the content type, with any
1181 * spaces suppressed, all letters lowercased, and no trailing ";"
1182 * or parameters.
1183 *
1184 * Note that we will silently remove even invalid whitespace. For
1185 * example, "text / plain" is specifically forbidden by RFC 2616,
1186 * but "text/plain" is the only reasonable output, and this keeps
1187 * our code simple.
1188 *
e3131626
JK
1189 * If the "charset" argument is not NULL, store the value of any
1190 * charset parameter there.
1191 *
bf197fd7 1192 * Example:
e3131626 1193 * "TEXT/PLAIN; charset=utf-8" -> "text/plain", "utf-8"
bf197fd7
JK
1194 * "text / plain" -> "text/plain"
1195 */
e3131626
JK
1196static void extract_content_type(struct strbuf *raw, struct strbuf *type,
1197 struct strbuf *charset)
bf197fd7
JK
1198{
1199 const char *p;
1200
1201 strbuf_reset(type);
1202 strbuf_grow(type, raw->len);
1203 for (p = raw->buf; *p; p++) {
1204 if (isspace(*p))
1205 continue;
e3131626
JK
1206 if (*p == ';') {
1207 p++;
bf197fd7 1208 break;
e3131626 1209 }
bf197fd7
JK
1210 strbuf_addch(type, tolower(*p));
1211 }
e3131626
JK
1212
1213 if (!charset)
1214 return;
1215
1216 strbuf_reset(charset);
1217 while (*p) {
f34a655d 1218 while (isspace(*p) || *p == ';')
e3131626
JK
1219 p++;
1220 if (!extract_param(p, "charset", charset))
1221 return;
1222 while (*p && !isspace(*p))
1223 p++;
1224 }
c553fd1c
JK
1225
1226 if (!charset->len && starts_with(type->buf, "text/"))
1227 strbuf_addstr(charset, "ISO-8859-1");
bf197fd7
JK
1228}
1229
f18604bb
YE
1230static void write_accept_language(struct strbuf *buf)
1231{
1232 /*
1233 * MAX_DECIMAL_PLACES must not be larger than 3. If it is larger than
1234 * that, q-value will be smaller than 0.001, the minimum q-value the
1235 * HTTP specification allows. See
1236 * http://tools.ietf.org/html/rfc7231#section-5.3.1 for q-value.
1237 */
1238 const int MAX_DECIMAL_PLACES = 3;
1239 const int MAX_LANGUAGE_TAGS = 1000;
1240 const int MAX_ACCEPT_LANGUAGE_HEADER_SIZE = 4000;
1241 char **language_tags = NULL;
1242 int num_langs = 0;
1243 const char *s = get_preferred_languages();
1244 int i;
1245 struct strbuf tag = STRBUF_INIT;
1246
1247 /* Don't add Accept-Language header if no language is preferred. */
1248 if (!s)
1249 return;
1250
1251 /*
1252 * Split the colon-separated string of preferred languages into
1253 * language_tags array.
1254 */
1255 do {
1256 /* collect language tag */
1257 for (; *s && (isalnum(*s) || *s == '_'); s++)
1258 strbuf_addch(&tag, *s == '_' ? '-' : *s);
1259
1260 /* skip .codeset, @modifier and any other unnecessary parts */
1261 while (*s && *s != ':')
1262 s++;
1263
1264 if (tag.len) {
1265 num_langs++;
1266 REALLOC_ARRAY(language_tags, num_langs);
1267 language_tags[num_langs - 1] = strbuf_detach(&tag, NULL);
1268 if (num_langs >= MAX_LANGUAGE_TAGS - 1) /* -1 for '*' */
1269 break;
1270 }
1271 } while (*s++);
1272
1273 /* write Accept-Language header into buf */
1274 if (num_langs) {
1275 int last_buf_len = 0;
1276 int max_q;
1277 int decimal_places;
1278 char q_format[32];
1279
1280 /* add '*' */
1281 REALLOC_ARRAY(language_tags, num_langs + 1);
1282 language_tags[num_langs++] = "*"; /* it's OK; this won't be freed */
1283
1284 /* compute decimal_places */
1285 for (max_q = 1, decimal_places = 0;
1286 max_q < num_langs && decimal_places <= MAX_DECIMAL_PLACES;
1287 decimal_places++, max_q *= 10)
1288 ;
1289
5096d490 1290 xsnprintf(q_format, sizeof(q_format), ";q=0.%%0%dd", decimal_places);
f18604bb
YE
1291
1292 strbuf_addstr(buf, "Accept-Language: ");
1293
1294 for (i = 0; i < num_langs; i++) {
1295 if (i > 0)
1296 strbuf_addstr(buf, ", ");
1297
1298 strbuf_addstr(buf, language_tags[i]);
1299
1300 if (i > 0)
1301 strbuf_addf(buf, q_format, max_q - i);
1302
1303 if (buf->len > MAX_ACCEPT_LANGUAGE_HEADER_SIZE) {
1304 strbuf_remove(buf, last_buf_len, buf->len - last_buf_len);
1305 break;
1306 }
1307
1308 last_buf_len = buf->len;
1309 }
1310 }
1311
1312 /* free language tags -- last one is a static '*' */
1313 for (i = 0; i < num_langs - 1; i++)
1314 free(language_tags[i]);
1315 free(language_tags);
1316}
1317
1318/*
1319 * Get an Accept-Language header which indicates user's preferred languages.
1320 *
1321 * Examples:
1322 * LANGUAGE= -> ""
1323 * LANGUAGE=ko:en -> "Accept-Language: ko, en; q=0.9, *; q=0.1"
1324 * LANGUAGE=ko_KR.UTF-8:sr@latin -> "Accept-Language: ko-KR, sr; q=0.9, *; q=0.1"
1325 * LANGUAGE=ko LANG=en_US.UTF-8 -> "Accept-Language: ko, *; q=0.1"
1326 * LANGUAGE= LANG=en_US.UTF-8 -> "Accept-Language: en-US, *; q=0.1"
1327 * LANGUAGE= LANG=C -> ""
1328 */
1329static const char *get_accept_language(void)
1330{
1331 if (!cached_accept_language) {
1332 struct strbuf buf = STRBUF_INIT;
1333 write_accept_language(&buf);
1334 if (buf.len > 0)
1335 cached_accept_language = strbuf_detach(&buf, NULL);
1336 }
1337
1338 return cached_accept_language;
1339}
1340
835c4d36
DT
1341static void http_opt_request_remainder(CURL *curl, off_t pos)
1342{
1343 char buf[128];
1344 xsnprintf(buf, sizeof(buf), "%"PRIuMAX"-", (uintmax_t)pos);
1345 curl_easy_setopt(curl, CURLOPT_RANGE, buf);
1346}
1347
e929cd20
MH
1348/* http_request() targets */
1349#define HTTP_REQUEST_STRBUF 0
1350#define HTTP_REQUEST_FILE 1
1351
1bbcc224
JK
1352static int http_request(const char *url,
1353 void *result, int target,
1354 const struct http_get_options *options)
e929cd20
MH
1355{
1356 struct active_request_slot *slot;
1357 struct slot_results results;
1358 struct curl_slist *headers = NULL;
1359 struct strbuf buf = STRBUF_INIT;
f18604bb 1360 const char *accept_language;
e929cd20
MH
1361 int ret;
1362
1363 slot = get_active_slot();
e929cd20
MH
1364 curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
1365
1366 if (result == NULL) {
1367 curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 1);
1368 } else {
1369 curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
1370 curl_easy_setopt(slot->curl, CURLOPT_FILE, result);
1371
1372 if (target == HTTP_REQUEST_FILE) {
f8117f55 1373 off_t posn = ftello(result);
e929cd20
MH
1374 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
1375 fwrite);
835c4d36
DT
1376 if (posn > 0)
1377 http_opt_request_remainder(slot->curl, posn);
e929cd20
MH
1378 } else
1379 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
1380 fwrite_buffer);
1381 }
1382
f18604bb
YE
1383 accept_language = get_accept_language();
1384
1385 if (accept_language)
1386 headers = curl_slist_append(headers, accept_language);
1387
e929cd20 1388 strbuf_addstr(&buf, "Pragma:");
1bbcc224 1389 if (options && options->no_cache)
e929cd20 1390 strbuf_addstr(&buf, " no-cache");
1bbcc224 1391 if (options && options->keep_error)
6d052d78 1392 curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 0);
e929cd20
MH
1393
1394 headers = curl_slist_append(headers, buf.buf);
1395
1396 curl_easy_setopt(slot->curl, CURLOPT_URL, url);
1397 curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, headers);
aa90b969 1398 curl_easy_setopt(slot->curl, CURLOPT_ENCODING, "gzip");
e929cd20 1399
beed336c 1400 ret = run_one_slot(slot, &results);
e929cd20 1401
bf197fd7
JK
1402 if (options && options->content_type) {
1403 struct strbuf raw = STRBUF_INIT;
1404 curlinfo_strbuf(slot->curl, CURLINFO_CONTENT_TYPE, &raw);
e3131626
JK
1405 extract_content_type(&raw, options->content_type,
1406 options->charset);
bf197fd7
JK
1407 strbuf_release(&raw);
1408 }
4656bf47 1409
78868962
JK
1410 if (options && options->effective_url)
1411 curlinfo_strbuf(slot->curl, CURLINFO_EFFECTIVE_URL,
1412 options->effective_url);
4656bf47 1413
e929cd20
MH
1414 curl_slist_free_all(headers);
1415 strbuf_release(&buf);
1416
1417 return ret;
1418}
1419
c93c92f3
JK
1420/*
1421 * Update the "base" url to a more appropriate value, as deduced by
1422 * redirects seen when requesting a URL starting with "url".
1423 *
1424 * The "asked" parameter is a URL that we asked curl to access, and must begin
1425 * with "base".
1426 *
1427 * The "got" parameter is the URL that curl reported to us as where we ended
1428 * up.
1429 *
1430 * Returns 1 if we updated the base url, 0 otherwise.
1431 *
1432 * Our basic strategy is to compare "base" and "asked" to find the bits
1433 * specific to our request. We then strip those bits off of "got" to yield the
1434 * new base. So for example, if our base is "http://example.com/foo.git",
1435 * and we ask for "http://example.com/foo.git/info/refs", we might end up
1436 * with "https://other.example.com/foo.git/info/refs". We would want the
1437 * new URL to become "https://other.example.com/foo.git".
1438 *
1439 * Note that this assumes a sane redirect scheme. It's entirely possible
1440 * in the example above to end up at a URL that does not even end in
1441 * "info/refs". In such a case we simply punt, as there is not much we can
1442 * do (and such a scheme is unlikely to represent a real git repository,
1443 * which means we are likely about to abort anyway).
1444 */
1445static int update_url_from_redirect(struct strbuf *base,
1446 const char *asked,
1447 const struct strbuf *got)
1448{
1449 const char *tail;
1450 size_t tail_len;
1451
1452 if (!strcmp(asked, got->buf))
1453 return 0;
1454
de8118e1 1455 if (!skip_prefix(asked, base->buf, &tail))
c93c92f3
JK
1456 die("BUG: update_url_from_redirect: %s is not a superset of %s",
1457 asked, base->buf);
1458
c93c92f3
JK
1459 tail_len = strlen(tail);
1460
1461 if (got->len < tail_len ||
1462 strcmp(tail, got->buf + got->len - tail_len))
1463 return 0; /* insane redirect scheme */
1464
1465 strbuf_reset(base);
1466 strbuf_add(base, got->buf, got->len - tail_len);
1467 return 1;
1468}
1469
4656bf47 1470static int http_request_reauth(const char *url,
4656bf47 1471 void *result, int target,
1bbcc224 1472 struct http_get_options *options)
8d677edc 1473{
1bbcc224 1474 int ret = http_request(url, result, target, options);
c93c92f3
JK
1475
1476 if (options && options->effective_url && options->base_url) {
1477 if (update_url_from_redirect(options->base_url,
1478 url, options->effective_url)) {
1479 credential_from_url(&http_auth, options->base_url->buf);
1480 url = options->effective_url->buf;
1481 }
1482 }
1483
8d677edc
JK
1484 if (ret != HTTP_REAUTH)
1485 return ret;
6d052d78
JK
1486
1487 /*
1488 * If we are using KEEP_ERROR, the previous request may have
1489 * put cruft into our output stream; we should clear it out before
1490 * making our next request. We only know how to do this for
1491 * the strbuf case, but that is enough to satisfy current callers.
1492 */
1bbcc224 1493 if (options && options->keep_error) {
6d052d78
JK
1494 switch (target) {
1495 case HTTP_REQUEST_STRBUF:
1496 strbuf_reset(result);
1497 break;
1498 default:
1499 die("BUG: HTTP_KEEP_ERROR is only supported with strbufs");
1500 }
1501 }
2501aff8
JK
1502
1503 credential_fill(&http_auth);
1504
1bbcc224 1505 return http_request(url, result, target, options);
8d677edc
JK
1506}
1507
4656bf47 1508int http_get_strbuf(const char *url,
1bbcc224
JK
1509 struct strbuf *result,
1510 struct http_get_options *options)
e929cd20 1511{
1bbcc224 1512 return http_request_reauth(url, result, HTTP_REQUEST_STRBUF, options);
e929cd20
MH
1513}
1514
83e41e2e 1515/*
a7793a74 1516 * Downloads a URL and stores the result in the given file.
83e41e2e
JH
1517 *
1518 * If a previous interrupted download is detected (i.e. a previous temporary
1519 * file is still around) the download is resumed.
1520 */
1bbcc224
JK
1521static int http_get_file(const char *url, const char *filename,
1522 struct http_get_options *options)
e929cd20
MH
1523{
1524 int ret;
1525 struct strbuf tmpfile = STRBUF_INIT;
1526 FILE *result;
1527
1528 strbuf_addf(&tmpfile, "%s.temp", filename);
1529 result = fopen(tmpfile.buf, "a");
3d1fb769 1530 if (!result) {
e929cd20
MH
1531 error("Unable to open local file %s", tmpfile.buf);
1532 ret = HTTP_ERROR;
1533 goto cleanup;
1534 }
1535
1bbcc224 1536 ret = http_request_reauth(url, result, HTTP_REQUEST_FILE, options);
e929cd20
MH
1537 fclose(result);
1538
cb5add58 1539 if (ret == HTTP_OK && finalize_object_file(tmpfile.buf, filename))
e929cd20
MH
1540 ret = HTTP_ERROR;
1541cleanup:
1542 strbuf_release(&tmpfile);
1543 return ret;
1544}
1545
c13b2633 1546int http_fetch_ref(const char *base, struct ref *ref)
d7e92806 1547{
1bbcc224 1548 struct http_get_options options = {0};
d7e92806
MH
1549 char *url;
1550 struct strbuf buffer = STRBUF_INIT;
0d5896e1 1551 int ret = -1;
d7e92806 1552
1bbcc224
JK
1553 options.no_cache = 1;
1554
c13b2633 1555 url = quote_ref_url(base, ref->name);
1bbcc224 1556 if (http_get_strbuf(url, &buffer, &options) == HTTP_OK) {
0d5896e1
MH
1557 strbuf_rtrim(&buffer);
1558 if (buffer.len == 40)
f4e54d02 1559 ret = get_oid_hex(buffer.buf, &ref->old_oid);
59556548 1560 else if (starts_with(buffer.buf, "ref: ")) {
0d5896e1
MH
1561 ref->symref = xstrdup(buffer.buf + 5);
1562 ret = 0;
d7e92806 1563 }
d7e92806
MH
1564 }
1565
1566 strbuf_release(&buffer);
1567 free(url);
1568 return ret;
1569}
b8caac2b
TRC
1570
1571/* Helpers for fetching packs */
750ef425 1572static char *fetch_pack_index(unsigned char *sha1, const char *base_url)
b8caac2b 1573{
750ef425 1574 char *url, *tmp;
b8caac2b 1575 struct strbuf buf = STRBUF_INIT;
b8caac2b 1576
b8caac2b 1577 if (http_is_verbose)
162eb5f8 1578 fprintf(stderr, "Getting index for pack %s\n", sha1_to_hex(sha1));
b8caac2b
TRC
1579
1580 end_url_with_slash(&buf, base_url);
162eb5f8 1581 strbuf_addf(&buf, "objects/pack/pack-%s.idx", sha1_to_hex(sha1));
b8caac2b
TRC
1582 url = strbuf_detach(&buf, NULL);
1583
750ef425
SP
1584 strbuf_addf(&buf, "%s.temp", sha1_pack_index_name(sha1));
1585 tmp = strbuf_detach(&buf, NULL);
1586
70900eda 1587 if (http_get_file(url, tmp, NULL) != HTTP_OK) {
82247e9b 1588 error("Unable to get pack index %s", url);
750ef425
SP
1589 free(tmp);
1590 tmp = NULL;
1591 }
b8caac2b 1592
b8caac2b 1593 free(url);
750ef425 1594 return tmp;
b8caac2b
TRC
1595}
1596
1597static int fetch_and_setup_pack_index(struct packed_git **packs_head,
1598 unsigned char *sha1, const char *base_url)
1599{
1600 struct packed_git *new_pack;
750ef425
SP
1601 char *tmp_idx = NULL;
1602 int ret;
b8caac2b 1603
750ef425 1604 if (has_pack_index(sha1)) {
8b9c2dd4 1605 new_pack = parse_pack_index(sha1, sha1_pack_index_name(sha1));
750ef425
SP
1606 if (!new_pack)
1607 return -1; /* parse_pack_index() already issued error message */
1608 goto add_pack;
1609 }
1610
1611 tmp_idx = fetch_pack_index(sha1, base_url);
1612 if (!tmp_idx)
b8caac2b
TRC
1613 return -1;
1614
750ef425
SP
1615 new_pack = parse_pack_index(sha1, tmp_idx);
1616 if (!new_pack) {
1617 unlink(tmp_idx);
1618 free(tmp_idx);
1619
b8caac2b 1620 return -1; /* parse_pack_index() already issued error message */
750ef425
SP
1621 }
1622
1623 ret = verify_pack_index(new_pack);
1624 if (!ret) {
1625 close_pack_index(new_pack);
cb5add58 1626 ret = finalize_object_file(tmp_idx, sha1_pack_index_name(sha1));
750ef425
SP
1627 }
1628 free(tmp_idx);
1629 if (ret)
1630 return -1;
1631
1632add_pack:
b8caac2b
TRC
1633 new_pack->next = *packs_head;
1634 *packs_head = new_pack;
1635 return 0;
1636}
1637
1638int http_get_info_packs(const char *base_url, struct packed_git **packs_head)
1639{
1bbcc224 1640 struct http_get_options options = {0};
b8caac2b
TRC
1641 int ret = 0, i = 0;
1642 char *url, *data;
1643 struct strbuf buf = STRBUF_INIT;
1644 unsigned char sha1[20];
1645
1646 end_url_with_slash(&buf, base_url);
1647 strbuf_addstr(&buf, "objects/info/packs");
1648 url = strbuf_detach(&buf, NULL);
1649
1bbcc224
JK
1650 options.no_cache = 1;
1651 ret = http_get_strbuf(url, &buf, &options);
b8caac2b
TRC
1652 if (ret != HTTP_OK)
1653 goto cleanup;
1654
1655 data = buf.buf;
1656 while (i < buf.len) {
1657 switch (data[i]) {
1658 case 'P':
1659 i++;
1660 if (i + 52 <= buf.len &&
59556548
CC
1661 starts_with(data + i, " pack-") &&
1662 starts_with(data + i + 46, ".pack\n")) {
b8caac2b
TRC
1663 get_sha1_hex(data + i + 6, sha1);
1664 fetch_and_setup_pack_index(packs_head, sha1,
1665 base_url);
1666 i += 51;
1667 break;
1668 }
1669 default:
1670 while (i < buf.len && data[i] != '\n')
1671 i++;
1672 }
1673 i++;
1674 }
1675
1676cleanup:
1677 free(url);
1678 return ret;
1679}
2264dfa5
TRC
1680
1681void release_http_pack_request(struct http_pack_request *preq)
1682{
1683 if (preq->packfile != NULL) {
1684 fclose(preq->packfile);
1685 preq->packfile = NULL;
2264dfa5 1686 }
2264dfa5
TRC
1687 preq->slot = NULL;
1688 free(preq->url);
826aed50 1689 free(preq);
2264dfa5
TRC
1690}
1691
1692int finish_http_pack_request(struct http_pack_request *preq)
1693{
2264dfa5 1694 struct packed_git **lst;
021ab6f0 1695 struct packed_git *p = preq->target;
fe72d420 1696 char *tmp_idx;
9ae97018 1697 size_t len;
d3180279 1698 struct child_process ip = CHILD_PROCESS_INIT;
fe72d420 1699 const char *ip_argv[8];
2264dfa5 1700
fe72d420 1701 close_pack_index(p);
2264dfa5 1702
3065274c
SP
1703 fclose(preq->packfile);
1704 preq->packfile = NULL;
2264dfa5
TRC
1705
1706 lst = preq->lst;
021ab6f0 1707 while (*lst != p)
2264dfa5
TRC
1708 lst = &((*lst)->next);
1709 *lst = (*lst)->next;
1710
9ae97018
JK
1711 if (!strip_suffix(preq->tmpfile, ".pack.temp", &len))
1712 die("BUG: pack tmpfile does not end in .pack.temp?");
1713 tmp_idx = xstrfmt("%.*s.idx.temp", (int)len, preq->tmpfile);
fe72d420
SP
1714
1715 ip_argv[0] = "index-pack";
1716 ip_argv[1] = "-o";
1717 ip_argv[2] = tmp_idx;
1718 ip_argv[3] = preq->tmpfile;
1719 ip_argv[4] = NULL;
1720
fe72d420
SP
1721 ip.argv = ip_argv;
1722 ip.git_cmd = 1;
1723 ip.no_stdin = 1;
1724 ip.no_stdout = 1;
1725
1726 if (run_command(&ip)) {
1727 unlink(preq->tmpfile);
1728 unlink(tmp_idx);
1729 free(tmp_idx);
2264dfa5 1730 return -1;
fe72d420
SP
1731 }
1732
1733 unlink(sha1_pack_index_name(p->sha1));
2264dfa5 1734
cb5add58
JH
1735 if (finalize_object_file(preq->tmpfile, sha1_pack_name(p->sha1))
1736 || finalize_object_file(tmp_idx, sha1_pack_index_name(p->sha1))) {
fe72d420 1737 free(tmp_idx);
2264dfa5 1738 return -1;
fe72d420 1739 }
2264dfa5 1740
fe72d420
SP
1741 install_packed_git(p);
1742 free(tmp_idx);
2264dfa5
TRC
1743 return 0;
1744}
1745
1746struct http_pack_request *new_http_pack_request(
1747 struct packed_git *target, const char *base_url)
1748{
f8117f55 1749 off_t prev_posn = 0;
2264dfa5
TRC
1750 struct strbuf buf = STRBUF_INIT;
1751 struct http_pack_request *preq;
1752
ec99c9a8 1753 preq = xcalloc(1, sizeof(*preq));
2264dfa5 1754 preq->target = target;
2264dfa5
TRC
1755
1756 end_url_with_slash(&buf, base_url);
1757 strbuf_addf(&buf, "objects/pack/pack-%s.pack",
1758 sha1_to_hex(target->sha1));
bb99190e 1759 preq->url = strbuf_detach(&buf, NULL);
2264dfa5 1760
90d05713
TRC
1761 snprintf(preq->tmpfile, sizeof(preq->tmpfile), "%s.temp",
1762 sha1_pack_name(target->sha1));
2264dfa5
TRC
1763 preq->packfile = fopen(preq->tmpfile, "a");
1764 if (!preq->packfile) {
1765 error("Unable to open local file %s for pack",
1766 preq->tmpfile);
1767 goto abort;
1768 }
1769
1770 preq->slot = get_active_slot();
2264dfa5
TRC
1771 curl_easy_setopt(preq->slot->curl, CURLOPT_FILE, preq->packfile);
1772 curl_easy_setopt(preq->slot->curl, CURLOPT_WRITEFUNCTION, fwrite);
bb99190e 1773 curl_easy_setopt(preq->slot->curl, CURLOPT_URL, preq->url);
2264dfa5
TRC
1774 curl_easy_setopt(preq->slot->curl, CURLOPT_HTTPHEADER,
1775 no_pragma_header);
1776
1777 /*
1778 * If there is data present from a previous transfer attempt,
1779 * resume where it left off
1780 */
f8117f55 1781 prev_posn = ftello(preq->packfile);
2264dfa5
TRC
1782 if (prev_posn>0) {
1783 if (http_is_verbose)
1784 fprintf(stderr,
838ecf0b
RJ
1785 "Resuming fetch of pack %s at byte %"PRIuMAX"\n",
1786 sha1_to_hex(target->sha1), (uintmax_t)prev_posn);
835c4d36 1787 http_opt_request_remainder(preq->slot->curl, prev_posn);
2264dfa5
TRC
1788 }
1789
1790 return preq;
1791
1792abort:
bb99190e 1793 free(preq->url);
5ae9ebfd 1794 free(preq);
2264dfa5
TRC
1795 return NULL;
1796}
5424bc55
TRC
1797
1798/* Helpers for fetching objects (loose) */
a04ff3ec 1799static size_t fwrite_sha1_file(char *ptr, size_t eltsize, size_t nmemb,
5424bc55
TRC
1800 void *data)
1801{
1802 unsigned char expn[4096];
1803 size_t size = eltsize * nmemb;
1804 int posn = 0;
1805 struct http_object_request *freq =
1806 (struct http_object_request *)data;
1807 do {
1808 ssize_t retval = xwrite(freq->localfile,
1809 (char *) ptr + posn, size - posn);
1810 if (retval < 0)
1811 return posn;
1812 posn += retval;
1813 } while (posn < size);
1814
1815 freq->stream.avail_in = size;
a04ff3ec 1816 freq->stream.next_in = (void *)ptr;
5424bc55
TRC
1817 do {
1818 freq->stream.next_out = expn;
1819 freq->stream.avail_out = sizeof(expn);
1820 freq->zret = git_inflate(&freq->stream, Z_SYNC_FLUSH);
1821 git_SHA1_Update(&freq->c, expn,
1822 sizeof(expn) - freq->stream.avail_out);
1823 } while (freq->stream.avail_in && freq->zret == Z_OK);
5424bc55
TRC
1824 return size;
1825}
1826
1827struct http_object_request *new_http_object_request(const char *base_url,
1828 unsigned char *sha1)
1829{
1830 char *hex = sha1_to_hex(sha1);
30d6c6ea 1831 const char *filename;
5424bc55 1832 char prevfile[PATH_MAX];
5424bc55 1833 int prevlocal;
a04ff3ec 1834 char prev_buf[PREV_BUF_SIZE];
5424bc55 1835 ssize_t prev_read = 0;
f8117f55 1836 off_t prev_posn = 0;
5424bc55
TRC
1837 struct http_object_request *freq;
1838
ec99c9a8 1839 freq = xcalloc(1, sizeof(*freq));
5424bc55
TRC
1840 hashcpy(freq->sha1, sha1);
1841 freq->localfile = -1;
1842
1843 filename = sha1_file_name(sha1);
5424bc55
TRC
1844 snprintf(freq->tmpfile, sizeof(freq->tmpfile),
1845 "%s.temp", filename);
1846
1847 snprintf(prevfile, sizeof(prevfile), "%s.prev", filename);
1848 unlink_or_warn(prevfile);
1849 rename(freq->tmpfile, prevfile);
1850 unlink_or_warn(freq->tmpfile);
1851
1852 if (freq->localfile != -1)
1853 error("fd leakage in start: %d", freq->localfile);
1854 freq->localfile = open(freq->tmpfile,
1855 O_WRONLY | O_CREAT | O_EXCL, 0666);
1856 /*
1857 * This could have failed due to the "lazy directory creation";
1858 * try to mkdir the last path component.
1859 */
1860 if (freq->localfile < 0 && errno == ENOENT) {
1861 char *dir = strrchr(freq->tmpfile, '/');
1862 if (dir) {
1863 *dir = 0;
1864 mkdir(freq->tmpfile, 0777);
1865 *dir = '/';
1866 }
1867 freq->localfile = open(freq->tmpfile,
1868 O_WRONLY | O_CREAT | O_EXCL, 0666);
1869 }
1870
1871 if (freq->localfile < 0) {
0da8b2e7
SP
1872 error("Couldn't create temporary file %s: %s",
1873 freq->tmpfile, strerror(errno));
5424bc55
TRC
1874 goto abort;
1875 }
1876
5424bc55
TRC
1877 git_inflate_init(&freq->stream);
1878
1879 git_SHA1_Init(&freq->c);
1880
bb99190e 1881 freq->url = get_remote_object_url(base_url, hex, 0);
5424bc55
TRC
1882
1883 /*
1884 * If a previous temp file is present, process what was already
1885 * fetched.
1886 */
1887 prevlocal = open(prevfile, O_RDONLY);
1888 if (prevlocal != -1) {
1889 do {
1890 prev_read = xread(prevlocal, prev_buf, PREV_BUF_SIZE);
1891 if (prev_read>0) {
1892 if (fwrite_sha1_file(prev_buf,
1893 1,
1894 prev_read,
1895 freq) == prev_read) {
1896 prev_posn += prev_read;
1897 } else {
1898 prev_read = -1;
1899 }
1900 }
1901 } while (prev_read > 0);
1902 close(prevlocal);
1903 }
1904 unlink_or_warn(prevfile);
1905
1906 /*
1907 * Reset inflate/SHA1 if there was an error reading the previous temp
1908 * file; also rewind to the beginning of the local file.
1909 */
1910 if (prev_read == -1) {
1911 memset(&freq->stream, 0, sizeof(freq->stream));
1912 git_inflate_init(&freq->stream);
1913 git_SHA1_Init(&freq->c);
1914 if (prev_posn>0) {
1915 prev_posn = 0;
1916 lseek(freq->localfile, 0, SEEK_SET);
0c4f21e4 1917 if (ftruncate(freq->localfile, 0) < 0) {
0da8b2e7
SP
1918 error("Couldn't truncate temporary file %s: %s",
1919 freq->tmpfile, strerror(errno));
0c4f21e4
JL
1920 goto abort;
1921 }
5424bc55
TRC
1922 }
1923 }
1924
1925 freq->slot = get_active_slot();
1926
1927 curl_easy_setopt(freq->slot->curl, CURLOPT_FILE, freq);
1928 curl_easy_setopt(freq->slot->curl, CURLOPT_WRITEFUNCTION, fwrite_sha1_file);
1929 curl_easy_setopt(freq->slot->curl, CURLOPT_ERRORBUFFER, freq->errorstr);
bb99190e 1930 curl_easy_setopt(freq->slot->curl, CURLOPT_URL, freq->url);
5424bc55
TRC
1931 curl_easy_setopt(freq->slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);
1932
1933 /*
1934 * If we have successfully processed data from a previous fetch
1935 * attempt, only fetch the data we don't already have.
1936 */
1937 if (prev_posn>0) {
1938 if (http_is_verbose)
1939 fprintf(stderr,
838ecf0b
RJ
1940 "Resuming fetch of object %s at byte %"PRIuMAX"\n",
1941 hex, (uintmax_t)prev_posn);
835c4d36 1942 http_opt_request_remainder(freq->slot->curl, prev_posn);
5424bc55
TRC
1943 }
1944
1945 return freq;
1946
5424bc55 1947abort:
bb99190e 1948 free(freq->url);
5424bc55
TRC
1949 free(freq);
1950 return NULL;
1951}
1952
1953void process_http_object_request(struct http_object_request *freq)
1954{
1955 if (freq->slot == NULL)
1956 return;
1957 freq->curl_result = freq->slot->curl_result;
1958 freq->http_code = freq->slot->http_code;
1959 freq->slot = NULL;
1960}
1961
1962int finish_http_object_request(struct http_object_request *freq)
1963{
1964 struct stat st;
1965
1966 close(freq->localfile);
1967 freq->localfile = -1;
1968
1969 process_http_object_request(freq);
1970
1971 if (freq->http_code == 416) {
bd757c18 1972 warning("requested range invalid; we may already have all the data.");
5424bc55
TRC
1973 } else if (freq->curl_result != CURLE_OK) {
1974 if (stat(freq->tmpfile, &st) == 0)
1975 if (st.st_size == 0)
1976 unlink_or_warn(freq->tmpfile);
1977 return -1;
1978 }
1979
1980 git_inflate_end(&freq->stream);
1981 git_SHA1_Final(freq->real_sha1, &freq->c);
1982 if (freq->zret != Z_STREAM_END) {
1983 unlink_or_warn(freq->tmpfile);
1984 return -1;
1985 }
1986 if (hashcmp(freq->sha1, freq->real_sha1)) {
1987 unlink_or_warn(freq->tmpfile);
1988 return -1;
1989 }
1990 freq->rename =
cb5add58 1991 finalize_object_file(freq->tmpfile, sha1_file_name(freq->sha1));
5424bc55
TRC
1992
1993 return freq->rename;
1994}
1995
1996void abort_http_object_request(struct http_object_request *freq)
1997{
1998 unlink_or_warn(freq->tmpfile);
1999
2000 release_http_object_request(freq);
2001}
2002
2003void release_http_object_request(struct http_object_request *freq)
2004{
2005 if (freq->localfile != -1) {
2006 close(freq->localfile);
2007 freq->localfile = -1;
2008 }
2009 if (freq->url != NULL) {
2010 free(freq->url);
2011 freq->url = NULL;
2012 }
4b9fa0e3
TRC
2013 if (freq->slot != NULL) {
2014 freq->slot->callback_func = NULL;
2015 freq->slot->callback_data = NULL;
2016 release_active_slot(freq->slot);
2017 freq->slot = NULL;
2018 }
5424bc55 2019}