Coverage Report

Created: 2026-09-14 06:43

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