Coverage Report

Created: 2026-10-15 06:18

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