Coverage Report

Created: 2026-08-28 06:36

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 "transfer.h"
74
#include "curl_addrinfo.h"
75
#include "curl_trc.h"
76
#include "progress.h"
77
#include "cookie.h"
78
#include "strcase.h"
79
#include "escape.h"
80
#include "curl_share.h"
81
#include "http_digest.h"
82
#include "multiif.h"
83
#include "getinfo.h"
84
#include "pop3.h"
85
#include "urlapi-int.h"
86
#include "system_win32.h"
87
#include "hsts.h"
88
#include "proxy.h"
89
#include "cfilters.h"
90
#include "idn.h"
91
#include "http_proxy.h"
92
#include "conncache.h"
93
#include "multihandle.h"
94
#include "curlx/strdup.h"
95
#include "setopt.h"
96
#include "altsvc.h"
97
#include "curlx/dynbuf.h"
98
#include "headers.h"
99
#include "curlx/strerr.h"
100
#include "curlx/strparse.h"
101
#include "peer.h"
102
103
/* Now for the protocols */
104
#include "ftp.h"
105
#include "dict.h"
106
#include "telnet.h"
107
#include "tftp.h"
108
#include "http.h"
109
#include "vauth/vauth.h"
110
#include "file.h"
111
#include "curl_ldap.h"
112
#include "vssh/ssh.h"
113
#include "imap.h"
114
#include "url.h"
115
#include "connect.h"
116
#include "gopher.h"
117
#include "mqtt.h"
118
#include "rtsp.h"
119
#include "smtp.h"
120
#include "ws.h"
121
122
/* Some parts of the code (e.g. chunked encoding) assume this buffer has more
123
 * than a few bytes to play with. Do not let it become too small or bad things
124
 * will happen.
125
 */
126
#if READBUFFER_SIZE < READBUFFER_MIN
127
# error READBUFFER_SIZE is too small
128
#endif
129
130
/*
131
 * get_protocol_family()
132
 *
133
 * This is used to return the protocol family for a given protocol.
134
 *
135
 * Parameters:
136
 *
137
 * 's'  [in]  - struct Curl_scheme pointer.
138
 *
139
 * Returns the family as a single bit protocol identifier.
140
 */
141
static curl_prot_t get_protocol_family(const struct Curl_scheme *s)
142
22.8k
{
143
22.8k
  DEBUGASSERT(s);
144
22.8k
  DEBUGASSERT(s->family);
145
22.8k
  return s->family;
146
22.8k
}
147
148
void Curl_freeset(struct Curl_easy *data)
149
482k
{
150
  /* Free all dynamic strings stored in the data->set substructure. */
151
482k
  enum dupblob j;
152
153
482k
  CURL_EASY_STR_CLEAR0(data, STRING_PASSWORD);
154
482k
  CURL_EASY_STR_CLEAR0(data, STRING_KEY_PASSWD);
155
482k
  CURL_EASY_STR_CLEAR0(data, STRING_BEARER);
156
482k
#ifndef CURL_DISABLE_PROXY
157
482k
  CURL_EASY_STR_CLEAR0(data, STRING_PROXYPASSWORD);
158
482k
  CURL_EASY_STR_CLEAR0(data, STRING_KEY_PASSWD_PROXY);
159
482k
#endif
160
482k
  Curl_u8_strset_clear(&data->set.strings);
161
482k
  curlx_safefree(data->set.str_copypostfields);
162
163
4.34M
  for(j = (enum dupblob)0; j < BLOB_LAST; j++) {
164
3.86M
    curlx_safefree(data->set.blobs[j]);
165
3.86M
  }
166
167
482k
  Curl_bufref_free(&data->state.referer);
168
482k
  Curl_bufref_free(&data->state.url);
169
170
482k
#if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
171
482k
  Curl_mime_cleanpart(data->set.mimepostp);
172
482k
  curlx_safefree(data->set.mimepostp);
173
482k
#endif
174
175
482k
#ifndef CURL_DISABLE_COOKIES
176
482k
  curl_slist_free_all(data->state.cookielist);
177
482k
  data->state.cookielist = NULL;
178
482k
#endif
179
482k
}
180
181
/* free the URL pieces */
182
static void up_free(struct Curl_easy *data)
183
678k
{
184
678k
  struct urlpieces *up = &data->state.up;
185
678k
  curlx_safefree(up->options);
186
678k
  curlx_safefree(up->path);
187
678k
  curlx_safefree(up->query);
188
678k
  curl_url_cleanup(data->state.uh);
189
678k
  data->state.uh = NULL;
190
678k
}
191
192
/*
193
 * This is the internal function curl_easy_cleanup() calls. This should
194
 * cleanup and free all resources associated with this Curl_easy.
195
 *
196
 * We ignore SIGPIPE when this is called from curl_easy_cleanup.
197
 */
198
CURLcode Curl_close(struct Curl_easy **datap)
199
482k
{
200
482k
  struct Curl_easy *data;
201
202
482k
  if(!datap || !*datap)
203
118
    return CURLE_OK;
204
205
482k
  data = *datap;
206
482k
  *datap = NULL;
207
208
482k
  if(!data->state.internal && data->multi) {
209
    /* This handle is still part of a multi handle, take care of this first
210
       and detach this handle from there.
211
       This detaches the connection. */
212
0
    Curl_multi_remove_handle(data->multi, data);
213
0
  }
214
482k
  else {
215
    /* Detach connection if any is left. This should not be normal, but can be
216
       the case for example with CONNECT_ONLY + recv/send (test 556) */
217
482k
    Curl_detach_connection(data);
218
482k
    if(!data->state.internal && data->multi_easy) {
219
      /* when curl_easy_perform() is used, it creates its own multi handle to
220
         use and this is the one */
221
0
      curl_multi_cleanup(data->multi_easy);
222
0
      data->multi_easy = NULL;
223
0
    }
224
482k
  }
225
482k
  DEBUGASSERT(!data->conn || data->state.internal);
226
227
482k
  Curl_expire_clear_all(data); /* shut off any timers left */
228
229
482k
  if(data->state.rangestringalloc)
230
3.31k
    curlx_free(data->state.range);
231
232
  /* release any resolve information this transfer kept */
233
482k
  Curl_resolv_destroy_all(data);
234
235
482k
  data->set.verbose = FALSE; /* no more calls to DEBUGFUNCTION */
236
482k
  data->magic = 0; /* force a clear AFTER the possibly enforced removal from
237
                    * the multi handle and async dns shutdown. The multi
238
                    * handle might check the magic and so might any
239
                    * DEBUGFUNCTION invoked for tracing */
240
241
  /* freed here in case DONE was not called */
242
482k
  Curl_req_free(&data->req, data);
243
244
  /* Close down all open SSL info and sessions */
245
482k
  Curl_ssl_close_all(data);
246
482k
  Curl_peer_unlink(&data->state.origin);
247
482k
  Curl_peer_unlink(&data->state.initial_origin);
248
482k
  Curl_ssl_free_certinfo(data);
249
250
482k
  Curl_bufref_free(&data->state.referer);
251
252
482k
  up_free(data);
253
482k
  curlx_dyn_free(&data->state.headerb);
254
482k
  Curl_flush_cookies(data, TRUE);
255
482k
#ifndef CURL_DISABLE_ALTSVC
256
482k
  Curl_altsvc_save(data, data->asi, CURL_EASY_STR(data, STRING_ALTSVC));
257
482k
  Curl_altsvc_cleanup(&data->asi);
258
482k
#endif
259
482k
#ifndef CURL_DISABLE_HSTS
260
482k
  Curl_hsts_save(data, data->hsts, CURL_EASY_STR(data, STRING_HSTS));
261
482k
  if(!data->share || !data->share->hsts)
262
482k
    Curl_hsts_cleanup(&data->hsts);
263
482k
  curl_slist_free_all(data->state.hstslist); /* clean up list */
264
482k
#endif
265
482k
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH)
266
482k
  Curl_http_auth_cleanup_digest(data);
267
482k
#endif
268
482k
  curlx_safefree(data->state.most_recent_ftp_entrypath);
269
482k
  curlx_safefree(data->info.contenttype);
270
482k
  curlx_safefree(data->info.wouldredirect);
271
272
  /* No longer a dirty share, if it exists */
273
482k
  if(Curl_share_easy_unlink(data))
274
482k
    DEBUGASSERT(0);
275
276
482k
  Curl_hash_destroy(&data->meta_hash);
277
482k
  Curl_creds_unlink(&data->state.creds);
278
482k
#ifndef CURL_DISABLE_HTTP
279
482k
  curlx_safefree(data->state.rangeline);
280
482k
  curlx_safefree(data->state.http_host);
281
482k
#endif
282
482k
#ifndef CURL_DISABLE_COOKIES
283
482k
  curlx_safefree(data->req.cookiehost);
284
482k
#endif
285
286
482k
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_FORM_API)
287
482k
  Curl_mime_cleanpart(data->state.formp);
288
482k
  curlx_safefree(data->state.formp);
289
482k
#endif
290
291
  /* destruct wildcard structures if it is needed */
292
482k
  Curl_wildcard_dtor(&data->wildcard);
293
482k
  Curl_freeset(data);
294
482k
  Curl_headers_cleanup(data);
295
482k
  Curl_netrc_cleanup(&data->state.netrc);
296
482k
#ifndef CURL_DISABLE_DIGEST_AUTH
297
482k
  curlx_free(data->state.envproxy);
298
482k
#endif
299
482k
  Curl_ssl_config_cleanup(&data->set.ssl.primary);
300
482k
#ifndef CURL_DISABLE_PROXY
301
482k
  Curl_ssl_config_cleanup(&data->set.proxy_ssl.primary);
302
482k
#endif
303
482k
  curlx_memzero(data, sizeof(*data));
304
482k
  curlx_free(data);
305
482k
  return CURLE_OK;
306
482k
}
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
482k
{
314
482k
  struct UserDefined *set = &data->set;
315
316
482k
  set->out = stdout;  /* default output to stdout */
317
482k
  set->in_set = stdin;  /* default input from stdin */
318
482k
  set->err = stderr;  /* default stderr to stderr */
319
320
482k
  Curl_u8_strset_init(&data->set.strings);
321
322
482k
#if defined(__clang__) && __clang_major__ >= 16
323
482k
#pragma clang diagnostic push
324
482k
#pragma clang diagnostic ignored "-Wcast-function-type-strict"
325
482k
#endif
326
  /* use fwrite as default function to store output */
327
482k
  set->fwrite_func = (curl_write_callback)fwrite;
328
329
  /* use fread as default function to read input */
330
482k
  set->fread_func_set = (curl_read_callback)fread;
331
482k
#if defined(__clang__) && __clang_major__ >= 16
332
482k
#pragma clang diagnostic pop
333
482k
#endif
334
482k
  set->is_fread_set = 0;
335
336
482k
  set->seek_client = ZERO_NULL;
337
338
482k
  set->filesize = -1;        /* we do not know the size */
339
482k
  set->postfieldsize = -1;   /* unknown size */
340
482k
  set->maxredirs = 30;       /* sensible default */
341
342
482k
  set->method = HTTPREQ_GET; /* Default HTTP request */
343
482k
#ifndef CURL_DISABLE_RTSP
344
482k
  set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */
345
482k
#endif
346
482k
#ifndef CURL_DISABLE_FTP
347
482k
  set->ftp_use_epsv = TRUE;   /* FTP defaults to EPSV operations */
348
482k
  set->ftp_use_eprt = TRUE;   /* FTP defaults to EPRT operations */
349
482k
  set->ftp_use_pret = FALSE;  /* mainly useful for drftpd servers */
350
482k
  set->ftp_filemethod = FTPFILE_MULTICWD;
351
482k
  set->ftp_skip_ip = TRUE;    /* skip PASV IP by default */
352
482k
#endif
353
482k
  set->dns_cache_timeout_ms = 60000; /* Timeout every 60 seconds by default */
354
355
  /* Timeout every 24 hours by default */
356
482k
  set->general_ssl.ca_cache_timeout = 24 * 60 * 60;
357
358
482k
  set->httpauth = CURLAUTH_BASIC;  /* defaults to basic */
359
360
482k
  Curl_ssl_config_init(&data->set.ssl.primary);
361
482k
#ifndef CURL_DISABLE_PROXY
362
482k
  Curl_ssl_config_init(&data->set.proxy_ssl.primary);
363
482k
  set->proxyport = 0;
364
482k
  set->proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */
365
482k
  set->proxyauth = CURLAUTH_BASIC; /* defaults to basic */
366
  /* SOCKS5 proxy auth defaults to username/password + GSS-API */
367
482k
  set->socks5auth = CURLAUTH_BASIC | CURLAUTH_GSSAPI;
368
482k
#endif
369
370
482k
#ifndef CURL_DISABLE_DOH
371
482k
  set->doh_verifyhost = TRUE;
372
482k
  set->doh_verifypeer = TRUE;
373
482k
#endif
374
#ifdef USE_SSH
375
  /* defaults to any auth type */
376
  set->ssh_auth_types = CURLSSH_AUTH_DEFAULT;
377
  set->new_directory_perms = 0755; /* Default permissions */
378
#endif
379
380
482k
  set->new_file_perms = 0644;    /* Default permissions */
381
482k
  set->allowed_protocols = (curl_prot_t)CURLPROTO_64ALL;
382
482k
  set->redir_protocols = CURLPROTO_REDIR;
383
384
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
385
  /*
386
   * disallow unprotected protection negotiation NEC reference implementation
387
   * seem not to follow rfc1961 section 4.3/4.4
388
   */
389
  set->socks5_gssapi_nec = FALSE;
390
#endif
391
392
  /* set default minimum TLS version */
393
482k
#ifdef USE_SSL
394
482k
  Curl_setopt_SSLVERSION(data, CURLOPT_SSLVERSION, CURL_SSLVERSION_DEFAULT);
395
482k
#ifndef CURL_DISABLE_PROXY
396
482k
  Curl_setopt_SSLVERSION(data, CURLOPT_PROXY_SSLVERSION,
397
482k
                         CURL_SSLVERSION_DEFAULT);
398
482k
#endif
399
482k
#endif
400
482k
#ifndef CURL_DISABLE_FTP
401
482k
  set->wildcard_enabled = FALSE;
402
482k
  set->chunk_bgn = ZERO_NULL;
403
482k
  set->chunk_end = ZERO_NULL;
404
482k
  set->fnmatch = ZERO_NULL;
405
482k
#endif
406
482k
  set->tcp_keepalive = FALSE;
407
482k
  set->tcp_keepintvl = 60;
408
482k
  set->tcp_keepidle = 60;
409
482k
  set->tcp_keepcnt = 9;
410
482k
  set->tcp_fastopen = FALSE;
411
482k
  set->tcp_nodelay = TRUE;
412
482k
  set->ssl_enable_alpn = TRUE;
413
482k
  set->expect_100_timeout = 1000L; /* Wait for a second by default. */
414
482k
  set->sep_headers = TRUE; /* separated header lists by default */
415
482k
  set->buffer_size = READBUFFER_SIZE;
416
482k
  set->upload_buffer_size = UPLOADBUFFER_DEFAULT;
417
482k
  set->upload_flags = CURLULFLAG_SEEN;
418
482k
  set->happy_eyeballs_timeout = CURL_HET_DEFAULT;
419
482k
  set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT;
420
482k
  set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
421
482k
  set->conn_max_idle_ms = 118 * 1000;
422
482k
  set->conn_max_age_ms = 24 * 3600 * 1000;
423
482k
  set->http09_allowed = FALSE;
424
482k
  set->httpwant = CURL_HTTP_VERSION_NONE;
425
482k
#if defined(USE_HTTP2) || defined(USE_HTTP3)
426
482k
  set->weight = 0;
427
482k
#endif
428
482k
  set->quick_exit = 0L;
429
482k
#ifndef CURL_DISABLE_WEBSOCKETS
430
482k
  set->ws_raw_mode = FALSE;
431
482k
  set->ws_no_auto_pong = FALSE;
432
482k
#endif
433
482k
}
434
435
/* easy->meta_hash destructor. Should never be called as elements
436
 * MUST be added with their own destructor */
437
static void easy_meta_freeentry(void *p)
438
0
{
439
0
  (void)p;
440
  /* Always FALSE. Cannot use a 0 assert here since compilers
441
   * are not in agreement if they then want a NORETURN attribute or
442
   * not. *sigh* */
443
0
  DEBUGASSERT(!p);
444
0
}
445
446
/**
447
 * Curl_open()
448
 *
449
 * @param curl is a pointer to a Curl_easy pointer that gets set by this
450
 * function.
451
 * @return CURLcode
452
 */
453
CURLcode Curl_open(struct Curl_easy **curl)
454
482k
{
455
482k
  struct Curl_easy *data;
456
457
  /* simple start-up: alloc the struct, init it with zeroes and return */
458
482k
  data = curlx_calloc(1, sizeof(struct Curl_easy));
459
482k
  if(!data) {
460
    /* this is a serious error */
461
0
    DEBUGF(curl_mfprintf(stderr, "Error: calloc of Curl_easy failed\n"));
462
0
    return CURLE_OUT_OF_MEMORY;
463
0
  }
464
465
482k
  data->magic = CURLEASY_MAGIC_NUMBER;
466
  /* most recent connection is not yet defined */
467
482k
  data->state.lastconnect_id = -1;
468
  /* and not assigned an id yet */
469
482k
  data->id = -1;
470
482k
  data->mid = UINT32_MAX;
471
482k
  data->master_mid = UINT32_MAX;
472
482k
  data->progress.hide = TRUE;
473
474
482k
  Curl_hash_init(&data->meta_hash, 23,
475
482k
                 Curl_hash_str, curlx_str_key_compare, easy_meta_freeentry);
476
482k
  DEBUGASSERT(STRING_LAST <= UINT8_MAX);
477
482k
  Curl_u8_strset_init(&data->set.strings);
478
482k
  curlx_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER);
479
482k
  Curl_bufref_init(&data->state.url);
480
482k
  Curl_bufref_init(&data->state.referer);
481
482k
  Curl_req_init(&data->req);
482
482k
  Curl_initinfo(data);
483
482k
#ifndef CURL_DISABLE_HTTP
484
482k
  Curl_llist_init(&data->state.httphdrs, NULL);
485
482k
#endif
486
482k
  Curl_netrc_init(&data->state.netrc);
487
482k
  Curl_init_userdefined(data);
488
489
482k
  *curl = data;
490
482k
  return CURLE_OK;
491
482k
}
492
493
void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn)
494
177k
{
495
177k
  int8_t i;
496
497
177k
  DEBUGASSERT(conn);
498
499
177k
  if(conn->scheme && conn->scheme->run->disconnect &&
500
40.0k
     !conn->bits.shutdown_handler)
501
519
    conn->scheme->run->disconnect(data, conn, TRUE);
502
503
533k
  for(i = 0; i < (int8_t)CURL_ARRAYSIZE(conn->cfilter); ++i) {
504
355k
    Curl_conn_cf_discard_all(data, conn, i);
505
355k
  }
506
507
177k
#ifndef CURL_DISABLE_PROXY
508
177k
  Curl_peer_unlink(&conn->http_proxy.peer);
509
177k
  Curl_peer_unlink(&conn->socks_proxy.peer);
510
177k
  Curl_creds_unlink(&conn->http_proxy.creds);
511
177k
  Curl_creds_unlink(&conn->socks_proxy.creds);
512
177k
#endif
513
177k
  Curl_creds_unlink(&conn->creds);
514
177k
  Curl_peer_unlink(&conn->creds_origin);
515
177k
  curlx_safefree(conn->options);
516
177k
  curlx_safefree(conn->localdev);
517
177k
  Curl_ssl_conn_config_cleanup(conn);
518
519
177k
  curlx_safefree(conn->destination);
520
177k
  Curl_hash_destroy(&conn->meta_hash);
521
177k
  Curl_peer_unlink(&conn->origin);
522
177k
  Curl_peer_unlink(&conn->via_peer);
523
177k
  Curl_peer_unlink(&conn->origin2);
524
177k
  Curl_peer_unlink(&conn->via_peer2);
525
526
177k
  curlx_free(conn); /* free all the connection oriented data */
527
177k
}
528
529
/*
530
 * xfer_may_multiplex()
531
 *
532
 * Return a TRUE, iff the transfer can be done over an (appropriate)
533
 * multiplexed connection.
534
 */
535
static bool xfer_may_multiplex(const struct Curl_easy *data,
536
                               const struct connectdata *conn)
537
146k
{
538
146k
#ifndef CURL_DISABLE_HTTP
539
  /* If an HTTP protocol and multiplexing is enabled */
540
146k
  if((conn->scheme->protocol & PROTO_FAMILY_HTTP) &&
541
53.5k
     (!conn->bits.protoconnstart || !conn->bits.close)) {
542
543
53.5k
    if(Curl_multiplex_wanted(data->multi) &&
544
53.5k
       (data->state.http_neg.allowed & (CURL_HTTP_V2x | CURL_HTTP_V3x)))
545
      /* allows HTTP/2 or newer */
546
51.6k
      return TRUE;
547
53.5k
  }
548
#else
549
  (void)data;
550
  (void)conn;
551
#endif
552
94.5k
  return FALSE;
553
146k
}
554
555
#ifndef CURL_DISABLE_PROXY
556
static bool proxy_info_matches(const struct proxy_info *data,
557
                               const struct proxy_info *needle)
558
46.0k
{
559
46.0k
  if((data->proxytype == needle->proxytype) &&
560
46.0k
     Curl_peer_same_destination(data->peer, needle->peer) &&
561
46.0k
     Curl_creds_same(data->creds, needle->creds)) {
562
46.0k
    return TRUE;
563
46.0k
  }
564
0
  return FALSE;
565
46.0k
}
566
#endif
567
568
#ifdef USE_SSH
569
static bool ssh_config_matches(struct connectdata *one,
570
                               struct connectdata *two)
571
{
572
  struct ssh_conn *sshc1, *sshc2;
573
574
  sshc1 = Curl_conn_meta_get(one, CURL_META_SSH_CONN);
575
  sshc2 = Curl_conn_meta_get(two, CURL_META_SSH_CONN);
576
  return sshc1 && sshc2 && Curl_safecmp(sshc1->priv_key, sshc2->priv_key) &&
577
         Curl_safecmp(sshc1->pub_key, sshc2->pub_key);
578
}
579
#endif
580
581
struct url_conn_match {
582
  struct connectdata *found;
583
  struct Curl_easy *data;
584
  struct connectdata *needle;
585
  struct curltime now;
586
  BIT(may_multiplex);
587
  BIT(want_ntlm_http);
588
  BIT(want_proxy_ntlm_http);
589
  BIT(want_nego_http);
590
  BIT(want_proxy_nego_http);
591
  BIT(may_tls); /* May upgrade clear-text connection to TLS, can only reuse
592
                 * connections that have matching TLS configuration.
593
                 * Always TRUE if `req_tls` is TRUE. */
594
  BIT(require_tls); /* Requires TLS use from a clear-text start, can only
595
                 * reuse connections that have TLS. */
596
  BIT(wait_pipe);
597
  BIT(force_reuse);
598
  BIT(seen_pending_conn);
599
  BIT(seen_single_use_conn);
600
  BIT(seen_multiplex_conn);
601
};
602
603
static bool url_match_connect_config(struct connectdata *conn,
604
                                     struct url_conn_match *m)
605
26.6k
{
606
  /* connect-only or to-be-closed connections will not be reused */
607
26.6k
  if(conn->bits.connect_only || conn->bits.close || conn->bits.no_reuse)
608
3
    return FALSE;
609
610
  /* ip_version must match */
611
26.6k
  if(m->data->set.ipver != CURL_IPRESOLVE_WHATEVER &&
612
91
     m->data->set.ipver != conn->ip_version)
613
0
    return FALSE;
614
615
26.6k
  if(m->needle->localdev || m->needle->localport) {
616
    /* If we are bound to a specific local end (IP+port), we must not reuse a
617
       random other one, although if we did not ask for a particular one we
618
       can reuse one that was bound.
619
620
       This comparison is a bit rough and too strict. Since the input
621
       parameters can be specified in numerous ways and still end up the same
622
       it would take a lot of processing to make it really accurate. Instead,
623
       this matching will assume that reuses of bound connections will most
624
       likely also reuse the exact same binding parameters and missing out a
625
       few edge cases should not hurt anyone much. */
626
2.29k
    if((conn->localport != m->needle->localport) ||
627
2.29k
       (conn->localportrange != m->needle->localportrange) ||
628
2.29k
       (m->needle->localdev &&
629
1.77k
        (!conn->localdev || strcmp(conn->localdev, m->needle->localdev))))
630
0
      return FALSE;
631
2.29k
  }
632
633
26.6k
  if(!m->needle->via_peer != !conn->via_peer)
634
    /* do not mix connections that use the "connect to host" feature and
635
     * connections that do not use this feature */
636
35
    return FALSE;
637
638
26.6k
  return TRUE;
639
26.6k
}
640
641
static bool url_match_fully_connected(struct connectdata *conn,
642
                                      struct url_conn_match *m)
643
26.5k
{
644
26.5k
  if(!Curl_conn_is_connected(conn, FIRSTSOCKET) ||
645
23.0k
     conn->bits.upgrade_in_progress) {
646
    /* Not yet connected, or a protocol upgrade is in progress. The later
647
     * happens for HTTP/2 Upgrade: requests that need a response. */
648
3.52k
    if(m->may_multiplex) {
649
3.52k
      m->seen_pending_conn = TRUE;
650
      /* Do not pick a connection that has not connected yet */
651
3.52k
      infof(m->data, "Connection #%" FMT_OFF_T
652
3.52k
            " is not open enough, cannot reuse", conn->connection_id);
653
3.52k
    }
654
    /* Do not pick a connection that has not connected yet */
655
3.52k
    return FALSE;
656
3.52k
  }
657
23.0k
  return TRUE;
658
26.5k
}
659
660
static bool url_match_multi(struct connectdata *conn,
661
                            struct url_conn_match *m)
662
0
{
663
0
  if(CONN_INUSE(conn)) {
664
0
    DEBUGASSERT(conn->attached_multi);
665
0
    if(conn->attached_multi != m->data->multi)
666
0
      return FALSE;
667
0
  }
668
0
  return TRUE;
669
0
}
670
671
static bool url_match_multiplex_needs(struct connectdata *conn,
672
                                      struct url_conn_match *m)
673
23.0k
{
674
23.0k
  if(CONN_INUSE(conn)) {
675
0
    if(!conn->bits.multiplex) {
676
      /* conn busy and conn cannot take more transfers */
677
0
      m->seen_single_use_conn = TRUE;
678
0
      return FALSE;
679
0
    }
680
0
    m->seen_multiplex_conn = TRUE;
681
0
    if(!m->may_multiplex || !url_match_multi(conn, m))
682
      /* conn busy and transfer cannot be multiplexed */
683
0
      return FALSE;
684
0
  }
685
23.0k
  return TRUE;
686
23.0k
}
687
688
static bool url_match_multiplex_limits(struct connectdata *conn,
689
                                       struct url_conn_match *m)
690
22.8k
{
691
22.8k
  if(CONN_INUSE(conn) && m->may_multiplex) {
692
0
    DEBUGASSERT(conn->bits.multiplex);
693
    /* If multiplexed, make sure we do not go over concurrency limit */
694
0
    if(conn->attached_xfers >=
695
0
            Curl_multi_max_concurrent_streams(m->data->multi)) {
696
0
      infof(m->data, "client side MAX_CONCURRENT_STREAMS reached"
697
0
            ", skip (%u)", conn->attached_xfers);
698
0
      return FALSE;
699
0
    }
700
0
    if(conn->attached_xfers >=
701
0
       Curl_conn_get_max_concurrent(m->data, conn, FIRSTSOCKET)) {
702
0
      infof(m->data, "MAX_CONCURRENT_STREAMS reached, skip (%u)",
703
0
            conn->attached_xfers);
704
0
      return FALSE;
705
0
    }
706
    /* When not multiplexed, we have a match here! */
707
0
    infof(m->data, "Multiplexed connection found");
708
0
  }
709
22.8k
  return TRUE;
710
22.8k
}
711
712
static bool url_match_ssl_use(struct connectdata *conn,
713
                              struct url_conn_match *m)
714
23.0k
{
715
23.0k
  if(m->needle->scheme->flags & PROTOPT_SSL) {
716
    /* We are looking for SSL, if `conn` does not do it, not a match. */
717
0
    if(!Curl_conn_is_ssl(conn, FIRSTSOCKET))
718
0
      return FALSE;
719
0
  }
720
23.0k
  else if(Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
721
    /* If the protocol does not allow reuse of SSL connections OR
722
       is of another protocol family, not a match. */
723
0
    if(!(m->needle->scheme->flags & PROTOPT_SSL_REUSE) ||
724
0
       (get_protocol_family(conn->scheme) != m->needle->scheme->protocol))
725
0
      return FALSE;
726
    /* We may reuse this as an auto-TLS upgrade, but only if the SSL
727
     * config parameters match. */
728
0
    if(!Curl_ssl_conn_config_match(m->data, conn, FALSE))
729
0
      return FALSE;
730
0
  }
731
23.0k
  else if(m->require_tls)
732
    /* a clear-text STARTTLS protocol with required TLS */
733
10
    return FALSE;
734
23.0k
  return TRUE;
735
23.0k
}
736
737
#ifndef CURL_DISABLE_PROXY
738
static bool url_match_proxy_use(struct connectdata *conn,
739
                                struct url_conn_match *m)
740
23.0k
{
741
23.0k
  if(m->needle->bits.origin_is_proxy != conn->bits.origin_is_proxy)
742
0
    return FALSE;
743
744
23.0k
  if(!proxy_info_matches(&m->needle->socks_proxy, &conn->socks_proxy))
745
0
    return FALSE;
746
747
23.0k
  if(!proxy_info_matches(&m->needle->http_proxy, &conn->http_proxy))
748
0
    return FALSE;
749
750
23.0k
  if(CURL_PROXY_IS_HTTPS(m->needle->http_proxy.proxytype)) {
751
    /* https proxies come in different types, http/1.1, h2, ... */
752
    /* match SSL config to proxy */
753
0
    if(!Curl_ssl_conn_config_match(m->data, conn, TRUE)) {
754
0
      DEBUGF(infof(m->data,
755
0
                   "Connection #%" FMT_OFF_T
756
0
                   " has different SSL proxy parameters, cannot reuse",
757
0
                   conn->connection_id));
758
0
      return FALSE;
759
0
    }
760
    /* the SSL config to the server, which may apply here is checked
761
     * further below */
762
0
  }
763
23.0k
  return TRUE;
764
23.0k
}
765
#else
766
#define url_match_proxy_use(c, m) ((void)(c), (void)(m), TRUE)
767
#endif
768
769
#ifndef CURL_DISABLE_HTTP
770
static bool url_match_http_multiplex(struct connectdata *conn,
771
                                     struct url_conn_match *m)
772
23.0k
{
773
23.0k
  if(m->may_multiplex &&
774
5.73k
     (m->data->state.http_neg.allowed & (CURL_HTTP_V2x | CURL_HTTP_V3x)) &&
775
5.73k
     (m->needle->scheme->protocol & CURLPROTO_HTTP) &&
776
5.73k
     !conn->httpversion_seen) {
777
0
    if(m->data->set.pipewait) {
778
0
      infof(m->data, "Server upgrade does not support multiplex yet, wait");
779
0
      m->found = NULL;
780
0
      m->wait_pipe = TRUE;
781
0
      return TRUE; /* stop searching, we want to wait */
782
0
    }
783
0
    infof(m->data, "Server upgrade cannot be used");
784
0
    return FALSE;
785
0
  }
786
23.0k
  return TRUE;
787
23.0k
}
788
789
static bool url_match_http_version(struct connectdata *conn,
790
                                   struct url_conn_match *m)
791
23.0k
{
792
  /* If looking for HTTP and the HTTP versions allowed do not include
793
   * the HTTP version of conn, continue looking. */
794
23.0k
  if((m->needle->scheme->protocol & PROTO_FAMILY_HTTP)) {
795
6.03k
    switch(Curl_conn_http_version(m->data, conn)) {
796
0
    case 30:
797
0
      if(!(m->data->state.http_neg.allowed & CURL_HTTP_V3x)) {
798
0
        DEBUGF(infof(m->data, "not reusing conn #%" CURL_FORMAT_CURL_OFF_T
799
0
                     ", we do not want h3", conn->connection_id));
800
0
        return FALSE;
801
0
      }
802
0
      break;
803
279
    case 20:
804
279
      if(!(m->data->state.http_neg.allowed & CURL_HTTP_V2x)) {
805
143
        DEBUGF(infof(m->data, "not reusing conn #%" CURL_FORMAT_CURL_OFF_T
806
143
                     ", we do not want h2", conn->connection_id));
807
143
        return FALSE;
808
143
      }
809
136
      break;
810
5.76k
    default:
811
5.76k
      if(!(m->data->state.http_neg.allowed & CURL_HTTP_V1x)) {
812
6
        DEBUGF(infof(m->data, "not reusing conn #%" CURL_FORMAT_CURL_OFF_T
813
6
                     ", we do not want h1", conn->connection_id));
814
6
        return FALSE;
815
6
      }
816
5.75k
      break;
817
6.03k
    }
818
6.03k
  }
819
22.8k
  return TRUE;
820
23.0k
}
821
#else
822
#define url_match_http_multiplex(c, m) ((void)(c), (void)(m), TRUE)
823
#define url_match_http_version(c, m)   ((void)(c), (void)(m), TRUE)
824
#endif
825
826
static bool url_match_proto_config(struct connectdata *conn,
827
                                   struct url_conn_match *m)
828
23.0k
{
829
23.0k
  if(!url_match_http_version(conn, m))
830
149
    return FALSE;
831
832
#ifdef USE_SSH
833
  if(get_protocol_family(m->needle->scheme) & PROTO_FAMILY_SSH) {
834
    if(!ssh_config_matches(m->needle, conn))
835
      return FALSE;
836
  }
837
#endif
838
22.8k
#ifndef CURL_DISABLE_FTP
839
22.8k
  else if(get_protocol_family(m->needle->scheme) & PROTO_FAMILY_FTP) {
840
143
    if(!Curl_ftp_conns_match(m->needle, conn))
841
0
      return FALSE;
842
143
  }
843
22.8k
#endif
844
22.8k
  return TRUE;
845
23.0k
}
846
847
static bool url_match_auth(struct connectdata *conn,
848
                           struct url_conn_match *m)
849
23.0k
{
850
23.0k
  if(!Curl_creds_same(m->needle->creds, conn->creds)) {
851
13
    if(m->needle->creds)
852
10
      return FALSE;
853
3
    if(!Curl_creds_same(m->data->state.creds, conn->creds))
854
3
      return FALSE;
855
3
  }
856
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
857
  /* GSS delegation differences do not actually affect every connection and
858
     auth method, but this check takes precaution before efficiency */
859
  if(m->needle->gssapi_delegation != conn->gssapi_delegation)
860
    return FALSE;
861
#endif
862
863
23.0k
  return TRUE;
864
23.0k
}
865
866
static bool url_match_destination(struct connectdata *conn,
867
                                  struct url_conn_match *m)
868
26.6k
{
869
  /* Different connect-to peers never match */
870
26.6k
  if(!Curl_peer_same_destination(m->needle->via_peer, conn->via_peer))
871
0
    return FALSE;
872
873
26.6k
  if(m->needle->origin->scheme != conn->origin->scheme) {
874
    /* `needle` and `conn` not having the same scheme.
875
     * This is allowed for the same family *if* conn is using TLS.
876
     * - IMAP+STARTTLS works for IMAPS.
877
     * - IMAPS works for IMAP. */
878
10
    if(get_protocol_family(conn->origin->scheme) !=
879
10
       m->needle->scheme->protocol) {
880
10
      return FALSE;
881
10
    }
882
10
  }
883
  /* Scheme mismatch is acceptable, compare hostname/port */
884
26.6k
  return Curl_peer_same_destination(m->needle->origin, conn->origin);
885
26.6k
}
886
887
static bool url_match_ssl_config(struct connectdata *conn,
888
                                 struct url_conn_match *m)
889
23.0k
{
890
  /* If talking/upgrading to TLS, conn needs to use the same SSL options. */
891
23.0k
  if(((m->needle->scheme->flags & PROTOPT_SSL) || m->may_tls) &&
892
73
     !Curl_ssl_conn_config_match(m->data, conn, FALSE)) {
893
0
    DEBUGF(infof(m->data, "Connection #%" FMT_OFF_T
894
0
                 " has different SSL parameters, cannot reuse",
895
0
                 conn->connection_id));
896
0
    return FALSE;
897
0
  }
898
23.0k
  return TRUE;
899
23.0k
}
900
901
#if defined(USE_SPNEGO) || defined(USE_NTLM)
902
static bool url_allow_sspi_empty_creds(struct Curl_creds *conn_creds,
903
                                       struct Curl_easy *data,
904
                                       struct connectdata *conn)
905
{
906
#ifdef USE_WINDOWS_SSPI
907
  /* Empty user: SSPI on Windows can make use of an "ambient"
908
   * user from a "SecurityToken" associated with the current thread or
909
   * process. This token can be switched at any time. We are therefore
910
   * not able to find out reliably what token the connection really
911
   * used, nor what token in the next connect attempt will use.
912
   * To avoid TOCTOU attacks, do not reuse on empty credentials
913
   * UNLESS this connection is the one used by this transfer before. */
914
  if(!Curl_creds_has_user(conn_creds) &&
915
     (data->state.lastconnect_id != conn->connection_id))
916
    return FALSE;
917
#else
918
  (void)conn_creds;
919
  (void)data;
920
  (void)conn;
921
#endif
922
  return TRUE;
923
}
924
#endif /* USE_SPNEGO || USE_NTLM */
925
926
#ifdef USE_NTLM
927
static bool url_match_auth_ntlm(struct connectdata *conn,
928
                                struct url_conn_match *m)
929
{
930
  if(conn->http_ntlm_state != NTLMSTATE_NONE) {
931
    /* Connection is using NTLM. We cannot reuse if transfer
932
     * has different Auth input parameters. */
933
    if(!m->want_ntlm_http ||
934
       !Curl_creds_same(conn->creds, m->data->state.creds) ||
935
       !Curl_peer_equal(conn->creds_origin, m->data->state.origin))
936
      return FALSE;
937
    /* Empty credentials need more careful matching for WINDOWS_SSPI */
938
    if(!url_allow_sspi_empty_creds(conn->creds, m->data, conn))
939
      return FALSE;
940
  }
941
  else if(m->want_ntlm_http) {
942
    /* Transfer wants NTLM, connection is not using it.
943
     * Do not reuse when connection has credentials and they differ. */
944
    if(conn->creds &&
945
       (!Curl_creds_same(conn->creds, m->data->state.creds) ||
946
        !Curl_peer_equal(conn->creds_origin, m->data->state.origin)))
947
      return FALSE;
948
  }
949
950
#ifndef CURL_DISABLE_PROXY
951
  /* Same for Proxy NTLM authentication */
952
  if(conn->proxy_ntlm_state != NTLMSTATE_NONE) {
953
    if(!m->want_proxy_ntlm_http ||
954
       !Curl_creds_same(m->needle->http_proxy.creds, conn->http_proxy.creds))
955
      return FALSE;
956
    if(!url_allow_sspi_empty_creds(m->needle->http_proxy.creds,
957
                                   m->data, conn))
958
      return FALSE;
959
  }
960
  else if(m->want_proxy_ntlm_http) {
961
    if(conn->http_proxy.creds &&
962
       !Curl_creds_same(m->needle->http_proxy.creds, conn->http_proxy.creds))
963
      return FALSE;
964
  }
965
#endif
966
  if(m->want_ntlm_http || m->want_proxy_ntlm_http) {
967
    /* Credentials are already checked, we may use this connection.
968
     * With NTLM being weird as it is, we MUST use a
969
     * connection where it has already been fully negotiated.
970
     * If it has not, we keep on looking for a better one. */
971
    m->found = conn;
972
973
    if((m->want_ntlm_http &&
974
       (conn->http_ntlm_state != NTLMSTATE_NONE)) ||
975
        (m->want_proxy_ntlm_http &&
976
         (conn->proxy_ntlm_state != NTLMSTATE_NONE))) {
977
      /* We must use this connection, no other */
978
      m->force_reuse = TRUE;
979
      return TRUE;
980
    }
981
    /* Continue look up for a better connection */
982
    return FALSE;
983
  }
984
  return TRUE;
985
}
986
#else
987
22.8k
#define url_match_auth_ntlm(c, m) ((void)(c), (void)(m), TRUE)
988
#endif
989
990
#ifdef USE_SPNEGO
991
static bool url_match_auth_nego(struct connectdata *conn,
992
                                struct url_conn_match *m)
993
{
994
  if(conn->http_negotiate_state != GSS_AUTHNONE) {
995
    /* Connection is using Negotiate. We cannot reuse if transfer
996
     * has different Auth input parameters. */
997
    if(!m->want_nego_http ||
998
       !Curl_creds_same(conn->creds, m->data->state.creds) ||
999
       !Curl_peer_equal(conn->creds_origin, m->data->state.origin))
1000
      return FALSE;
1001
    if(!url_allow_sspi_empty_creds(conn->creds, m->data, conn))
1002
      return FALSE;
1003
  }
1004
  else if(m->want_nego_http) {
1005
    /* Transfer wants Negotiate, connection is not using it.
1006
     * Do not reuse when connection has credentials and they differ. */
1007
    if(conn->creds &&
1008
       (!Curl_creds_same(conn->creds, m->data->state.creds) ||
1009
        !Curl_peer_equal(conn->creds_origin, m->data->state.origin)))
1010
      return FALSE;
1011
  }
1012
1013
#ifndef CURL_DISABLE_PROXY
1014
  /* Same for Proxy Negotiate authentication */
1015
  if(conn->proxy_negotiate_state != GSS_AUTHNONE) {
1016
    if(!m->want_proxy_nego_http ||
1017
       !Curl_creds_same(m->needle->http_proxy.creds, conn->http_proxy.creds))
1018
      return FALSE;
1019
    if(!url_allow_sspi_empty_creds(m->needle->http_proxy.creds,
1020
                                   m->data, conn))
1021
      return FALSE;
1022
  }
1023
  else if(m->want_proxy_nego_http) {
1024
    if(conn->http_proxy.creds &&
1025
       !Curl_creds_same(m->needle->http_proxy.creds, conn->http_proxy.creds))
1026
      return FALSE;
1027
  }
1028
#endif
1029
  if(m->want_nego_http || m->want_proxy_nego_http) {
1030
    /* Credentials are already checked, we may use this connection. We MUST
1031
     * use a connection where it has already been fully negotiated. If it has
1032
     * not, we keep on looking for a better one. */
1033
    m->found = conn;
1034
    if((m->want_nego_http &&
1035
        (conn->http_negotiate_state != GSS_AUTHNONE)) ||
1036
       (m->want_proxy_nego_http &&
1037
        (conn->proxy_negotiate_state != GSS_AUTHNONE))) {
1038
      /* We must use this connection, no other */
1039
      m->force_reuse = TRUE;
1040
      return TRUE;
1041
    }
1042
    return FALSE; /* get another */
1043
  }
1044
  return TRUE;
1045
}
1046
#else
1047
22.8k
#define url_match_auth_nego(c, m) ((void)(c), (void)(m), TRUE)
1048
#endif
1049
1050
static bool url_match_conn(struct connectdata *conn, void *userdata)
1051
26.6k
{
1052
26.6k
  struct url_conn_match *m = userdata;
1053
  /* Check if `conn` can be used for transfer `m->data` */
1054
1055
  /* general connect config setting match? */
1056
26.6k
  if(!url_match_connect_config(conn, m))
1057
38
    return FALSE;
1058
1059
  /* match for destination and protocol? */
1060
26.6k
  if(!url_match_destination(conn, m))
1061
65
    return FALSE;
1062
1063
26.5k
  if(!url_match_fully_connected(conn, m))
1064
3.52k
    return FALSE;
1065
1066
23.0k
  if(!url_match_multiplex_needs(conn, m))
1067
0
    return FALSE;
1068
1069
23.0k
  if(!url_match_ssl_use(conn, m))
1070
10
    return FALSE;
1071
1072
23.0k
  if(!url_match_proxy_use(conn, m))
1073
0
    return FALSE;
1074
23.0k
  if(!url_match_ssl_config(conn, m))
1075
0
    return FALSE;
1076
1077
23.0k
  if(!url_match_http_multiplex(conn, m))
1078
0
    return FALSE;
1079
23.0k
  else if(m->wait_pipe)
1080
    /* wait on multiplexing */
1081
0
    return TRUE;
1082
1083
23.0k
  if(!url_match_auth(conn, m))
1084
13
    return FALSE;
1085
1086
23.0k
  if(!url_match_proto_config(conn, m))
1087
149
    return FALSE;
1088
1089
22.8k
  if(!url_match_auth_ntlm(conn, m))
1090
0
    return FALSE;
1091
22.8k
  else if(m->force_reuse)
1092
0
    return TRUE;
1093
1094
22.8k
  if(!url_match_auth_nego(conn, m))
1095
0
    return FALSE;
1096
22.8k
  else if(m->force_reuse)
1097
0
    return TRUE;
1098
1099
22.8k
  if(!url_match_multiplex_limits(conn, m))
1100
0
    return FALSE;
1101
1102
22.8k
  if(m->data->set.conn_max_age_ms > 0) {
1103
22.8k
    timediff_t age_ms = curlx_ptimediff_ms(&m->now, &conn->created);
1104
22.8k
    if(age_ms > m->data->set.conn_max_age_ms) {
1105
      /* Transfer is looking for a younger connection. */
1106
0
      if(!CONN_INUSE(conn))
1107
0
        Curl_conn_close(m->data, conn, FALSE);
1108
0
      return FALSE;
1109
0
    }
1110
22.8k
  }
1111
1112
  /* If we are going to pick an idle connection, do an extra
1113
   * health check before we reuse it. */
1114
22.8k
  if(!CONN_INUSE(conn) &&
1115
22.8k
     !Curl_cpool_conn_seems_healthy(conn, m->data, &m->now)) {
1116
0
    infof(m->data, "Connection %" FMT_OFF_T " seems to be dead, terminating",
1117
0
          conn->connection_id);
1118
0
    Curl_conn_close(m->data, conn, FALSE);
1119
0
    return FALSE;
1120
0
  }
1121
1122
  /* conn matches our needs. */
1123
22.8k
  m->found = conn;
1124
22.8k
  return TRUE;
1125
22.8k
}
1126
1127
static bool url_match_result(void *userdata)
1128
146k
{
1129
146k
  struct url_conn_match *match = userdata;
1130
146k
  if(match->found) {
1131
    /* Attach it now while still under lock, so the connection does
1132
     * no longer appear idle and can be reaped. */
1133
22.8k
    Curl_attach_connection(match->data, match->found, TRUE);
1134
22.8k
    return TRUE;
1135
22.8k
  }
1136
123k
  else if(match->seen_single_use_conn && !match->seen_multiplex_conn) {
1137
    /* We have seen a single-use, existing connection to the destination and
1138
     * no multiplexed one. It seems safe to assume that the server does
1139
     * not support multiplexing. */
1140
0
    match->wait_pipe = FALSE;
1141
0
  }
1142
123k
  else if(match->seen_pending_conn && match->data->set.pipewait) {
1143
3.03k
    infof(match->data,
1144
3.03k
          "Found pending candidate for reuse and CURLOPT_PIPEWAIT is set");
1145
3.03k
    match->wait_pipe = TRUE;
1146
3.03k
  }
1147
123k
  match->force_reuse = FALSE;
1148
123k
  return FALSE;
1149
146k
}
1150
1151
/*
1152
 * Given a transfer and a prototype connection (needle),
1153
 * find and attach an existing connection that matches.
1154
 *
1155
 * Return TRUE if an existing connection was attached.
1156
 * `waitpipe` is TRUE if no existing connection matched, but there
1157
 * might be suitable one in the near future (common cause: multiplexing
1158
 * capability has not been determined yet, e.g. ALPN handshake).
1159
 */
1160
static bool url_attach_existing(struct Curl_easy *data,
1161
                                struct connectdata *needle,
1162
                                bool *waitpipe)
1163
146k
{
1164
146k
  struct cpool *cpool = Curl_cpool_get_instance(data);
1165
146k
  struct url_conn_match match;
1166
146k
  bool success;
1167
1168
146k
  DEBUGASSERT(!data->conn);
1169
1170
146k
  memset(&match, 0, sizeof(match));
1171
146k
  match.data = data;
1172
146k
  match.needle = needle;
1173
146k
  match.now = *Curl_pgrs_now(data);
1174
146k
  match.may_multiplex = xfer_may_multiplex(data, needle);
1175
1176
146k
  Curl_cpool_prune_dead(cpool, data);
1177
1178
#ifdef USE_NTLM
1179
  match.want_ntlm_http =
1180
    (data->state.authhost.want & CURLAUTH_NTLM) &&
1181
    (needle->scheme->protocol & PROTO_FAMILY_HTTP);
1182
#ifndef CURL_DISABLE_PROXY
1183
  match.want_proxy_ntlm_http =
1184
    needle->http_proxy.creds &&
1185
    (data->state.authproxy.want & CURLAUTH_NTLM) &&
1186
    (needle->scheme->protocol & PROTO_FAMILY_HTTP);
1187
#endif
1188
#endif
1189
1190
#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO)
1191
  match.want_nego_http =
1192
    (data->state.authhost.want & CURLAUTH_NEGOTIATE) &&
1193
    (needle->scheme->protocol & PROTO_FAMILY_HTTP);
1194
#ifndef CURL_DISABLE_PROXY
1195
  match.want_proxy_nego_http =
1196
    needle->http_proxy.creds &&
1197
    (data->state.authproxy.want & CURLAUTH_NEGOTIATE) &&
1198
    (needle->scheme->protocol & PROTO_FAMILY_HTTP);
1199
#endif
1200
#endif
1201
146k
  match.require_tls = data->set.use_ssl >= CURLUSESSL_CONTROL;
1202
146k
  match.may_tls = data->set.use_ssl > CURLUSESSL_NONE;
1203
1204
  /* Find a connection in the pool that matches what "data + needle"
1205
   * requires. If a suitable candidate is found, it is attached to "data". */
1206
146k
  success = Curl_cpool_find(data, needle->destination,
1207
146k
                            url_match_conn, url_match_result, &match);
1208
1209
  /* wait_pipe is TRUE if we encounter a bundle that is undecided. There
1210
   * is no matching connection then, yet. */
1211
146k
  *waitpipe = (bool)match.wait_pipe;
1212
146k
  return success;
1213
146k
}
1214
1215
/*
1216
 * Allocate and initialize a new connectdata object.
1217
 */
1218
static struct connectdata *allocate_conn(struct Curl_easy *data)
1219
177k
{
1220
177k
  struct connectdata *conn = curlx_calloc(1, sizeof(struct connectdata));
1221
177k
  if(!conn)
1222
0
    return NULL;
1223
1224
  /* and we setup a few fields in case we end up actually using this struct */
1225
1226
177k
  conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD;     /* no file descriptor */
1227
177k
  conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
1228
177k
  conn->recv_idx = 0; /* default for receiving transfer data */
1229
177k
  conn->send_idx = 0; /* default for sending transfer data */
1230
177k
  conn->connection_id = -1;    /* no ID */
1231
177k
  conn->attached_xfers = 0;
1232
1233
  /* Remember time this connection started */
1234
177k
  conn->lastused = conn->lastupkeep = conn->created = *Curl_pgrs_now(data);
1235
1236
177k
#ifndef CURL_DISABLE_FTP
1237
177k
  conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
1238
177k
  conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
1239
177k
#endif
1240
177k
  conn->ip_version = data->set.ipver;
1241
177k
  conn->bits.connect_only = (bool)data->set.connect_only;
1242
177k
  conn->transport_wanted = TRNSPRT_TCP; /* most of them are TCP streams */
1243
1244
  /* Store the local bind parameters that will be used for this connection */
1245
177k
  if(CURL_EASY_STR(data, STRING_DEVICE)) {
1246
5.27k
    conn->localdev = curlx_strdup(CURL_EASY_STR(data, STRING_DEVICE));
1247
5.27k
    if(!conn->localdev)
1248
0
      goto error;
1249
5.27k
  }
1250
177k
#ifndef CURL_DISABLE_BINDLOCAL
1251
177k
  conn->localportrange = data->set.localportrange;
1252
177k
  conn->localport = data->set.localport;
1253
177k
#endif
1254
1255
  /* the close socket stuff needs to be copied to the connection struct as
1256
     it may live on without (this specific) Curl_easy */
1257
177k
  conn->fclosesocket = data->set.fclosesocket;
1258
177k
  conn->closesocket_client = data->set.closesocket_client;
1259
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
1260
  conn->gssapi_delegation = data->set.gssapi_delegation;
1261
#endif
1262
177k
  return conn;
1263
0
error:
1264
1265
0
  curlx_free(conn->localdev);
1266
0
  curlx_free(conn);
1267
0
  return NULL;
1268
177k
}
1269
1270
static CURLcode url_set_conn_scheme(struct Curl_easy *data,
1271
                                    struct connectdata *conn,
1272
                                    const struct Curl_scheme *scheme)
1273
177k
{
1274
  /* URL scheme is usable for connection when it is
1275
   * - allowed
1276
   * - not from a redirect or an allowed redirect protocol */
1277
177k
  if(scheme->run &&
1278
177k
     (data->set.allowed_protocols & scheme->protocol) &&
1279
166k
     (!data->state.this_is_a_follow ||
1280
166k
       (data->set.redir_protocols & scheme->protocol))) {
1281
166k
    conn->scheme = conn->given = scheme;
1282
166k
    return CURLE_OK;
1283
166k
  }
1284
11.4k
  if(scheme->flags & PROTOPT_NO_TRANSFER)
1285
10
    failf(data, "Protocol \"%s\" is not for transfers", scheme->name);
1286
11.3k
  else
1287
11.3k
    failf(data, "Protocol \"%s\" is disabled%s", scheme->name,
1288
11.3k
          data->state.this_is_a_follow ? " (in redirect)" : "");
1289
11.4k
  return CURLE_UNSUPPORTED_PROTOCOL;
1290
177k
}
1291
1292
CURLcode Curl_uc_to_curlcode(CURLUcode uc)
1293
13.1k
{
1294
13.1k
  switch(uc) {
1295
13.0k
  default:
1296
13.0k
    return CURLE_URL_MALFORMAT;
1297
34
  case CURLUE_UNSUPPORTED_SCHEME:
1298
34
    return CURLE_UNSUPPORTED_PROTOCOL;
1299
0
  case CURLUE_OUT_OF_MEMORY:
1300
0
    return CURLE_OUT_OF_MEMORY;
1301
14
  case CURLUE_USER_NOT_ALLOWED:
1302
14
    return CURLE_LOGIN_DENIED;
1303
13.1k
  }
1304
13.1k
}
1305
1306
#ifndef CURL_DISABLE_HSTS
1307
static CURLcode hsts_upgrade(struct Curl_easy *data,
1308
                             CURLU *uh,
1309
                             uint16_t port_override,
1310
                             uint32_t scope_id)
1311
178k
{
1312
  /* HSTS upgrade */
1313
178k
  if(data->hsts && (data->state.origin->scheme == &Curl_scheme_http) &&
1314
59.5k
     Curl_hsts_applies(data->hsts, data->state.origin)) {
1315
1
    char *url;
1316
1
    CURLUcode uc;
1317
1
    CURLcode result;
1318
1319
1
    uc = curl_url_set(uh, CURLUPART_SCHEME, "https", 0);
1320
1
    if(uc)
1321
0
      return Curl_uc_to_curlcode(uc);
1322
1
    Curl_bufref_free(&data->state.url);
1323
    /* after update, get the updated version */
1324
1
    uc = curl_url_get(uh, CURLUPART_URL, &url, 0);
1325
1
    if(uc)
1326
0
      return Curl_uc_to_curlcode(uc);
1327
1
    Curl_bufref_set(&data->state.url, url, 0, curl_free);
1328
1329
1
    result = Curl_peer_from_url(uh, data, port_override, scope_id,
1330
1
                                &data->state.origin);
1331
1
    if(result)
1332
0
      return result;
1333
1
    infof(data, "Switched from HTTP to HTTPS due to HSTS => %s", url);
1334
1
  }
1335
178k
  return CURLE_OK;
1336
178k
}
1337
#else
1338
#define hsts_upgrade(x, y, z, a) CURLE_OK
1339
#endif
1340
1341
static bool str_has_ctrl(const char *input)
1342
31.5k
{
1343
31.5k
  if(input) {
1344
31.5k
    const unsigned char *str = (const unsigned char *)input;
1345
3.39M
    while(*str) {
1346
3.35M
      if(*str < 0x20)
1347
111
        return TRUE;
1348
3.35M
      str++;
1349
3.35M
    }
1350
31.5k
  }
1351
31.4k
  return FALSE;
1352
31.5k
}
1353
1354
#ifndef CURL_DISABLE_NETRC
1355
/*
1356
 * Override the login details from the URL with that in the CURLOPT_USERPWD
1357
 * option or a .netrc file, if applicable.
1358
 */
1359
static CURLcode url_set_data_creds_netrc(struct Curl_easy *data,
1360
                                         struct Curl_creds **pcreds)
1361
177k
{
1362
177k
  struct Curl_creds *ncreds_out = NULL;
1363
177k
  CURLcode result = CURLE_OK;
1364
1365
177k
  if(data->set.use_netrc) { /* not CURL_NETRC_IGNORED */
1366
4.18k
    struct Curl_creds *ncreds_in = NULL;
1367
4.18k
    bool scan_netrc = TRUE;
1368
4.18k
    NETRCcode ret;
1369
4.18k
    CURLUcode uc;
1370
1371
4.18k
    if(*pcreds) {
1372
3.36k
      switch((*pcreds)->source) {
1373
204
      case CREDS_OPTION:
1374
        /* we never override credentials set via CURLOPT_*, leave. */
1375
204
        scan_netrc = FALSE;
1376
204
        break;
1377
3.16k
      case CREDS_URL: /* only apply when netrc is not required */
1378
3.16k
        if(data->set.use_netrc == CURL_NETRC_REQUIRED) {
1379
          /* We ignore password from URL */
1380
2.25k
          ncreds_in = *pcreds;
1381
2.25k
        }
1382
911
        else if(!Curl_creds_has_user(*pcreds) ||
1383
768
                !Curl_creds_has_passwd(*pcreds)) {
1384
          /* We use netrc to complete what is missing */
1385
768
          ncreds_in = *pcreds;
1386
768
        }
1387
143
        else
1388
143
          scan_netrc = FALSE;
1389
3.16k
        break;
1390
0
      default: /* ignore credentials from other sources */
1391
0
        break;
1392
3.36k
      }
1393
3.36k
    }
1394
1395
4.18k
    if(!scan_netrc)
1396
347
      goto out;
1397
1398
3.83k
    ret = Curl_netrc_scan(data, &data->state.netrc,
1399
3.83k
                          data->state.origin->hostname,
1400
3.83k
                          Curl_creds_user(ncreds_in),
1401
3.83k
                          CURL_EASY_STR(data, STRING_NETRC_FILE),
1402
3.83k
                          &ncreds_out);
1403
3.83k
    DEBUGASSERT(!ret || !ncreds_out);
1404
3.83k
    if(ret == NETRC_OUT_OF_MEMORY) {
1405
0
      result = CURLE_OUT_OF_MEMORY;
1406
0
      goto out;
1407
0
    }
1408
3.83k
    else if(ret && ((ret == NETRC_NO_MATCH) ||
1409
3.83k
                    (data->set.use_netrc == CURL_NETRC_OPTIONAL))) {
1410
3.83k
      infof(data, "Could not find host %s in the %s file; using defaults",
1411
3.83k
            data->state.origin->hostname,
1412
3.83k
            (CURL_EASY_STR(data, STRING_NETRC_FILE) ?
1413
3.83k
             CURL_EASY_STR(data, STRING_NETRC_FILE) : ".netrc"));
1414
3.83k
    }
1415
0
    else if(ret) {
1416
0
      const char *m = Curl_netrc_strerror(ret);
1417
0
      failf(data, ".netrc error: %s", m);
1418
0
      result = CURLE_READ_ERROR;
1419
0
      goto out;
1420
0
    }
1421
0
    else if(ncreds_out) {
1422
0
      if(!(data->state.origin->scheme->flags & PROTOPT_USERPWDCTRL)) {
1423
        /* if the protocol cannot handle control codes in credentials, make
1424
           sure there are none */
1425
0
        if(str_has_ctrl(ncreds_out->user) ||
1426
0
           str_has_ctrl(ncreds_out->passwd)) {
1427
0
          failf(data, "control code detected in .netrc credentials");
1428
0
          result = CURLE_READ_ERROR;
1429
0
          goto out;
1430
0
        }
1431
0
      }
1432
0
      CURL_TRC_M(data, "netrc: using credentials for %s as %s",
1433
0
                 data->state.origin->hostname, ncreds_out->user);
1434
0
      result = Curl_creds_merge(ncreds_out->user, ncreds_out->passwd,
1435
0
                                *pcreds, CREDS_NETRC, pcreds);
1436
0
      if(result)
1437
0
        goto out;
1438
      /* for updated strings, we update them in the URL */
1439
0
      uc = curl_url_set(data->state.uh, CURLUPART_USER,
1440
0
                        Curl_creds_user(*pcreds), CURLU_URLENCODE);
1441
0
      if(!uc)
1442
0
        uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD,
1443
0
                          Curl_creds_passwd(*pcreds),
1444
0
                          CURLU_URLENCODE);
1445
0
      if(uc)
1446
0
        result = Curl_uc_to_curlcode(uc);
1447
0
    }
1448
0
    else
1449
0
      DEBUGASSERT(0);
1450
3.83k
  }
1451
1452
177k
#ifdef CURLVERBOSE
1453
177k
  Curl_creds_trace(data, data->state.creds, "transfer credentials");
1454
177k
#endif
1455
1456
177k
out:
1457
177k
  Curl_creds_unlink(&ncreds_out);
1458
177k
  return result;
1459
177k
}
1460
#endif /* CURL_DISABLE_NETRC */
1461
1462
static CURLcode url_set_data_creds(struct Curl_easy *data, CURLU *uh)
1463
178k
{
1464
178k
  struct Curl_creds *newcreds = NULL;
1465
178k
  CURLcode result = CURLE_OK;
1466
1467
178k
  if((CURL_EASY_STR(data, STRING_USERNAME) ||
1468
170k
      CURL_EASY_STR(data, STRING_PASSWORD) ||
1469
163k
      CURL_EASY_STR(data, STRING_BEARER) ||
1470
160k
      CURL_EASY_STR(data, STRING_SASL_AUTHZID) ||
1471
160k
      CURL_EASY_STR(data, STRING_SERVICE_NAME)) &&
1472
19.4k
     Curl_auth_allowed_to_origin(data, data->state.origin)) {
1473
19.4k
    result = Curl_creds_create(CURL_EASY_STR(data, STRING_USERNAME),
1474
19.4k
                               CURL_EASY_STR(data, STRING_PASSWORD),
1475
19.4k
                               CURL_EASY_STR(data, STRING_BEARER),
1476
19.4k
                               CURL_EASY_STR(data, STRING_SASL_AUTHZID),
1477
19.4k
                               CURL_EASY_STR(data, STRING_SERVICE_NAME),
1478
19.4k
                               CREDS_OPTION, &newcreds);
1479
19.4k
    if(result)
1480
0
      goto out;
1481
19.4k
    if(newcreds &&
1482
17.2k
       !(data->state.origin->scheme->flags & PROTOPT_USERPWDCTRL) &&
1483
15.7k
       (str_has_ctrl(Curl_creds_user(newcreds)) ||
1484
15.7k
        str_has_ctrl(Curl_creds_passwd(newcreds)))) {
1485
      /* if the protocol cannot handle control codes in credentials, make
1486
         sure there are none */
1487
111
      failf(data, "control code detected in credentials");
1488
111
      result = CURLE_BAD_FUNCTION_ARGUMENT;
1489
111
      goto out;
1490
111
    }
1491
19.4k
  }
1492
1493
  /* Extract credentials from the URL only if there are none OR
1494
   * if no CURLOPT_USER was set. */
1495
177k
  if(!newcreds || !Curl_creds_has_user(newcreds)) {
1496
174k
    char *user = NULL;
1497
174k
    char *passwd = NULL;
1498
174k
    char *udecoded = NULL;
1499
174k
    char *pdecoded = NULL;
1500
174k
    CURLUcode uc;
1501
1502
174k
    uc = curl_url_get(uh, CURLUPART_USER, &user, 0);
1503
174k
    if(uc && (uc != CURLUE_NO_USER))
1504
0
      result = Curl_uc_to_curlcode(uc);
1505
174k
    if(!result) {
1506
174k
      uc = curl_url_get(uh, CURLUPART_PASSWORD, &passwd, 0);
1507
174k
      if(uc && (uc != CURLUE_NO_PASSWORD))
1508
0
        result = Curl_uc_to_curlcode(uc);
1509
174k
    }
1510
174k
    if(!result && user) {
1511
22.8k
      result = Curl_urldecode(user, 0, &udecoded, NULL,
1512
22.8k
                              (data->state.origin->scheme->flags &
1513
22.8k
                               PROTOPT_USERPWDCTRL) ?
1514
13.5k
                              REJECT_ZERO : REJECT_CTRL);
1515
22.8k
    }
1516
174k
    if(!result && passwd) {
1517
3.90k
      result = Curl_urldecode(passwd, 0, &pdecoded, NULL,
1518
3.90k
                              (data->state.origin->scheme->flags &
1519
3.90k
                               PROTOPT_USERPWDCTRL) ?
1520
2.04k
                              REJECT_ZERO : REJECT_CTRL);
1521
3.90k
    }
1522
174k
    if(!result)
1523
174k
      result = Curl_creds_merge(udecoded, pdecoded, newcreds,
1524
174k
                                CREDS_URL, &newcreds);
1525
1526
174k
    curlx_free(udecoded);
1527
174k
    curlx_free(pdecoded);
1528
174k
    curlx_free(passwd);
1529
174k
    curlx_free(user);
1530
174k
    if(result) {
1531
53
      failf(data, "error extracting credentials from URL");
1532
53
      goto out;
1533
53
    }
1534
174k
  }
1535
1536
177k
#ifndef CURL_DISABLE_NETRC
1537
  /* Check for overridden login details and set them accordingly so that
1538
     they are known when protocol->setup_connection is called! */
1539
177k
  result = url_set_data_creds_netrc(data, &newcreds);
1540
177k
#endif /* CURL_DISABLE_NETRC */
1541
1542
178k
out:
1543
178k
  if(!result && !Curl_creds_equal(data->state.creds, newcreds)) {
1544
    /* Do we have more things to trigger on credentials change? */
1545
21.8k
    Curl_creds_link(&data->state.creds, newcreds);
1546
21.8k
  }
1547
178k
  Curl_creds_unlink(&newcreds);
1548
178k
  return result;
1549
177k
}
1550
1551
static CURLcode url_set_conn_origin_etc(struct Curl_easy *data,
1552
                                        struct connectdata *conn)
1553
177k
{
1554
177k
  CURLcode result = CURLE_OK;
1555
1556
177k
  Curl_peer_link(&conn->origin, data->state.origin);
1557
1558
  /* set the connection scheme */
1559
177k
  result = url_set_conn_scheme(data, conn, conn->origin->scheme);
1560
177k
  if(result)
1561
11.4k
    goto out;
1562
1563
  /* set the connection options */
1564
166k
  if(CURL_EASY_STR(data, STRING_OPTIONS)) {
1565
3.03k
    conn->options = curlx_strdup(CURL_EASY_STR(data, STRING_OPTIONS));
1566
3.03k
    if(!conn->options) {
1567
0
      result = CURLE_OUT_OF_MEMORY;
1568
0
      goto out;
1569
0
    }
1570
3.03k
  }
1571
163k
  else if(data->state.up.options) {
1572
119
    conn->options = curlx_strdup(data->state.up.options);
1573
119
    if(!conn->options) {
1574
0
      result = CURLE_OUT_OF_MEMORY;
1575
0
      goto out;
1576
0
    }
1577
119
  }
1578
1579
166k
#ifdef USE_IPV6
1580
166k
  conn->scope_id = data->set.scope_id ?
1581
162k
                   data->set.scope_id : data->state.origin->scopeid;
1582
166k
#endif
1583
1584
177k
out:
1585
177k
  return result;
1586
166k
}
1587
1588
/*
1589
 * If we are doing a resumed transfer, we need to setup our stuff
1590
 * properly.
1591
 */
1592
static CURLcode setup_range(struct Curl_easy *data)
1593
162k
{
1594
162k
  struct UrlState *s = &data->state;
1595
162k
  s->resume_from = data->set.set_resume_from;
1596
162k
  if(s->resume_from || CURL_EASY_STR(data, STRING_SET_RANGE)) {
1597
5.16k
    if(s->rangestringalloc)
1598
1.84k
      curlx_free(s->range);
1599
1600
5.16k
    if(s->resume_from)
1601
2.32k
      s->range = curl_maprintf("%" FMT_OFF_T "-", s->resume_from);
1602
2.83k
    else
1603
2.83k
      s->range = curlx_strdup(CURL_EASY_STR(data, STRING_SET_RANGE));
1604
1605
5.16k
    if(!s->range)
1606
0
      return CURLE_OUT_OF_MEMORY;
1607
1608
5.16k
    s->rangestringalloc = TRUE;
1609
1610
    /* tell ourselves to fetch this range */
1611
5.16k
    s->use_range = TRUE;        /* enable range download */
1612
5.16k
  }
1613
157k
  else
1614
157k
    s->use_range = FALSE; /* disable range download */
1615
1616
162k
  return CURLE_OK;
1617
162k
}
1618
1619
/*
1620
 * setup_connection_internals() -
1621
 *
1622
 * Setup connection internals specific to the requested protocol in the
1623
 * Curl_easy. This is inited and setup before the connection is made but
1624
 * is about the particular protocol that is to be used.
1625
 *
1626
 * This MUST get called after proxy magic has been figured out.
1627
 */
1628
static CURLcode setup_connection_internals(struct Curl_easy *data,
1629
                                           struct connectdata *conn)
1630
166k
{
1631
166k
  struct Curl_peer *peer = NULL;
1632
166k
  CURLcode result;
1633
1634
166k
  if(conn->scheme->run->setup_connection) {
1635
153k
    result = conn->scheme->run->setup_connection(data, conn);
1636
153k
    if(result)
1637
121
      return result;
1638
153k
  }
1639
1640
  /* Now create the destination name */
1641
166k
  peer = Curl_conn_get_destination(conn, FIRSTSOCKET);
1642
166k
  if(!peer)
1643
0
    return CURLE_FAILED_INIT;
1644
1645
  /* IPv6 addresses with a scope_id (0 is default == global) have a
1646
   * printable representation with a '%<scope_id>' suffix. */
1647
166k
  if(peer->ipv6)
1648
639
    if(peer->scopeid)
1649
65
      conn->destination = curl_maprintf("[%s%%%u]:%u",
1650
65
        peer->hostname, peer->scopeid, peer->port);
1651
574
    else
1652
574
      conn->destination = curl_maprintf("[%s]:%u",
1653
574
        peer->hostname, peer->port);
1654
165k
  else
1655
165k
    conn->destination = curl_maprintf("%s:%u", peer->hostname, peer->port);
1656
166k
  if(!conn->destination)
1657
0
    return CURLE_OUT_OF_MEMORY;
1658
1659
166k
  Curl_strntolower(conn->destination, conn->destination,
1660
166k
                   strlen(conn->destination));
1661
1662
166k
  return CURLE_OK;
1663
166k
}
1664
1665
/*
1666
 * Curl_parse_login_details()
1667
 *
1668
 * This is used to parse a login string for username, password and options in
1669
 * the following formats:
1670
 *
1671
 *   user
1672
 *   user:password
1673
 *   user:password;options
1674
 *   user;options
1675
 *   user;options:password
1676
 *   :password
1677
 *   :password;options
1678
 *   ;options
1679
 *   ;options:password
1680
 *
1681
 * Parameters:
1682
 *
1683
 * login    [in]     - login string.
1684
 * len      [in]     - length of the login string.
1685
 * userp    [in/out] - address where a pointer to newly allocated memory
1686
 *                     holding the user will be stored upon completion.
1687
 * passwdp  [in/out] - address where a pointer to newly allocated memory
1688
 *                     holding the password will be stored upon completion.
1689
 * optionsp [in/out] - OPTIONAL address where a pointer to newly allocated
1690
 *                     memory holding the options will be stored upon
1691
 *                     completion.
1692
 *
1693
 * Returns CURLE_OK on success.
1694
 */
1695
CURLcode Curl_parse_login_details(const char *login, const size_t len,
1696
                                  char **userp, char **passwdp,
1697
                                  char **optionsp)
1698
54.0k
{
1699
54.0k
  char *ubuf = NULL;
1700
54.0k
  char *pbuf = NULL;
1701
54.0k
  const char *psep = NULL;
1702
54.0k
  const char *osep = NULL;
1703
54.0k
  size_t ulen;
1704
54.0k
  size_t plen;
1705
54.0k
  size_t olen;
1706
1707
54.0k
  DEBUGASSERT(userp);
1708
54.0k
  DEBUGASSERT(passwdp);
1709
1710
  /* Attempt to find the password separator */
1711
54.0k
  psep = memchr(login, ':', len);
1712
1713
  /* Attempt to find the options separator */
1714
54.0k
  if(optionsp)
1715
1.72k
    osep = memchr(login, ';', len);
1716
1717
  /* Calculate the portion lengths */
1718
54.0k
  ulen = (psep ?
1719
11.4k
          (size_t)(osep && psep > osep ? osep - login : psep - login) :
1720
54.0k
          (osep ? (size_t)(osep - login) : len));
1721
54.0k
  plen = (psep ?
1722
11.4k
          (osep && osep > psep ? (size_t)(osep - psep) :
1723
42.5k
           (size_t)(login + len - psep)) - 1 : 0);
1724
54.0k
  olen = (osep ?
1725
327
          (psep && psep > osep ? (size_t)(psep - osep) :
1726
53.6k
           (size_t)(login + len - osep)) - 1 : 0);
1727
1728
  /* Clone the user portion buffer, which can be zero length */
1729
54.0k
  ubuf = curlx_memdup0(login, ulen);
1730
54.0k
  if(!ubuf)
1731
0
    goto error;
1732
1733
  /* Clone the password portion buffer */
1734
54.0k
  if(psep) {
1735
11.4k
    pbuf = curlx_memdup0(&psep[1], plen);
1736
11.4k
    if(!pbuf)
1737
0
      goto error;
1738
11.4k
  }
1739
1740
  /* Allocate the options portion buffer */
1741
54.0k
  if(optionsp) {
1742
1.72k
    char *obuf = NULL;
1743
1.72k
    if(olen) {
1744
239
      obuf = curlx_memdup0(&osep[1], olen);
1745
239
      if(!obuf)
1746
0
        goto error;
1747
239
    }
1748
1.72k
    *optionsp = obuf;
1749
1.72k
  }
1750
54.0k
  *userp = ubuf;
1751
54.0k
  *passwdp = pbuf;
1752
54.0k
  return CURLE_OK;
1753
0
error:
1754
0
  curlx_free(ubuf);
1755
0
  curlx_free(pbuf);
1756
0
  return CURLE_OUT_OF_MEMORY;
1757
54.0k
}
1758
1759
/*
1760
 * Set the login details so they are available in the connection
1761
 */
1762
static CURLcode url_set_conn_login(struct Curl_easy *data,
1763
                                   struct connectdata *conn)
1764
166k
{
1765
  /* If our protocol needs a password and we have none, use the defaults */
1766
166k
  if((conn->scheme->flags & PROTOPT_NEEDSPWD) && !conn->creds) {
1767
7.96k
    Curl_peer_link(&conn->creds_origin, data->state.origin);
1768
7.96k
    if(data->state.creds)
1769
1.40k
      Curl_creds_link(&conn->creds, data->state.creds);
1770
6.56k
    else
1771
6.56k
      return Curl_creds_create(CURL_DEFAULT_USER, CURL_DEFAULT_PASSWORD,
1772
6.56k
                               NULL, NULL, NULL, CREDS_NONE, &conn->creds);
1773
7.96k
  }
1774
158k
  else if(!(conn->scheme->flags & PROTOPT_CREDSPERREQUEST)) {
1775
    /* for protocols that do not handle credentials per request,
1776
     * the connection credentials are set by the initial transfer. */
1777
86.8k
    Curl_peer_link(&conn->creds_origin, data->state.origin);
1778
86.8k
    Curl_creds_link(&conn->creds, data->state.creds);
1779
86.8k
  }
1780
1781
159k
  return CURLE_OK;
1782
166k
}
1783
1784
/*
1785
 * Parses one "connect to" string in the form:
1786
 * "HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT".
1787
 */
1788
static CURLcode parse_connect_to_string(struct Curl_easy *data,
1789
                                        const struct Curl_peer *dest,
1790
                                        const char *conn_to_line,
1791
                                        struct Curl_peer **pvia_dest)
1792
148k
{
1793
148k
  CURLcode result = CURLE_OK;
1794
148k
  const char *ptr = conn_to_line;
1795
148k
  bool host_match = FALSE;
1796
148k
  bool port_match = FALSE;
1797
1798
148k
  *pvia_dest = NULL;
1799
1800
148k
  if(*ptr == ':') {
1801
    /* an empty hostname always matches */
1802
148k
    host_match = TRUE;
1803
148k
    ptr++;
1804
148k
  }
1805
0
  else {
1806
    /* check whether the URL's hostname matches. Use the URL hostname
1807
     * when it was an IPv6 address. Otherwise use the connection's hostname
1808
     * that has IDN conversion. */
1809
0
    size_t hlen = strlen(dest->hostname);
1810
0
    host_match = curl_strnequal(ptr, dest->hostname, hlen);
1811
0
    if(!host_match && (dest->user_hostname != dest->hostname)) {
1812
      /* hostname was normalized, could be IPv6 or IDN */
1813
0
      hlen = strlen(dest->user_hostname);
1814
0
      host_match = curl_strnequal(ptr, dest->user_hostname, hlen);
1815
0
    }
1816
0
    host_match = host_match && ptr[hlen] == ':';
1817
0
    if(host_match)
1818
0
      ptr += hlen + 1;
1819
0
  }
1820
1821
148k
  if(host_match) {
1822
148k
    if(*ptr == ':') {
1823
      /* an empty port always matches */
1824
148k
      port_match = TRUE;
1825
148k
      ptr++;
1826
148k
    }
1827
0
    else {
1828
      /* check whether the URL's port matches */
1829
0
      const char *ptr_next = strchr(ptr, ':');
1830
0
      if(ptr_next) {
1831
0
        curl_off_t port_to_match;
1832
0
        if(!curlx_str_number(&ptr, &port_to_match, 0xffff) &&
1833
0
           ((uint16_t)port_to_match == dest->port)) {
1834
0
          port_match = TRUE;
1835
0
        }
1836
0
        ptr = ptr_next + 1;
1837
0
      }
1838
0
    }
1839
148k
  }
1840
1841
148k
  if(host_match && port_match && ptr && *ptr)
1842
148k
    result = Curl_peer_from_connect_to(data, dest, ptr, pvia_dest);
1843
1844
148k
  return result;
1845
148k
}
1846
1847
/* With `conn->origin` known, determine if we should talk to that
1848
 * directly or via another peer. This is the result of inspecting
1849
 * the "connect to" slist and "alt-svc" settings. */
1850
static CURLcode url_set_conn_peer(struct Curl_easy *data,
1851
                                  struct connectdata *conn)
1852
157k
{
1853
157k
  CURLcode result = CURLE_OK;
1854
157k
  struct Curl_peer *origin = conn->origin;
1855
157k
  struct Curl_peer *via_peer = NULL;
1856
157k
  struct curl_slist *conn_to_entry = data->set.connect_to;
1857
1858
157k
  DEBUGASSERT(!conn->via_peer);
1859
157k
  Curl_peer_unlink(&conn->via_peer);
1860
1861
306k
  while(conn_to_entry && !via_peer) {
1862
148k
    result = parse_connect_to_string(data, origin, conn_to_entry->data,
1863
148k
                                     &via_peer);
1864
148k
    if(result)
1865
0
      return result;
1866
148k
    conn_to_entry = conn_to_entry->next;
1867
148k
  }
1868
1869
157k
#ifndef CURL_DISABLE_ALTSVC
1870
157k
  if(data->asi && !via_peer &&
1871
0
     ((conn->scheme->protocol == CURLPROTO_HTTPS) ||
1872
0
#ifdef DEBUGBUILD
1873
      /* allow debug builds to circumvent the HTTPS restriction */
1874
0
      getenv("CURL_ALTSVC_HTTP")
1875
#else
1876
      0
1877
#endif
1878
0
       )) {
1879
    /* no connect_to match, try alt-svc! */
1880
0
    enum alpnid srcalpnid = ALPN_none;
1881
0
    bool hit = FALSE;
1882
0
    struct altsvc *as = NULL;
1883
0
    int allowed_alpns = ALPN_none;
1884
0
    struct http_negotiation *neg = &data->state.http_neg;
1885
0
    bool same_dest = FALSE;
1886
1887
0
    DEBUGF(infof(data, "Alt-svc check wanted=%x, allowed=%x",
1888
0
                 neg->wanted, neg->allowed));
1889
#ifdef USE_HTTP3
1890
    if(neg->allowed & CURL_HTTP_V3x)
1891
      allowed_alpns |= ALPN_h3;
1892
#endif
1893
0
#ifdef USE_HTTP2
1894
0
    if(neg->allowed & CURL_HTTP_V2x)
1895
0
      allowed_alpns |= ALPN_h2;
1896
0
#endif
1897
0
    if(neg->allowed & CURL_HTTP_V1x)
1898
0
      allowed_alpns |= ALPN_h1;
1899
0
    allowed_alpns &= (int)data->asi->flags;
1900
1901
0
    DEBUGF(infof(data, "check Alt-Svc for host '%s'", origin->hostname));
1902
#ifdef USE_HTTP3
1903
    if(!hit && (neg->wanted & CURL_HTTP_V3x)) {
1904
      srcalpnid = ALPN_h3;
1905
      hit = Curl_altsvc_lookup(data->asi,
1906
                               origin, ALPN_h3, /* from */
1907
                               &as /* to */,
1908
                               allowed_alpns, &same_dest);
1909
    }
1910
#endif
1911
0
#ifdef USE_HTTP2
1912
0
    if(!hit && (neg->wanted & CURL_HTTP_V2x) &&
1913
0
       !neg->h2_prior_knowledge) {
1914
0
      srcalpnid = ALPN_h2;
1915
0
      hit = Curl_altsvc_lookup(data->asi,
1916
0
                               origin, ALPN_h2, /* from */
1917
0
                               &as /* to */,
1918
0
                               allowed_alpns, &same_dest);
1919
0
    }
1920
0
#endif
1921
0
    if(!hit && (neg->wanted & CURL_HTTP_V1x) &&
1922
0
       !neg->only_10) {
1923
0
      srcalpnid = ALPN_h1;
1924
0
      hit = Curl_altsvc_lookup(data->asi,
1925
0
                               origin, ALPN_h1, /* from */
1926
0
                               &as /* to */,
1927
0
                               allowed_alpns, &same_dest);
1928
0
    }
1929
1930
0
    if(hit && same_dest) {
1931
      /* same destination, but more HTTPS version options */
1932
0
      switch(as->dst.alpnid) {
1933
0
      case ALPN_h1:
1934
0
        neg->wanted |= CURL_HTTP_V1x;
1935
0
        neg->preferred = CURL_HTTP_V1x;
1936
0
        break;
1937
0
      case ALPN_h2:
1938
0
        neg->wanted |= CURL_HTTP_V2x;
1939
0
        neg->preferred = CURL_HTTP_V2x;
1940
0
        break;
1941
0
      case ALPN_h3:
1942
0
        neg->wanted |= CURL_HTTP_V3x;
1943
0
        neg->preferred = CURL_HTTP_V3x;
1944
0
        break;
1945
0
      default: /* should not be possible */
1946
0
        break;
1947
0
      }
1948
0
    }
1949
0
    else if(hit) {
1950
0
      result = Curl_peer_create(data, conn->origin->scheme,
1951
0
                                as->dst.host, as->dst.port,
1952
0
                                &via_peer);
1953
0
      if(result)
1954
0
        return result;
1955
0
      infof(data, "Alt-svc connecting from [%s]%s:%u to [%s]%s:%u",
1956
0
            Curl_alpnid2str(srcalpnid), origin->hostname, origin->port,
1957
0
            Curl_alpnid2str(as->dst.alpnid),
1958
0
            via_peer->hostname, via_peer->port);
1959
0
      conn->bits.altused = TRUE;
1960
0
      if(srcalpnid != as->dst.alpnid) {
1961
        /* protocol version switch */
1962
0
        switch(as->dst.alpnid) {
1963
0
        case ALPN_h1:
1964
0
          neg->wanted = neg->allowed = CURL_HTTP_V1x;
1965
0
          neg->only_10 = FALSE;
1966
0
          break;
1967
0
        case ALPN_h2:
1968
0
          neg->wanted = neg->allowed = CURL_HTTP_V2x;
1969
0
          break;
1970
0
        case ALPN_h3:
1971
0
          conn->transport_wanted = TRNSPRT_QUIC;
1972
0
          neg->wanted = neg->allowed = CURL_HTTP_V3x;
1973
0
          break;
1974
0
        default: /* should not be possible */
1975
0
          break;
1976
0
        }
1977
0
      }
1978
0
    }
1979
0
  }
1980
157k
#endif
1981
1982
157k
  if(via_peer)
1983
148k
    conn->via_peer = via_peer;
1984
1985
157k
  return result;
1986
157k
}
1987
1988
/*
1989
 * Adjust reused connection settings to the transfer/needle.
1990
 */
1991
static void url_conn_reuse_adjust(struct Curl_easy *data,
1992
                                  struct connectdata *needle)
1993
22.8k
{
1994
22.8k
  struct connectdata *conn = data->conn;
1995
1996
  /* get the user+password information from the needle since it may
1997
   * be new for this request even when we reuse conn */
1998
22.8k
  if(needle->creds) {
1999
    /* use the new username and password though */
2000
13.8k
    Curl_creds_link(&conn->creds, needle->creds);
2001
13.8k
  }
2002
2003
22.8k
#ifndef CURL_DISABLE_PROXY
2004
  /* use the new proxy username and proxy password though */
2005
22.8k
  Curl_creds_link(&conn->http_proxy.creds, needle->http_proxy.creds);
2006
22.8k
  Curl_creds_link(&conn->socks_proxy.creds, needle->socks_proxy.creds);
2007
22.8k
#endif
2008
2009
  /* Finding a connection for reuse in the cpool matches, among other
2010
   * things on the "remote-relevant" hostname. This is not necessarily
2011
   * the authority of the URL, e.g. conn->origin. For example:
2012
   * - we use a proxy (not tunneling). we want to send all requests
2013
   *   that use the same proxy on this connection.
2014
   * - we have a "connect-to" setting that may redirect the hostname of
2015
   *   a new request to the same remote endpoint of an existing conn.
2016
   *   We want to reuse an existing conn to the remote endpoint.
2017
   * Since connection reuse does not match on conn->origin necessarily, we
2018
   * switch conn to needle's host settings.
2019
   */
2020
22.8k
  Curl_peer_link(&conn->origin, needle->origin);
2021
22.8k
  Curl_peer_link(&conn->via_peer, needle->via_peer);
2022
22.8k
  Curl_peer_link(&conn->origin2, needle->origin2);
2023
22.8k
  Curl_peer_link(&conn->via_peer2, needle->via_peer2);
2024
22.8k
}
2025
2026
static void conn_meta_freeentry(void *p)
2027
0
{
2028
0
  (void)p;
2029
  /* Always FALSE. Cannot use a 0 assert here since compilers
2030
   * are not in agreement if they then want a NORETURN attribute or
2031
   * not. *sigh* */
2032
0
  DEBUGASSERT(!p);
2033
0
}
2034
2035
static CURLcode url_create_needle(struct Curl_easy *data,
2036
                                  struct connectdata **pneedle)
2037
177k
{
2038
177k
  struct connectdata *needle = NULL;
2039
177k
  CURLcode result = CURLE_OK;
2040
177k
  bool network_scheme = TRUE; /* almost all are */
2041
2042
  /* Allocate a temporary connection data struct (needle) and fill in for
2043
     comparison purposes. */
2044
177k
  needle = allocate_conn(data);
2045
177k
  if(!needle) {
2046
0
    result = CURLE_OUT_OF_MEMORY;
2047
0
    goto out;
2048
0
  }
2049
2050
  /* Do the unfailable inits first, before checks that may early return */
2051
177k
  Curl_hash_init(&needle->meta_hash, 23,
2052
177k
                 Curl_hash_str, curlx_str_key_compare, conn_meta_freeentry);
2053
2054
  /*************************************************************
2055
   * Determine `conn->origin` and populate `data->state.up` and
2056
   * other URL related properties.
2057
   *************************************************************/
2058
177k
  result = url_set_conn_origin_etc(data, needle);
2059
177k
  if(result)
2060
11.4k
    goto out;
2061
2062
166k
  DEBUGASSERT(needle->origin);
2063
166k
  network_scheme = !(needle->origin->scheme->flags & PROTOPT_NONETWORK);
2064
2065
166k
#ifdef USE_UNIX_SOCKETS
2066
  /*************************************************************
2067
   * Set UDS first. It overrides "via_peer" and proxy settings.
2068
   *************************************************************/
2069
166k
  if(network_scheme && CURL_EASY_STR(data, STRING_UNIX_SOCKET_PATH)) {
2070
7.85k
    result = Curl_peer_uds_create(
2071
7.85k
      needle->origin->scheme, CURL_EASY_STR(data, STRING_UNIX_SOCKET_PATH),
2072
7.85k
      (bool)data->set.abstract_unix_socket, &needle->via_peer);
2073
7.85k
    if(result)
2074
19
      goto out;
2075
7.85k
  }
2076
166k
#endif /* USE_UNIX_SOCKETS */
2077
2078
166k
  if(network_scheme && !needle->via_peer) {
2079
    /*************************************************************
2080
     * If the `via_peer` is not already set (via UDS above),
2081
     * determine if we talk to `conn->origin` directly or use
2082
     * `conn->via_peer` using "connect to" and "alt-svc" properties.
2083
     *************************************************************/
2084
157k
    result = url_set_conn_peer(data, needle);
2085
157k
    if(result)
2086
0
      goto out;
2087
157k
  }
2088
2089
  /*************************************************************
2090
   * Check whether the host and the "connect to host" are equal.
2091
   * Do this after the hostnames have been IDN-converted and
2092
   * before initializing the proxy.
2093
   *************************************************************/
2094
166k
  if(Curl_peer_equal(needle->origin, needle->via_peer)) {
2095
3.36k
    Curl_peer_unlink(&needle->via_peer);
2096
3.36k
  }
2097
2098
166k
#ifndef CURL_DISABLE_PROXY
2099
  /* Going via a unix socket ignores any proxy settings */
2100
166k
  if(network_scheme &&
2101
165k
     (!needle->via_peer || !needle->via_peer->unix_socket)) {
2102
157k
    result = Curl_proxy_init_conn(data, needle);
2103
157k
    if(result)
2104
302
      goto out;
2105
157k
  }
2106
166k
#endif /* CURL_DISABLE_PROXY */
2107
2108
166k
  result = url_set_conn_login(data, needle); /* default credentials */
2109
166k
  if(result)
2110
0
    goto out;
2111
2112
  /*************************************************************
2113
   * Setup internals depending on protocol. Needs to be done after
2114
   * we figured out what/if proxy to use.
2115
   *************************************************************/
2116
166k
  result = setup_connection_internals(data, needle);
2117
166k
  if(result)
2118
121
    goto out;
2119
2120
166k
  if(needle->scheme->flags & PROTOPT_ALPN) {
2121
    /* The protocol wants it, so set the bits if enabled in the easy handle
2122
       (default) */
2123
13.8k
    if(data->set.ssl_enable_alpn)
2124
13.7k
      needle->bits.tls_enable_alpn = TRUE;
2125
13.8k
  }
2126
2127
166k
  if(network_scheme) {
2128
    /* Setup callbacks for network connections */
2129
164k
    needle->recv[FIRSTSOCKET] = Curl_cf_recv;
2130
164k
    needle->send[FIRSTSOCKET] = Curl_cf_send;
2131
164k
    needle->recv[SECONDARYSOCKET] = Curl_cf_recv;
2132
164k
    needle->send[SECONDARYSOCKET] = Curl_cf_send;
2133
164k
    needle->bits.tcp_fastopen = data->set.tcp_fastopen;
2134
164k
#ifdef USE_UNIX_SOCKETS
2135
164k
    if(Curl_conn_get_first_peer(needle, FIRSTSOCKET)->unix_socket)
2136
7.85k
      needle->transport_wanted = TRNSPRT_UNIX;
2137
164k
#endif
2138
164k
  }
2139
2140
177k
out:
2141
177k
  if(!result) {
2142
166k
    DEBUGASSERT(needle);
2143
166k
    DEBUGASSERT(needle->origin);
2144
166k
    *pneedle = needle;
2145
166k
  }
2146
11.8k
  else {
2147
11.8k
    *pneedle = NULL;
2148
11.8k
    if(needle)
2149
11.8k
      Curl_conn_free(data, needle);
2150
11.8k
  }
2151
177k
  return result;
2152
177k
}
2153
2154
static CURLcode url_set_data_origin_and_creds(struct Curl_easy *data)
2155
196k
{
2156
196k
  CURLcode result = CURLE_OK;
2157
196k
  CURLU *uh;
2158
196k
  CURLUcode uc;
2159
196k
  bool use_set_uh = (data->set.uh && !data->state.this_is_a_follow);
2160
196k
  uint16_t port_override = data->state.allow_port ? data->set.use_port : 0;
2161
196k
  uint32_t scope_id = 0;
2162
2163
  /*************************************************************
2164
   * Check input data
2165
   *************************************************************/
2166
196k
  if(!Curl_bufref_ptr(&data->state.url)) {
2167
0
    result = CURLE_URL_MALFORMAT;
2168
0
    goto out;
2169
0
  }
2170
2171
196k
  up_free(data); /* cleanup previous leftovers first */
2172
2173
  /* parse the URL */
2174
196k
  if(use_set_uh)
2175
0
    uh = data->state.uh = curl_url_dup(data->set.uh);
2176
196k
  else
2177
196k
    uh = data->state.uh = curl_url();
2178
196k
  if(!uh) {
2179
0
    result = CURLE_OUT_OF_MEMORY;
2180
0
    goto out;
2181
0
  }
2182
2183
  /* Calculate the *real* URL this transfer uses, applying defaults
2184
   * where information is missing. */
2185
196k
  if(CURL_EASY_STR(data, STRING_DEFAULT_PROTOCOL) &&
2186
20.0k
     !Curl_is_absolute_url(Curl_bufref_ptr(&data->state.url), NULL, 0, TRUE)) {
2187
10.9k
    char *url = curl_maprintf("%s://%s",
2188
10.9k
                              CURL_EASY_STR(data, STRING_DEFAULT_PROTOCOL),
2189
10.9k
                              Curl_bufref_ptr(&data->state.url));
2190
10.9k
    if(!url) {
2191
0
      result = CURLE_OUT_OF_MEMORY;
2192
0
      goto out;
2193
0
    }
2194
10.9k
    Curl_bufref_set(&data->state.url, url, 0, curl_free);
2195
10.9k
  }
2196
2197
196k
  if(!use_set_uh) {
2198
196k
    char *newurl;
2199
196k
    uc = curl_url_set(uh, CURLUPART_URL, Curl_bufref_ptr(&data->state.url),
2200
196k
                      (unsigned int)(CURLU_GUESS_SCHEME |
2201
196k
                       CURLU_NON_SUPPORT_SCHEME |
2202
196k
                       (data->set.disallow_username_in_url ?
2203
196k
                        CURLU_DISALLOW_USER : 0) |
2204
196k
                       (data->set.path_as_is ? CURLU_PATH_AS_IS : 0)));
2205
196k
    if(uc) {
2206
13.0k
      failf(data, "URL rejected: %s", curl_url_strerror(uc));
2207
13.0k
      result = Curl_uc_to_curlcode(uc);
2208
13.0k
      goto out;
2209
13.0k
    }
2210
2211
    /* after it was parsed, get the generated normalized version */
2212
183k
    uc = curl_url_get(uh, CURLUPART_URL, &newurl, CURLU_GET_EMPTY);
2213
183k
    if(uc) {
2214
0
      result = Curl_uc_to_curlcode(uc);
2215
0
      goto out;
2216
0
    }
2217
183k
    Curl_bufref_set(&data->state.url, newurl, 0, curl_free);
2218
183k
  }
2219
2220
183k
#ifdef USE_IPV6
2221
183k
  scope_id = data->set.scope_id;
2222
183k
#endif
2223
2224
  /* `uh` is now as the connection should use it, probably. */
2225
183k
  result = Curl_peer_from_url(uh, data, port_override, scope_id,
2226
183k
                              &data->state.origin);
2227
183k
  if(result)
2228
5.03k
    goto out;
2229
  /* The origin might get changed when HSTS applies */
2230
178k
  result = hsts_upgrade(data, uh, port_override, scope_id);
2231
178k
  if(result)
2232
0
    goto out;
2233
2234
  /* When the transfers initial_origin is not set, this is the initial
2235
   * request. Remember this starting point. */
2236
178k
  if(!data->state.initial_origin)
2237
149k
    Curl_peer_link(&data->state.initial_origin, data->state.origin);
2238
2239
178k
  uc = curl_url_get(uh, CURLUPART_PATH, &data->state.up.path, CURLU_URLENCODE);
2240
178k
  if(uc) {
2241
0
    result = Curl_uc_to_curlcode(uc);
2242
0
    goto out;
2243
0
  }
2244
178k
  uc = curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query,
2245
178k
                    CURLU_GET_EMPTY);
2246
178k
  if(uc && (uc != CURLUE_NO_QUERY)) {
2247
0
    result = CURLE_OUT_OF_MEMORY;
2248
0
    goto out;
2249
0
  }
2250
2251
178k
  uc = curl_url_get(uh, CURLUPART_OPTIONS, &data->state.up.options,
2252
178k
                    CURLU_URLDECODE);
2253
178k
  if(uc && (uc != CURLUE_NO_OPTIONS)) {
2254
10
    result = Curl_uc_to_curlcode(uc);
2255
10
    goto out;
2256
10
  }
2257
2258
178k
  result = url_set_data_creds(data, uh);
2259
178k
  if(result)
2260
164
    goto out;
2261
2262
196k
out:
2263
196k
  return result;
2264
178k
}
2265
2266
/**
2267
 * Find an existing connection for the transfer or create a new one.
2268
 * Returns
2269
 * - CURLE_OK on success with a connection attached to data
2270
 * - CURLE_NO_CONNECTION_AVAILABLE when connection limits apply or when
2271
 *   a suitable connection has not determined its multiplex capability.
2272
 * - a fatal error
2273
 */
2274
static CURLcode url_find_or_create_conn(struct Curl_easy *data)
2275
177k
{
2276
177k
  struct connectdata *needle = NULL;
2277
177k
  bool waitpipe = FALSE;
2278
177k
  CURLcode result;
2279
2280
  /* create the template connection for transfer data. Use this needle to
2281
   * find an existing connection or, if none exists, convert needle
2282
   * to a full connection and attach it to data. */
2283
177k
  result = url_create_needle(data, &needle);
2284
177k
  if(result)
2285
11.8k
    goto out;
2286
166k
  DEBUGASSERT(needle);
2287
2288
  /***********************************************************************
2289
   * file: is a special case in that it does not need a network connection
2290
   ***********************************************************************/
2291
166k
#ifndef CURL_DISABLE_FILE
2292
166k
  if(needle->scheme->flags & PROTOPT_NONETWORK) {
2293
1.39k
    bool done;
2294
    /* this is supposed to be the connect function so we better at least check
2295
       that the file is present here! */
2296
1.39k
    DEBUGASSERT(needle->scheme->run->connect_it);
2297
1.39k
    data->info.conn_scheme = needle->scheme->name;
2298
    /* conn_protocol can only provide "old" protocols */
2299
1.39k
    data->info.conn_protocol = (needle->scheme->protocol) & CURLPROTO_MASK;
2300
1.39k
    result = needle->scheme->run->connect_it(data, &done);
2301
1.39k
    if(result)
2302
128
      goto out;
2303
2304
    /* Setup a "faked" transfer that will do nothing */
2305
1.26k
    result = Curl_cpool_add(data, needle);
2306
1.26k
    Curl_attach_connection(data, needle, TRUE);
2307
1.26k
    needle = NULL;
2308
1.26k
    if(!result) {
2309
      /* Setup whatever necessary for a resumed transfer */
2310
1.26k
      result = setup_range(data);
2311
1.26k
      if(!result) {
2312
1.26k
        Curl_xfer_setup_nop(data);
2313
1.26k
        result = Curl_init_transfer(data, data->conn);
2314
1.26k
      }
2315
1.26k
    }
2316
2317
1.26k
    if(result) {
2318
0
      DEBUGASSERT(data->conn->scheme->run->done);
2319
      /* we ignore the return code for the protocol-specific DONE */
2320
0
      (void)data->conn->scheme->run->done(data, result, FALSE);
2321
0
    }
2322
1.26k
    goto out;
2323
1.26k
  }
2324
164k
#endif
2325
2326
  /* Complete the easy's SSL configuration for connection cache matching */
2327
164k
  result = Curl_ssl_easy_config_complete(data, needle->origin);
2328
164k
  if(result)
2329
0
    goto out;
2330
2331
  /*************************************************************
2332
   * Reuse of existing connection is not allowed when
2333
   * - connect_only is set or
2334
   * - reuse_fresh is set and this is not a follow-up request
2335
   *   (like with HTTP followlocation)
2336
   *************************************************************/
2337
164k
  if((!data->set.reuse_fresh || data->state.followlocation) &&
2338
164k
     !data->set.connect_only) {
2339
    /* Ok, try to find and attach an existing one */
2340
146k
    url_attach_existing(data, needle, &waitpipe);
2341
146k
  }
2342
2343
164k
  if(data->conn) {
2344
    /* We attached an existing connection for this transfer. Copy
2345
     * over transfer specific properties over from needle. */
2346
22.8k
    struct connectdata *conn = data->conn;
2347
22.8k
    VERBOSE(bool tls_upgraded = (!(needle->given->flags & PROTOPT_SSL) &&
2348
22.8k
                                 Curl_conn_is_ssl(conn, FIRSTSOCKET)));
2349
2350
22.8k
    conn->bits.reuse = TRUE;
2351
22.8k
    url_conn_reuse_adjust(data, needle);
2352
2353
22.8k
#ifndef CURL_DISABLE_PROXY
2354
22.8k
    infof(data, "Reusing existing %s: connection%s with %s %s",
2355
22.8k
          conn->given->name,
2356
22.8k
          tls_upgraded ? " (upgraded to SSL)" : "",
2357
22.8k
          (conn->socks_proxy.peer || conn->http_proxy.peer) ? "proxy" : "host",
2358
22.8k
          conn->socks_proxy.peer ? conn->socks_proxy.peer->user_hostname :
2359
22.8k
          conn->http_proxy.peer ? conn->http_proxy.peer->user_hostname :
2360
22.8k
          conn->origin->hostname);
2361
#else
2362
    infof(data, "Reusing existing %s: connection%s with host %s",
2363
          conn->given->name,
2364
          tls_upgraded ? " (upgraded to SSL)" : "",
2365
          conn->origin->hostname);
2366
#endif
2367
22.8k
  }
2368
141k
  else {
2369
    /* We have decided that we want a new connection. We may not be able to do
2370
       that if we have reached the limit of how many connections we are
2371
       allowed to open. */
2372
2373
141k
    if(waitpipe) {
2374
      /* There is a connection that *might* become usable for multiplexing
2375
         "soon", and we wait for that */
2376
3.03k
      infof(data, "Waiting on connection to negotiate possible multiplexing.");
2377
3.03k
      result = CURLE_NO_CONNECTION_AVAILABLE;
2378
3.03k
      goto out;
2379
3.03k
    }
2380
138k
    else {
2381
138k
      switch(Curl_cpool_check_limits(data, needle)) {
2382
0
      case CPOOL_LIMIT_DEST:
2383
0
        infof(data, "No more connections allowed to host");
2384
0
        result = CURLE_NO_CONNECTION_AVAILABLE;
2385
0
        goto out;
2386
0
      case CPOOL_LIMIT_TOTAL:
2387
0
        if(data->master_mid != UINT32_MAX)
2388
0
          CURL_TRC_M(data, "Allowing sub-requests (like DoH) to override "
2389
0
                     "max connection limit");
2390
0
        else {
2391
0
          infof(data, "No connections available, total of %zu reached.",
2392
0
                data->multi->max_total_connections);
2393
0
          result = CURLE_NO_CONNECTION_AVAILABLE;
2394
0
          goto out;
2395
0
        }
2396
0
        break;
2397
138k
      default:
2398
138k
        break;
2399
138k
      }
2400
138k
    }
2401
2402
    /* Convert needle into a full connection by filling in all the
2403
     * remaining parts like the cloned SSL configuration. */
2404
138k
    result = Curl_ssl_conn_config_init(data, needle);
2405
138k
    if(result) {
2406
0
      DEBUGF(curl_mfprintf(stderr, "Error: init connection SSL config\n"));
2407
0
      goto out;
2408
0
    }
2409
2410
    /* Add needle to conn pool, which assigns the connection id.
2411
     * Attach regardless of result, for correct handling. */
2412
138k
    result = Curl_cpool_add(data, needle);
2413
138k
    Curl_attach_connection(data, needle, TRUE);
2414
138k
    needle = NULL;
2415
138k
    if(result)
2416
0
      goto out;
2417
2418
#ifdef USE_NTLM
2419
    /* If NTLM is requested in a part of this connection, make sure we do not
2420
       assume the state is fine as this is a fresh connection and NTLM is
2421
       connection based. */
2422
    if((data->state.authhost.picked & CURLAUTH_NTLM) &&
2423
       data->state.authhost.done) {
2424
      infof(data, "NTLM picked AND auth done set, clear picked");
2425
      data->state.authhost.picked = CURLAUTH_NONE;
2426
      data->state.authhost.done = FALSE;
2427
    }
2428
2429
    if((data->state.authproxy.picked & CURLAUTH_NTLM) &&
2430
       data->state.authproxy.done) {
2431
      infof(data, "NTLM-proxy picked AND auth done set, clear picked");
2432
      data->state.authproxy.picked = CURLAUTH_NONE;
2433
      data->state.authproxy.done = FALSE;
2434
    }
2435
#endif
2436
138k
  }
2437
2438
  /* Setup and init stuff before DO starts, in preparing for the transfer. */
2439
161k
  result = Curl_init_transfer(data, data->conn);
2440
161k
  if(result)
2441
0
    goto out;
2442
2443
  /* Setup whatever necessary for a resumed transfer */
2444
161k
  result = setup_range(data);
2445
161k
  if(result)
2446
0
    goto out;
2447
2448
  /* persist the scheme and handler the transfer is using */
2449
161k
  data->info.conn_scheme = data->conn->scheme->name;
2450
  /* conn_protocol can only provide "old" protocols */
2451
161k
  data->info.conn_protocol = (data->conn->scheme->protocol) & CURLPROTO_MASK;
2452
161k
  data->info.used_proxy =
2453
#ifdef CURL_DISABLE_PROXY
2454
    0
2455
#else
2456
161k
    (data->conn->socks_proxy.peer || data->conn->http_proxy.peer)
2457
161k
#endif
2458
161k
    ;
2459
2460
  /* Lastly, inform connection filters that a new transfer is attached */
2461
161k
  result = Curl_conn_ev_data_setup(data);
2462
2463
177k
out:
2464
177k
  if(needle)
2465
26.0k
    Curl_conn_free(data, needle);
2466
177k
  DEBUGASSERT(result || data->conn);
2467
177k
  return result;
2468
177k
}
2469
2470
CURLcode Curl_connect(struct Curl_easy *data, bool *pconnected)
2471
196k
{
2472
196k
  CURLcode result;
2473
196k
  struct connectdata *conn = NULL;
2474
2475
196k
  *pconnected = FALSE;
2476
2477
  /* Set the request to virgin state based on transfer settings */
2478
196k
  Curl_req_hard_reset(&data->req, data);
2479
  /* Determine the origin of the transfer and what credentials to use */
2480
196k
  result = url_set_data_origin_and_creds(data);
2481
196k
  if(result)
2482
18.2k
    goto out;
2483
177k
  if(!data->state.origin) { /* just make really sure */
2484
0
    DEBUGASSERT(0);
2485
0
    result = CURLE_FAILED_INIT;
2486
0
    goto out;
2487
0
  }
2488
2489
  /* Get or create a connection for the transfer. */
2490
177k
  result = url_find_or_create_conn(data);
2491
177k
  conn = data->conn;
2492
177k
  if(result)
2493
15.0k
    goto out;
2494
162k
  if(!data->conn) { /* just make really sure */
2495
0
    DEBUGASSERT(0);
2496
0
    result = CURLE_FAILED_INIT;
2497
0
    goto out;
2498
0
  }
2499
2500
162k
  Curl_pgrsTime(data, TIMER_POSTQUEUE);
2501
162k
  if(conn->bits.reuse) {
2502
22.8k
    if(conn->attached_xfers > 1)
2503
      /* multiplexed */
2504
0
      *pconnected = TRUE;
2505
22.8k
  }
2506
140k
  else if(conn->scheme->flags & PROTOPT_NONETWORK) {
2507
1.26k
    Curl_pgrsTime(data, TIMER_NAMELOOKUP);
2508
1.26k
    *pconnected = TRUE;
2509
1.26k
  }
2510
138k
  else {
2511
138k
    result = Curl_conn_setup(data, conn, FIRSTSOCKET, CURL_CF_SSL_DEFAULT);
2512
138k
    if(!result)
2513
138k
      result = Curl_headers_init(data);
2514
138k
    CURL_TRC_M(data, "Curl_conn_setup() -> %d", (int)result);
2515
138k
  }
2516
2517
196k
out:
2518
196k
  if(result == CURLE_NO_CONNECTION_AVAILABLE)
2519
196k
    DEBUGASSERT(!conn);
2520
2521
196k
  if(result && conn) {
2522
    /* We are not allowed to return failure with memory left allocated in the
2523
       connectdata struct, free those here */
2524
0
    Curl_detach_connection(data);
2525
0
    Curl_conn_close(data, conn, TRUE);
2526
0
  }
2527
2528
196k
  return result;
2529
196k
}
2530
2531
/*
2532
 * Curl_init_transfer() is called each time before the transfer starts - to
2533
 * prepare for a transfer, sometimes multiple times on the same Curl_easy.
2534
 * Make sure nothing in here depends on stuff that is setup dynamically for
2535
 * the transfer.
2536
 *
2537
 * Allow this function to get called with 'conn' set to NULL.
2538
 */
2539
2540
CURLcode Curl_init_transfer(struct Curl_easy *data, struct connectdata *conn)
2541
162k
{
2542
162k
  CURLcode result;
2543
2544
162k
  if(conn) {
2545
162k
    conn->bits.do_more = FALSE; /* by default there is no curl_do_more() to
2546
                                   use */
2547
    /* if the protocol used does not support wildcards, switch it off */
2548
162k
    if(data->state.wildcardmatch &&
2549
939
       !(conn->scheme->flags & PROTOPT_WILDCARD))
2550
33
      data->state.wildcardmatch = FALSE;
2551
162k
  }
2552
2553
162k
  data->state.done = FALSE; /* *_done() is not called yet */
2554
2555
162k
  data->req.no_body = data->set.opt_no_body;
2556
162k
  if(data->req.no_body)
2557
    /* in HTTP lingo, no body means using the HEAD request... */
2558
1.14k
    data->state.httpreq = HTTPREQ_HEAD;
2559
2560
162k
  result = Curl_req_start(&data->req, data);
2561
162k
  if(!result) {
2562
162k
    Curl_pgrsReset(data);
2563
162k
  }
2564
162k
  return result;
2565
162k
}
2566
2567
#if defined(USE_HTTP2) || defined(USE_HTTP3)
2568
2569
void Curl_data_priority_clear_state(struct Curl_easy *data)
2570
167k
{
2571
167k
  data->state.weight = 0;
2572
167k
}
2573
2574
#endif /* USE_HTTP2 || USE_HTTP3 */
2575
2576
CURLcode Curl_conn_meta_set(struct connectdata *conn, const char *key,
2577
                            void *meta_data, Curl_meta_dtor *meta_dtor)
2578
71.9k
{
2579
71.9k
  if(!Curl_hash_add2(&conn->meta_hash, CURL_UNCONST(key), strlen(key) + 1,
2580
71.9k
                     meta_data, meta_dtor)) {
2581
0
    meta_dtor(CURL_UNCONST(key), strlen(key) + 1, meta_data);
2582
0
    return CURLE_OUT_OF_MEMORY;
2583
0
  }
2584
71.9k
  return CURLE_OK;
2585
71.9k
}
2586
2587
void Curl_conn_meta_remove(struct connectdata *conn, const char *key)
2588
140k
{
2589
140k
  Curl_hash_delete(&conn->meta_hash, CURL_UNCONST(key), strlen(key) + 1);
2590
140k
}
2591
2592
void *Curl_conn_meta_get(struct connectdata *conn, const char *key)
2593
3.12M
{
2594
3.12M
  return Curl_hash_pick(&conn->meta_hash, CURL_UNCONST(key), strlen(key) + 1);
2595
3.12M
}
2596
2597
struct Curl_easy *Curl_get_admin(struct Curl_easy *data)
2598
454k
{
2599
454k
  struct Curl_easy *admin;
2600
2601
454k
  if(!data->mid) /* already an admin handle */
2602
7.42k
    admin = data;
2603
446k
  else if(data->multi)
2604
446k
    admin = data->multi->admin;
2605
0
  else if(data->multi_easy)
2606
0
    admin = data->multi_easy->admin;
2607
0
  else {
2608
0
    DEBUGASSERT(0); /* we do not want this. does it happen? */
2609
0
    admin = data;
2610
0
  }
2611
454k
  if(admin != data) {
2612
446k
    admin->set.conn_max_idle_ms = data->set.conn_max_idle_ms;
2613
446k
    admin->set.conn_max_age_ms = data->set.conn_max_age_ms;
2614
446k
    admin->set.upkeep_interval_ms = data->set.upkeep_interval_ms;
2615
446k
    admin->set.timeout = data->set.timeout;
2616
446k
    admin->set.server_response_timeout = data->set.server_response_timeout;
2617
446k
    admin->set.no_signal = data->set.no_signal;
2618
446k
  }
2619
454k
  return admin;
2620
454k
}
2621
2622
CURLcode Curl_1st_fatal(CURLcode r1, CURLcode r2)
2623
192k
{
2624
192k
  if(r1 && (r1 != CURLE_AGAIN))
2625
125k
    return r1;
2626
66.5k
  if(r2 && (r2 != CURLE_AGAIN))
2627
4
    return r2;
2628
66.5k
  return r1;
2629
66.5k
}