Coverage Report

Created: 2026-06-30 08:33

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