Coverage Report

Created: 2026-07-14 07:09

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