Coverage Report

Created: 2026-06-01 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/curl/lib/url.c
Line
Count
Source
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9
 *
10
 * This software is licensed as described in the file COPYING, which
11
 * you should have received as part of this distribution. The terms
12
 * are also available at https://curl.se/docs/copyright.html.
13
 *
14
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15
 * copies of the Software, and permit persons to whom the Software is
16
 * furnished to do so, under the terms of the COPYING file.
17
 *
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
 * KIND, either express or implied.
20
 *
21
 * SPDX-License-Identifier: curl
22
 *
23
 ***************************************************************************/
24
#include "curl_setup.h"
25
26
#ifdef HAVE_NETINET_IN_H
27
#include <netinet/in.h>
28
#endif
29
#ifdef HAVE_NETDB_H
30
#include <netdb.h>
31
#endif
32
#ifdef HAVE_ARPA_INET_H
33
#include <arpa/inet.h>
34
#endif
35
#ifdef HAVE_NET_IF_H
36
#include <net/if.h>
37
#endif
38
#ifdef HAVE_IPHLPAPI_H
39
#include <Iphlpapi.h>
40
#endif
41
#ifdef HAVE_SYS_IOCTL_H
42
#include <sys/ioctl.h>
43
#endif
44
#ifdef HAVE_SYS_PARAM_H
45
#include <sys/param.h>
46
#endif
47
48
#ifdef __VMS
49
#include <in.h>
50
#include <inet.h>
51
#endif
52
53
#ifdef HAVE_SYS_UN_H
54
#include <sys/un.h>
55
#endif
56
57
#ifndef HAVE_SOCKET
58
#error "We cannot compile without socket() support!"
59
#endif
60
61
#if defined(HAVE_IF_NAMETOINDEX) && defined(USE_WINSOCK)
62
#if defined(__MINGW32__) && (__MINGW64_VERSION_MAJOR <= 5)
63
#include <wincrypt.h>  /* workaround for old mingw-w64 missing to include it */
64
#endif
65
#include <iphlpapi.h>
66
#endif
67
68
#include "urldata.h"
69
#include "mime.h"
70
#include "bufref.h"
71
#include "vtls/vtls.h"
72
#include "vssh/vssh.h"
73
#include "hostip.h"
74
#include "transfer.h"
75
#include "curl_addrinfo.h"
76
#include "curl_trc.h"
77
#include "progress.h"
78
#include "cookie.h"
79
#include "strcase.h"
80
#include "escape.h"
81
#include "curl_share.h"
82
#include "http_digest.h"
83
#include "multiif.h"
84
#include "getinfo.h"
85
#include "pop3.h"
86
#include "urlapi-int.h"
87
#include "system_win32.h"
88
#include "hsts.h"
89
#include "noproxy.h"
90
#include "cfilters.h"
91
#include "idn.h"
92
#include "http_proxy.h"
93
#include "conncache.h"
94
#include "multihandle.h"
95
#include "curlx/strdup.h"
96
#include "setopt.h"
97
#include "altsvc.h"
98
#include "curlx/dynbuf.h"
99
#include "headers.h"
100
#include "curlx/strerr.h"
101
#include "curlx/strparse.h"
102
#include "peer.h"
103
104
/* Now for the protocols */
105
#include "ftp.h"
106
#include "dict.h"
107
#include "telnet.h"
108
#include "tftp.h"
109
#include "http.h"
110
#include "vauth/vauth.h"
111
#include "file.h"
112
#include "curl_ldap.h"
113
#include "vssh/ssh.h"
114
#include "imap.h"
115
#include "url.h"
116
#include "connect.h"
117
#include "gopher.h"
118
#include "mqtt.h"
119
#include "rtsp.h"
120
#include "smtp.h"
121
#include "ws.h"
122
123
/* Some parts of the code (e.g. chunked encoding) assume this buffer has more
124
 * than a few bytes to play with. Do not let it become too small or bad things
125
 * will happen.
126
 */
127
#if READBUFFER_SIZE < READBUFFER_MIN
128
# error READBUFFER_SIZE is too small
129
#endif
130
131
/*
132
 * get_protocol_family()
133
 *
134
 * This is used to return the protocol family for a given protocol.
135
 *
136
 * Parameters:
137
 *
138
 * 's'  [in]  - struct Curl_scheme pointer.
139
 *
140
 * Returns the family as a single bit protocol identifier.
141
 */
142
static curl_prot_t get_protocol_family(const struct Curl_scheme *s)
143
13.9k
{
144
13.9k
  DEBUGASSERT(s);
145
13.9k
  DEBUGASSERT(s->family);
146
13.9k
  return s->family;
147
13.9k
}
148
149
void Curl_freeset(struct Curl_easy *data)
150
413k
{
151
  /* Free all dynamic strings stored in the data->set substructure. */
152
413k
  enum dupstring i;
153
413k
  enum dupblob j;
154
155
31.4M
  for(i = (enum dupstring)0; i < STRING_LAST; i++) {
156
30.9M
    curlx_safefree(data->set.str[i]);
157
30.9M
  }
158
159
3.71M
  for(j = (enum dupblob)0; j < BLOB_LAST; j++) {
160
3.30M
    curlx_safefree(data->set.blobs[j]);
161
3.30M
  }
162
163
413k
  Curl_bufref_free(&data->state.referer);
164
413k
  Curl_bufref_free(&data->state.url);
165
166
413k
#if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
167
413k
  Curl_mime_cleanpart(data->set.mimepostp);
168
413k
  curlx_safefree(data->set.mimepostp);
169
413k
#endif
170
171
413k
#ifndef CURL_DISABLE_COOKIES
172
413k
  curl_slist_free_all(data->state.cookielist);
173
413k
  data->state.cookielist = NULL;
174
413k
#endif
175
413k
}
176
177
/* free the URL pieces */
178
static void up_free(struct Curl_easy *data)
179
572k
{
180
572k
  struct urlpieces *up = &data->state.up;
181
572k
  curlx_safefree(up->scheme);
182
572k
  curlx_safefree(up->hostname);
183
572k
  curlx_safefree(up->port);
184
572k
  curlx_safefree(up->user);
185
572k
  curlx_safefree(up->password);
186
572k
  curlx_safefree(up->options);
187
572k
  curlx_safefree(up->path);
188
572k
  curlx_safefree(up->query);
189
572k
  curl_url_cleanup(data->state.uh);
190
572k
  data->state.uh = NULL;
191
572k
}
192
193
/*
194
 * This is the internal function curl_easy_cleanup() calls. This should
195
 * cleanup and free all resources associated with this sessionhandle.
196
 *
197
 * We ignore SIGPIPE when this is called from curl_easy_cleanup.
198
 */
199
200
CURLcode Curl_close(struct Curl_easy **datap)
201
413k
{
202
413k
  struct Curl_easy *data;
203
204
413k
  if(!datap || !*datap)
205
107
    return CURLE_OK;
206
207
413k
  data = *datap;
208
413k
  *datap = NULL;
209
210
413k
  if(!data->state.internal && data->multi) {
211
    /* This handle is still part of a multi handle, take care of this first
212
       and detach this handle from there.
213
       This detaches the connection. */
214
0
    curl_multi_remove_handle(data->multi, data);
215
0
  }
216
413k
  else {
217
    /* Detach connection if any is left. This should not be normal, but can be
218
       the case for example with CONNECT_ONLY + recv/send (test 556) */
219
413k
    Curl_detach_connection(data);
220
413k
    if(!data->state.internal && data->multi_easy) {
221
      /* when curl_easy_perform() is used, it creates its own multi handle to
222
         use and this is the one */
223
0
      curl_multi_cleanup(data->multi_easy);
224
0
      data->multi_easy = NULL;
225
0
    }
226
413k
  }
227
413k
  DEBUGASSERT(!data->conn || data->state.internal);
228
229
413k
  Curl_expire_clear(data); /* shut off any timers left */
230
231
413k
  if(data->state.rangestringalloc)
232
2.80k
    curlx_free(data->state.range);
233
234
  /* release any resolve information this transfer kept */
235
413k
  Curl_resolv_destroy_all(data);
236
237
413k
  data->set.verbose = FALSE; /* no more calls to DEBUGFUNCTION */
238
413k
  data->magic = 0; /* force a clear AFTER the possibly enforced removal from
239
                    * the multi handle and async dns shutdown. The multi
240
                    * handle might check the magic and so might any
241
                    * DEBUGFUNCTION invoked for tracing */
242
243
  /* freed here in case DONE was not called */
244
413k
  Curl_req_free(&data->req, data);
245
246
  /* Close down all open SSL info and sessions */
247
413k
  Curl_ssl_close_all(data);
248
413k
  Curl_peer_unlink(&data->state.initial_origin);
249
413k
  Curl_ssl_free_certinfo(data);
250
251
413k
  Curl_bufref_free(&data->state.referer);
252
253
413k
  up_free(data);
254
413k
  curlx_dyn_free(&data->state.headerb);
255
413k
  Curl_flush_cookies(data, TRUE);
256
413k
#ifndef CURL_DISABLE_ALTSVC
257
413k
  Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]);
258
413k
  Curl_altsvc_cleanup(&data->asi);
259
413k
#endif
260
413k
#ifndef CURL_DISABLE_HSTS
261
413k
  Curl_hsts_save(data, data->hsts, data->set.str[STRING_HSTS]);
262
413k
  if(!data->share || !data->share->hsts)
263
413k
    Curl_hsts_cleanup(&data->hsts);
264
413k
  curl_slist_free_all(data->state.hstslist); /* clean up list */
265
413k
#endif
266
413k
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH)
267
413k
  Curl_http_auth_cleanup_digest(data);
268
413k
#endif
269
413k
  curlx_safefree(data->state.most_recent_ftp_entrypath);
270
413k
  curlx_safefree(data->info.contenttype);
271
413k
  curlx_safefree(data->info.wouldredirect);
272
273
  /* No longer a dirty share, if it exists */
274
413k
  if(Curl_share_easy_unlink(data))
275
413k
    DEBUGASSERT(0);
276
277
413k
  Curl_hash_destroy(&data->meta_hash);
278
413k
  Curl_creds_unlink(&data->state.creds);
279
413k
  curlx_safefree(data->state.aptr.uagent);
280
413k
  curlx_safefree(data->state.aptr.accept_encoding);
281
413k
  curlx_safefree(data->state.aptr.rangeline);
282
413k
  curlx_safefree(data->state.aptr.ref);
283
413k
  curlx_safefree(data->state.aptr.host);
284
413k
#ifndef CURL_DISABLE_COOKIES
285
413k
  curlx_safefree(data->req.cookiehost);
286
413k
#endif
287
413k
#ifndef CURL_DISABLE_RTSP
288
413k
  curlx_safefree(data->state.aptr.rtsp_transport);
289
413k
#endif
290
291
413k
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_FORM_API)
292
413k
  Curl_mime_cleanpart(data->state.formp);
293
413k
  curlx_safefree(data->state.formp);
294
413k
#endif
295
296
  /* destruct wildcard structures if it is needed */
297
413k
  Curl_wildcard_dtor(&data->wildcard);
298
413k
  Curl_freeset(data);
299
413k
  Curl_headers_cleanup(data);
300
413k
  Curl_netrc_cleanup(&data->state.netrc);
301
413k
#ifndef CURL_DISABLE_DIGEST_AUTH
302
413k
  curlx_free(data->state.envproxy);
303
413k
#endif
304
413k
  curlx_free(data);
305
413k
  return CURLE_OK;
306
413k
}
307
308
/*
309
 * Initialize the UserDefined fields within a Curl_easy.
310
 * This may be safely called on a new or existing Curl_easy.
311
 */
312
void Curl_init_userdefined(struct Curl_easy *data)
313
413k
{
314
413k
  struct UserDefined *set = &data->set;
315
316
413k
  set->out = stdout;  /* default output to stdout */
317
413k
  set->in_set = stdin;  /* default input from stdin */
318
413k
  set->err = stderr;  /* default stderr to stderr */
319
320
413k
#if defined(__clang__) && __clang_major__ >= 16
321
413k
#pragma clang diagnostic push
322
413k
#pragma clang diagnostic ignored "-Wcast-function-type-strict"
323
413k
#endif
324
  /* use fwrite as default function to store output */
325
413k
  set->fwrite_func = (curl_write_callback)fwrite;
326
327
  /* use fread as default function to read input */
328
413k
  set->fread_func_set = (curl_read_callback)fread;
329
413k
#if defined(__clang__) && __clang_major__ >= 16
330
413k
#pragma clang diagnostic pop
331
413k
#endif
332
413k
  set->is_fread_set = 0;
333
334
413k
  set->seek_client = ZERO_NULL;
335
336
413k
  set->filesize = -1;        /* we do not know the size */
337
413k
  set->postfieldsize = -1;   /* unknown size */
338
413k
  set->maxredirs = 30;       /* sensible default */
339
340
413k
  set->method = HTTPREQ_GET; /* Default HTTP request */
341
413k
#ifndef CURL_DISABLE_RTSP
342
413k
  set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */
343
413k
#endif
344
413k
#ifndef CURL_DISABLE_FTP
345
413k
  set->ftp_use_epsv = TRUE;   /* FTP defaults to EPSV operations */
346
413k
  set->ftp_use_eprt = TRUE;   /* FTP defaults to EPRT operations */
347
413k
  set->ftp_use_pret = FALSE;  /* mainly useful for drftpd servers */
348
413k
  set->ftp_filemethod = FTPFILE_MULTICWD;
349
413k
  set->ftp_skip_ip = TRUE;    /* skip PASV IP by default */
350
413k
#endif
351
413k
  set->dns_cache_timeout_ms = 60000; /* Timeout every 60 seconds by default */
352
353
  /* Timeout every 24 hours by default */
354
413k
  set->general_ssl.ca_cache_timeout = 24 * 60 * 60;
355
356
413k
  set->httpauth = CURLAUTH_BASIC;  /* defaults to basic */
357
358
413k
#ifndef CURL_DISABLE_PROXY
359
413k
  set->proxyport = 0;
360
413k
  set->proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */
361
413k
  set->proxyauth = CURLAUTH_BASIC; /* defaults to basic */
362
  /* SOCKS5 proxy auth defaults to username/password + GSS-API */
363
413k
  set->socks5auth = CURLAUTH_BASIC | CURLAUTH_GSSAPI;
364
413k
#endif
365
366
413k
  Curl_ssl_easy_config_init(data);
367
413k
#ifndef CURL_DISABLE_DOH
368
413k
  set->doh_verifyhost = TRUE;
369
413k
  set->doh_verifypeer = TRUE;
370
413k
#endif
371
#ifdef USE_SSH
372
  /* defaults to any auth type */
373
  set->ssh_auth_types = CURLSSH_AUTH_DEFAULT;
374
  set->new_directory_perms = 0755; /* Default permissions */
375
#endif
376
377
413k
  set->new_file_perms = 0644;    /* Default permissions */
378
413k
  set->allowed_protocols = (curl_prot_t)CURLPROTO_64ALL;
379
413k
  set->redir_protocols = CURLPROTO_REDIR;
380
381
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
382
  /*
383
   * disallow unprotected protection negotiation NEC reference implementation
384
   * seem not to follow rfc1961 section 4.3/4.4
385
   */
386
  set->socks5_gssapi_nec = FALSE;
387
#endif
388
389
  /* set default minimum TLS version */
390
413k
#ifdef USE_SSL
391
413k
  Curl_setopt_SSLVERSION(data, CURLOPT_SSLVERSION, CURL_SSLVERSION_DEFAULT);
392
413k
#ifndef CURL_DISABLE_PROXY
393
413k
  Curl_setopt_SSLVERSION(data, CURLOPT_PROXY_SSLVERSION,
394
413k
                         CURL_SSLVERSION_DEFAULT);
395
413k
#endif
396
413k
#endif
397
413k
#ifndef CURL_DISABLE_FTP
398
413k
  set->wildcard_enabled = FALSE;
399
413k
  set->chunk_bgn = ZERO_NULL;
400
413k
  set->chunk_end = ZERO_NULL;
401
413k
  set->fnmatch = ZERO_NULL;
402
413k
#endif
403
413k
  set->tcp_keepalive = FALSE;
404
413k
  set->tcp_keepintvl = 60;
405
413k
  set->tcp_keepidle = 60;
406
413k
  set->tcp_keepcnt = 9;
407
413k
  set->tcp_fastopen = FALSE;
408
413k
  set->tcp_nodelay = TRUE;
409
413k
  set->ssl_enable_alpn = TRUE;
410
413k
  set->expect_100_timeout = 1000L; /* Wait for a second by default. */
411
413k
  set->sep_headers = TRUE; /* separated header lists by default */
412
413k
  set->buffer_size = READBUFFER_SIZE;
413
413k
  set->upload_buffer_size = UPLOADBUFFER_DEFAULT;
414
413k
  set->upload_flags = CURLULFLAG_SEEN;
415
413k
  set->happy_eyeballs_timeout = CURL_HET_DEFAULT;
416
413k
  set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT;
417
413k
  set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
418
413k
  set->conn_max_idle_ms = 118 * 1000;
419
413k
  set->conn_max_age_ms = 24 * 3600 * 1000;
420
413k
  set->http09_allowed = FALSE;
421
413k
  set->httpwant = CURL_HTTP_VERSION_NONE;
422
413k
#if defined(USE_HTTP2) || defined(USE_HTTP3)
423
413k
  memset(&set->priority, 0, sizeof(set->priority));
424
413k
#endif
425
413k
  set->quick_exit = 0L;
426
413k
#ifndef CURL_DISABLE_WEBSOCKETS
427
413k
  set->ws_raw_mode = FALSE;
428
413k
  set->ws_no_auto_pong = FALSE;
429
413k
#endif
430
413k
}
431
432
/* easy->meta_hash destructor. Should never be called as elements
433
 * MUST be added with their own destructor */
434
static void easy_meta_freeentry(void *p)
435
0
{
436
0
  (void)p;
437
  /* Always FALSE. Cannot use a 0 assert here since compilers
438
   * are not in agreement if they then want a NORETURN attribute or
439
   * not. *sigh* */
440
0
  DEBUGASSERT(p == NULL);
441
0
}
442
443
/**
444
 * Curl_open()
445
 *
446
 * @param curl is a pointer to a sessionhandle pointer that gets set by this
447
 * function.
448
 * @return CURLcode
449
 */
450
451
CURLcode Curl_open(struct Curl_easy **curl)
452
413k
{
453
413k
  struct Curl_easy *data;
454
455
  /* simple start-up: alloc the struct, init it with zeroes and return */
456
413k
  data = curlx_calloc(1, sizeof(struct Curl_easy));
457
413k
  if(!data) {
458
    /* this is a serious error */
459
0
    DEBUGF(curl_mfprintf(stderr, "Error: calloc of Curl_easy failed\n"));
460
0
    return CURLE_OUT_OF_MEMORY;
461
0
  }
462
463
413k
  data->magic = CURLEASY_MAGIC_NUMBER;
464
  /* most recent connection is not yet defined */
465
413k
  data->state.lastconnect_id = -1;
466
413k
  data->state.recent_conn_id = -1;
467
  /* and not assigned an id yet */
468
413k
  data->id = -1;
469
413k
  data->mid = UINT32_MAX;
470
413k
  data->master_mid = UINT32_MAX;
471
413k
  data->progress.hide = TRUE;
472
413k
  data->state.current_speed = -1; /* init to negative == impossible */
473
474
413k
  Curl_hash_init(&data->meta_hash, 23,
475
413k
                 Curl_hash_str, curlx_str_key_compare, easy_meta_freeentry);
476
413k
  curlx_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER);
477
413k
  Curl_bufref_init(&data->state.url);
478
413k
  Curl_bufref_init(&data->state.referer);
479
413k
  Curl_req_init(&data->req);
480
413k
  Curl_initinfo(data);
481
413k
#ifndef CURL_DISABLE_HTTP
482
413k
  Curl_llist_init(&data->state.httphdrs, NULL);
483
413k
#endif
484
413k
  Curl_netrc_init(&data->state.netrc);
485
413k
  Curl_init_userdefined(data);
486
487
413k
  *curl = data;
488
413k
  return CURLE_OK;
489
413k
}
490
491
void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn)
492
159k
{
493
159k
  size_t i;
494
495
159k
  DEBUGASSERT(conn);
496
497
159k
  if(conn->scheme && conn->scheme->run->disconnect &&
498
34.1k
     !conn->bits.shutdown_handler)
499
619
    conn->scheme->run->disconnect(data, conn, TRUE);
500
501
477k
  for(i = 0; i < CURL_ARRAYSIZE(conn->cfilter); ++i) {
502
318k
    Curl_conn_cf_discard_all(data, conn, (int)i);
503
318k
  }
504
505
159k
#ifndef CURL_DISABLE_PROXY
506
159k
  Curl_peer_unlink(&conn->http_proxy.peer);
507
159k
  Curl_peer_unlink(&conn->socks_proxy.peer);
508
159k
  Curl_creds_unlink(&conn->http_proxy.creds);
509
159k
  Curl_creds_unlink(&conn->socks_proxy.creds);
510
159k
#endif
511
159k
  Curl_creds_unlink(&conn->creds);
512
159k
  curlx_safefree(conn->options);
513
159k
  curlx_safefree(conn->localdev);
514
159k
  Curl_ssl_conn_config_cleanup(conn);
515
516
159k
  curlx_safefree(conn->destination);
517
159k
  Curl_hash_destroy(&conn->meta_hash);
518
159k
  Curl_peer_unlink(&conn->origin);
519
159k
  Curl_peer_unlink(&conn->via_peer);
520
159k
  Curl_peer_unlink(&conn->origin2);
521
159k
  Curl_peer_unlink(&conn->via_peer2);
522
523
159k
  curlx_free(conn); /* free all the connection oriented data */
524
159k
}
525
526
/*
527
 * xfer_may_multiplex()
528
 *
529
 * Return a TRUE, iff the transfer can be done over an (appropriate)
530
 * multiplexed connection.
531
 */
532
static bool xfer_may_multiplex(const struct Curl_easy *data,
533
                               const struct connectdata *conn)
534
122k
{
535
122k
#ifndef CURL_DISABLE_HTTP
536
  /* If an HTTP protocol and multiplexing is enabled */
537
122k
  if((conn->scheme->protocol & PROTO_FAMILY_HTTP) &&
538
48.3k
     (!conn->bits.protoconnstart || !conn->bits.close)) {
539
540
48.3k
    if(Curl_multiplex_wanted(data->multi) &&
541
48.3k
       (data->state.http_neg.allowed & (CURL_HTTP_V2x | CURL_HTTP_V3x)))
542
      /* allows HTTP/2 or newer */
543
46.8k
      return TRUE;
544
48.3k
  }
545
#else
546
  (void)data;
547
  (void)conn;
548
#endif
549
75.7k
  return FALSE;
550
122k
}
551
552
#ifndef CURL_DISABLE_PROXY
553
static bool proxy_info_matches(const struct proxy_info *data,
554
                               const struct proxy_info *needle)
555
415
{
556
415
  if((data->proxytype == needle->proxytype) &&
557
415
     Curl_peer_same_destination(data->peer, needle->peer) &&
558
415
     Curl_creds_same(data->creds, needle->creds)) {
559
415
    return TRUE;
560
415
  }
561
0
  return FALSE;
562
415
}
563
#endif
564
565
/* A connection has to have been idle for less than 'conn_max_idle_ms'
566
   (the success rate is too low after this), or created less than
567
   'conn_max_age_ms' ago, to be subject for reuse. */
568
static bool conn_maxage(struct Curl_easy *data,
569
                        struct connectdata *conn,
570
                        struct curltime now)
571
13.9k
{
572
13.9k
  timediff_t age_ms;
573
574
13.9k
  if(data->set.conn_max_idle_ms) {
575
13.9k
    age_ms = curlx_ptimediff_ms(&now, &conn->lastused);
576
13.9k
    if(age_ms > data->set.conn_max_idle_ms) {
577
0
      infof(data, "Too old connection (%" FMT_TIMEDIFF_T
578
0
            " ms idle, max idle is %" FMT_TIMEDIFF_T " ms), disconnect it",
579
0
            age_ms, data->set.conn_max_idle_ms);
580
0
      return TRUE;
581
0
    }
582
13.9k
  }
583
584
13.9k
  if(data->set.conn_max_age_ms) {
585
13.8k
    age_ms = curlx_ptimediff_ms(&now, &conn->created);
586
13.8k
    if(age_ms > data->set.conn_max_age_ms) {
587
0
      infof(data,
588
0
            "Too old connection (created %" FMT_TIMEDIFF_T
589
0
            " ms ago, max lifetime is %" FMT_TIMEDIFF_T " ms), disconnect it",
590
0
            age_ms, data->set.conn_max_age_ms);
591
0
      return TRUE;
592
0
    }
593
13.8k
  }
594
595
13.9k
  return FALSE;
596
13.9k
}
597
598
/*
599
 * Return TRUE iff the given connection is considered dead.
600
 */
601
bool Curl_conn_seems_dead(struct connectdata *conn,
602
                          struct Curl_easy *data)
603
13.9k
{
604
13.9k
  DEBUGASSERT(!data->conn);
605
13.9k
  if(!CONN_INUSE(conn)) {
606
    /* The check for a dead socket makes sense only if the connection is not in
607
       use */
608
13.9k
    bool dead;
609
610
13.9k
    if(conn_maxage(data, conn, *Curl_pgrs_now(data))) {
611
      /* avoid check if already too old */
612
0
      dead = TRUE;
613
0
    }
614
13.9k
    else if(conn->scheme->run->connection_is_dead) {
615
      /* The protocol has a special method for checking the state of the
616
         connection. Use it to check if the connection is dead. */
617
      /* briefly attach the connection for the check */
618
9.64k
      Curl_attach_connection(data, conn);
619
9.64k
      dead = conn->scheme->run->connection_is_dead(data, conn);
620
9.64k
      Curl_detach_connection(data);
621
9.64k
    }
622
4.30k
    else {
623
4.30k
      bool input_pending = FALSE;
624
625
4.30k
      Curl_attach_connection(data, conn);
626
4.30k
      dead = !Curl_conn_is_alive(data, conn, &input_pending);
627
4.30k
      if(input_pending) {
628
        /* For reuse, we want a "clean" connection state. This includes
629
         * that we expect - in general - no waiting input data. Input
630
         * waiting might be a TLS Notify Close, for example. We reject
631
         * that.
632
         * For protocols where data from other end may arrive at
633
         * any time (HTTP/2 PING for example), the protocol handler needs
634
         * to install its own `connection_check` callback.
635
         */
636
940
        DEBUGF(infof(data, "connection has input pending, not reusable"));
637
940
        dead = TRUE;
638
940
      }
639
4.30k
      Curl_detach_connection(data);
640
4.30k
    }
641
642
13.9k
    if(dead) {
643
      /* remove connection from cpool */
644
940
      infof(data, "Connection %" FMT_OFF_T " seems to be dead",
645
940
            conn->connection_id);
646
940
      return TRUE;
647
940
    }
648
13.9k
  }
649
13.0k
  return FALSE;
650
13.9k
}
651
652
CURLcode Curl_conn_upkeep(struct Curl_easy *data,
653
                          struct connectdata *conn)
654
0
{
655
0
  CURLcode result = CURLE_OK;
656
0
  if(curlx_ptimediff_ms(Curl_pgrs_now(data), &conn->keepalive) <=
657
0
     data->set.upkeep_interval_ms)
658
0
    return result;
659
660
  /* briefly attach for action */
661
0
  Curl_attach_connection(data, conn);
662
0
  result = Curl_conn_keep_alive(data, conn, FIRSTSOCKET);
663
0
  Curl_detach_connection(data);
664
665
0
  conn->keepalive = *Curl_pgrs_now(data);
666
0
  return result;
667
0
}
668
669
struct url_conn_match {
670
  struct connectdata *found;
671
  struct Curl_easy *data;
672
  struct connectdata *needle;
673
  BIT(may_multiplex);
674
  BIT(want_ntlm_http);
675
  BIT(want_proxy_ntlm_http);
676
  BIT(want_nego_http);
677
  BIT(want_proxy_nego_http);
678
  BIT(may_tls); /* May upgrade clear-text connection to TLS, can only reuse
679
                 * connections that have matching TLS configuration.
680
                 * Always TRUE if `req_tls` is TRUE. */
681
  BIT(require_tls); /* Requires TLS use from a clear-text start, can only
682
                 * reuse connections that have TLS. */
683
  BIT(wait_pipe);
684
  BIT(force_reuse);
685
  BIT(seen_pending_conn);
686
  BIT(seen_single_use_conn);
687
  BIT(seen_multiplex_conn);
688
};
689
690
static bool url_match_connect_config(struct connectdata *conn,
691
                                     struct url_conn_match *m)
692
17.0k
{
693
  /* connect-only or to-be-closed connections will not be reused */
694
17.0k
  if(conn->bits.connect_only || conn->bits.close || conn->bits.no_reuse)
695
0
    return FALSE;
696
697
  /* ip_version must match */
698
17.0k
  if(m->data->set.ipver != CURL_IPRESOLVE_WHATEVER &&
699
52
     m->data->set.ipver != conn->ip_version)
700
0
    return FALSE;
701
702
17.0k
  if(m->needle->localdev || m->needle->localport) {
703
    /* If we are bound to a specific local end (IP+port), we must not reuse a
704
       random other one, although if we did not ask for a particular one we
705
       can reuse one that was bound.
706
707
       This comparison is a bit rough and too strict. Since the input
708
       parameters can be specified in numerous ways and still end up the same
709
       it would take a lot of processing to make it really accurate. Instead,
710
       this matching will assume that reuses of bound connections will most
711
       likely also reuse the exact same binding parameters and missing out a
712
       few edge cases should not hurt anyone much.
713
    */
714
1.24k
    if((conn->localport != m->needle->localport) ||
715
1.24k
       (conn->localportrange != m->needle->localportrange) ||
716
1.24k
       (m->needle->localdev &&
717
1.03k
        (!conn->localdev || strcmp(conn->localdev, m->needle->localdev))))
718
0
      return FALSE;
719
1.24k
  }
720
721
17.0k
  if(!m->needle->via_peer != !conn->via_peer)
722
    /* do not mix connections that use the "connect to host" feature and
723
     * connections that do not use this feature */
724
11
    return FALSE;
725
726
17.0k
  return TRUE;
727
17.0k
}
728
729
static bool url_match_fully_connected(struct connectdata *conn,
730
                                      struct url_conn_match *m)
731
17.0k
{
732
17.0k
  if(!Curl_conn_is_connected(conn, FIRSTSOCKET) ||
733
14.0k
     conn->bits.upgrade_in_progress) {
734
    /* Not yet connected, or a protocol upgrade is in progress. The later
735
     * happens for HTTP/2 Upgrade: requests that need a response. */
736
2.95k
    if(m->may_multiplex) {
737
2.95k
      m->seen_pending_conn = TRUE;
738
      /* Do not pick a connection that has not connected yet */
739
2.95k
      infof(m->data, "Connection #%" FMT_OFF_T
740
2.95k
            " is not open enough, cannot reuse", conn->connection_id);
741
2.95k
    }
742
    /* Do not pick a connection that has not connected yet */
743
2.95k
    return FALSE;
744
2.95k
  }
745
14.0k
  return TRUE;
746
17.0k
}
747
748
static bool url_match_multi(struct connectdata *conn,
749
                            struct url_conn_match *m)
750
0
{
751
0
  if(CONN_INUSE(conn)) {
752
0
    DEBUGASSERT(conn->attached_multi);
753
0
    if(conn->attached_multi != m->data->multi)
754
0
      return FALSE;
755
0
  }
756
0
  return TRUE;
757
0
}
758
759
static bool url_match_multiplex_needs(struct connectdata *conn,
760
                                      struct url_conn_match *m)
761
14.0k
{
762
14.0k
  if(CONN_INUSE(conn)) {
763
0
    if(!conn->bits.multiplex) {
764
      /* conn busy and conn cannot take more transfers */
765
0
      m->seen_single_use_conn = TRUE;
766
0
      return FALSE;
767
0
    }
768
0
    m->seen_multiplex_conn = TRUE;
769
0
    if(!m->may_multiplex || !url_match_multi(conn, m))
770
      /* conn busy and transfer cannot be multiplexed */
771
0
      return FALSE;
772
0
  }
773
14.0k
  return TRUE;
774
14.0k
}
775
776
static bool url_match_multiplex_limits(struct connectdata *conn,
777
                                       struct url_conn_match *m)
778
13.9k
{
779
13.9k
  if(CONN_INUSE(conn) && m->may_multiplex) {
780
0
    DEBUGASSERT(conn->bits.multiplex);
781
    /* If multiplexed, make sure we do not go over concurrency limit */
782
0
    if(conn->attached_xfers >=
783
0
            Curl_multi_max_concurrent_streams(m->data->multi)) {
784
0
      infof(m->data, "client side MAX_CONCURRENT_STREAMS reached"
785
0
            ", skip (%u)", conn->attached_xfers);
786
0
      return FALSE;
787
0
    }
788
0
    if(conn->attached_xfers >=
789
0
       Curl_conn_get_max_concurrent(m->data, conn, FIRSTSOCKET)) {
790
0
      infof(m->data, "MAX_CONCURRENT_STREAMS reached, skip (%u)",
791
0
            conn->attached_xfers);
792
0
      return FALSE;
793
0
    }
794
    /* When not multiplexed, we have a match here! */
795
0
    infof(m->data, "Multiplexed connection found");
796
0
  }
797
13.9k
  return TRUE;
798
13.9k
}
799
800
static bool url_match_ssl_use(struct connectdata *conn,
801
                              struct url_conn_match *m)
802
14.0k
{
803
14.0k
  if(m->needle->scheme->flags & PROTOPT_SSL) {
804
    /* We are looking for SSL, if `conn` does not do it, not a match. */
805
0
    if(!Curl_conn_is_ssl(conn, FIRSTSOCKET))
806
0
      return FALSE;
807
0
  }
808
14.0k
  else if(Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
809
    /* If the protocol does not allow reuse of SSL connections OR
810
       is of another protocol family, not a match. */
811
0
    if(!(m->needle->scheme->flags & PROTOPT_SSL_REUSE) ||
812
0
       (get_protocol_family(conn->scheme) != m->needle->scheme->protocol))
813
0
      return FALSE;
814
0
  }
815
14.0k
  else if(m->require_tls)
816
    /* a clear-text STARTTLS protocol with required TLS */
817
8
    return FALSE;
818
14.0k
  return TRUE;
819
14.0k
}
820
821
#ifndef CURL_DISABLE_PROXY
822
static bool url_match_proxy_use(struct connectdata *conn,
823
                                struct url_conn_match *m)
824
14.0k
{
825
14.0k
  if(m->needle->bits.httpproxy != conn->bits.httpproxy ||
826
14.0k
     m->needle->bits.socksproxy != conn->bits.socksproxy)
827
0
    return FALSE;
828
829
14.0k
  if(m->needle->bits.socksproxy &&
830
3
     !proxy_info_matches(&m->needle->socks_proxy, &conn->socks_proxy))
831
0
    return FALSE;
832
833
14.0k
  if(m->needle->bits.httpproxy) {
834
412
    if(m->needle->bits.tunnel_proxy != conn->bits.tunnel_proxy)
835
0
      return FALSE;
836
837
412
    if(!proxy_info_matches(&m->needle->http_proxy, &conn->http_proxy))
838
0
      return FALSE;
839
840
412
    if(IS_HTTPS_PROXY(m->needle->http_proxy.proxytype)) {
841
      /* https proxies come in different types, http/1.1, h2, ... */
842
0
      if(m->needle->http_proxy.proxytype != conn->http_proxy.proxytype)
843
0
        return FALSE;
844
      /* match SSL config to proxy */
845
0
      if(!Curl_ssl_conn_config_match(m->data, conn, TRUE)) {
846
0
        DEBUGF(infof(m->data,
847
0
                     "Connection #%" FMT_OFF_T
848
0
                     " has different SSL proxy parameters, cannot reuse",
849
0
                     conn->connection_id));
850
0
        return FALSE;
851
0
      }
852
      /* the SSL config to the server, which may apply here is checked
853
       * further below */
854
0
    }
855
412
  }
856
14.0k
  return TRUE;
857
14.0k
}
858
#else
859
#define url_match_proxy_use(c, m) ((void)(c), (void)(m), TRUE)
860
#endif
861
862
#ifndef CURL_DISABLE_HTTP
863
static bool url_match_http_multiplex(struct connectdata *conn,
864
                                     struct url_conn_match *m)
865
14.0k
{
866
14.0k
  if(m->may_multiplex &&
867
4.05k
     (m->data->state.http_neg.allowed & (CURL_HTTP_V2x | CURL_HTTP_V3x)) &&
868
4.05k
     (m->needle->scheme->protocol & CURLPROTO_HTTP) &&
869
4.05k
     !conn->httpversion_seen) {
870
0
    if(m->data->set.pipewait) {
871
0
      infof(m->data, "Server upgrade does not support multiplex yet, wait");
872
0
      m->found = NULL;
873
0
      m->wait_pipe = TRUE;
874
0
      return TRUE; /* stop searching, we want to wait */
875
0
    }
876
0
    infof(m->data, "Server upgrade cannot be used");
877
0
    return FALSE;
878
0
  }
879
14.0k
  return TRUE;
880
14.0k
}
881
882
static bool url_match_http_version(struct connectdata *conn,
883
                                   struct url_conn_match *m)
884
14.0k
{
885
  /* If looking for HTTP and the HTTP versions allowed do not include
886
   * the HTTP version of conn, continue looking. */
887
14.0k
  if((m->needle->scheme->protocol & PROTO_FAMILY_HTTP)) {
888
4.27k
    switch(Curl_conn_http_version(m->data, conn)) {
889
0
    case 30:
890
0
      if(!(m->data->state.http_neg.allowed & CURL_HTTP_V3x)) {
891
0
        DEBUGF(infof(m->data, "not reusing conn #%" CURL_FORMAT_CURL_OFF_T
892
0
                     ", we do not want h3", conn->connection_id));
893
0
        return FALSE;
894
0
      }
895
0
      break;
896
234
    case 20:
897
234
      if(!(m->data->state.http_neg.allowed & CURL_HTTP_V2x)) {
898
93
        DEBUGF(infof(m->data, "not reusing conn #%" CURL_FORMAT_CURL_OFF_T
899
93
                     ", we do not want h2", conn->connection_id));
900
93
        return FALSE;
901
93
      }
902
141
      break;
903
4.03k
    default:
904
4.03k
      if(!(m->data->state.http_neg.allowed & CURL_HTTP_V1x)) {
905
1
        DEBUGF(infof(m->data, "not reusing conn #%" CURL_FORMAT_CURL_OFF_T
906
1
                     ", we do not want h1", conn->connection_id));
907
1
        return FALSE;
908
1
      }
909
4.03k
      break;
910
4.27k
    }
911
4.27k
  }
912
13.9k
  return TRUE;
913
14.0k
}
914
#else
915
#define url_match_http_multiplex(c, m) ((void)(c), (void)(m), TRUE)
916
#define url_match_http_version(c, m)   ((void)(c), (void)(m), TRUE)
917
#endif
918
919
static bool url_match_proto_config(struct connectdata *conn,
920
                                   struct url_conn_match *m)
921
14.0k
{
922
14.0k
  if(!url_match_http_version(conn, m))
923
94
    return FALSE;
924
925
13.9k
#ifndef CURL_DISABLE_FTP
926
13.9k
  else if(get_protocol_family(m->needle->scheme) & PROTO_FAMILY_FTP) {
927
105
    if(!ftp_conns_match(m->needle, conn))
928
0
      return FALSE;
929
105
  }
930
13.9k
#endif
931
13.9k
  return TRUE;
932
14.0k
}
933
934
static bool url_match_auth(struct connectdata *conn,
935
                           struct url_conn_match *m)
936
14.0k
{
937
14.0k
  if(!Curl_creds_same(m->needle->creds, conn->creds)) {
938
15
    if(m->needle->creds)
939
10
      return FALSE;
940
5
    if(!Curl_creds_same(m->data->state.creds, conn->creds))
941
5
      return FALSE;
942
5
  }
943
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
944
  /* GSS delegation differences do not actually affect every connection and
945
     auth method, but this check takes precaution before efficiency */
946
  if(m->needle->gssapi_delegation != conn->gssapi_delegation)
947
    return FALSE;
948
#endif
949
950
14.0k
  return TRUE;
951
14.0k
}
952
953
static bool url_match_destination(struct connectdata *conn,
954
                                  struct url_conn_match *m)
955
17.0k
{
956
  /* Different connect-to peers never match */
957
17.0k
  if(!Curl_peer_same_destination(m->needle->via_peer, conn->via_peer))
958
0
    return FALSE;
959
960
17.0k
#ifndef CURL_DISABLE_PROXY
961
17.0k
  if(m->needle->bits.httpproxy && !m->needle->bits.tunnel_proxy) {
962
    /* Talking to a non-tunneling HTTP proxy matches on proxy peers. */
963
77
    return Curl_peer_equal(m->needle->http_proxy.peer,
964
77
                           conn->http_proxy.peer);
965
77
  }
966
16.9k
#endif
967
968
16.9k
  if(m->needle->origin->scheme != conn->origin->scheme) {
969
    /* `needle` and `conn` not having the same scheme.
970
     * This is allowed for the same family *if* conn is using TLS.
971
     * - IMAP+STARTTLS works for IMAPS.
972
     * - IMAPS works for IMAP. */
973
0
    if(get_protocol_family(conn->origin->scheme) !=
974
0
       m->needle->scheme->protocol) {
975
0
      return FALSE;
976
0
    }
977
0
  }
978
  /* Scheme mismatch is acceptable, just compare hostname/port */
979
16.9k
  return Curl_peer_same_destination(m->needle->origin, conn->origin);
980
16.9k
}
981
982
static bool url_match_ssl_config(struct connectdata *conn,
983
                                 struct url_conn_match *m)
984
14.0k
{
985
  /* If talking/upgrading to TLS, conn needs to use the same SSL options. */
986
14.0k
  if(((m->needle->scheme->flags & PROTOPT_SSL) || m->may_tls) &&
987
71
     !Curl_ssl_conn_config_match(m->data, conn, FALSE)) {
988
0
    DEBUGF(infof(m->data, "Connection #%" FMT_OFF_T
989
0
                 " has different SSL parameters, cannot reuse",
990
0
                 conn->connection_id));
991
0
    return FALSE;
992
0
  }
993
14.0k
  return TRUE;
994
14.0k
}
995
996
#ifdef USE_NTLM
997
static bool url_match_auth_ntlm(struct connectdata *conn,
998
                                struct url_conn_match *m)
999
{
1000
  /* If we are looking for an HTTP+NTLM connection, check if this is
1001
     already authenticating with the right credentials. If not, keep
1002
     looking so that we can reuse NTLM connections if
1003
     possible. (Especially we must not reuse the same connection if
1004
     partway through a handshake!) */
1005
  if(m->want_ntlm_http) {
1006
    if(!Curl_creds_same(m->data->state.creds, conn->creds)) {
1007
      /* we prefer a credential match, but this is at least a connection
1008
         that can be reused and "upgraded" to NTLM if it does
1009
         not have any auth ongoing. */
1010
#ifdef USE_SPNEGO
1011
      if((conn->http_ntlm_state == NTLMSTATE_NONE) &&
1012
         (conn->http_negotiate_state == GSS_AUTHNONE)) {
1013
#else
1014
      if(conn->http_ntlm_state == NTLMSTATE_NONE) {
1015
#endif
1016
        m->found = conn;
1017
      }
1018
      return FALSE;
1019
    }
1020
  }
1021
  else if(conn->http_ntlm_state != NTLMSTATE_NONE) {
1022
    /* Connection is using NTLM auth but we do not want NTLM */
1023
    return FALSE;
1024
  }
1025
1026
#ifndef CURL_DISABLE_PROXY
1027
  /* Same for Proxy NTLM authentication */
1028
  if(m->want_proxy_ntlm_http) {
1029
    /* Both conn->http_proxy.user and conn->http_proxy.passwd can be
1030
     * NULL */
1031
    if(!conn->http_proxy.creds)
1032
      return FALSE;
1033
1034
    if(!Curl_creds_same(m->needle->http_proxy.creds, conn->http_proxy.creds))
1035
      return FALSE;
1036
  }
1037
  else if(conn->proxy_ntlm_state != NTLMSTATE_NONE) {
1038
    /* Proxy connection is using NTLM auth but we do not want NTLM */
1039
    return FALSE;
1040
  }
1041
#endif
1042
  if(m->want_ntlm_http || m->want_proxy_ntlm_http) {
1043
    /* Credentials are already checked, we may use this connection.
1044
     * With NTLM being weird as it is, we MUST use a
1045
     * connection where it has already been fully negotiated.
1046
     * If it has not, we keep on looking for a better one. */
1047
    m->found = conn;
1048
1049
    if((m->want_ntlm_http &&
1050
       (conn->http_ntlm_state != NTLMSTATE_NONE)) ||
1051
        (m->want_proxy_ntlm_http &&
1052
         (conn->proxy_ntlm_state != NTLMSTATE_NONE))) {
1053
      /* We must use this connection, no other */
1054
      m->force_reuse = TRUE;
1055
      return TRUE;
1056
    }
1057
    /* Continue look up for a better connection */
1058
    return FALSE;
1059
  }
1060
  return TRUE;
1061
}
1062
#else
1063
13.9k
#define url_match_auth_ntlm(c, m) ((void)(c), (void)(m), TRUE)
1064
#endif
1065
1066
#ifdef USE_SPNEGO
1067
static bool url_match_auth_nego(struct connectdata *conn,
1068
                                struct url_conn_match *m)
1069
{
1070
  /* If we are looking for an HTTP+Negotiate connection, check if this is
1071
     already authenticating with the right credentials. If not, keep looking
1072
     so that we can reuse Negotiate connections if possible. */
1073
  if(m->want_nego_http) {
1074
    if(!Curl_creds_same(m->needle->creds, conn->creds))
1075
      return FALSE;
1076
  }
1077
  else if(conn->http_negotiate_state != GSS_AUTHNONE) {
1078
    /* Connection is using Negotiate auth but we do not want Negotiate */
1079
    return FALSE;
1080
  }
1081
1082
#ifndef CURL_DISABLE_PROXY
1083
  /* Same for Proxy Negotiate authentication */
1084
  if(m->want_proxy_nego_http) {
1085
    /* Both conn->http_proxy.user and conn->http_proxy.passwd can be
1086
     * NULL */
1087
    if(!conn->http_proxy.creds)
1088
      return FALSE;
1089
1090
    if(!Curl_creds_same(m->needle->http_proxy.creds, conn->http_proxy.creds))
1091
      return FALSE;
1092
  }
1093
  else if(conn->proxy_negotiate_state != GSS_AUTHNONE) {
1094
    /* Proxy connection is using Negotiate auth but we do not want Negotiate */
1095
    return FALSE;
1096
  }
1097
#endif
1098
  if(m->want_nego_http || m->want_proxy_nego_http) {
1099
    /* Credentials are already checked, we may use this connection. We MUST
1100
     * use a connection where it has already been fully negotiated. If it has
1101
     * not, we keep on looking for a better one. */
1102
    m->found = conn;
1103
    if((m->want_nego_http &&
1104
        (conn->http_negotiate_state != GSS_AUTHNONE)) ||
1105
       (m->want_proxy_nego_http &&
1106
        (conn->proxy_negotiate_state != GSS_AUTHNONE))) {
1107
      /* We must use this connection, no other */
1108
      m->force_reuse = TRUE;
1109
      return TRUE;
1110
    }
1111
    return FALSE; /* get another */
1112
  }
1113
  return TRUE;
1114
}
1115
#else
1116
13.9k
#define url_match_auth_nego(c, m) ((void)(c), (void)(m), TRUE)
1117
#endif
1118
1119
static bool url_match_conn(struct connectdata *conn, void *userdata)
1120
17.0k
{
1121
17.0k
  struct url_conn_match *m = userdata;
1122
  /* Check if `conn` can be used for transfer `m->data` */
1123
1124
  /* general connect config setting match? */
1125
17.0k
  if(!url_match_connect_config(conn, m))
1126
11
    return FALSE;
1127
1128
  /* match for destination and protocol? */
1129
17.0k
  if(!url_match_destination(conn, m))
1130
48
    return FALSE;
1131
1132
17.0k
  if(!url_match_fully_connected(conn, m))
1133
2.95k
    return FALSE;
1134
1135
14.0k
  if(!url_match_multiplex_needs(conn, m))
1136
0
    return FALSE;
1137
1138
14.0k
  if(!url_match_ssl_use(conn, m))
1139
8
    return FALSE;
1140
1141
14.0k
  if(!url_match_proxy_use(conn, m))
1142
0
    return FALSE;
1143
14.0k
  if(!url_match_ssl_config(conn, m))
1144
0
    return FALSE;
1145
1146
14.0k
  if(!url_match_http_multiplex(conn, m))
1147
0
    return FALSE;
1148
14.0k
  else if(m->wait_pipe)
1149
    /* we decided to wait on PIPELINING */
1150
0
    return TRUE;
1151
1152
14.0k
  if(!url_match_auth(conn, m))
1153
15
    return FALSE;
1154
1155
14.0k
  if(!url_match_proto_config(conn, m))
1156
94
    return FALSE;
1157
1158
13.9k
  if(!url_match_auth_ntlm(conn, m))
1159
0
    return FALSE;
1160
13.9k
  else if(m->force_reuse)
1161
0
    return TRUE;
1162
1163
13.9k
  if(!url_match_auth_nego(conn, m))
1164
0
    return FALSE;
1165
13.9k
  else if(m->force_reuse)
1166
0
    return TRUE;
1167
1168
13.9k
  if(!url_match_multiplex_limits(conn, m))
1169
0
    return FALSE;
1170
1171
13.9k
  if(!CONN_INUSE(conn) && Curl_conn_seems_dead(conn, m->data)) {
1172
    /* remove and disconnect. */
1173
917
    Curl_conn_terminate(m->data, conn, FALSE);
1174
917
    return FALSE;
1175
917
  }
1176
1177
  /* conn matches our needs. */
1178
13.0k
  m->found = conn;
1179
13.0k
  return TRUE;
1180
13.9k
}
1181
1182
static bool url_match_result(void *userdata)
1183
122k
{
1184
122k
  struct url_conn_match *match = userdata;
1185
122k
  if(match->found) {
1186
    /* Attach it now while still under lock, so the connection does
1187
     * no longer appear idle and can be reaped. */
1188
13.0k
    Curl_attach_connection(match->data, match->found);
1189
13.0k
    return TRUE;
1190
13.0k
  }
1191
109k
  else if(match->seen_single_use_conn && !match->seen_multiplex_conn) {
1192
    /* We have seen a single-use, existing connection to the destination and
1193
     * no multiplexed one. It seems safe to assume that the server does
1194
     * not support multiplexing. */
1195
0
    match->wait_pipe = FALSE;
1196
0
  }
1197
109k
  else if(match->seen_pending_conn && match->data->set.pipewait) {
1198
2.94k
    infof(match->data,
1199
2.94k
          "Found pending candidate for reuse and CURLOPT_PIPEWAIT is set");
1200
2.94k
    match->wait_pipe = TRUE;
1201
2.94k
  }
1202
109k
  match->force_reuse = FALSE;
1203
109k
  return FALSE;
1204
122k
}
1205
1206
/*
1207
 * Given a transfer and a prototype connection (needle),
1208
 * find and attach an existing connection that matches.
1209
 *
1210
 * Return TRUE if an existing connection was attached.
1211
 * `waitpipe` is TRUE if no existing connection matched, but there
1212
 * might be suitable one in the near future (common cause: multiplexing
1213
 * capability has not been determined yet, e.g. ALPN handshake).
1214
 */
1215
static bool url_attach_existing(struct Curl_easy *data,
1216
                                struct connectdata *needle,
1217
                                bool *waitpipe)
1218
122k
{
1219
122k
  struct url_conn_match match;
1220
122k
  bool success;
1221
1222
122k
  DEBUGASSERT(!data->conn);
1223
122k
  memset(&match, 0, sizeof(match));
1224
122k
  match.data = data;
1225
122k
  match.needle = needle;
1226
122k
  match.may_multiplex = xfer_may_multiplex(data, needle);
1227
1228
#ifdef USE_NTLM
1229
  match.want_ntlm_http =
1230
    (data->state.authhost.want & CURLAUTH_NTLM) &&
1231
    (needle->scheme->protocol & PROTO_FAMILY_HTTP);
1232
#ifndef CURL_DISABLE_PROXY
1233
  match.want_proxy_ntlm_http =
1234
    needle->http_proxy.creds &&
1235
    (data->state.authproxy.want & CURLAUTH_NTLM) &&
1236
    (needle->scheme->protocol & PROTO_FAMILY_HTTP);
1237
#endif
1238
#endif
1239
1240
#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO)
1241
  match.want_nego_http =
1242
    (data->state.authhost.want & CURLAUTH_NEGOTIATE) &&
1243
    (needle->scheme->protocol & PROTO_FAMILY_HTTP);
1244
#ifndef CURL_DISABLE_PROXY
1245
  match.want_proxy_nego_http =
1246
    needle->http_proxy.creds &&
1247
    (data->state.authproxy.want & CURLAUTH_NEGOTIATE) &&
1248
    (needle->scheme->protocol & PROTO_FAMILY_HTTP);
1249
#endif
1250
#endif
1251
122k
  match.require_tls = data->set.use_ssl >= CURLUSESSL_CONTROL;
1252
122k
  match.may_tls = data->set.use_ssl > CURLUSESSL_NONE;
1253
1254
  /* Find a connection in the pool that matches what "data + needle"
1255
   * requires. If a suitable candidate is found, it is attached to "data". */
1256
122k
  success = Curl_cpool_find(data, needle->destination,
1257
122k
                            url_match_conn, url_match_result, &match);
1258
1259
  /* wait_pipe is TRUE if we encounter a bundle that is undecided. There
1260
   * is no matching connection then, yet. */
1261
122k
  *waitpipe = (bool)match.wait_pipe;
1262
122k
  return success;
1263
122k
}
1264
1265
/*
1266
 * Allocate and initialize a new connectdata object.
1267
 */
1268
static struct connectdata *allocate_conn(struct Curl_easy *data)
1269
159k
{
1270
159k
  struct connectdata *conn = curlx_calloc(1, sizeof(struct connectdata));
1271
159k
  if(!conn)
1272
0
    return NULL;
1273
1274
  /* and we setup a few fields in case we end up actually using this struct */
1275
1276
159k
  conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD;     /* no file descriptor */
1277
159k
  conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
1278
159k
  conn->recv_idx = 0; /* default for receiving transfer data */
1279
159k
  conn->send_idx = 0; /* default for sending transfer data */
1280
159k
  conn->connection_id = -1;    /* no ID */
1281
159k
  conn->attached_xfers = 0;
1282
1283
  /* Store creation time to help future close decision making */
1284
159k
  conn->created = *Curl_pgrs_now(data);
1285
1286
  /* Store current time to give a baseline to keepalive connection times. */
1287
159k
  conn->keepalive = conn->created;
1288
1289
159k
#ifndef CURL_DISABLE_PROXY
1290
159k
  conn->http_proxy.proxytype = data->set.proxytype;
1291
159k
  conn->socks_proxy.proxytype = CURLPROXY_SOCKS4;
1292
1293
  /* note that these two proxy bits are set on what looks to be
1294
     requested, they may be altered down the road */
1295
159k
  conn->bits.proxy = (data->set.str[STRING_PROXY] &&
1296
39.9k
                      *data->set.str[STRING_PROXY]);
1297
159k
  conn->bits.httpproxy = (conn->bits.proxy &&
1298
39.0k
                          (conn->http_proxy.proxytype == CURLPROXY_HTTP ||
1299
13.7k
                           conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0 ||
1300
13.6k
                           IS_HTTPS_PROXY(conn->http_proxy.proxytype)));
1301
159k
  conn->bits.socksproxy = (conn->bits.proxy && !conn->bits.httpproxy);
1302
1303
159k
  if(data->set.str[STRING_PRE_PROXY] && *data->set.str[STRING_PRE_PROXY]) {
1304
5.63k
    conn->bits.proxy = TRUE;
1305
5.63k
    conn->bits.socksproxy = TRUE;
1306
5.63k
  }
1307
1308
159k
  conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
1309
159k
#endif /* CURL_DISABLE_PROXY */
1310
1311
159k
#ifndef CURL_DISABLE_FTP
1312
159k
  conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
1313
159k
  conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
1314
159k
#endif
1315
159k
  conn->ip_version = data->set.ipver;
1316
159k
  conn->bits.connect_only = (bool)data->set.connect_only;
1317
159k
  conn->transport_wanted = TRNSPRT_TCP; /* most of them are TCP streams */
1318
1319
  /* Store the local bind parameters that will be used for this connection */
1320
159k
  if(data->set.str[STRING_DEVICE]) {
1321
2.24k
    conn->localdev = curlx_strdup(data->set.str[STRING_DEVICE]);
1322
2.24k
    if(!conn->localdev)
1323
0
      goto error;
1324
2.24k
  }
1325
159k
#ifndef CURL_DISABLE_BINDLOCAL
1326
159k
  conn->localportrange = data->set.localportrange;
1327
159k
  conn->localport = data->set.localport;
1328
159k
#endif
1329
1330
  /* the close socket stuff needs to be copied to the connection struct as
1331
     it may live on without (this specific) Curl_easy */
1332
159k
  conn->fclosesocket = data->set.fclosesocket;
1333
159k
  conn->closesocket_client = data->set.closesocket_client;
1334
159k
  conn->lastused = conn->created;
1335
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
1336
  conn->gssapi_delegation = data->set.gssapi_delegation;
1337
#endif
1338
159k
  DEBUGF(infof(data, "alloc connection, bits.close=%d", conn->bits.close));
1339
159k
  return conn;
1340
0
error:
1341
1342
0
  curlx_free(conn->localdev);
1343
0
  curlx_free(conn);
1344
0
  return NULL;
1345
159k
}
1346
1347
static CURLcode url_set_conn_scheme(struct Curl_easy *data,
1348
                                    struct connectdata *conn,
1349
                                    const struct Curl_scheme *scheme)
1350
145k
{
1351
  /* URL scheme is usable for connection when it is
1352
   * - allowed
1353
   * - not from a redirect or an allowed redirect protocol */
1354
145k
  if(scheme->run &&
1355
145k
     (data->set.allowed_protocols & scheme->protocol) &&
1356
139k
     (!data->state.this_is_a_follow ||
1357
138k
       (data->set.redir_protocols & scheme->protocol))) {
1358
138k
    conn->scheme = conn->given = scheme;
1359
138k
    return CURLE_OK;
1360
138k
  }
1361
6.92k
  if(scheme->flags & PROTOPT_NO_TRANSFER)
1362
0
    failf(data, "Protocol \"%s\" is not for transfers", scheme->name);
1363
6.92k
  else
1364
6.92k
    failf(data, "Protocol \"%s\" is disabled%s", scheme->name,
1365
6.92k
          data->state.this_is_a_follow ? " (in redirect)" : "");
1366
6.92k
  return CURLE_UNSUPPORTED_PROTOCOL;
1367
145k
}
1368
1369
CURLcode Curl_uc_to_curlcode(CURLUcode uc)
1370
10.9k
{
1371
10.9k
  switch(uc) {
1372
10.9k
  default:
1373
10.9k
    return CURLE_URL_MALFORMAT;
1374
29
  case CURLUE_UNSUPPORTED_SCHEME:
1375
29
    return CURLE_UNSUPPORTED_PROTOCOL;
1376
0
  case CURLUE_OUT_OF_MEMORY:
1377
0
    return CURLE_OUT_OF_MEMORY;
1378
14
  case CURLUE_USER_NOT_ALLOWED:
1379
14
    return CURLE_LOGIN_DENIED;
1380
10.9k
  }
1381
10.9k
}
1382
1383
#ifndef CURL_DISABLE_HSTS
1384
static CURLcode hsts_upgrade(struct Curl_easy *data,
1385
                             struct connectdata *conn,
1386
                             CURLU *uh,
1387
                             uint16_t port_override,
1388
                             uint32_t scope_id)
1389
145k
{
1390
  /* HSTS upgrade */
1391
145k
  if(data->hsts && (conn->origin->scheme == &Curl_scheme_http) &&
1392
41.9k
     Curl_hsts_applies(data->hsts, conn->origin)) {
1393
1
    char *url;
1394
1
    CURLUcode uc;
1395
1
    CURLcode result;
1396
1397
1
    curlx_safefree(data->state.up.scheme);
1398
1
    uc = curl_url_set(uh, CURLUPART_SCHEME, "https", 0);
1399
1
    if(uc)
1400
0
      return Curl_uc_to_curlcode(uc);
1401
1
    Curl_bufref_free(&data->state.url);
1402
    /* after update, get the updated version */
1403
1
    uc = curl_url_get(uh, CURLUPART_URL, &url, 0);
1404
1
    if(uc)
1405
0
      return Curl_uc_to_curlcode(uc);
1406
1
    Curl_bufref_set(&data->state.url, url, 0, curl_free);
1407
1408
1
    result = Curl_peer_from_url(uh, data, port_override, scope_id,
1409
1
                                &data->state.up, &conn->origin);
1410
1
    if(result)
1411
0
      return result;
1412
1
    infof(data, "Switched from HTTP to HTTPS due to HSTS => %s", url);
1413
1
  }
1414
145k
  return CURLE_OK;
1415
145k
}
1416
#else
1417
#define hsts_upgrade(x, y, z, a, b) CURLE_OK
1418
#endif
1419
1420
static CURLcode url_set_data_creds(struct Curl_easy *data,
1421
                                   struct connectdata *conn,
1422
                                   CURLU *uh)
1423
138k
{
1424
138k
  CURLcode result = CURLE_OK;
1425
1426
  /* We reset any existing credentials on the transfer. Then
1427
   * set the CURLOPT_* credentials ONLY IF the origin is the initial one. */
1428
138k
  Curl_creds_unlink(&data->state.creds);
1429
138k
  if((data->set.str[STRING_USERNAME] ||
1430
133k
      data->set.str[STRING_PASSWORD] ||
1431
128k
      data->set.str[STRING_BEARER] ||
1432
126k
      data->set.str[STRING_SASL_AUTHZID] ||
1433
126k
      data->set.str[STRING_SERVICE_NAME]) &&
1434
12.9k
     Curl_auth_allowed_to_origin(data, conn->origin)) {
1435
12.8k
    result = Curl_creds_create(data->set.str[STRING_USERNAME],
1436
12.8k
                               data->set.str[STRING_PASSWORD],
1437
12.8k
                               data->set.str[STRING_BEARER],
1438
12.8k
                               data->set.str[STRING_SASL_AUTHZID],
1439
12.8k
                               data->set.str[STRING_SERVICE_NAME],
1440
12.8k
                               CREDS_OPTION, &data->state.creds);
1441
12.8k
    if(result)
1442
0
      return result;
1443
12.8k
  }
1444
1445
  /* Extract credentials from the URL only if there are none OR
1446
   * if no CURLOPT_USER was set. */
1447
138k
  if(!data->state.creds || !Curl_creds_has_user(data->state.creds)) {
1448
135k
    char *udecoded = NULL;
1449
135k
    char *pdecoded = NULL;
1450
135k
    CURLUcode uc;
1451
1452
135k
    uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user, 0);
1453
135k
    if(uc && (uc != CURLUE_NO_USER)) {
1454
0
      result = Curl_uc_to_curlcode(uc);
1455
0
      goto out;
1456
0
    }
1457
135k
    uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0);
1458
135k
    if(uc && (uc != CURLUE_NO_PASSWORD)) {
1459
0
      result = Curl_uc_to_curlcode(uc);
1460
0
      goto out;
1461
0
    }
1462
135k
    if(data->state.up.user) {
1463
20.4k
      result = Curl_urldecode(data->state.up.user, 0, &udecoded, NULL,
1464
20.4k
                              conn->scheme->flags&PROTOPT_USERPWDCTRL ?
1465
12.6k
                              REJECT_ZERO : REJECT_CTRL);
1466
20.4k
    }
1467
135k
    if(!result && data->state.up.password) {
1468
3.53k
      result = Curl_urldecode(data->state.up.password, 0, &pdecoded, NULL,
1469
3.53k
                              conn->scheme->flags&PROTOPT_USERPWDCTRL ?
1470
2.33k
                              REJECT_ZERO : REJECT_CTRL);
1471
3.53k
    }
1472
135k
    if(!result)
1473
134k
      result = Curl_creds_merge(udecoded, pdecoded, data->state.creds,
1474
134k
                                CREDS_URL, &data->state.creds);
1475
135k
out:
1476
135k
    curlx_free(udecoded);
1477
135k
    curlx_free(pdecoded);
1478
135k
    if(result)
1479
80
      failf(data, "error extracting credentials from URL");
1480
135k
  }
1481
138k
  return result;
1482
138k
}
1483
1484
/*
1485
 * Parse URL and fill in the relevant members of the connection struct.
1486
 */
1487
static CURLcode parseurlandfillconn(struct Curl_easy *data,
1488
                                    struct connectdata *conn)
1489
159k
{
1490
159k
  CURLcode result = CURLE_OK;
1491
159k
  CURLU *uh;
1492
159k
  CURLUcode uc;
1493
159k
  bool use_set_uh = (data->set.uh && !data->state.this_is_a_follow);
1494
159k
  uint16_t port_override = data->state.allow_port ? data->set.use_port : 0;
1495
159k
  uint32_t scope_id = 0;
1496
1497
159k
  up_free(data); /* cleanup previous leftovers first */
1498
1499
  /* parse the URL */
1500
159k
  if(use_set_uh)
1501
0
    uh = data->state.uh = curl_url_dup(data->set.uh);
1502
159k
  else
1503
159k
    uh = data->state.uh = curl_url();
1504
159k
  if(!uh) {
1505
0
    result = CURLE_OUT_OF_MEMORY;
1506
0
    goto out;
1507
0
  }
1508
1509
  /* Calculate the *real* URL this transfer uses, applying defaults
1510
   * where information is missing. */
1511
159k
  if(data->set.str[STRING_DEFAULT_PROTOCOL] &&
1512
18.6k
     !Curl_is_absolute_url(Curl_bufref_ptr(&data->state.url), NULL, 0, TRUE)) {
1513
9.54k
    char *url = curl_maprintf("%s://%s",
1514
9.54k
                              data->set.str[STRING_DEFAULT_PROTOCOL],
1515
9.54k
                              Curl_bufref_ptr(&data->state.url));
1516
9.54k
    if(!url) {
1517
0
      result = CURLE_OUT_OF_MEMORY;
1518
0
      goto out;
1519
0
    }
1520
9.54k
    Curl_bufref_set(&data->state.url, url, 0, curl_free);
1521
9.54k
  }
1522
1523
159k
  if(!use_set_uh) {
1524
159k
    char *newurl;
1525
159k
    uc = curl_url_set(uh, CURLUPART_URL, Curl_bufref_ptr(&data->state.url),
1526
159k
                      (unsigned int)(CURLU_GUESS_SCHEME |
1527
159k
                       CURLU_NON_SUPPORT_SCHEME |
1528
159k
                       (data->set.disallow_username_in_url ?
1529
159k
                        CURLU_DISALLOW_USER : 0) |
1530
159k
                       (data->set.path_as_is ? CURLU_PATH_AS_IS : 0)));
1531
159k
    if(uc) {
1532
10.9k
      failf(data, "URL rejected: %s", curl_url_strerror(uc));
1533
10.9k
      result = Curl_uc_to_curlcode(uc);
1534
10.9k
      goto out;
1535
10.9k
    }
1536
1537
    /* after it was parsed, get the generated normalized version */
1538
148k
    uc = curl_url_get(uh, CURLUPART_URL, &newurl, CURLU_GET_EMPTY);
1539
148k
    if(uc) {
1540
0
      result = Curl_uc_to_curlcode(uc);
1541
0
      goto out;
1542
0
    }
1543
148k
    Curl_bufref_set(&data->state.url, newurl, 0, curl_free);
1544
148k
  }
1545
1546
148k
#ifdef USE_IPV6
1547
148k
  scope_id = data->set.scope_id;
1548
148k
#endif
1549
1550
  /* `uh` is now as the connection should use it, probably. */
1551
148k
  result = Curl_peer_from_url(uh, data, port_override, scope_id,
1552
148k
                              &data->state.up, &conn->origin);
1553
148k
  if(result)
1554
2.59k
    goto out;
1555
1556
145k
  result = hsts_upgrade(data, conn, uh, port_override, scope_id);
1557
145k
  if(result)
1558
0
    goto out;
1559
1560
  /* now that the origin is fixed, check and set the connection scheme */
1561
145k
  result = url_set_conn_scheme(data, conn, conn->origin->scheme);
1562
145k
  if(result)
1563
6.92k
    goto out;
1564
1565
  /* When the transfers initial_origin is not set, this is the initial
1566
   * request. Remember this starting point. This is used to
1567
   * select credentials. */
1568
138k
  if(!data->state.initial_origin)
1569
120k
    Curl_peer_link(&data->state.initial_origin, conn->origin);
1570
1571
138k
  result = url_set_data_creds(data, conn, uh);
1572
138k
  if(result)
1573
80
    goto out;
1574
1575
138k
  uc = curl_url_get(uh, CURLUPART_OPTIONS, &data->state.up.options,
1576
138k
                    CURLU_URLDECODE);
1577
138k
  if(!uc) {
1578
75
    conn->options = curlx_strdup(data->state.up.options);
1579
75
    if(!conn->options) {
1580
0
      result = CURLE_OUT_OF_MEMORY;
1581
0
      goto out;
1582
0
    }
1583
75
  }
1584
138k
  else if(uc != CURLUE_NO_OPTIONS) {
1585
3
    result = Curl_uc_to_curlcode(uc);
1586
3
    goto out;
1587
3
  }
1588
1589
138k
  uc = curl_url_get(uh, CURLUPART_PATH, &data->state.up.path, CURLU_URLENCODE);
1590
138k
  if(uc) {
1591
0
    result = Curl_uc_to_curlcode(uc);
1592
0
    goto out;
1593
0
  }
1594
1595
138k
  uc = curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query,
1596
138k
                    CURLU_GET_EMPTY);
1597
138k
  if(uc && (uc != CURLUE_NO_QUERY)) {
1598
0
    result = CURLE_OUT_OF_MEMORY;
1599
0
    goto out;
1600
0
  }
1601
1602
138k
#ifdef USE_IPV6
1603
  /* Fill in the conn parts that do not use authority, yet. */
1604
138k
  conn->scope_id = conn->origin->scopeid;
1605
138k
#endif
1606
1607
138k
#ifdef CURLVERBOSE
1608
138k
  Curl_creds_trace(data, data->state.creds, "transfer credentials");
1609
138k
#endif
1610
1611
159k
out:
1612
159k
  return result;
1613
138k
}
1614
1615
/*
1616
 * If we are doing a resumed transfer, we need to setup our stuff
1617
 * properly.
1618
 */
1619
static CURLcode setup_range(struct Curl_easy *data)
1620
135k
{
1621
135k
  struct UrlState *s = &data->state;
1622
135k
  s->resume_from = data->set.set_resume_from;
1623
135k
  if(s->resume_from || data->set.str[STRING_SET_RANGE]) {
1624
3.62k
    if(s->rangestringalloc)
1625
814
      curlx_free(s->range);
1626
1627
3.62k
    if(s->resume_from)
1628
1.77k
      s->range = curl_maprintf("%" FMT_OFF_T "-", s->resume_from);
1629
1.84k
    else
1630
1.84k
      s->range = curlx_strdup(data->set.str[STRING_SET_RANGE]);
1631
1632
3.62k
    if(!s->range)
1633
0
      return CURLE_OUT_OF_MEMORY;
1634
1635
3.62k
    s->rangestringalloc = TRUE;
1636
1637
    /* tell ourselves to fetch this range */
1638
3.62k
    s->use_range = TRUE;        /* enable range download */
1639
3.62k
  }
1640
131k
  else
1641
131k
    s->use_range = FALSE; /* disable range download */
1642
1643
135k
  return CURLE_OK;
1644
135k
}
1645
1646
/*
1647
 * setup_connection_internals() -
1648
 *
1649
 * Setup connection internals specific to the requested protocol in the
1650
 * Curl_easy. This is inited and setup before the connection is made but
1651
 * is about the particular protocol that is to be used.
1652
 *
1653
 * This MUST get called after proxy magic has been figured out.
1654
 */
1655
static CURLcode setup_connection_internals(struct Curl_easy *data,
1656
                                           struct connectdata *conn)
1657
138k
{
1658
138k
  struct Curl_peer *peer = NULL;
1659
138k
  CURLcode result;
1660
1661
138k
  DEBUGF(infof(data, "setup connection, bits.close=%d", conn->bits.close));
1662
138k
  if(conn->scheme->run->setup_connection) {
1663
127k
    result = conn->scheme->run->setup_connection(data, conn);
1664
127k
    if(result)
1665
137
      return result;
1666
127k
  }
1667
138k
  DEBUGF(infof(data, "setup connection, bits.close=%d", conn->bits.close));
1668
1669
  /* Now create the destination name */
1670
138k
  peer = Curl_conn_get_destination(conn, FIRSTSOCKET);
1671
138k
  if(!peer)
1672
0
    return CURLE_FAILED_INIT;
1673
1674
  /* IPv6 addresses with a scope_id (0 is default == global) have a
1675
   * printable representation with a '%<scope_id>' suffix. */
1676
138k
  if(peer->ipv6)
1677
263
    if(peer->scopeid)
1678
77
      conn->destination = curl_maprintf("[%s%%%u]:%u",
1679
77
        peer->hostname, peer->scopeid, peer->port);
1680
186
    else
1681
186
      conn->destination = curl_maprintf("[%s]:%u",
1682
186
        peer->hostname, peer->port);
1683
138k
  else
1684
138k
    conn->destination = curl_maprintf("%s:%u", peer->hostname, peer->port);
1685
138k
  if(!conn->destination)
1686
0
    return CURLE_OUT_OF_MEMORY;
1687
1688
138k
  Curl_strntolower(conn->destination, conn->destination,
1689
138k
                   strlen(conn->destination));
1690
1691
138k
  return CURLE_OK;
1692
138k
}
1693
1694
#ifndef CURL_DISABLE_PROXY
1695
1696
#ifndef CURL_DISABLE_HTTP
1697
/****************************************************************
1698
 * Detect what (if any) proxy to use. Remember that this selects a host
1699
 * name and is not limited to HTTP proxies only.
1700
 * The returned pointer must be freed by the caller (unless NULL)
1701
 ****************************************************************/
1702
static char *url_detect_proxy(struct Curl_easy *data,
1703
                              struct connectdata *conn)
1704
87.8k
{
1705
87.8k
  char *proxy = NULL;
1706
1707
  /* If proxy was not specified, we check for default proxy environment
1708
   * variables, to enable i.e Lynx compliance:
1709
   *
1710
   * http_proxy=http://some.server.dom:port/
1711
   * https_proxy=http://some.server.dom:port/
1712
   * ftp_proxy=http://some.server.dom:port/
1713
   * no_proxy=domain1.dom,host.domain2.dom
1714
   *   (a comma-separated list of hosts which should
1715
   *   not be proxied, or an asterisk to override
1716
   *   all proxy variables)
1717
   * all_proxy=http://some.server.dom:port/
1718
   *   (seems to exist for the CERN www lib. Probably
1719
   *   the first to check for.)
1720
   *
1721
   * For compatibility, the all-uppercase versions of these variables are
1722
   * checked if the lowercase versions do not exist.
1723
   */
1724
87.8k
  char proxy_env[20];
1725
87.8k
  const char *envp;
1726
87.8k
  VERBOSE(envp = proxy_env);
1727
1728
87.8k
  curl_msnprintf(proxy_env, sizeof(proxy_env), "%s_proxy",
1729
87.8k
                 conn->scheme->name);
1730
1731
  /* read the protocol proxy: */
1732
87.8k
  proxy = curl_getenv(proxy_env);
1733
1734
  /*
1735
   * We do not try the uppercase version of HTTP_PROXY because of
1736
   * security reasons:
1737
   *
1738
   * When curl is used in a webserver application
1739
   * environment (cgi or php), this environment variable can
1740
   * be controlled by the web server user by setting the
1741
   * http header 'Proxy:' to some value.
1742
   *
1743
   * This can cause 'internal' http/ftp requests to be
1744
   * arbitrarily redirected by any external attacker.
1745
   */
1746
87.8k
  if(!proxy && !curl_strequal("http_proxy", proxy_env)) {
1747
    /* There was no lowercase variable, try the uppercase version: */
1748
56.4k
    Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env));
1749
56.4k
    proxy = curl_getenv(proxy_env);
1750
56.4k
  }
1751
1752
87.8k
  if(!proxy) {
1753
87.8k
#ifndef CURL_DISABLE_WEBSOCKETS
1754
    /* websocket proxy fallbacks */
1755
87.8k
    if(curl_strequal("ws_proxy", proxy_env)) {
1756
1.53k
      proxy = curl_getenv("http_proxy");
1757
1.53k
    }
1758
86.3k
    else if(curl_strequal("wss_proxy", proxy_env)) {
1759
2.33k
      proxy = curl_getenv("https_proxy");
1760
2.33k
      if(!proxy)
1761
2.33k
        proxy = curl_getenv("HTTPS_PROXY");
1762
2.33k
    }
1763
87.8k
    if(!proxy) {
1764
87.8k
#endif
1765
87.8k
      envp = "all_proxy";
1766
87.8k
      proxy = curl_getenv(envp); /* default proxy to use */
1767
87.8k
      if(!proxy) {
1768
87.8k
        envp = "ALL_PROXY";
1769
87.8k
        proxy = curl_getenv(envp);
1770
87.8k
      }
1771
87.8k
#ifndef CURL_DISABLE_WEBSOCKETS
1772
87.8k
    }
1773
87.8k
#endif
1774
87.8k
  }
1775
87.8k
  if(proxy)
1776
0
    infof(data, "Uses proxy env variable %s == '%s'", envp, proxy);
1777
1778
87.8k
  return proxy;
1779
87.8k
}
1780
#endif /* CURL_DISABLE_HTTP */
1781
1782
/*
1783
 * If this is supposed to use a proxy, we need to figure out the proxy
1784
 * hostname, so that we can reuse an existing connection
1785
 * that may exist registered to the same proxy host.
1786
 */
1787
static CURLcode parse_proxy(struct Curl_easy *data,
1788
                            const char *proxy,
1789
                            bool for_pre_proxy,
1790
                            struct proxy_info *proxyinfo)
1791
44.0k
{
1792
44.0k
  char *proxyuser = NULL;
1793
44.0k
  char *proxypasswd = NULL;
1794
44.0k
  char *scheme = NULL;
1795
44.0k
  CURLcode result = CURLE_OK;
1796
  /* Set the start proxy type for url scheme guessing */
1797
44.0k
  uint8_t proxytype = for_pre_proxy ? CURLPROXY_SOCKS4 : data->set.proxytype;
1798
44.0k
  CURLU *uhp = curl_url();
1799
44.0k
  CURLUcode uc;
1800
1801
44.0k
  if(!uhp) {
1802
0
    result = CURLE_OUT_OF_MEMORY;
1803
0
    goto error;
1804
0
  }
1805
  /* When parsing the proxy, allowing non-supported schemes since we have
1806
     these made up ones for proxies. Guess scheme for URLs without it. */
1807
44.0k
  uc = curl_url_set(uhp, CURLUPART_URL, proxy,
1808
44.0k
                    CURLU_NON_SUPPORT_SCHEME | CURLU_GUESS_SCHEME);
1809
44.0k
  if(!uc) {
1810
    /* parsed okay as a URL - only update proxytype when scheme was explicit */
1811
43.9k
    uc = curl_url_get(uhp, CURLUPART_SCHEME, &scheme, CURLU_NO_GUESS_SCHEME);
1812
43.9k
    if(!uc) {
1813
598
      result = Curl_scheme_to_proxytype(data, scheme, &proxytype, proxy);
1814
598
      if(result)
1815
20
        goto error;
1816
598
    }
1817
43.3k
    else if(uc != CURLUE_NO_SCHEME) {
1818
0
      result = CURLE_OUT_OF_MEMORY;
1819
0
      goto error;
1820
0
    }
1821
    /* else: no explicit scheme, keep the configured proxytype */
1822
43.9k
  }
1823
96
  else {
1824
96
    failf(data, "Unsupported proxy syntax in \'%s\': %s", proxy,
1825
96
          curl_url_strerror(uc));
1826
96
    result = CURLE_COULDNT_RESOLVE_PROXY;
1827
96
    goto error;
1828
96
  }
1829
1830
43.9k
  result = Curl_peer_from_proxy_url(uhp, data, proxy, proxytype,
1831
43.9k
                                    &proxyinfo->peer, &proxytype);
1832
43.9k
  if(result)
1833
78
    goto error;
1834
1835
43.8k
  switch(proxytype) {
1836
24.3k
    case CURLPROXY_HTTP:
1837
24.3k
    case CURLPROXY_HTTP_1_0:
1838
31.3k
    case CURLPROXY_HTTPS:
1839
37.9k
    case CURLPROXY_HTTPS2:
1840
37.9k
    case CURLPROXY_HTTPS3:
1841
37.9k
      if(for_pre_proxy) {
1842
14
        failf(data, "Unsupported pre-proxy type for \'%s\'", proxy);
1843
14
        result = CURLE_COULDNT_RESOLVE_PROXY;
1844
14
        goto error;
1845
14
      }
1846
37.9k
      break;
1847
37.9k
    case CURLPROXY_SOCKS4:
1848
5.48k
    case CURLPROXY_SOCKS4A:
1849
5.74k
    case CURLPROXY_SOCKS5:
1850
5.93k
    case CURLPROXY_SOCKS5_HOSTNAME:
1851
5.93k
      break;
1852
0
    default:
1853
0
      failf(data, "Unsupported proxy type %u for \'%s\'", proxytype, proxy);
1854
0
      result = CURLE_COULDNT_RESOLVE_PROXY;
1855
0
      goto error;
1856
43.8k
  }
1857
1858
  /* Is there a username and password given in this proxy URL? */
1859
43.8k
  uc = curl_url_get(uhp, CURLUPART_USER, &proxyuser, CURLU_URLDECODE);
1860
43.8k
  if(uc && (uc != CURLUE_NO_USER)) {
1861
12
    result = Curl_uc_to_curlcode(uc);
1862
12
    goto error;
1863
12
  }
1864
43.8k
  uc = curl_url_get(uhp, CURLUPART_PASSWORD, &proxypasswd, CURLU_URLDECODE);
1865
43.8k
  if(uc && (uc != CURLUE_NO_PASSWORD)) {
1866
12
    result = Curl_uc_to_curlcode(uc);
1867
12
    goto error;
1868
12
  }
1869
1870
43.8k
  if(proxyuser || proxypasswd) {
1871
9.40k
    result = Curl_creds_create(proxyuser, proxypasswd, NULL, NULL,
1872
9.40k
                               data->set.str[STRING_PROXY_SERVICE_NAME],
1873
9.40k
                               CREDS_URL, &proxyinfo->creds);
1874
9.40k
    if(result)
1875
0
      goto error;
1876
9.40k
  }
1877
34.4k
  else if(!for_pre_proxy &&
1878
29.5k
          (data->set.str[STRING_PROXYUSERNAME] ||
1879
28.5k
           data->set.str[STRING_PROXYPASSWORD] ||
1880
28.4k
           data->set.str[STRING_PROXY_SERVICE_NAME])) {
1881
    /* No user/passwd in URL, if this is not a pre-proxy, the
1882
     * CURLOPT_PROXY* settings apply. */
1883
1.33k
    result = Curl_creds_create(data->set.str[STRING_PROXYUSERNAME],
1884
1.33k
                               data->set.str[STRING_PROXYPASSWORD],
1885
1.33k
                               NULL, NULL,
1886
1.33k
                               data->set.str[STRING_PROXY_SERVICE_NAME],
1887
1.33k
                               CREDS_OPTION, &proxyinfo->creds);
1888
1.33k
  }
1889
33.0k
  else
1890
33.0k
    Curl_creds_unlink(&proxyinfo->creds);
1891
1892
43.8k
  proxyinfo->proxytype = proxytype;
1893
1894
44.0k
error:
1895
44.0k
  curlx_free(scheme);
1896
44.0k
  curlx_free(proxyuser);
1897
44.0k
  curlx_free(proxypasswd);
1898
44.0k
  curl_url_cleanup(uhp);
1899
44.0k
#ifdef DEBUGBUILD
1900
44.0k
  if(!result) {
1901
43.8k
    DEBUGASSERT(proxyinfo);
1902
43.8k
    DEBUGASSERT(proxyinfo->peer);
1903
43.8k
  }
1904
44.0k
#endif
1905
44.0k
  return result;
1906
44.0k
}
1907
1908
static CURLcode url_set_conn_proxies(struct Curl_easy *data,
1909
                                     struct connectdata *conn)
1910
132k
{
1911
132k
  char *proxy = NULL;
1912
132k
  char *pre_proxy = NULL;
1913
132k
  char *no_proxy = NULL;
1914
132k
  CURLcode result = CURLE_OK;
1915
1916
  /*************************************************************
1917
   * Detect what (if any) proxy to use
1918
   *************************************************************/
1919
132k
  if(data->set.str[STRING_PROXY]) {
1920
39.4k
    proxy = curlx_strdup(data->set.str[STRING_PROXY]);
1921
    /* if global proxy is set, this is it */
1922
39.4k
    if(!proxy) {
1923
0
      failf(data, "memory shortage");
1924
0
      result = CURLE_OUT_OF_MEMORY;
1925
0
      goto out;
1926
0
    }
1927
39.4k
  }
1928
1929
132k
  if(data->set.str[STRING_PRE_PROXY]) {
1930
6.99k
    pre_proxy = curlx_strdup(data->set.str[STRING_PRE_PROXY]);
1931
    /* if global socks proxy is set, this is it */
1932
6.99k
    if(!pre_proxy) {
1933
0
      failf(data, "memory shortage");
1934
0
      result = CURLE_OUT_OF_MEMORY;
1935
0
      goto out;
1936
0
    }
1937
6.99k
  }
1938
1939
132k
  if(!data->set.str[STRING_NOPROXY]) {
1940
129k
    const char *p = "no_proxy";
1941
129k
    no_proxy = curl_getenv(p);
1942
129k
    if(!no_proxy) {
1943
129k
      p = "NO_PROXY";
1944
129k
      no_proxy = curl_getenv(p);
1945
129k
    }
1946
129k
    if(no_proxy) {
1947
0
      infof(data, "Uses proxy env variable %s == '%s'", p, no_proxy);
1948
0
    }
1949
129k
  }
1950
1951
132k
  if(Curl_check_noproxy(conn->origin->hostname, data->set.str[STRING_NOPROXY] ?
1952
129k
                        data->set.str[STRING_NOPROXY] : no_proxy)) {
1953
136
    curlx_safefree(proxy);
1954
136
    curlx_safefree(pre_proxy);
1955
136
  }
1956
132k
#ifndef CURL_DISABLE_HTTP
1957
132k
  else if(!proxy && !pre_proxy)
1958
    /* if the host is not in the noproxy list, detect proxy. */
1959
87.8k
    proxy = url_detect_proxy(data, conn);
1960
132k
#endif /* CURL_DISABLE_HTTP */
1961
132k
  curlx_safefree(no_proxy);
1962
1963
132k
  if(proxy && (!*proxy || (conn->scheme->flags & PROTOPT_NONETWORK))) {
1964
868
    curlx_safefree(proxy);  /* Do not bother with an empty proxy string
1965
                               or if the protocol does not work with network */
1966
868
  }
1967
132k
  if(pre_proxy && (!*pre_proxy ||
1968
5.48k
                    (conn->scheme->flags & PROTOPT_NONETWORK))) {
1969
1.51k
    curlx_safefree(pre_proxy);  /* Do not bother with an empty socks proxy
1970
                                   string or if the protocol does not work
1971
                                   with network */
1972
1.51k
  }
1973
1974
  /***********************************************************************
1975
   * If this is supposed to use a proxy, we need to figure out the proxy host
1976
   * name, proxy type and port number, so that we can reuse an existing
1977
   * connection that may exist registered to the same proxy host.
1978
   ***********************************************************************/
1979
132k
  if(proxy || pre_proxy) {
1980
43.0k
    if(pre_proxy) {
1981
5.48k
      result = parse_proxy(data, pre_proxy, TRUE, &conn->socks_proxy);
1982
5.48k
      if(result)
1983
131
        goto out;
1984
5.48k
    }
1985
1986
42.8k
    if(proxy) {
1987
38.5k
      result = parse_proxy(data, proxy, FALSE, &conn->http_proxy);
1988
38.5k
      if(result)
1989
101
        goto out;
1990
38.4k
      switch(conn->http_proxy.proxytype) {
1991
41
      case CURLPROXY_SOCKS4:
1992
121
      case CURLPROXY_SOCKS4A:
1993
381
      case CURLPROXY_SOCKS5:
1994
571
      case CURLPROXY_SOCKS5_HOSTNAME:
1995
        /* Whoops, it's not a HTTP proxy */
1996
571
        if(conn->socks_proxy.peer) {
1997
          /* and we already have a SOCKS pre-proxy. Cannot have both */
1998
23
          failf(data, "Having a SOCKS pre-proxy and proxy is not "
1999
23
                "supported with \'%s\'", proxy);
2000
23
          result = CURLE_COULDNT_RESOLVE_PROXY;
2001
23
          goto out;
2002
23
        }
2003
        /* switch */
2004
548
        conn->socks_proxy = conn->http_proxy;
2005
548
        memset(&conn->http_proxy, 0, sizeof(conn->http_proxy));
2006
548
        break;
2007
37.9k
      default:
2008
37.9k
        break;
2009
38.4k
      }
2010
38.4k
    }
2011
2012
42.7k
    if(conn->http_proxy.peer) {
2013
#ifdef CURL_DISABLE_HTTP
2014
      /* asking for an HTTP proxy is a bit funny when HTTP is disabled... */
2015
      result = CURLE_UNSUPPORTED_PROTOCOL;
2016
      goto out;
2017
#else
2018
37.9k
#ifndef CURL_DISABLE_DIGEST_AUTH
2019
37.9k
      if(!Curl_safecmp(data->state.envproxy, proxy)) {
2020
        /* proxy changed */
2021
36.9k
        Curl_auth_digest_cleanup(&data->state.proxydigest);
2022
36.9k
        curlx_free(data->state.envproxy);
2023
36.9k
        data->state.envproxy = curlx_strdup(proxy);
2024
36.9k
      }
2025
37.9k
#endif
2026
37.9k
      if(conn->scheme->flags & PROTOPT_HTTP_PROXY_TUNNEL) {
2027
1.98k
        conn->bits.tunnel_proxy = TRUE;
2028
1.98k
      }
2029
35.9k
      else if(!(conn->scheme->protocol & PROTO_FAMILY_HTTP)) {
2030
        /* force this connection's protocol to become HTTP if compatible */
2031
32.0k
        if((conn->scheme->flags & PROTOPT_PROXY_AS_HTTP) &&
2032
8.59k
           !conn->bits.tunnel_proxy)
2033
8.58k
          conn->scheme = &Curl_scheme_http;
2034
23.4k
        else
2035
          /* if not converting to HTTP over the proxy, enforce tunneling */
2036
23.4k
          conn->bits.tunnel_proxy = TRUE;
2037
32.0k
      }
2038
37.9k
#endif
2039
37.9k
    }
2040
4.84k
    else
2041
4.84k
      conn->bits.tunnel_proxy = FALSE; /* no tunneling if not HTTP */
2042
42.7k
  }
2043
2044
132k
  conn->bits.socksproxy = !!conn->socks_proxy.peer;
2045
132k
  conn->bits.httpproxy = !!conn->http_proxy.peer;
2046
132k
  conn->bits.proxy = conn->bits.httpproxy || conn->bits.socksproxy;
2047
2048
132k
  if(!conn->bits.proxy) {
2049
    /* we are not using the proxy after all... */
2050
89.8k
    conn->bits.proxy = FALSE;
2051
89.8k
    conn->bits.httpproxy = FALSE;
2052
89.8k
    conn->bits.socksproxy = FALSE;
2053
89.8k
    conn->bits.tunnel_proxy = FALSE;
2054
    /* CURLPROXY_HTTPS does not have its own flag in conn->bits, yet we need
2055
       to signal that CURLPROXY_HTTPS is not used for this connection */
2056
89.8k
    conn->http_proxy.proxytype = CURLPROXY_HTTP;
2057
89.8k
  }
2058
2059
132k
out:
2060
2061
132k
  curlx_free(pre_proxy);
2062
132k
  curlx_free(proxy);
2063
132k
  return result;
2064
132k
}
2065
#endif /* CURL_DISABLE_PROXY */
2066
2067
/*
2068
 * Curl_parse_login_details()
2069
 *
2070
 * This is used to parse a login string for username, password and options in
2071
 * the following formats:
2072
 *
2073
 *   user
2074
 *   user:password
2075
 *   user:password;options
2076
 *   user;options
2077
 *   user;options:password
2078
 *   :password
2079
 *   :password;options
2080
 *   ;options
2081
 *   ;options:password
2082
 *
2083
 * Parameters:
2084
 *
2085
 * login    [in]     - login string.
2086
 * len      [in]     - length of the login string.
2087
 * userp    [in/out] - address where a pointer to newly allocated memory
2088
 *                     holding the user will be stored upon completion.
2089
 * passwdp  [in/out] - address where a pointer to newly allocated memory
2090
 *                     holding the password will be stored upon completion.
2091
 * optionsp [in/out] - OPTIONAL address where a pointer to newly allocated
2092
 *                     memory holding the options will be stored upon
2093
 *                     completion.
2094
 *
2095
 * Returns CURLE_OK on success.
2096
 */
2097
CURLcode Curl_parse_login_details(const char *login, const size_t len,
2098
                                  char **userp, char **passwdp,
2099
                                  char **optionsp)
2100
42.3k
{
2101
42.3k
  char *ubuf = NULL;
2102
42.3k
  char *pbuf = NULL;
2103
42.3k
  const char *psep = NULL;
2104
42.3k
  const char *osep = NULL;
2105
42.3k
  size_t ulen;
2106
42.3k
  size_t plen;
2107
42.3k
  size_t olen;
2108
2109
42.3k
  DEBUGASSERT(userp);
2110
42.3k
  DEBUGASSERT(passwdp);
2111
2112
  /* Attempt to find the password separator */
2113
42.3k
  psep = memchr(login, ':', len);
2114
2115
  /* Attempt to find the options separator */
2116
42.3k
  if(optionsp)
2117
1.20k
    osep = memchr(login, ';', len);
2118
2119
  /* Calculate the portion lengths */
2120
42.3k
  ulen = (psep ?
2121
7.37k
          (size_t)(osep && psep > osep ? osep - login : psep - login) :
2122
42.3k
          (osep ? (size_t)(osep - login) : len));
2123
42.3k
  plen = (psep ?
2124
7.37k
          (osep && osep > psep ? (size_t)(osep - psep) :
2125
34.9k
           (size_t)(login + len - psep)) - 1 : 0);
2126
42.3k
  olen = (osep ?
2127
227
          (psep && psep > osep ? (size_t)(psep - osep) :
2128
42.0k
           (size_t)(login + len - osep)) - 1 : 0);
2129
2130
  /* Clone the user portion buffer, which can be zero length */
2131
42.3k
  ubuf = curlx_memdup0(login, ulen);
2132
42.3k
  if(!ubuf)
2133
0
    goto error;
2134
2135
  /* Clone the password portion buffer */
2136
42.3k
  if(psep) {
2137
7.37k
    pbuf = curlx_memdup0(&psep[1], plen);
2138
7.37k
    if(!pbuf)
2139
0
      goto error;
2140
7.37k
  }
2141
2142
  /* Allocate the options portion buffer */
2143
42.3k
  if(optionsp) {
2144
1.20k
    char *obuf = NULL;
2145
1.20k
    if(olen) {
2146
155
      obuf = curlx_memdup0(&osep[1], olen);
2147
155
      if(!obuf)
2148
0
        goto error;
2149
155
    }
2150
1.20k
    *optionsp = obuf;
2151
1.20k
  }
2152
42.3k
  *userp = ubuf;
2153
42.3k
  *passwdp = pbuf;
2154
42.3k
  return CURLE_OK;
2155
0
error:
2156
0
  curlx_free(ubuf);
2157
0
  curlx_free(pbuf);
2158
0
  return CURLE_OUT_OF_MEMORY;
2159
42.3k
}
2160
2161
#ifndef CURL_DISABLE_NETRC
2162
static bool str_has_ctrl(const char *input)
2163
0
{
2164
0
  if(input) {
2165
0
    const unsigned char *str = (const unsigned char *)input;
2166
0
    while(*str) {
2167
0
      if(*str < 0x20)
2168
0
        return TRUE;
2169
0
      str++;
2170
0
    }
2171
0
  }
2172
0
  return FALSE;
2173
0
}
2174
#endif
2175
2176
/*
2177
 * Override the login details from the URL with that in the CURLOPT_USERPWD
2178
 * option or a .netrc file, if applicable.
2179
 */
2180
static CURLcode override_login(struct Curl_easy *data,
2181
                               struct connectdata *conn)
2182
138k
{
2183
138k
  char **optionsp = &conn->options;
2184
138k
#ifndef CURL_DISABLE_NETRC
2185
138k
  struct Curl_creds *ncreds_out = NULL;
2186
138k
#endif
2187
138k
  CURLcode result = CURLE_OK;
2188
2189
138k
  if(data->set.str[STRING_OPTIONS]) {
2190
1.86k
    curlx_free(*optionsp);
2191
1.86k
    *optionsp = curlx_strdup(data->set.str[STRING_OPTIONS]);
2192
1.86k
    if(!*optionsp) {
2193
0
      result = CURLE_OUT_OF_MEMORY;
2194
0
      goto out;
2195
0
    }
2196
1.86k
  }
2197
2198
138k
#ifndef CURL_DISABLE_NETRC
2199
138k
  if(data->set.use_netrc) { /* not CURL_NETRC_IGNORED */
2200
1.77k
    struct Curl_creds *ncreds_in = NULL;
2201
1.77k
    bool scan_netrc = TRUE;
2202
1.77k
    NETRCcode ret;
2203
1.77k
    CURLUcode uc;
2204
2205
1.77k
    if(data->state.creds) {
2206
1.42k
      switch(data->state.creds->source) {
2207
121
      case CREDS_OPTION:
2208
        /* we never override credentials set via CURLOPT_*, leave. */
2209
121
        scan_netrc = FALSE;
2210
121
        break;
2211
1.30k
      case CREDS_URL: /* only apply when netrc is not required */
2212
1.30k
        if(data->set.use_netrc == CURL_NETRC_REQUIRED) {
2213
          /* We ignore password from URL */
2214
1.08k
          ncreds_in = data->state.creds;
2215
1.08k
        }
2216
214
        else if(!Curl_creds_has_user(data->state.creds) ||
2217
184
                !Curl_creds_has_passwd(data->state.creds)) {
2218
          /* We use netrc to complete what is missing */
2219
184
          ncreds_in = data->state.creds;
2220
184
        }
2221
30
        else
2222
30
          scan_netrc = FALSE;
2223
1.30k
        break;
2224
0
      default: /* ignore credentials from other sources */
2225
0
        break;
2226
1.42k
      }
2227
1.42k
    }
2228
2229
1.77k
    if(!scan_netrc)
2230
151
      goto out;
2231
2232
1.62k
    ret = Curl_netrc_scan(data, &data->state.netrc,
2233
1.62k
                          conn->origin->hostname,
2234
1.62k
                          Curl_creds_user(ncreds_in),
2235
1.62k
                          data->set.str[STRING_NETRC_FILE],
2236
1.62k
                          &ncreds_out);
2237
1.62k
    DEBUGASSERT(!ret || !ncreds_out);
2238
1.62k
    if(ret == NETRC_OUT_OF_MEMORY) {
2239
0
      result = CURLE_OUT_OF_MEMORY;
2240
0
      goto out;
2241
0
    }
2242
1.62k
    else if(ret && ((ret == NETRC_NO_MATCH) ||
2243
1.62k
                    (data->set.use_netrc == CURL_NETRC_OPTIONAL))) {
2244
1.62k
      infof(data, "Could not find host %s in the %s file; using defaults",
2245
1.62k
            conn->origin->hostname,
2246
1.62k
            (data->set.str[STRING_NETRC_FILE] ?
2247
1.62k
             data->set.str[STRING_NETRC_FILE] : ".netrc"));
2248
1.62k
    }
2249
0
    else if(ret) {
2250
0
      const char *m = Curl_netrc_strerror(ret);
2251
0
      failf(data, ".netrc error: %s", m);
2252
0
      result = CURLE_READ_ERROR;
2253
0
      goto out;
2254
0
    }
2255
0
    else if(ncreds_out) {
2256
0
      if(!(conn->scheme->flags & PROTOPT_USERPWDCTRL)) {
2257
        /* if the protocol cannot handle control codes in credentials, make
2258
           sure there are none */
2259
0
        if(str_has_ctrl(ncreds_out->user) ||
2260
0
           str_has_ctrl(ncreds_out->passwd)) {
2261
0
          failf(data, "control code detected in .netrc credentials");
2262
0
          result = CURLE_READ_ERROR;
2263
0
          goto out;
2264
0
        }
2265
0
      }
2266
0
      CURL_TRC_M(data, "netrc: using credentials for %s as %s",
2267
0
                 conn->origin->hostname, ncreds_out->user);
2268
0
      result = Curl_creds_merge(ncreds_out->user, ncreds_out->passwd,
2269
0
                                data->state.creds, CREDS_NETRC,
2270
0
                                &data->state.creds);
2271
0
      if(result)
2272
0
        goto out;
2273
      /* for updated strings, we update them in the URL */
2274
0
      uc = curl_url_set(data->state.uh, CURLUPART_USER,
2275
0
                        Curl_creds_user(data->state.creds), CURLU_URLENCODE);
2276
0
      if(!uc)
2277
0
        uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD,
2278
0
                          Curl_creds_passwd(data->state.creds),
2279
0
                          CURLU_URLENCODE);
2280
0
      if(uc)
2281
0
        result = Curl_uc_to_curlcode(uc);
2282
0
    }
2283
0
    else
2284
0
      DEBUGASSERT(0);
2285
1.62k
  }
2286
138k
#endif
2287
2288
138k
out:
2289
138k
#ifndef CURL_DISABLE_NETRC
2290
138k
  Curl_creds_unlink(&ncreds_out);
2291
138k
#endif
2292
138k
  return result;
2293
138k
}
2294
2295
/*
2296
 * Set the login details so they are available in the connection
2297
 */
2298
static CURLcode url_set_conn_login(struct Curl_easy *data,
2299
                                   struct connectdata *conn)
2300
138k
{
2301
  /* If our protocol needs a password and we have none, use the defaults */
2302
138k
  if((conn->scheme->flags & PROTOPT_NEEDSPWD) && !conn->creds) {
2303
4.96k
    if(data->state.creds)
2304
223
      Curl_creds_link(&conn->creds, data->state.creds);
2305
4.73k
    else
2306
4.73k
      return Curl_creds_create(CURL_DEFAULT_USER, CURL_DEFAULT_PASSWORD,
2307
4.73k
                               NULL, NULL, NULL, CREDS_NONE, &conn->creds);
2308
4.96k
  }
2309
133k
  else if(!(conn->scheme->flags & PROTOPT_CREDSPERREQUEST)) {
2310
    /* for protocols that do not handle credentials per request,
2311
     * the connection credentials are set by the initial transfer. */
2312
71.2k
    Curl_creds_link(&conn->creds, data->state.creds);
2313
71.2k
  }
2314
2315
133k
  return CURLE_OK;
2316
138k
}
2317
2318
/*
2319
 * Parses one "connect to" string in the form:
2320
 * "HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT".
2321
 */
2322
static CURLcode parse_connect_to_string(struct Curl_easy *data,
2323
                                        const struct Curl_peer *dest,
2324
                                        const char *conn_to_line,
2325
                                        struct Curl_peer **pvia_dest)
2326
124k
{
2327
124k
  CURLcode result = CURLE_OK;
2328
124k
  const char *ptr = conn_to_line;
2329
124k
  bool host_match = FALSE;
2330
124k
  bool port_match = FALSE;
2331
2332
124k
  *pvia_dest = NULL;
2333
2334
124k
  if(*ptr == ':') {
2335
    /* an empty hostname always matches */
2336
124k
    host_match = TRUE;
2337
124k
    ptr++;
2338
124k
  }
2339
0
  else {
2340
    /* check whether the URL's hostname matches. Use the URL hostname
2341
     * when it was an IPv6 address. Otherwise use the connection's hostname
2342
     * that has IDN conversion. */
2343
0
    const char *hostname_to_match = (dest->user_hostname[0] == '[') ?
2344
0
      dest->user_hostname : dest->hostname;
2345
0
    size_t hlen = strlen(hostname_to_match);
2346
0
    host_match = curl_strnequal(ptr, hostname_to_match, hlen);
2347
0
    ptr += hlen;
2348
2349
0
    host_match = host_match && *ptr == ':';
2350
0
    ptr++;
2351
0
  }
2352
2353
124k
  if(host_match) {
2354
124k
    if(*ptr == ':') {
2355
      /* an empty port always matches */
2356
124k
      port_match = TRUE;
2357
124k
      ptr++;
2358
124k
    }
2359
0
    else {
2360
      /* check whether the URL's port matches */
2361
0
      const char *ptr_next = strchr(ptr, ':');
2362
0
      if(ptr_next) {
2363
0
        curl_off_t port_to_match;
2364
0
        if(!curlx_str_number(&ptr, &port_to_match, 0xffff) &&
2365
0
           ((uint16_t)port_to_match == dest->port)) {
2366
0
          port_match = TRUE;
2367
0
        }
2368
0
        ptr = ptr_next + 1;
2369
0
      }
2370
0
    }
2371
124k
  }
2372
2373
124k
  if(host_match && port_match && ptr && *ptr)
2374
124k
    result = Curl_peer_from_connect_to(data, dest, ptr, pvia_dest);
2375
2376
124k
  return result;
2377
124k
}
2378
2379
/* With `conn->origin` known, determine if we should talk to that
2380
 * directly or via another peer. This is the result of inspecting
2381
 * the "connect to" slist and "alt-svc" settings. */
2382
static CURLcode url_set_conn_peer(struct Curl_easy *data,
2383
                                  struct connectdata *conn)
2384
132k
{
2385
132k
  CURLcode result = CURLE_OK;
2386
132k
  const struct Curl_peer *origin = conn->origin;
2387
132k
  struct Curl_peer *via_peer = NULL;
2388
132k
  struct curl_slist *conn_to_entry = data->set.connect_to;
2389
2390
132k
  DEBUGASSERT(!conn->via_peer);
2391
132k
  Curl_peer_unlink(&conn->via_peer);
2392
2393
257k
  while(conn_to_entry && !via_peer) {
2394
124k
    result = parse_connect_to_string(data, origin, conn_to_entry->data,
2395
124k
                                     &via_peer);
2396
124k
    if(result)
2397
0
      return result;
2398
124k
    conn_to_entry = conn_to_entry->next;
2399
124k
  }
2400
2401
132k
#ifndef CURL_DISABLE_ALTSVC
2402
132k
  if(data->asi && !via_peer &&
2403
0
     ((conn->scheme->protocol == CURLPROTO_HTTPS) ||
2404
0
#ifdef DEBUGBUILD
2405
      /* allow debug builds to circumvent the HTTPS restriction */
2406
0
      getenv("CURL_ALTSVC_HTTP")
2407
#else
2408
      0
2409
#endif
2410
0
       )) {
2411
    /* no connect_to match, try alt-svc! */
2412
0
    enum alpnid srcalpnid = ALPN_none;
2413
0
    bool hit = FALSE;
2414
0
    struct altsvc *as = NULL;
2415
0
    int allowed_alpns = ALPN_none;
2416
0
    struct http_negotiation *neg = &data->state.http_neg;
2417
0
    bool same_dest = FALSE;
2418
2419
0
    DEBUGF(infof(data, "Alt-svc check wanted=%x, allowed=%x",
2420
0
                 neg->wanted, neg->allowed));
2421
#ifdef USE_HTTP3
2422
    if(neg->allowed & CURL_HTTP_V3x)
2423
      allowed_alpns |= ALPN_h3;
2424
#endif
2425
0
#ifdef USE_HTTP2
2426
0
    if(neg->allowed & CURL_HTTP_V2x)
2427
0
      allowed_alpns |= ALPN_h2;
2428
0
#endif
2429
0
    if(neg->allowed & CURL_HTTP_V1x)
2430
0
      allowed_alpns |= ALPN_h1;
2431
0
    allowed_alpns &= (int)data->asi->flags;
2432
2433
0
    DEBUGF(infof(data, "check Alt-Svc for host '%s'", origin->hostname));
2434
#ifdef USE_HTTP3
2435
    if(!hit && (neg->wanted & CURL_HTTP_V3x)) {
2436
      srcalpnid = ALPN_h3;
2437
      hit = Curl_altsvc_lookup(data->asi,
2438
                               ALPN_h3, origin->hostname,
2439
                               origin->port, /* from */
2440
                               &as /* to */,
2441
                               allowed_alpns, &same_dest);
2442
    }
2443
#endif
2444
0
#ifdef USE_HTTP2
2445
0
    if(!hit && (neg->wanted & CURL_HTTP_V2x) &&
2446
0
       !neg->h2_prior_knowledge) {
2447
0
      srcalpnid = ALPN_h2;
2448
0
      hit = Curl_altsvc_lookup(data->asi,
2449
0
                               ALPN_h2, origin->hostname,
2450
0
                               origin->port, /* from */
2451
0
                               &as /* to */,
2452
0
                               allowed_alpns, &same_dest);
2453
0
    }
2454
0
#endif
2455
0
    if(!hit && (neg->wanted & CURL_HTTP_V1x) &&
2456
0
       !neg->only_10) {
2457
0
      srcalpnid = ALPN_h1;
2458
0
      hit = Curl_altsvc_lookup(data->asi,
2459
0
                               ALPN_h1, origin->hostname,
2460
0
                               origin->port, /* from */
2461
0
                               &as /* to */,
2462
0
                               allowed_alpns, &same_dest);
2463
0
    }
2464
2465
0
    if(hit && same_dest) {
2466
      /* same destination, but more HTTPS version options */
2467
0
      switch(as->dst.alpnid) {
2468
0
      case ALPN_h1:
2469
0
        neg->wanted |= CURL_HTTP_V1x;
2470
0
        neg->preferred = CURL_HTTP_V1x;
2471
0
        break;
2472
0
      case ALPN_h2:
2473
0
        neg->wanted |= CURL_HTTP_V2x;
2474
0
        neg->preferred = CURL_HTTP_V2x;
2475
0
        break;
2476
0
      case ALPN_h3:
2477
0
        neg->wanted |= CURL_HTTP_V3x;
2478
0
        neg->preferred = CURL_HTTP_V3x;
2479
0
        break;
2480
0
      default: /* should not be possible */
2481
0
        break;
2482
0
      }
2483
0
    }
2484
0
    else if(hit) {
2485
0
      result = Curl_peer_create(data, conn->origin->scheme,
2486
0
                                as->dst.host, as->dst.port,
2487
0
                                &via_peer);
2488
0
      if(result)
2489
0
        return result;
2490
0
      infof(data, "Alt-svc connecting from [%s]%s:%u to [%s]%s:%u",
2491
0
            Curl_alpnid2str(srcalpnid), origin->hostname, origin->port,
2492
0
            Curl_alpnid2str(as->dst.alpnid),
2493
0
            via_peer->hostname, via_peer->port);
2494
0
      conn->bits.altused = TRUE;
2495
0
      if(srcalpnid != as->dst.alpnid) {
2496
        /* protocol version switch */
2497
0
        switch(as->dst.alpnid) {
2498
0
        case ALPN_h1:
2499
0
          neg->wanted = neg->allowed = CURL_HTTP_V1x;
2500
0
          neg->only_10 = FALSE;
2501
0
          break;
2502
0
        case ALPN_h2:
2503
0
          neg->wanted = neg->allowed = CURL_HTTP_V2x;
2504
0
          break;
2505
0
        case ALPN_h3:
2506
0
          conn->transport_wanted = TRNSPRT_QUIC;
2507
0
          neg->wanted = neg->allowed = CURL_HTTP_V3x;
2508
0
          break;
2509
0
        default: /* should not be possible */
2510
0
          break;
2511
0
        }
2512
0
      }
2513
0
    }
2514
0
  }
2515
132k
#endif
2516
2517
132k
  if(via_peer)
2518
124k
    conn->via_peer = via_peer;
2519
2520
132k
  return result;
2521
132k
}
2522
2523
/*
2524
 * Adjust reused connection settings to the transfer/needle.
2525
 */
2526
static void url_conn_reuse_adjust(struct Curl_easy *data,
2527
                                  struct connectdata *needle)
2528
13.0k
{
2529
13.0k
  struct connectdata *conn = data->conn;
2530
2531
  /* get the user+password information from the needle since it may
2532
   * be new for this request even when we reuse conn */
2533
13.0k
  if(needle->creds) {
2534
    /* use the new username and password though */
2535
7.50k
    Curl_creds_link(&conn->creds, needle->creds);
2536
7.50k
  }
2537
2538
13.0k
#ifndef CURL_DISABLE_PROXY
2539
  /* use the new proxy username and proxy password though */
2540
13.0k
  Curl_creds_link(&conn->http_proxy.creds, needle->http_proxy.creds);
2541
13.0k
  Curl_creds_link(&conn->socks_proxy.creds, needle->socks_proxy.creds);
2542
13.0k
#endif
2543
2544
  /* Finding a connection for reuse in the cpool matches, among other
2545
   * things on the "remote-relevant" hostname. This is not necessarily
2546
   * the authority of the URL, e.g. conn->origin. For example:
2547
   * - we use a proxy (not tunneling). we want to send all requests
2548
   *   that use the same proxy on this connection.
2549
   * - we have a "connect-to" setting that may redirect the hostname of
2550
   *   a new request to the same remote endpoint of an existing conn.
2551
   *   We want to reuse an existing conn to the remote endpoint.
2552
   * Since connection reuse does not match on conn->origin necessarily, we
2553
   * switch conn to needle's host settings.
2554
   */
2555
13.0k
  Curl_peer_link(&conn->origin, needle->origin);
2556
13.0k
  Curl_peer_link(&conn->via_peer, needle->via_peer);
2557
13.0k
  Curl_peer_link(&conn->origin2, needle->origin2);
2558
13.0k
  Curl_peer_link(&conn->via_peer2, needle->via_peer2);
2559
13.0k
}
2560
2561
static void conn_meta_freeentry(void *p)
2562
0
{
2563
0
  (void)p;
2564
  /* Always FALSE. Cannot use a 0 assert here since compilers
2565
   * are not in agreement if they then want a NORETURN attribute or
2566
   * not. *sigh* */
2567
0
  DEBUGASSERT(p == NULL);
2568
0
}
2569
2570
static CURLcode url_create_needle(struct Curl_easy *data,
2571
                                  struct connectdata **pneedle)
2572
159k
{
2573
159k
  struct connectdata *needle = NULL;
2574
159k
  CURLcode result = CURLE_OK;
2575
159k
  bool network_scheme = TRUE; /* almost all are */
2576
2577
  /*************************************************************
2578
   * Check input data
2579
   *************************************************************/
2580
159k
  if(!Curl_bufref_ptr(&data->state.url)) {
2581
0
    result = CURLE_URL_MALFORMAT;
2582
0
    goto out;
2583
0
  }
2584
2585
  /* First, split up the current URL in parts so that we can use the
2586
     parts for checking against the already present connections. In order
2587
     to not have to modify everything at once, we allocate a temporary
2588
     connection data struct and fill in for comparison purposes. */
2589
159k
  needle = allocate_conn(data);
2590
159k
  if(!needle) {
2591
0
    result = CURLE_OUT_OF_MEMORY;
2592
0
    goto out;
2593
0
  }
2594
2595
  /* Do the unfailable inits first, before checks that may early return */
2596
159k
  Curl_hash_init(&needle->meta_hash, 23,
2597
159k
                 Curl_hash_str, curlx_str_key_compare, conn_meta_freeentry);
2598
2599
  /*************************************************************
2600
   * Determine `conn->origin` and propulate `data->state.up` and
2601
   * other URL related properties.
2602
   *************************************************************/
2603
159k
  result = parseurlandfillconn(data, needle);
2604
159k
  if(result)
2605
20.5k
    goto out;
2606
138k
  DEBUGASSERT(needle->origin);
2607
138k
  network_scheme = !(needle->origin->scheme->flags & PROTOPT_NONETWORK);
2608
2609
138k
#ifdef USE_UNIX_SOCKETS
2610
  /*************************************************************
2611
   * Set UDS first. It overrides "via_peer" and proxy settings.
2612
   *************************************************************/
2613
138k
  if(network_scheme && data->set.str[STRING_UNIX_SOCKET_PATH]) {
2614
4.47k
    result = Curl_peer_uds_create(needle->origin->scheme,
2615
4.47k
                                  data->set.str[STRING_UNIX_SOCKET_PATH],
2616
4.47k
                                  (bool)data->set.abstract_unix_socket,
2617
4.47k
                                  &needle->via_peer);
2618
4.47k
    if(result)
2619
114
      goto out;
2620
4.47k
  }
2621
138k
#endif /* USE_UNIX_SOCKETS */
2622
2623
138k
  if(network_scheme && !needle->via_peer) {
2624
    /*************************************************************
2625
     * If the `via_peer` is not already set (via UDS above),
2626
     * determine if we talk to `conn->origin` directly or use
2627
     * `conn->via_peer` using "connect to" and "alt-svc" properties.
2628
     *************************************************************/
2629
132k
    result = url_set_conn_peer(data, needle);
2630
132k
    if(result)
2631
0
      goto out;
2632
132k
  }
2633
2634
138k
#ifndef CURL_DISABLE_PROXY
2635
  /* Going via a unix socket ignores any proxy settings */
2636
138k
  if(needle->via_peer && needle->via_peer->unix_socket) {
2637
4.36k
    needle->bits.socksproxy = FALSE;
2638
4.36k
    needle->bits.httpproxy = FALSE;
2639
4.36k
    needle->bits.proxy = FALSE;
2640
4.36k
  }
2641
134k
  else if(network_scheme) {
2642
132k
    result = url_set_conn_proxies(data, needle);
2643
132k
    if(result)
2644
255
      goto out;
2645
2646
    /*************************************************************
2647
     * If the protocol is using SSL and HTTP proxy is used, we set
2648
     * the tunnel_proxy bit.
2649
     *************************************************************/
2650
132k
    if((needle->given->flags & PROTOPT_SSL) && needle->bits.httpproxy)
2651
2.26k
      needle->bits.tunnel_proxy = TRUE;
2652
132k
  }
2653
138k
#endif /* CURL_DISABLE_PROXY */
2654
2655
  /* Check for overridden login details and set them accordingly so that
2656
     they are known when protocol->setup_connection is called! */
2657
138k
  result = override_login(data, needle);
2658
138k
  if(result)
2659
0
    goto out;
2660
2661
138k
  result = url_set_conn_login(data, needle); /* default credentials */
2662
138k
  if(result)
2663
0
    goto out;
2664
2665
  /*************************************************************
2666
   * Check whether the host and the "connect to host" are equal.
2667
   * Do this after the hostnames have been IDN-converted.
2668
   *************************************************************/
2669
138k
  if(Curl_peer_equal(needle->origin, needle->via_peer)) {
2670
569
    Curl_peer_unlink(&needle->via_peer);
2671
569
  }
2672
2673
138k
#ifndef CURL_DISABLE_PROXY
2674
  /*************************************************************
2675
   * If the "connect to" feature is used with an HTTP proxy,
2676
   * we set the tunnel_proxy bit.
2677
   *************************************************************/
2678
138k
  if(needle->via_peer && needle->bits.httpproxy)
2679
37.4k
    needle->bits.tunnel_proxy = TRUE;
2680
138k
#endif
2681
2682
  /*************************************************************
2683
   * Setup internals depending on protocol. Needs to be done after
2684
   * we figured out what/if proxy to use.
2685
   *************************************************************/
2686
138k
  result = setup_connection_internals(data, needle);
2687
138k
  if(result)
2688
137
    goto out;
2689
2690
138k
  if(needle->scheme->flags & PROTOPT_ALPN) {
2691
    /* The protocol wants it, so set the bits if enabled in the easy handle
2692
       (default) */
2693
13.6k
    if(data->set.ssl_enable_alpn)
2694
13.5k
      needle->bits.tls_enable_alpn = TRUE;
2695
13.6k
  }
2696
2697
138k
  if(network_scheme) {
2698
    /* Setup callbacks for network connections */
2699
136k
    needle->recv[FIRSTSOCKET] = Curl_cf_recv;
2700
136k
    needle->send[FIRSTSOCKET] = Curl_cf_send;
2701
136k
    needle->recv[SECONDARYSOCKET] = Curl_cf_recv;
2702
136k
    needle->send[SECONDARYSOCKET] = Curl_cf_send;
2703
136k
    needle->bits.tcp_fastopen = data->set.tcp_fastopen;
2704
136k
#ifdef USE_UNIX_SOCKETS
2705
136k
    if(Curl_conn_get_first_peer(needle, FIRSTSOCKET)->unix_socket)
2706
4.38k
      needle->transport_wanted = TRNSPRT_UNIX;
2707
136k
#endif
2708
136k
  }
2709
2710
159k
out:
2711
159k
  if(!result) {
2712
138k
    DEBUGASSERT(needle);
2713
138k
    DEBUGASSERT(needle->origin);
2714
138k
    *pneedle = needle;
2715
138k
  }
2716
21.0k
  else {
2717
21.0k
    *pneedle = NULL;
2718
21.0k
    if(needle)
2719
21.0k
      Curl_conn_free(data, needle);
2720
21.0k
  }
2721
159k
  return result;
2722
159k
}
2723
2724
/**
2725
 * Find an existing connection for the transfer or create a new one.
2726
 * Returns
2727
 * - CURLE_OK on success with a connection attached to data
2728
 * - CURLE_NO_CONNECTION_AVAILABLE when connection limits apply or when
2729
 *   a suitable connection has not determined its multiplex capability.
2730
 * - a fatal error
2731
 */
2732
static CURLcode url_find_or_create_conn(struct Curl_easy *data)
2733
159k
{
2734
159k
  struct connectdata *needle = NULL;
2735
159k
  bool waitpipe = FALSE;
2736
159k
  CURLcode result;
2737
2738
  /* create the template connection for transfer data. Use this needle to
2739
   * find an existing connection or, if none exists, convert needle
2740
   * to a full connection and attach it to data. */
2741
159k
  result = url_create_needle(data, &needle);
2742
159k
  if(result)
2743
21.0k
    goto out;
2744
138k
  DEBUGASSERT(needle);
2745
2746
  /***********************************************************************
2747
   * file: is a special case in that it does not need a network connection
2748
   ***********************************************************************/
2749
138k
#ifndef CURL_DISABLE_FILE
2750
138k
  if(needle->scheme->flags & PROTOPT_NONETWORK) {
2751
1.51k
    bool done;
2752
    /* this is supposed to be the connect function so we better at least check
2753
       that the file is present here! */
2754
1.51k
    DEBUGASSERT(needle->scheme->run->connect_it);
2755
1.51k
    data->info.conn_scheme = needle->scheme->name;
2756
    /* conn_protocol can only provide "old" protocols */
2757
1.51k
    data->info.conn_protocol = (needle->scheme->protocol) & CURLPROTO_MASK;
2758
1.51k
    result = needle->scheme->run->connect_it(data, &done);
2759
1.51k
    if(result)
2760
371
      goto out;
2761
2762
    /* Setup a "faked" transfer that will do nothing */
2763
1.14k
    Curl_attach_connection(data, needle);
2764
1.14k
    needle = NULL;
2765
1.14k
    result = Curl_cpool_add(data, data->conn);
2766
1.14k
    if(!result) {
2767
      /* Setup whatever necessary for a resumed transfer */
2768
1.14k
      result = setup_range(data);
2769
1.14k
      if(!result) {
2770
1.14k
        Curl_xfer_setup_nop(data);
2771
1.14k
        result = Curl_init_do(data, data->conn);
2772
1.14k
      }
2773
1.14k
    }
2774
2775
1.14k
    if(result) {
2776
0
      DEBUGASSERT(data->conn->scheme->run->done);
2777
      /* we ignore the return code for the protocol-specific DONE */
2778
0
      (void)data->conn->scheme->run->done(data, result, FALSE);
2779
0
    }
2780
1.14k
    goto out;
2781
1.14k
  }
2782
136k
#endif
2783
2784
  /* Complete the easy's SSL configuration for connection cache matching */
2785
136k
  result = Curl_ssl_easy_config_complete(data);
2786
136k
  if(result)
2787
0
    goto out;
2788
2789
  /* Get rid of any dead connections so limit are easier kept. */
2790
136k
  Curl_cpool_prune_dead(data);
2791
2792
  /*************************************************************
2793
   * Reuse of existing connection is not allowed when
2794
   * - connect_only is set or
2795
   * - reuse_fresh is set and this is not a follow-up request
2796
   *   (like with HTTP followlocation)
2797
   *************************************************************/
2798
136k
  if((!data->set.reuse_fresh || data->state.followlocation) &&
2799
136k
     !data->set.connect_only) {
2800
    /* Ok, try to find and attach an existing one */
2801
122k
    url_attach_existing(data, needle, &waitpipe);
2802
122k
  }
2803
2804
136k
  if(data->conn) {
2805
    /* We attached an existing connection for this transfer. Copy
2806
     * over transfer specific properties over from needle. */
2807
13.0k
    struct connectdata *conn = data->conn;
2808
13.0k
    VERBOSE(bool tls_upgraded = (!(needle->given->flags & PROTOPT_SSL) &&
2809
13.0k
                                 Curl_conn_is_ssl(conn, FIRSTSOCKET)));
2810
2811
13.0k
    conn->bits.reuse = TRUE;
2812
13.0k
    url_conn_reuse_adjust(data, needle);
2813
2814
13.0k
#ifndef CURL_DISABLE_PROXY
2815
13.0k
    infof(data, "Reusing existing %s: connection%s with %s %s",
2816
13.0k
          conn->given->name,
2817
13.0k
          tls_upgraded ? " (upgraded to SSL)" : "",
2818
13.0k
          conn->bits.proxy ? "proxy" : "host",
2819
13.0k
          conn->socks_proxy.peer ? conn->socks_proxy.peer->user_hostname :
2820
13.0k
          conn->http_proxy.peer ? conn->http_proxy.peer->user_hostname :
2821
13.0k
          conn->origin->hostname);
2822
#else
2823
    infof(data, "Reusing existing %s: connection%s with host %s",
2824
          conn->given->name,
2825
          tls_upgraded ? " (upgraded to SSL)" : "",
2826
          conn->origin->hostname);
2827
#endif
2828
13.0k
  }
2829
123k
  else {
2830
    /* We have decided that we want a new connection. We may not be able to do
2831
       that if we have reached the limit of how many connections we are
2832
       allowed to open. */
2833
123k
    DEBUGF(infof(data, "new connection, bits.close=%d", needle->bits.close));
2834
2835
123k
    if(waitpipe) {
2836
      /* There is a connection that *might* become usable for multiplexing
2837
         "soon", and we wait for that */
2838
2.94k
      infof(data, "Waiting on connection to negotiate possible multiplexing.");
2839
2.94k
      result = CURLE_NO_CONNECTION_AVAILABLE;
2840
2.94k
      goto out;
2841
2.94k
    }
2842
120k
    else {
2843
120k
      switch(Curl_cpool_check_limits(data, needle)) {
2844
0
      case CPOOL_LIMIT_DEST:
2845
0
        infof(data, "No more connections allowed to host");
2846
0
        result = CURLE_NO_CONNECTION_AVAILABLE;
2847
0
        goto out;
2848
0
      case CPOOL_LIMIT_TOTAL:
2849
0
        if(data->master_mid != UINT32_MAX)
2850
0
          CURL_TRC_M(data, "Allowing sub-requests (like DoH) to override "
2851
0
                     "max connection limit");
2852
0
        else {
2853
0
          infof(data, "No connections available, total of %zu reached.",
2854
0
                data->multi->max_total_connections);
2855
0
          result = CURLE_NO_CONNECTION_AVAILABLE;
2856
0
          goto out;
2857
0
        }
2858
0
        break;
2859
120k
      default:
2860
120k
        break;
2861
120k
      }
2862
120k
    }
2863
2864
    /* Convert needle into a full connection by filling in all the
2865
     * remaining parts like the cloned SSL configuration. */
2866
120k
    result = Curl_ssl_conn_config_init(data, needle);
2867
120k
    if(result) {
2868
0
      DEBUGF(curl_mfprintf(stderr, "Error: init connection SSL config\n"));
2869
0
      goto out;
2870
0
    }
2871
    /* attach it and no longer own it */
2872
120k
    Curl_attach_connection(data, needle);
2873
120k
    needle = NULL;
2874
2875
120k
    result = Curl_cpool_add(data, data->conn);
2876
120k
    if(result)
2877
0
      goto out;
2878
2879
#ifdef USE_NTLM
2880
    /* If NTLM is requested in a part of this connection, make sure we do not
2881
       assume the state is fine as this is a fresh connection and NTLM is
2882
       connection based. */
2883
    if((data->state.authhost.picked & CURLAUTH_NTLM) &&
2884
       data->state.authhost.done) {
2885
      infof(data, "NTLM picked AND auth done set, clear picked");
2886
      data->state.authhost.picked = CURLAUTH_NONE;
2887
      data->state.authhost.done = FALSE;
2888
    }
2889
2890
    if((data->state.authproxy.picked & CURLAUTH_NTLM) &&
2891
       data->state.authproxy.done) {
2892
      infof(data, "NTLM-proxy picked AND auth done set, clear picked");
2893
      data->state.authproxy.picked = CURLAUTH_NONE;
2894
      data->state.authproxy.done = FALSE;
2895
    }
2896
#endif
2897
120k
  }
2898
2899
  /* Setup and init stuff before DO starts, in preparing for the transfer. */
2900
133k
  result = Curl_init_do(data, data->conn);
2901
133k
  if(result)
2902
0
    goto out;
2903
2904
  /* Setup whatever necessary for a resumed transfer */
2905
133k
  result = setup_range(data);
2906
133k
  if(result)
2907
0
    goto out;
2908
2909
  /* persist the scheme and handler the transfer is using */
2910
133k
  data->info.conn_scheme = data->conn->scheme->name;
2911
  /* conn_protocol can only provide "old" protocols */
2912
133k
  data->info.conn_protocol = (data->conn->scheme->protocol) & CURLPROTO_MASK;
2913
133k
  data->info.used_proxy =
2914
#ifdef CURL_DISABLE_PROXY
2915
    0
2916
#else
2917
133k
    data->conn->bits.proxy
2918
133k
#endif
2919
133k
    ;
2920
2921
  /* Lastly, inform connection filters that a new transfer is attached */
2922
133k
  result = Curl_conn_ev_data_setup(data);
2923
2924
159k
out:
2925
159k
  if(needle)
2926
16.3k
    Curl_conn_free(data, needle);
2927
159k
  DEBUGASSERT(result || data->conn);
2928
159k
  return result;
2929
159k
}
2930
2931
CURLcode Curl_connect(struct Curl_easy *data, bool *pconnected)
2932
159k
{
2933
159k
  CURLcode result;
2934
159k
  struct connectdata *conn;
2935
2936
159k
  *pconnected = FALSE;
2937
2938
  /* Set the request to virgin state based on transfer settings */
2939
159k
  Curl_req_hard_reset(&data->req, data);
2940
2941
  /* Get or create a connection for the transfer. */
2942
159k
  result = url_find_or_create_conn(data);
2943
159k
  conn = data->conn;
2944
2945
159k
  if(result)
2946
24.3k
    goto out;
2947
2948
135k
  DEBUGASSERT(conn);
2949
135k
  Curl_pgrsTime(data, TIMER_POSTQUEUE);
2950
135k
  if(conn->bits.reuse) {
2951
13.0k
    if(conn->attached_xfers > 1)
2952
      /* multiplexed */
2953
0
      *pconnected = TRUE;
2954
13.0k
  }
2955
121k
  else if(conn->scheme->flags & PROTOPT_NONETWORK) {
2956
1.14k
    Curl_pgrsTime(data, TIMER_NAMELOOKUP);
2957
1.14k
    *pconnected = TRUE;
2958
1.14k
  }
2959
120k
  else {
2960
120k
    result = Curl_conn_setup(data, conn, FIRSTSOCKET, CURL_CF_SSL_DEFAULT);
2961
120k
    if(!result)
2962
120k
      result = Curl_headers_init(data);
2963
120k
    CURL_TRC_M(data, "Curl_conn_setup() -> %d", result);
2964
120k
  }
2965
2966
159k
out:
2967
159k
  if(result == CURLE_NO_CONNECTION_AVAILABLE)
2968
159k
    DEBUGASSERT(!conn);
2969
2970
159k
  if(result && conn) {
2971
    /* We are not allowed to return failure with memory left allocated in the
2972
       connectdata struct, free those here */
2973
0
    Curl_detach_connection(data);
2974
0
    Curl_conn_terminate(data, conn, TRUE);
2975
0
  }
2976
2977
159k
  return result;
2978
159k
}
2979
2980
/*
2981
 * Curl_init_do() inits the readwrite session. This is inited each time (in
2982
 * the DO function before the protocol-specific DO functions are invoked) for
2983
 * a transfer, sometimes multiple times on the same Curl_easy. Make sure
2984
 * nothing in here depends on stuff that are setup dynamically for the
2985
 * transfer.
2986
 *
2987
 * Allow this function to get called with 'conn' set to NULL.
2988
 */
2989
2990
CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
2991
135k
{
2992
135k
  CURLcode result;
2993
2994
135k
  if(conn) {
2995
135k
    conn->bits.do_more = FALSE; /* by default there is no curl_do_more() to
2996
                                   use */
2997
    /* if the protocol used does not support wildcards, switch it off */
2998
135k
    if(data->state.wildcardmatch &&
2999
802
       !(conn->scheme->flags & PROTOPT_WILDCARD))
3000
53
      data->state.wildcardmatch = FALSE;
3001
135k
  }
3002
3003
135k
  data->state.done = FALSE; /* *_done() is not called yet */
3004
3005
135k
  data->req.no_body = data->set.opt_no_body;
3006
135k
  if(data->req.no_body)
3007
    /* in HTTP lingo, no body means using the HEAD request... */
3008
2.48k
    data->state.httpreq = HTTPREQ_HEAD;
3009
3010
135k
  result = Curl_req_start(&data->req, data);
3011
135k
  if(!result) {
3012
135k
    Curl_pgrsReset(data);
3013
135k
  }
3014
135k
  return result;
3015
135k
}
3016
3017
#if defined(USE_HTTP2) || defined(USE_HTTP3)
3018
3019
void Curl_data_priority_clear_state(struct Curl_easy *data)
3020
140k
{
3021
140k
  memset(&data->state.priority, 0, sizeof(data->state.priority));
3022
140k
}
3023
3024
#endif /* USE_HTTP2 || USE_HTTP3 */
3025
3026
CURLcode Curl_conn_meta_set(struct connectdata *conn, const char *key,
3027
                            void *meta_data, Curl_meta_dtor *meta_dtor)
3028
56.2k
{
3029
56.2k
  if(!Curl_hash_add2(&conn->meta_hash, CURL_UNCONST(key), strlen(key) + 1,
3030
56.2k
                     meta_data, meta_dtor)) {
3031
0
    meta_dtor(CURL_UNCONST(key), strlen(key) + 1, meta_data);
3032
0
    return CURLE_OUT_OF_MEMORY;
3033
0
  }
3034
56.2k
  return CURLE_OK;
3035
56.2k
}
3036
3037
void Curl_conn_meta_remove(struct connectdata *conn, const char *key)
3038
121k
{
3039
121k
  Curl_hash_delete(&conn->meta_hash, CURL_UNCONST(key), strlen(key) + 1);
3040
121k
}
3041
3042
void *Curl_conn_meta_get(struct connectdata *conn, const char *key)
3043
17.4M
{
3044
17.4M
  return Curl_hash_pick(&conn->meta_hash, CURL_UNCONST(key), strlen(key) + 1);
3045
17.4M
}
3046
3047
CURLcode Curl_1st_fatal(CURLcode r1, CURLcode r2)
3048
154k
{
3049
154k
  if(r1 && (r1 != CURLE_AGAIN))
3050
109k
    return r1;
3051
45.3k
  if(r2 && (r2 != CURLE_AGAIN))
3052
4
    return r2;
3053
45.3k
  return r1;
3054
45.3k
}