Coverage Report

Created: 2025-07-12 06:36

/src/curl/lib/url.c
Line
Count
Source (jump to first uncovered line)
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
25
#include "curl_setup.h"
26
27
#ifdef HAVE_NETINET_IN_H
28
#include <netinet/in.h>
29
#endif
30
#ifdef HAVE_NETDB_H
31
#include <netdb.h>
32
#endif
33
#ifdef HAVE_ARPA_INET_H
34
#include <arpa/inet.h>
35
#endif
36
#ifdef HAVE_NET_IF_H
37
#include <net/if.h>
38
#endif
39
#ifdef HAVE_IPHLPAPI_H
40
#include <Iphlpapi.h>
41
#endif
42
#ifdef HAVE_SYS_IOCTL_H
43
#include <sys/ioctl.h>
44
#endif
45
#ifdef HAVE_SYS_PARAM_H
46
#include <sys/param.h>
47
#endif
48
49
#ifdef __VMS
50
#include <in.h>
51
#include <inet.h>
52
#endif
53
54
#ifdef HAVE_SYS_UN_H
55
#include <sys/un.h>
56
#endif
57
58
#ifndef HAVE_SOCKET
59
#error "We cannot compile without socket() support!"
60
#endif
61
62
#if defined(HAVE_IF_NAMETOINDEX) && defined(_WIN32)
63
#include <iphlpapi.h>
64
#endif
65
66
#include <limits.h>
67
68
#include "doh.h"
69
#include "urldata.h"
70
#include "netrc.h"
71
#include "formdata.h"
72
#include "mime.h"
73
#include "vtls/vtls.h"
74
#include "hostip.h"
75
#include "transfer.h"
76
#include "sendf.h"
77
#include "progress.h"
78
#include "cookie.h"
79
#include "strcase.h"
80
#include "strerror.h"
81
#include "escape.h"
82
#include "share.h"
83
#include "content_encoding.h"
84
#include "http_digest.h"
85
#include "http_negotiate.h"
86
#include "select.h"
87
#include "multiif.h"
88
#include "easyif.h"
89
#include "speedcheck.h"
90
#include "curlx/warnless.h"
91
#include "getinfo.h"
92
#include "pop3.h"
93
#include "urlapi-int.h"
94
#include "system_win32.h"
95
#include "hsts.h"
96
#include "noproxy.h"
97
#include "cfilters.h"
98
#include "curl_krb5.h"
99
#include "idn.h"
100
101
/* And now for the protocols */
102
#include "ftp.h"
103
#include "dict.h"
104
#include "telnet.h"
105
#include "tftp.h"
106
#include "http.h"
107
#include "http2.h"
108
#include "file.h"
109
#include "curl_ldap.h"
110
#include "vssh/ssh.h"
111
#include "imap.h"
112
#include "url.h"
113
#include "connect.h"
114
#include "http_ntlm.h"
115
#include "curl_rtmp.h"
116
#include "gopher.h"
117
#include "mqtt.h"
118
#include "http_proxy.h"
119
#include "conncache.h"
120
#include "multihandle.h"
121
#include "strdup.h"
122
#include "setopt.h"
123
#include "altsvc.h"
124
#include "curlx/dynbuf.h"
125
#include "headers.h"
126
#include "curlx/strparse.h"
127
/* The last 3 #include files should be in this order */
128
#include "curl_printf.h"
129
#include "curl_memory.h"
130
#include "memdebug.h"
131
132
#ifdef USE_NGHTTP2
133
static void data_priority_cleanup(struct Curl_easy *data);
134
#else
135
#define data_priority_cleanup(x)
136
#endif
137
138
/* Some parts of the code (e.g. chunked encoding) assume this buffer has at
139
 * more than just a few bytes to play with. Do not let it become too small or
140
 * bad things will happen.
141
 */
142
#if READBUFFER_SIZE < READBUFFER_MIN
143
# error READBUFFER_SIZE is too small
144
#endif
145
146
#ifdef USE_UNIX_SOCKETS
147
4.65k
#define UNIX_SOCKET_PREFIX "localhost"
148
#endif
149
150
/* Reject URLs exceeding this length */
151
116k
#define MAX_URL_LEN 0xffff
152
153
/*
154
* get_protocol_family()
155
*
156
* This is used to return the protocol family for a given protocol.
157
*
158
* Parameters:
159
*
160
* 'h'  [in]  - struct Curl_handler pointer.
161
*
162
* Returns the family as a single bit protocol identifier.
163
*/
164
static curl_prot_t get_protocol_family(const struct Curl_handler *h)
165
7.42k
{
166
7.42k
  DEBUGASSERT(h);
167
7.42k
  DEBUGASSERT(h->family);
168
7.42k
  return h->family;
169
7.42k
}
170
171
void Curl_freeset(struct Curl_easy *data)
172
311k
{
173
  /* Free all dynamic strings stored in the data->set substructure. */
174
311k
  enum dupstring i;
175
311k
  enum dupblob j;
176
177
23.6M
  for(i = (enum dupstring)0; i < STRING_LAST; i++) {
178
23.3M
    Curl_safefree(data->set.str[i]);
179
23.3M
  }
180
181
2.80M
  for(j = (enum dupblob)0; j < BLOB_LAST; j++) {
182
2.49M
    Curl_safefree(data->set.blobs[j]);
183
2.49M
  }
184
185
311k
  if(data->state.referer_alloc) {
186
0
    Curl_safefree(data->state.referer);
187
0
    data->state.referer_alloc = FALSE;
188
0
  }
189
311k
  data->state.referer = NULL;
190
311k
  if(data->state.url_alloc) {
191
110k
    Curl_safefree(data->state.url);
192
110k
    data->state.url_alloc = FALSE;
193
110k
  }
194
311k
  data->state.url = NULL;
195
196
311k
  Curl_mime_cleanpart(&data->set.mimepost);
197
198
311k
#ifndef CURL_DISABLE_COOKIES
199
311k
  curl_slist_free_all(data->state.cookielist);
200
311k
  data->state.cookielist = NULL;
201
311k
#endif
202
311k
}
203
204
/* free the URL pieces */
205
static void up_free(struct Curl_easy *data)
206
438k
{
207
438k
  struct urlpieces *up = &data->state.up;
208
438k
  Curl_safefree(up->scheme);
209
438k
  Curl_safefree(up->hostname);
210
438k
  Curl_safefree(up->port);
211
438k
  Curl_safefree(up->user);
212
438k
  Curl_safefree(up->password);
213
438k
  Curl_safefree(up->options);
214
438k
  Curl_safefree(up->path);
215
438k
  Curl_safefree(up->query);
216
438k
  curl_url_cleanup(data->state.uh);
217
438k
  data->state.uh = NULL;
218
438k
}
219
220
/*
221
 * This is the internal function curl_easy_cleanup() calls. This should
222
 * cleanup and free all resources associated with this sessionhandle.
223
 *
224
 * We ignore SIGPIPE when this is called from curl_easy_cleanup.
225
 */
226
227
CURLcode Curl_close(struct Curl_easy **datap)
228
311k
{
229
311k
  struct Curl_easy *data;
230
231
311k
  if(!datap || !*datap)
232
86
    return CURLE_OK;
233
234
311k
  data = *datap;
235
311k
  *datap = NULL;
236
237
311k
  if(!data->state.internal && data->multi) {
238
    /* This handle is still part of a multi handle, take care of this first
239
       and detach this handle from there.
240
       This detaches the connection. */
241
0
    curl_multi_remove_handle(data->multi, data);
242
0
  }
243
311k
  else {
244
    /* Detach connection if any is left. This should not be normal, but can be
245
       the case for example with CONNECT_ONLY + recv/send (test 556) */
246
311k
    Curl_detach_connection(data);
247
311k
    if(!data->state.internal && data->multi_easy) {
248
      /* when curl_easy_perform() is used, it creates its own multi handle to
249
         use and this is the one */
250
0
      curl_multi_cleanup(data->multi_easy);
251
0
      data->multi_easy = NULL;
252
0
    }
253
311k
  }
254
311k
  DEBUGASSERT(!data->conn || data->state.internal);
255
256
311k
  Curl_expire_clear(data); /* shut off any timers left */
257
258
311k
  data->magic = 0; /* force a clear AFTER the possibly enforced removal from
259
                      the multi handle, since that function uses the magic
260
                      field! */
261
262
311k
  if(data->state.rangestringalloc)
263
3.45k
    free(data->state.range);
264
265
  /* freed here just in case DONE was not called */
266
311k
  Curl_req_free(&data->req, data);
267
268
  /* Close down all open SSL info and sessions */
269
311k
  Curl_ssl_close_all(data);
270
311k
  Curl_safefree(data->state.first_host);
271
311k
  Curl_ssl_free_certinfo(data);
272
273
311k
  if(data->state.referer_alloc) {
274
138
    Curl_safefree(data->state.referer);
275
138
    data->state.referer_alloc = FALSE;
276
138
  }
277
311k
  data->state.referer = NULL;
278
279
311k
  up_free(data);
280
311k
  curlx_dyn_free(&data->state.headerb);
281
311k
  Curl_flush_cookies(data, TRUE);
282
311k
#ifndef CURL_DISABLE_ALTSVC
283
311k
  Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]);
284
311k
  Curl_altsvc_cleanup(&data->asi);
285
311k
#endif
286
311k
#ifndef CURL_DISABLE_HSTS
287
311k
  Curl_hsts_save(data, data->hsts, data->set.str[STRING_HSTS]);
288
311k
  if(!data->share || !data->share->hsts)
289
311k
    Curl_hsts_cleanup(&data->hsts);
290
311k
  curl_slist_free_all(data->state.hstslist); /* clean up list */
291
311k
#endif
292
311k
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH)
293
311k
  Curl_http_auth_cleanup_digest(data);
294
311k
#endif
295
311k
  Curl_safefree(data->state.most_recent_ftp_entrypath);
296
311k
  Curl_safefree(data->info.contenttype);
297
311k
  Curl_safefree(data->info.wouldredirect);
298
299
  /* release any resolve information this transfer kept */
300
311k
  Curl_async_destroy(data);
301
311k
  Curl_resolv_unlink(data, &data->state.dns[0]); /* done with this */
302
311k
  Curl_resolv_unlink(data, &data->state.dns[1]);
303
304
311k
  data_priority_cleanup(data);
305
306
  /* No longer a dirty share, if it exists */
307
311k
  if(data->share) {
308
0
    Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
309
0
    data->share->dirty--;
310
0
    Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
311
0
  }
312
313
311k
  Curl_hash_destroy(&data->meta_hash);
314
311k
#ifndef CURL_DISABLE_PROXY
315
311k
  Curl_safefree(data->state.aptr.proxyuserpwd);
316
311k
#endif
317
311k
  Curl_safefree(data->state.aptr.uagent);
318
311k
  Curl_safefree(data->state.aptr.userpwd);
319
311k
  Curl_safefree(data->state.aptr.accept_encoding);
320
311k
  Curl_safefree(data->state.aptr.te);
321
311k
  Curl_safefree(data->state.aptr.rangeline);
322
311k
  Curl_safefree(data->state.aptr.ref);
323
311k
  Curl_safefree(data->state.aptr.host);
324
311k
#ifndef CURL_DISABLE_COOKIES
325
311k
  Curl_safefree(data->state.aptr.cookiehost);
326
311k
#endif
327
311k
#ifndef CURL_DISABLE_RTSP
328
311k
  Curl_safefree(data->state.aptr.rtsp_transport);
329
311k
#endif
330
311k
  Curl_safefree(data->state.aptr.user);
331
311k
  Curl_safefree(data->state.aptr.passwd);
332
311k
#ifndef CURL_DISABLE_PROXY
333
311k
  Curl_safefree(data->state.aptr.proxyuser);
334
311k
  Curl_safefree(data->state.aptr.proxypasswd);
335
311k
#endif
336
337
311k
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_FORM_API)
338
311k
  Curl_mime_cleanpart(data->state.formp);
339
311k
  Curl_safefree(data->state.formp);
340
311k
#endif
341
342
  /* destruct wildcard structures if it is needed */
343
311k
  Curl_wildcard_dtor(&data->wildcard);
344
311k
  Curl_freeset(data);
345
311k
  Curl_headers_cleanup(data);
346
311k
  Curl_netrc_cleanup(&data->state.netrc);
347
311k
  free(data);
348
311k
  return CURLE_OK;
349
311k
}
350
351
/*
352
 * Initialize the UserDefined fields within a Curl_easy.
353
 * This may be safely called on a new or existing Curl_easy.
354
 */
355
CURLcode Curl_init_userdefined(struct Curl_easy *data)
356
311k
{
357
311k
  struct UserDefined *set = &data->set;
358
311k
  CURLcode result = CURLE_OK;
359
360
311k
  set->out = stdout; /* default output to stdout */
361
311k
  set->in_set = stdin;  /* default input from stdin */
362
311k
  set->err  = stderr;  /* default stderr to stderr */
363
364
  /* use fwrite as default function to store output */
365
311k
  set->fwrite_func = (curl_write_callback)fwrite;
366
367
  /* use fread as default function to read input */
368
311k
  set->fread_func_set = (curl_read_callback)fread;
369
311k
  set->is_fread_set = 0;
370
371
311k
  set->seek_client = ZERO_NULL;
372
373
311k
  set->filesize = -1;        /* we do not know the size */
374
311k
  set->postfieldsize = -1;   /* unknown size */
375
311k
  set->maxredirs = 30;       /* sensible default */
376
377
311k
  set->method = HTTPREQ_GET; /* Default HTTP request */
378
311k
#ifndef CURL_DISABLE_RTSP
379
311k
  set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */
380
311k
#endif
381
311k
#ifndef CURL_DISABLE_FTP
382
311k
  set->ftp_use_epsv = TRUE;   /* FTP defaults to EPSV operations */
383
311k
  set->ftp_use_eprt = TRUE;   /* FTP defaults to EPRT operations */
384
311k
  set->ftp_use_pret = FALSE;  /* mainly useful for drftpd servers */
385
311k
  set->ftp_filemethod = FTPFILE_MULTICWD;
386
311k
  set->ftp_skip_ip = TRUE;    /* skip PASV IP by default */
387
311k
#endif
388
311k
  set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */
389
390
  /* Timeout every 24 hours by default */
391
311k
  set->general_ssl.ca_cache_timeout = 24 * 60 * 60;
392
393
311k
  set->httpauth = CURLAUTH_BASIC;  /* defaults to basic */
394
395
311k
#ifndef CURL_DISABLE_PROXY
396
311k
  set->proxyport = 0;
397
311k
  set->proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */
398
311k
  set->proxyauth = CURLAUTH_BASIC; /* defaults to basic */
399
  /* SOCKS5 proxy auth defaults to username/password + GSS-API */
400
311k
  set->socks5auth = CURLAUTH_BASIC | CURLAUTH_GSSAPI;
401
311k
#endif
402
403
311k
  Curl_mime_initpart(&set->mimepost);
404
405
311k
  Curl_ssl_easy_config_init(data);
406
311k
#ifndef CURL_DISABLE_DOH
407
311k
  set->doh_verifyhost = TRUE;
408
311k
  set->doh_verifypeer = TRUE;
409
311k
#endif
410
#ifdef USE_SSH
411
  /* defaults to any auth type */
412
  set->ssh_auth_types = CURLSSH_AUTH_DEFAULT;
413
  set->new_directory_perms = 0755; /* Default permissions */
414
#endif
415
416
311k
  set->new_file_perms = 0644;    /* Default permissions */
417
311k
  set->allowed_protocols = (curl_prot_t) CURLPROTO_ALL;
418
311k
  set->redir_protocols = CURLPROTO_REDIR;
419
420
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
421
  /*
422
   * disallow unprotected protection negotiation NEC reference implementation
423
   * seem not to follow rfc1961 section 4.3/4.4
424
   */
425
  set->socks5_gssapi_nec = FALSE;
426
#endif
427
428
  /* Set the default CA cert bundle/path detected/specified at build time.
429
   *
430
   * If Schannel is the selected SSL backend then these locations are ignored.
431
   * We allow setting CA location for Schannel when explicitly specified by
432
   * the user via CURLOPT_CAINFO / --cacert.
433
   */
434
311k
  if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) {
435
311k
#ifdef CURL_CA_BUNDLE
436
311k
    result = Curl_setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE);
437
311k
    if(result)
438
0
      return result;
439
311k
#ifndef CURL_DISABLE_PROXY
440
311k
    result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY],
441
311k
                            CURL_CA_BUNDLE);
442
311k
    if(result)
443
0
      return result;
444
311k
#endif
445
311k
#endif
446
311k
#ifdef CURL_CA_PATH
447
311k
    result = Curl_setstropt(&set->str[STRING_SSL_CAPATH], CURL_CA_PATH);
448
311k
    if(result)
449
0
      return result;
450
311k
#ifndef CURL_DISABLE_PROXY
451
311k
    result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH);
452
311k
    if(result)
453
0
      return result;
454
311k
#endif
455
311k
#endif
456
311k
  }
457
458
311k
#ifndef CURL_DISABLE_FTP
459
311k
  set->wildcard_enabled = FALSE;
460
311k
  set->chunk_bgn      = ZERO_NULL;
461
311k
  set->chunk_end      = ZERO_NULL;
462
311k
  set->fnmatch = ZERO_NULL;
463
311k
#endif
464
311k
  set->tcp_keepalive = FALSE;
465
311k
  set->tcp_keepintvl = 60;
466
311k
  set->tcp_keepidle = 60;
467
311k
  set->tcp_keepcnt = 9;
468
311k
  set->tcp_fastopen = FALSE;
469
311k
  set->tcp_nodelay = TRUE;
470
311k
  set->ssl_enable_alpn = TRUE;
471
311k
  set->expect_100_timeout = 1000L; /* Wait for a second by default. */
472
311k
  set->sep_headers = TRUE; /* separated header lists by default */
473
311k
  set->buffer_size = READBUFFER_SIZE;
474
311k
  set->upload_buffer_size = UPLOADBUFFER_DEFAULT;
475
311k
  set->happy_eyeballs_timeout = CURL_HET_DEFAULT;
476
311k
  set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT;
477
311k
  set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
478
311k
  set->conn_max_idle_ms = 118 * 1000;
479
311k
  set->conn_max_age_ms = 0;
480
311k
  set->http09_allowed = FALSE;
481
311k
  set->httpwant = CURL_HTTP_VERSION_NONE
482
311k
    ;
483
311k
#if defined(USE_HTTP2) || defined(USE_HTTP3)
484
311k
  memset(&set->priority, 0, sizeof(set->priority));
485
311k
#endif
486
311k
  set->quick_exit = 0L;
487
311k
#ifndef CURL_DISABLE_WEBSOCKETS
488
311k
  set->ws_raw_mode = FALSE;
489
311k
  set->ws_no_auto_pong = FALSE;
490
311k
#endif
491
492
311k
  return result;
493
311k
}
494
495
/* easy->meta_hash destructor. Should never be called as elements
496
 * MUST be added with their own destructor */
497
static void easy_meta_freeentry(void *p)
498
0
{
499
0
  (void)p;
500
  /* Will always be FALSE. Cannot use a 0 assert here since compilers
501
   * are not in agreement if they then want a NORETURN attribute or
502
   * not. *sigh* */
503
0
  DEBUGASSERT(p == NULL);
504
0
}
505
506
/**
507
 * Curl_open()
508
 *
509
 * @param curl is a pointer to a sessionhandle pointer that gets set by this
510
 * function.
511
 * @return CURLcode
512
 */
513
514
CURLcode Curl_open(struct Curl_easy **curl)
515
311k
{
516
311k
  CURLcode result;
517
311k
  struct Curl_easy *data;
518
519
  /* simple start-up: alloc the struct, init it with zeroes and return */
520
311k
  data = calloc(1, sizeof(struct Curl_easy));
521
311k
  if(!data) {
522
    /* this is a serious error */
523
0
    DEBUGF(fprintf(stderr, "Error: calloc of Curl_easy failed\n"));
524
0
    return CURLE_OUT_OF_MEMORY;
525
0
  }
526
527
311k
  data->magic = CURLEASY_MAGIC_NUMBER;
528
  /* most recent connection is not yet defined */
529
311k
  data->state.lastconnect_id = -1;
530
311k
  data->state.recent_conn_id = -1;
531
  /* and not assigned an id yet */
532
311k
  data->id = -1;
533
311k
  data->mid = UINT_MAX;
534
311k
  data->master_mid = UINT_MAX;
535
311k
  data->progress.hide = TRUE;
536
311k
  data->state.current_speed = -1; /* init to negative == impossible */
537
538
311k
  Curl_hash_init(&data->meta_hash, 23,
539
311k
                 Curl_hash_str, curlx_str_key_compare, easy_meta_freeentry);
540
311k
  curlx_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER);
541
311k
  Curl_req_init(&data->req);
542
311k
  Curl_initinfo(data);
543
311k
#ifndef CURL_DISABLE_HTTP
544
311k
  Curl_llist_init(&data->state.httphdrs, NULL);
545
311k
#endif
546
311k
  Curl_netrc_init(&data->state.netrc);
547
548
311k
  result = Curl_init_userdefined(data);
549
550
311k
  if(result) {
551
0
    curlx_dyn_free(&data->state.headerb);
552
0
    Curl_freeset(data);
553
0
    Curl_req_free(&data->req, data);
554
0
    Curl_hash_destroy(&data->meta_hash);
555
0
    data->magic = 0;
556
0
    free(data);
557
0
    data = NULL;
558
0
  }
559
311k
  else
560
311k
    *curl = data;
561
311k
  return result;
562
311k
}
563
564
void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn)
565
126k
{
566
126k
  size_t i;
567
568
126k
  DEBUGASSERT(conn);
569
570
126k
  if(conn->handler && conn->handler->disconnect &&
571
126k
     !conn->bits.shutdown_handler)
572
34
    conn->handler->disconnect(data, conn, TRUE);
573
574
379k
  for(i = 0; i < CURL_ARRAYSIZE(conn->cfilter); ++i) {
575
252k
    Curl_conn_cf_discard_all(data, conn, (int)i);
576
252k
  }
577
578
126k
  Curl_free_idnconverted_hostname(&conn->host);
579
126k
  Curl_free_idnconverted_hostname(&conn->conn_to_host);
580
126k
#ifndef CURL_DISABLE_PROXY
581
126k
  Curl_free_idnconverted_hostname(&conn->http_proxy.host);
582
126k
  Curl_free_idnconverted_hostname(&conn->socks_proxy.host);
583
126k
  Curl_safefree(conn->http_proxy.user);
584
126k
  Curl_safefree(conn->socks_proxy.user);
585
126k
  Curl_safefree(conn->http_proxy.passwd);
586
126k
  Curl_safefree(conn->socks_proxy.passwd);
587
126k
  Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */
588
126k
  Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */
589
126k
#endif
590
126k
  Curl_sec_conn_destroy(conn);
591
126k
  Curl_safefree(conn->user);
592
126k
  Curl_safefree(conn->passwd);
593
126k
  Curl_safefree(conn->sasl_authzid);
594
126k
  Curl_safefree(conn->options);
595
126k
  Curl_safefree(conn->oauth_bearer);
596
126k
  Curl_safefree(conn->host.rawalloc); /* hostname buffer */
597
126k
  Curl_safefree(conn->conn_to_host.rawalloc); /* hostname buffer */
598
126k
  Curl_safefree(conn->hostname_resolve);
599
126k
  Curl_safefree(conn->secondaryhostname);
600
126k
  Curl_safefree(conn->localdev);
601
126k
  Curl_ssl_conn_config_cleanup(conn);
602
603
126k
#ifdef USE_UNIX_SOCKETS
604
126k
  Curl_safefree(conn->unix_domain_socket);
605
126k
#endif
606
126k
  Curl_safefree(conn->destination);
607
126k
  Curl_uint_spbset_destroy(&conn->xfers_attached);
608
126k
  Curl_hash_destroy(&conn->meta_hash);
609
610
126k
  free(conn); /* free all the connection oriented data */
611
126k
}
612
613
/*
614
 * xfer_may_multiplex()
615
 *
616
 * Return a TRUE, iff the transfer can be done over an (appropriate)
617
 * multiplexed connection.
618
 */
619
static bool xfer_may_multiplex(const struct Curl_easy *data,
620
                               const struct connectdata *conn)
621
94.1k
{
622
94.1k
#ifndef CURL_DISABLE_HTTP
623
  /* If an HTTP protocol and multiplexing is enabled */
624
94.1k
  if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
625
94.1k
     (!conn->bits.protoconnstart || !conn->bits.close)) {
626
627
33.6k
    if(Curl_multiplex_wanted(data->multi) &&
628
33.6k
       (data->state.http_neg.allowed & (CURL_HTTP_V2x|CURL_HTTP_V3x)))
629
      /* allows HTTP/2 or newer */
630
33.5k
      return TRUE;
631
33.6k
  }
632
#else
633
  (void)data;
634
  (void)conn;
635
#endif
636
60.6k
  return FALSE;
637
94.1k
}
638
639
#ifndef CURL_DISABLE_PROXY
640
static bool
641
proxy_info_matches(const struct proxy_info *data,
642
                   const struct proxy_info *needle)
643
673
{
644
673
  if((data->proxytype == needle->proxytype) &&
645
673
     (data->port == needle->port) &&
646
673
     curl_strequal(data->host.name, needle->host.name))
647
673
    return TRUE;
648
649
0
  return FALSE;
650
673
}
651
652
static bool
653
socks_proxy_info_matches(const struct proxy_info *data,
654
                         const struct proxy_info *needle)
655
10
{
656
10
  if(!proxy_info_matches(data, needle))
657
0
    return FALSE;
658
659
  /* the user information is case-sensitive
660
     or at least it is not defined as case-insensitive
661
     see https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.1 */
662
663
  /* curl_strequal does a case insensitive comparison,
664
     so do not use it here! */
665
10
  if(Curl_timestrcmp(data->user, needle->user) ||
666
10
     Curl_timestrcmp(data->passwd, needle->passwd))
667
0
    return FALSE;
668
10
  return TRUE;
669
10
}
670
#else
671
/* disabled, will not get called */
672
#define proxy_info_matches(x,y) FALSE
673
#define socks_proxy_info_matches(x,y) FALSE
674
#endif
675
676
/* A connection has to have been idle for less than 'conn_max_idle_ms'
677
   (the success rate is just too low after this), or created less than
678
   'conn_max_age_ms' ago, to be subject for reuse. */
679
static bool conn_maxage(struct Curl_easy *data,
680
                        struct connectdata *conn,
681
                        struct curltime now)
682
6.84k
{
683
6.84k
  timediff_t age_ms;
684
685
6.84k
  if(data->set.conn_max_idle_ms) {
686
6.82k
    age_ms = curlx_timediff(now, conn->lastused);
687
6.82k
    if(age_ms > data->set.conn_max_idle_ms) {
688
0
      infof(data, "Too old connection (%" FMT_TIMEDIFF_T
689
0
            " ms idle, max idle is %" FMT_TIMEDIFF_T " ms), disconnect it",
690
0
            age_ms, data->set.conn_max_idle_ms);
691
0
      return TRUE;
692
0
    }
693
6.82k
  }
694
695
6.84k
  if(data->set.conn_max_age_ms) {
696
345
    age_ms = curlx_timediff(now, conn->created);
697
345
    if(age_ms > data->set.conn_max_age_ms) {
698
0
      infof(data,
699
0
            "Too old connection (created %" FMT_TIMEDIFF_T
700
0
            " ms ago, max lifetime is %" FMT_TIMEDIFF_T " ms), disconnect it",
701
0
            age_ms, data->set.conn_max_age_ms);
702
0
      return TRUE;
703
0
    }
704
345
  }
705
706
6.84k
  return FALSE;
707
6.84k
}
708
709
/*
710
 * Return TRUE iff the given connection is considered dead.
711
 */
712
bool Curl_conn_seems_dead(struct connectdata *conn,
713
                          struct Curl_easy *data,
714
                          struct curltime *pnow)
715
6.84k
{
716
6.84k
  DEBUGASSERT(!data->conn);
717
6.84k
  if(!CONN_INUSE(conn)) {
718
    /* The check for a dead socket makes sense only if the connection is not in
719
       use */
720
6.84k
    bool dead;
721
6.84k
    struct curltime now;
722
6.84k
    if(!pnow) {
723
6.84k
      now = curlx_now();
724
6.84k
      pnow = &now;
725
6.84k
    }
726
727
6.84k
    if(conn_maxage(data, conn, *pnow)) {
728
      /* avoid check if already too old */
729
0
      dead = TRUE;
730
0
    }
731
6.84k
    else if(conn->handler->connection_check) {
732
      /* The protocol has a special method for checking the state of the
733
         connection. Use it to check if the connection is dead. */
734
6.45k
      unsigned int state;
735
736
      /* briefly attach the connection to this transfer for the purpose of
737
         checking it */
738
6.45k
      Curl_attach_connection(data, conn);
739
740
6.45k
      state = conn->handler->connection_check(data, conn, CONNCHECK_ISDEAD);
741
6.45k
      dead = (state & CONNRESULT_DEAD);
742
      /* detach the connection again */
743
6.45k
      Curl_detach_connection(data);
744
745
6.45k
    }
746
390
    else {
747
390
      bool input_pending = FALSE;
748
749
390
      Curl_attach_connection(data, conn);
750
390
      dead = !Curl_conn_is_alive(data, conn, &input_pending);
751
390
      if(input_pending) {
752
        /* For reuse, we want a "clean" connection state. The includes
753
         * that we expect - in general - no waiting input data. Input
754
         * waiting might be a TLS Notify Close, for example. We reject
755
         * that.
756
         * For protocols where data from other end may arrive at
757
         * any time (HTTP/2 PING for example), the protocol handler needs
758
         * to install its own `connection_check` callback.
759
         */
760
229
        DEBUGF(infof(data, "connection has input pending, not reusable"));
761
229
        dead = TRUE;
762
229
      }
763
390
      Curl_detach_connection(data);
764
390
    }
765
766
6.84k
    if(dead) {
767
      /* remove connection from cpool */
768
229
      infof(data, "Connection %" FMT_OFF_T " seems to be dead",
769
229
            conn->connection_id);
770
229
      return TRUE;
771
229
    }
772
6.84k
  }
773
6.61k
  return FALSE;
774
6.84k
}
775
776
CURLcode Curl_conn_upkeep(struct Curl_easy *data,
777
                          struct connectdata *conn,
778
                          struct curltime *now)
779
0
{
780
0
  CURLcode result = CURLE_OK;
781
0
  if(curlx_timediff(*now, conn->keepalive) <= data->set.upkeep_interval_ms)
782
0
    return result;
783
784
  /* briefly attach for action */
785
0
  Curl_attach_connection(data, conn);
786
0
  if(conn->handler->connection_check) {
787
    /* Do a protocol-specific keepalive check on the connection. */
788
0
    unsigned int rc;
789
0
    rc = conn->handler->connection_check(data, conn, CONNCHECK_KEEPALIVE);
790
0
    if(rc & CONNRESULT_DEAD)
791
0
      result = CURLE_RECV_ERROR;
792
0
  }
793
0
  else {
794
    /* Do the generic action on the FIRSTSOCKET filter chain */
795
0
    result = Curl_conn_keep_alive(data, conn, FIRSTSOCKET);
796
0
  }
797
0
  Curl_detach_connection(data);
798
799
0
  conn->keepalive = *now;
800
0
  return result;
801
0
}
802
803
#ifdef USE_SSH
804
static bool ssh_config_matches(struct connectdata *one,
805
                               struct connectdata *two)
806
{
807
  struct ssh_conn *sshc1, *sshc2;
808
809
  sshc1 = Curl_conn_meta_get(one, CURL_META_SSH_CONN);
810
  sshc2 = Curl_conn_meta_get(two, CURL_META_SSH_CONN);
811
  return (sshc1 && sshc2 && Curl_safecmp(sshc1->rsa, sshc2->rsa) &&
812
          Curl_safecmp(sshc1->rsa_pub, sshc2->rsa_pub));
813
}
814
#endif
815
816
struct url_conn_match {
817
  struct connectdata *found;
818
  struct Curl_easy *data;
819
  struct connectdata *needle;
820
  BIT(may_multiplex);
821
  BIT(want_ntlm_http);
822
  BIT(want_proxy_ntlm_http);
823
824
  BIT(wait_pipe);
825
  BIT(force_reuse);
826
  BIT(seen_pending_conn);
827
  BIT(seen_single_use_conn);
828
  BIT(seen_multiplex_conn);
829
};
830
831
static bool url_match_connect_config(struct connectdata *conn,
832
                                     struct url_conn_match *m)
833
9.56k
{
834
  /* connect-only or to-be-closed connections will not be reused */
835
9.56k
  if(conn->connect_only || conn->bits.close)
836
3
    return FALSE;
837
838
  /* ip_version must match */
839
9.56k
  if(m->data->set.ipver != CURL_IPRESOLVE_WHATEVER
840
9.56k
     && m->data->set.ipver != conn->ip_version)
841
0
    return FALSE;
842
843
9.56k
  if(m->needle->localdev || m->needle->localport) {
844
    /* If we are bound to a specific local end (IP+port), we must not reuse a
845
       random other one, although if we did not ask for a particular one we
846
       can reuse one that was bound.
847
848
       This comparison is a bit rough and too strict. Since the input
849
       parameters can be specified in numerous ways and still end up the same
850
       it would take a lot of processing to make it really accurate. Instead,
851
       this matching will assume that reuses of bound connections will most
852
       likely also reuse the exact same binding parameters and missing out a
853
       few edge cases should not hurt anyone much.
854
    */
855
564
    if((conn->localport != m->needle->localport) ||
856
564
       (conn->localportrange != m->needle->localportrange) ||
857
564
       (m->needle->localdev &&
858
564
        (!conn->localdev || strcmp(conn->localdev, m->needle->localdev))))
859
0
      return FALSE;
860
564
  }
861
862
9.56k
  if(m->needle->bits.conn_to_host != conn->bits.conn_to_host)
863
    /* do not mix connections that use the "connect to host" feature and
864
     * connections that do not use this feature */
865
7
    return FALSE;
866
867
9.55k
  if(m->needle->bits.conn_to_port != conn->bits.conn_to_port)
868
    /* do not mix connections that use the "connect to port" feature and
869
     * connections that do not use this feature */
870
0
    return FALSE;
871
872
  /* Does `conn` use the correct protocol? */
873
9.55k
#ifdef USE_UNIX_SOCKETS
874
9.55k
  if(m->needle->unix_domain_socket) {
875
1.18k
    if(!conn->unix_domain_socket)
876
0
      return FALSE;
877
1.18k
    if(strcmp(m->needle->unix_domain_socket, conn->unix_domain_socket))
878
0
      return FALSE;
879
1.18k
    if(m->needle->bits.abstract_unix_socket != conn->bits.abstract_unix_socket)
880
0
      return FALSE;
881
1.18k
  }
882
8.37k
  else if(conn->unix_domain_socket)
883
0
    return FALSE;
884
9.55k
#endif
885
886
9.55k
  return TRUE;
887
9.55k
}
888
889
static bool url_match_fully_connected(struct connectdata *conn,
890
                                      struct url_conn_match *m)
891
9.50k
{
892
9.50k
  if(!Curl_conn_is_connected(conn, FIRSTSOCKET) ||
893
9.50k
     conn->bits.asks_multiplex) {
894
    /* Not yet connected, or not yet decided if it multiplexes. The later
895
     * happens for HTTP/2 Upgrade: requests that need a response. */
896
1.99k
    if(m->may_multiplex) {
897
1.99k
      m->seen_pending_conn = TRUE;
898
      /* Do not pick a connection that has not connected yet */
899
1.99k
      infof(m->data, "Connection #%" FMT_OFF_T
900
1.99k
            " is not open enough, cannot reuse", conn->connection_id);
901
1.99k
    }
902
    /* Do not pick a connection that has not connected yet */
903
1.99k
    return FALSE;
904
1.99k
  }
905
7.51k
  return TRUE;
906
9.50k
}
907
908
static bool url_match_multi(struct connectdata *conn,
909
                            struct url_conn_match *m)
910
0
{
911
0
  if(CONN_INUSE(conn)) {
912
0
    DEBUGASSERT(conn->attached_multi);
913
0
    if(conn->attached_multi != m->data->multi)
914
0
      return FALSE;
915
0
  }
916
0
  return TRUE;
917
0
}
918
919
static bool url_match_multiplex_needs(struct connectdata *conn,
920
                                      struct url_conn_match *m)
921
7.51k
{
922
7.51k
  if(CONN_INUSE(conn)) {
923
0
    if(!conn->bits.multiplex) {
924
      /* conn busy and conn cannot take more transfers */
925
0
      m->seen_single_use_conn = TRUE;
926
0
      return FALSE;
927
0
    }
928
0
    m->seen_multiplex_conn = TRUE;
929
0
    if(!m->may_multiplex || !url_match_multi(conn, m))
930
      /* conn busy and transfer cannot be multiplexed */
931
0
      return FALSE;
932
0
  }
933
7.51k
  return TRUE;
934
7.51k
}
935
936
static bool url_match_multiplex_limits(struct connectdata *conn,
937
                                       struct url_conn_match *m)
938
6.84k
{
939
6.84k
  if(CONN_INUSE(conn) && m->may_multiplex) {
940
0
    DEBUGASSERT(conn->bits.multiplex);
941
    /* If multiplexed, make sure we do not go over concurrency limit */
942
0
    if(CONN_ATTACHED(conn) >=
943
0
            Curl_multi_max_concurrent_streams(m->data->multi)) {
944
0
      infof(m->data, "client side MAX_CONCURRENT_STREAMS reached"
945
0
            ", skip (%u)", CONN_ATTACHED(conn));
946
0
      return FALSE;
947
0
    }
948
0
    if(CONN_ATTACHED(conn) >=
949
0
            Curl_conn_get_max_concurrent(m->data, conn, FIRSTSOCKET)) {
950
0
      infof(m->data, "MAX_CONCURRENT_STREAMS reached, skip (%u)",
951
0
            CONN_ATTACHED(conn));
952
0
      return FALSE;
953
0
    }
954
    /* When not multiplexed, we have a match here! */
955
0
    infof(m->data, "Multiplexed connection found");
956
0
  }
957
6.84k
  return TRUE;
958
6.84k
}
959
960
static bool url_match_ssl_use(struct connectdata *conn,
961
                              struct url_conn_match *m)
962
7.51k
{
963
7.51k
  if(m->needle->handler->flags&PROTOPT_SSL) {
964
    /* We are looking for SSL, if `conn` does not do it, not a match. */
965
0
    if(!Curl_conn_is_ssl(conn, FIRSTSOCKET))
966
0
      return FALSE;
967
0
  }
968
7.51k
  else if(Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
969
    /* We are not *requiring* SSL, however `conn` has it. If the
970
     * protocol *family* is not the same, not a match. */
971
0
    if(get_protocol_family(conn->handler) != m->needle->handler->protocol)
972
0
      return FALSE;
973
0
  }
974
7.51k
  return TRUE;
975
7.51k
}
976
977
#ifndef CURL_DISABLE_PROXY
978
static bool url_match_proxy_use(struct connectdata *conn,
979
                                struct url_conn_match *m)
980
7.51k
{
981
7.51k
  if(m->needle->bits.httpproxy != conn->bits.httpproxy ||
982
7.51k
     m->needle->bits.socksproxy != conn->bits.socksproxy)
983
0
    return FALSE;
984
985
7.51k
  if(m->needle->bits.socksproxy &&
986
7.51k
    !socks_proxy_info_matches(&m->needle->socks_proxy,
987
10
                              &conn->socks_proxy))
988
0
    return FALSE;
989
990
7.51k
  if(m->needle->bits.httpproxy) {
991
663
    if(m->needle->bits.tunnel_proxy != conn->bits.tunnel_proxy)
992
0
      return FALSE;
993
994
663
    if(!proxy_info_matches(&m->needle->http_proxy, &conn->http_proxy))
995
0
      return FALSE;
996
997
663
    if(IS_HTTPS_PROXY(m->needle->http_proxy.proxytype)) {
998
      /* https proxies come in different types, http/1.1, h2, ... */
999
0
      if(m->needle->http_proxy.proxytype != conn->http_proxy.proxytype)
1000
0
        return FALSE;
1001
      /* match SSL config to proxy */
1002
0
      if(!Curl_ssl_conn_config_match(m->data, conn, TRUE)) {
1003
0
        DEBUGF(infof(m->data,
1004
0
          "Connection #%" FMT_OFF_T
1005
0
          " has different SSL proxy parameters, cannot reuse",
1006
0
          conn->connection_id));
1007
0
        return FALSE;
1008
0
      }
1009
      /* the SSL config to the server, which may apply here is checked
1010
       * further below */
1011
0
    }
1012
663
  }
1013
7.51k
  return TRUE;
1014
7.51k
}
1015
#else
1016
#define url_match_proxy_use(c,m)    ((void)c, (void)m, TRUE)
1017
#endif
1018
1019
#ifndef CURL_DISABLE_HTTP
1020
static bool url_match_http_multiplex(struct connectdata *conn,
1021
                                     struct url_conn_match *m)
1022
7.51k
{
1023
7.51k
  if(m->may_multiplex &&
1024
7.51k
     (m->data->state.http_neg.allowed & (CURL_HTTP_V2x|CURL_HTTP_V3x)) &&
1025
7.51k
     (m->needle->handler->protocol & CURLPROTO_HTTP) &&
1026
7.51k
     !conn->httpversion_seen) {
1027
0
    if(m->data->set.pipewait) {
1028
0
      infof(m->data, "Server upgrade does not support multiplex yet, wait");
1029
0
      m->found = NULL;
1030
0
      m->wait_pipe = TRUE;
1031
0
      return TRUE; /* stop searching, we want to wait */
1032
0
    }
1033
0
    infof(m->data, "Server upgrade cannot be used");
1034
0
    return FALSE;
1035
0
  }
1036
7.51k
  return TRUE;
1037
7.51k
}
1038
1039
static bool url_match_http_version(struct connectdata *conn,
1040
                                   struct url_conn_match *m)
1041
7.50k
{
1042
  /* If looking for HTTP and the HTTP versions allowed do not include
1043
   * the HTTP version of conn, continue looking. */
1044
7.50k
  if((m->needle->handler->protocol & PROTO_FAMILY_HTTP)) {
1045
905
    switch(Curl_conn_http_version(m->data, conn)) {
1046
0
    case 30:
1047
0
      if(!(m->data->state.http_neg.allowed & CURL_HTTP_V3x)) {
1048
0
        DEBUGF(infof(m->data, "not reusing conn #%" CURL_FORMAT_CURL_OFF_T
1049
0
               ", we do not want h3", conn->connection_id));
1050
0
        return FALSE;
1051
0
      }
1052
0
      break;
1053
192
    case 20:
1054
192
      if(!(m->data->state.http_neg.allowed & CURL_HTTP_V2x)) {
1055
72
        DEBUGF(infof(m->data, "not reusing conn #%" CURL_FORMAT_CURL_OFF_T
1056
72
               ", we do not want h2", conn->connection_id));
1057
72
        return FALSE;
1058
72
      }
1059
120
      break;
1060
713
    default:
1061
713
      if(!(m->data->state.http_neg.allowed & CURL_HTTP_V1x)) {
1062
8
        DEBUGF(infof(m->data, "not reusing conn #%" CURL_FORMAT_CURL_OFF_T
1063
8
               ", we do not want h1", conn->connection_id));
1064
8
        return FALSE;
1065
8
      }
1066
705
      break;
1067
905
    }
1068
905
  }
1069
7.42k
  return TRUE;
1070
7.50k
}
1071
#else
1072
#define url_match_http_multiplex(c,m)    ((void)c, (void)m, TRUE)
1073
#define url_match_http_version(c,m)      ((void)c, (void)m, TRUE)
1074
#endif
1075
1076
static bool url_match_proto_config(struct connectdata *conn,
1077
                                   struct url_conn_match *m)
1078
7.50k
{
1079
7.50k
  if(!url_match_http_version(conn, m))
1080
80
    return FALSE;
1081
1082
#ifdef USE_SSH
1083
  if(get_protocol_family(m->needle->handler) & PROTO_FAMILY_SSH) {
1084
    if(!ssh_config_matches(m->needle, conn))
1085
      return FALSE;
1086
  }
1087
#endif
1088
7.42k
#ifndef CURL_DISABLE_FTP
1089
7.42k
  else if(get_protocol_family(m->needle->handler) & PROTO_FAMILY_FTP) {
1090
87
    if(!ftp_conns_match(m->needle, conn))
1091
0
      return FALSE;
1092
87
  }
1093
7.42k
#endif
1094
7.42k
  return TRUE;
1095
7.50k
}
1096
1097
static bool url_match_auth(struct connectdata *conn,
1098
                           struct url_conn_match *m)
1099
7.51k
{
1100
7.51k
  if(!(m->needle->handler->flags & PROTOPT_CREDSPERREQUEST)) {
1101
    /* This protocol requires credentials per connection,
1102
       so verify that we are using the same name and password as well */
1103
6.60k
    if(Curl_timestrcmp(m->needle->user, conn->user) ||
1104
6.60k
       Curl_timestrcmp(m->needle->passwd, conn->passwd) ||
1105
6.60k
       Curl_timestrcmp(m->needle->sasl_authzid, conn->sasl_authzid) ||
1106
6.60k
       Curl_timestrcmp(m->needle->oauth_bearer, conn->oauth_bearer)) {
1107
      /* one of them was different */
1108
4
      return FALSE;
1109
4
    }
1110
6.60k
  }
1111
#ifdef HAVE_GSSAPI
1112
  /* GSS delegation differences do not actually affect every connection
1113
     and auth method, but this check takes precaution before efficiency */
1114
  if(m->needle->gssapi_delegation != conn->gssapi_delegation)
1115
    return FALSE;
1116
#endif
1117
1118
7.50k
  return TRUE;
1119
7.51k
}
1120
1121
static bool url_match_destination(struct connectdata *conn,
1122
                                  struct url_conn_match *m)
1123
9.55k
{
1124
  /* Additional match requirements if talking TLS OR
1125
   * not talking to an HTTP proxy OR using a tunnel through a proxy */
1126
9.55k
  if((m->needle->handler->flags&PROTOPT_SSL)
1127
9.55k
#ifndef CURL_DISABLE_PROXY
1128
9.55k
     || !m->needle->bits.httpproxy || m->needle->bits.tunnel_proxy
1129
9.55k
#endif
1130
9.55k
    ) {
1131
9.36k
    if(!curl_strequal(m->needle->handler->scheme, conn->handler->scheme)) {
1132
      /* `needle` and `conn` do not have the same scheme... */
1133
0
      if(get_protocol_family(conn->handler) != m->needle->handler->protocol) {
1134
        /* and `conn`s protocol family is not the protocol `needle` wants.
1135
         * IMAPS would work for IMAP, but no vice versa. */
1136
0
        return FALSE;
1137
0
      }
1138
      /* We are in an IMAPS vs IMAP like case. We expect `conn` to have SSL */
1139
0
      if(!Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
1140
0
        DEBUGF(infof(m->data,
1141
0
          "Connection #%" FMT_OFF_T " has compatible protocol family, "
1142
0
          "but no SSL, no match", conn->connection_id));
1143
0
        return FALSE;
1144
0
      }
1145
0
    }
1146
1147
    /* If needle has "conn_to_*" set, conn must match this */
1148
9.36k
    if((m->needle->bits.conn_to_host && !curl_strequal(
1149
7.34k
        m->needle->conn_to_host.name, conn->conn_to_host.name)) ||
1150
9.36k
       (m->needle->bits.conn_to_port &&
1151
9.36k
         m->needle->conn_to_port != conn->conn_to_port))
1152
0
      return FALSE;
1153
1154
    /* hostname and port must match */
1155
9.36k
    if(!curl_strequal(m->needle->host.name, conn->host.name) ||
1156
9.36k
       m->needle->remote_port != conn->remote_port)
1157
51
      return FALSE;
1158
9.36k
  }
1159
9.50k
  return TRUE;
1160
9.55k
}
1161
1162
static bool url_match_ssl_config(struct connectdata *conn,
1163
                                 struct url_conn_match *m)
1164
7.51k
{
1165
  /* If talking TLS, conn needs to use the same SSL options. */
1166
7.51k
  if((m->needle->handler->flags & PROTOPT_SSL) &&
1167
7.51k
     !Curl_ssl_conn_config_match(m->data, conn, FALSE)) {
1168
0
    DEBUGF(infof(m->data,
1169
0
                 "Connection #%" FMT_OFF_T
1170
0
                 " has different SSL parameters, cannot reuse",
1171
0
                 conn->connection_id));
1172
0
    return FALSE;
1173
0
  }
1174
7.51k
  return TRUE;
1175
7.51k
}
1176
1177
#ifdef USE_NTLM
1178
static bool url_match_auth_ntlm(struct connectdata *conn,
1179
                                struct url_conn_match *m)
1180
7.42k
{
1181
  /* If we are looking for an HTTP+NTLM connection, check if this is
1182
     already authenticating with the right credentials. If not, keep
1183
     looking so that we can reuse NTLM connections if
1184
     possible. (Especially we must not reuse the same connection if
1185
     partway through a handshake!) */
1186
7.42k
  if(m->want_ntlm_http) {
1187
436
    if(Curl_timestrcmp(m->needle->user, conn->user) ||
1188
436
       Curl_timestrcmp(m->needle->passwd, conn->passwd)) {
1189
1190
      /* we prefer a credential match, but this is at least a connection
1191
         that can be reused and "upgraded" to NTLM */
1192
14
      if(conn->http_ntlm_state == NTLMSTATE_NONE)
1193
14
        m->found = conn;
1194
14
      return FALSE;
1195
14
    }
1196
436
  }
1197
6.99k
  else if(conn->http_ntlm_state != NTLMSTATE_NONE) {
1198
    /* Connection is using NTLM auth but we do not want NTLM */
1199
62
    return FALSE;
1200
62
  }
1201
1202
7.35k
#ifndef CURL_DISABLE_PROXY
1203
  /* Same for Proxy NTLM authentication */
1204
7.35k
  if(m->want_proxy_ntlm_http) {
1205
    /* Both conn->http_proxy.user and conn->http_proxy.passwd can be
1206
     * NULL */
1207
90
    if(!conn->http_proxy.user || !conn->http_proxy.passwd)
1208
0
      return FALSE;
1209
1210
90
    if(Curl_timestrcmp(m->needle->http_proxy.user,
1211
90
                       conn->http_proxy.user) ||
1212
90
       Curl_timestrcmp(m->needle->http_proxy.passwd,
1213
90
                       conn->http_proxy.passwd))
1214
0
      return FALSE;
1215
90
  }
1216
7.26k
  else if(conn->proxy_ntlm_state != NTLMSTATE_NONE) {
1217
    /* Proxy connection is using NTLM auth but we do not want NTLM */
1218
2
    return FALSE;
1219
2
  }
1220
7.34k
#endif
1221
7.34k
  if(m->want_ntlm_http || m->want_proxy_ntlm_http) {
1222
    /* Credentials are already checked, we may use this connection.
1223
     * With NTLM being weird as it is, we MUST use a
1224
     * connection where it has already been fully negotiated.
1225
     * If it has not, we keep on looking for a better one. */
1226
508
    m->found = conn;
1227
1228
508
    if((m->want_ntlm_http &&
1229
508
       (conn->http_ntlm_state != NTLMSTATE_NONE)) ||
1230
508
        (m->want_proxy_ntlm_http &&
1231
507
         (conn->proxy_ntlm_state != NTLMSTATE_NONE))) {
1232
      /* We must use this connection, no other */
1233
1
      m->force_reuse = TRUE;
1234
1
      return TRUE;
1235
1
    }
1236
    /* Continue look up for a better connection */
1237
507
    return FALSE;
1238
508
  }
1239
6.84k
  return TRUE;
1240
7.34k
}
1241
#else
1242
#define url_match_auth_ntlm(c,m)    ((void)c, (void)m, TRUE)
1243
#endif
1244
1245
static bool url_match_conn(struct connectdata *conn, void *userdata)
1246
9.56k
{
1247
9.56k
  struct url_conn_match *m = userdata;
1248
  /* Check if `conn` can be used for transfer `m->data` */
1249
1250
  /* general connect config setting match? */
1251
9.56k
  if(!url_match_connect_config(conn, m))
1252
10
    return FALSE;
1253
1254
9.55k
  if(!url_match_destination(conn, m))
1255
51
    return FALSE;
1256
1257
9.50k
  if(!url_match_fully_connected(conn, m))
1258
1.99k
    return FALSE;
1259
1260
7.51k
  if(!url_match_multiplex_needs(conn, m))
1261
0
    return FALSE;
1262
1263
7.51k
  if(!url_match_ssl_use(conn, m))
1264
0
    return FALSE;
1265
7.51k
  if(!url_match_proxy_use(conn, m))
1266
0
    return FALSE;
1267
7.51k
  if(!url_match_ssl_config(conn, m))
1268
0
    return FALSE;
1269
1270
7.51k
  if(!url_match_http_multiplex(conn, m))
1271
0
    return FALSE;
1272
7.51k
  else if(m->wait_pipe)
1273
    /* we decided to wait on PIPELINING */
1274
0
    return TRUE;
1275
1276
7.51k
  if(!url_match_auth(conn, m))
1277
4
    return FALSE;
1278
1279
7.50k
  if(!url_match_proto_config(conn, m))
1280
80
    return FALSE;
1281
1282
7.42k
  if(!url_match_auth_ntlm(conn, m))
1283
585
    return FALSE;
1284
6.84k
  else if(m->force_reuse)
1285
1
    return TRUE;
1286
1287
6.84k
  if(!url_match_multiplex_limits(conn, m))
1288
0
    return FALSE;
1289
1290
6.84k
  if(!CONN_INUSE(conn) && Curl_conn_seems_dead(conn, m->data, NULL)) {
1291
    /* remove and disconnect. */
1292
229
    Curl_conn_terminate(m->data, conn, FALSE);
1293
229
    return FALSE;
1294
229
  }
1295
1296
  /* conn matches our needs. */
1297
6.61k
  m->found = conn;
1298
6.61k
  return TRUE;
1299
6.84k
}
1300
1301
static bool url_match_result(bool result, void *userdata)
1302
94.1k
{
1303
94.1k
  struct url_conn_match *match = userdata;
1304
94.1k
  (void)result;
1305
94.1k
  if(match->found) {
1306
    /* Attach it now while still under lock, so the connection does
1307
     * no longer appear idle and can be reaped. */
1308
7.13k
    Curl_attach_connection(match->data, match->found);
1309
7.13k
    return TRUE;
1310
7.13k
  }
1311
87.0k
  else if(match->seen_single_use_conn && !match->seen_multiplex_conn) {
1312
    /* We've seen a single-use, existing connection to the destination and
1313
     * no multiplexed one. It seems safe to assume that the server does
1314
     * not support multiplexing. */
1315
0
    match->wait_pipe = FALSE;
1316
0
  }
1317
87.0k
  else if(match->seen_pending_conn && match->data->set.pipewait) {
1318
1.97k
    infof(match->data,
1319
1.97k
          "Found pending candidate for reuse and CURLOPT_PIPEWAIT is set");
1320
1.97k
    match->wait_pipe = TRUE;
1321
1.97k
  }
1322
87.0k
  match->force_reuse = FALSE;
1323
87.0k
  return FALSE;
1324
94.1k
}
1325
1326
/*
1327
 * Given one filled in connection struct (named needle), this function should
1328
 * detect if there already is one that has all the significant details
1329
 * exactly the same and thus should be used instead.
1330
 *
1331
 * If there is a match, this function returns TRUE - and has marked the
1332
 * connection as 'in-use'. It must later be called with ConnectionDone() to
1333
 * return back to 'idle' (unused) state.
1334
 *
1335
 * The force_reuse flag is set if the connection must be used.
1336
 */
1337
static bool
1338
ConnectionExists(struct Curl_easy *data,
1339
                 struct connectdata *needle,
1340
                 struct connectdata **usethis,
1341
                 bool *force_reuse,
1342
                 bool *waitpipe)
1343
94.1k
{
1344
94.1k
  struct url_conn_match match;
1345
94.1k
  bool result;
1346
1347
94.1k
  memset(&match, 0, sizeof(match));
1348
94.1k
  match.data = data;
1349
94.1k
  match.needle = needle;
1350
94.1k
  match.may_multiplex = xfer_may_multiplex(data, needle);
1351
1352
94.1k
#ifdef USE_NTLM
1353
94.1k
  match.want_ntlm_http = ((data->state.authhost.want & CURLAUTH_NTLM) &&
1354
94.1k
                          (needle->handler->protocol & PROTO_FAMILY_HTTP));
1355
94.1k
#ifndef CURL_DISABLE_PROXY
1356
94.1k
  match.want_proxy_ntlm_http =
1357
94.1k
    (needle->bits.proxy_user_passwd &&
1358
94.1k
     (data->state.authproxy.want & CURLAUTH_NTLM) &&
1359
94.1k
     (needle->handler->protocol & PROTO_FAMILY_HTTP));
1360
94.1k
#endif
1361
94.1k
#endif
1362
1363
  /* Find a connection in the pool that matches what "data + needle"
1364
   * requires. If a suitable candidate is found, it is attached to "data". */
1365
94.1k
  result = Curl_cpool_find(data, needle->destination,
1366
94.1k
                           url_match_conn, url_match_result, &match);
1367
1368
  /* wait_pipe is TRUE if we encounter a bundle that is undecided. There
1369
   * is no matching connection then, yet. */
1370
94.1k
  *usethis = match.found;
1371
94.1k
  *force_reuse = match.force_reuse;
1372
94.1k
  *waitpipe = match.wait_pipe;
1373
94.1k
  return result;
1374
94.1k
}
1375
1376
/*
1377
 * verboseconnect() displays verbose information after a connect
1378
 */
1379
#ifndef CURL_DISABLE_VERBOSE_STRINGS
1380
void Curl_verboseconnect(struct Curl_easy *data,
1381
                         struct connectdata *conn, int sockindex)
1382
49.9k
{
1383
49.9k
  if(data->set.verbose && sockindex == SECONDARYSOCKET)
1384
0
    infof(data, "Connected 2nd connection to %s port %u",
1385
49.9k
          conn->secondary.remote_ip, conn->secondary.remote_port);
1386
49.9k
  else
1387
49.9k
    infof(data, "Connected to %s (%s) port %u",
1388
49.9k
          CURL_CONN_HOST_DISPNAME(conn), conn->primary.remote_ip,
1389
49.9k
          conn->primary.remote_port);
1390
49.9k
#ifndef CURL_DISABLE_HTTP
1391
49.9k
    if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
1392
28.3k
      switch(conn->alpn) {
1393
0
      case CURL_HTTP_VERSION_3:
1394
0
        infof(data, "using HTTP/3");
1395
0
        break;
1396
0
      case CURL_HTTP_VERSION_2:
1397
0
        infof(data, "using HTTP/2");
1398
0
        break;
1399
28.3k
      default:
1400
28.3k
        infof(data, "using HTTP/1.x");
1401
28.3k
        break;
1402
28.3k
      }
1403
28.3k
    }
1404
49.9k
#endif
1405
49.9k
}
1406
#endif
1407
1408
/*
1409
 * Allocate and initialize a new connectdata object.
1410
 */
1411
static struct connectdata *allocate_conn(struct Curl_easy *data)
1412
126k
{
1413
126k
  struct connectdata *conn = calloc(1, sizeof(struct connectdata));
1414
126k
  if(!conn)
1415
0
    return NULL;
1416
1417
  /* and we setup a few fields in case we end up actually using this struct */
1418
1419
126k
  conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD;     /* no file descriptor */
1420
126k
  conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
1421
126k
  conn->sockfd = CURL_SOCKET_BAD;
1422
126k
  conn->writesockfd = CURL_SOCKET_BAD;
1423
126k
  conn->connection_id = -1;    /* no ID */
1424
126k
  conn->primary.remote_port = -1; /* unknown at this point */
1425
126k
  conn->remote_port = -1; /* unknown at this point */
1426
1427
  /* Default protocol-independent behavior does not support persistent
1428
     connections, so we set this to force-close. Protocols that support
1429
     this need to set this to FALSE in their "curl_do" functions. */
1430
126k
  connclose(conn, "Default to force-close");
1431
1432
  /* Store creation time to help future close decision making */
1433
126k
  conn->created = curlx_now();
1434
1435
  /* Store current time to give a baseline to keepalive connection times. */
1436
126k
  conn->keepalive = conn->created;
1437
1438
126k
#ifndef CURL_DISABLE_PROXY
1439
126k
  conn->http_proxy.proxytype = data->set.proxytype;
1440
126k
  conn->socks_proxy.proxytype = CURLPROXY_SOCKS4;
1441
1442
  /* note that these two proxy bits are now just on what looks to be
1443
     requested, they may be altered down the road */
1444
126k
  conn->bits.proxy = (data->set.str[STRING_PROXY] &&
1445
126k
                      *data->set.str[STRING_PROXY]);
1446
126k
  conn->bits.httpproxy = (conn->bits.proxy &&
1447
126k
                          (conn->http_proxy.proxytype == CURLPROXY_HTTP ||
1448
16.9k
                           conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0 ||
1449
16.9k
                           IS_HTTPS_PROXY(conn->http_proxy.proxytype)));
1450
126k
  conn->bits.socksproxy = (conn->bits.proxy && !conn->bits.httpproxy);
1451
1452
126k
  if(data->set.str[STRING_PRE_PROXY] && *data->set.str[STRING_PRE_PROXY]) {
1453
20.7k
    conn->bits.proxy = TRUE;
1454
20.7k
    conn->bits.socksproxy = TRUE;
1455
20.7k
  }
1456
1457
126k
  conn->bits.proxy_user_passwd = !!data->state.aptr.proxyuser;
1458
126k
  conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
1459
126k
#endif /* CURL_DISABLE_PROXY */
1460
1461
126k
#ifndef CURL_DISABLE_FTP
1462
126k
  conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
1463
126k
  conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
1464
126k
#endif
1465
126k
  conn->ip_version = data->set.ipver;
1466
126k
  conn->connect_only = data->set.connect_only;
1467
126k
  conn->transport = TRNSPRT_TCP; /* most of them are TCP streams */
1468
1469
  /* Initialize the attached xfers bitset */
1470
126k
  Curl_uint_spbset_init(&conn->xfers_attached);
1471
1472
#ifdef HAVE_GSSAPI
1473
  conn->data_prot = PROT_CLEAR;
1474
#endif
1475
1476
  /* Store the local bind parameters that will be used for this connection */
1477
126k
  if(data->set.str[STRING_DEVICE]) {
1478
1.56k
    conn->localdev = strdup(data->set.str[STRING_DEVICE]);
1479
1.56k
    if(!conn->localdev)
1480
0
      goto error;
1481
1.56k
  }
1482
126k
#ifndef CURL_DISABLE_BINDLOCAL
1483
126k
  conn->localportrange = data->set.localportrange;
1484
126k
  conn->localport = data->set.localport;
1485
126k
#endif
1486
1487
  /* the close socket stuff needs to be copied to the connection struct as
1488
     it may live on without (this specific) Curl_easy */
1489
126k
  conn->fclosesocket = data->set.fclosesocket;
1490
126k
  conn->closesocket_client = data->set.closesocket_client;
1491
126k
  conn->lastused = conn->created;
1492
#ifdef HAVE_GSSAPI
1493
  conn->gssapi_delegation = data->set.gssapi_delegation;
1494
#endif
1495
126k
  return conn;
1496
0
error:
1497
1498
0
  free(conn->localdev);
1499
0
  free(conn);
1500
0
  return NULL;
1501
126k
}
1502
1503
const struct Curl_handler *Curl_get_scheme_handler(const char *scheme)
1504
481k
{
1505
481k
  return Curl_getn_scheme_handler(scheme, strlen(scheme));
1506
481k
}
1507
1508
/* returns the handler if the given scheme is built-in */
1509
const struct Curl_handler *Curl_getn_scheme_handler(const char *scheme,
1510
                                                    size_t len)
1511
765k
{
1512
  /* table generated by schemetable.c:
1513
     1. gcc schemetable.c && ./a.out
1514
     2. check how small the table gets
1515
     3. tweak the hash algorithm, then rerun from 1
1516
     4. when the table is good enough
1517
     5. copy the table into this source code
1518
     6. make sure this function uses the same hash function that worked for
1519
     schemetable.c
1520
     7. if needed, adjust the #ifdefs in schemetable.c and rerun
1521
     */
1522
765k
  static const struct Curl_handler * const protocols[67] = {
1523
765k
#ifndef CURL_DISABLE_FILE
1524
765k
    &Curl_handler_file,
1525
#else
1526
    NULL,
1527
#endif
1528
765k
    NULL, NULL,
1529
765k
#if defined(USE_SSL) && !defined(CURL_DISABLE_GOPHER)
1530
765k
    &Curl_handler_gophers,
1531
#else
1532
    NULL,
1533
#endif
1534
765k
    NULL,
1535
#ifdef USE_LIBRTMP
1536
    &Curl_handler_rtmpe,
1537
#else
1538
765k
    NULL,
1539
765k
#endif
1540
765k
#ifndef CURL_DISABLE_SMTP
1541
765k
    &Curl_handler_smtp,
1542
#else
1543
    NULL,
1544
#endif
1545
#ifdef USE_SSH
1546
    &Curl_handler_sftp,
1547
#else
1548
765k
    NULL,
1549
765k
#endif
1550
765k
#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \
1551
765k
  (SIZEOF_CURL_OFF_T > 4)
1552
765k
    &Curl_handler_smb,
1553
#else
1554
    NULL,
1555
#endif
1556
765k
#if defined(USE_SSL) && !defined(CURL_DISABLE_SMTP)
1557
765k
    &Curl_handler_smtps,
1558
#else
1559
    NULL,
1560
#endif
1561
765k
#ifndef CURL_DISABLE_TELNET
1562
765k
    &Curl_handler_telnet,
1563
#else
1564
    NULL,
1565
#endif
1566
765k
#ifndef CURL_DISABLE_GOPHER
1567
765k
    &Curl_handler_gopher,
1568
#else
1569
    NULL,
1570
#endif
1571
765k
#ifndef CURL_DISABLE_TFTP
1572
765k
    &Curl_handler_tftp,
1573
#else
1574
    NULL,
1575
#endif
1576
765k
    NULL, NULL, NULL,
1577
765k
#if defined(USE_SSL) && !defined(CURL_DISABLE_FTP)
1578
765k
    &Curl_handler_ftps,
1579
#else
1580
    NULL,
1581
#endif
1582
765k
#ifndef CURL_DISABLE_HTTP
1583
765k
    &Curl_handler_http,
1584
#else
1585
    NULL,
1586
#endif
1587
765k
#ifndef CURL_DISABLE_IMAP
1588
765k
    &Curl_handler_imap,
1589
#else
1590
    NULL,
1591
#endif
1592
#ifdef USE_LIBRTMP
1593
    &Curl_handler_rtmps,
1594
#else
1595
765k
    NULL,
1596
765k
#endif
1597
#ifdef USE_LIBRTMP
1598
    &Curl_handler_rtmpt,
1599
#else
1600
765k
    NULL,
1601
765k
#endif
1602
765k
    NULL, NULL, NULL,
1603
#if !defined(CURL_DISABLE_LDAP) && \
1604
  !defined(CURL_DISABLE_LDAPS) && \
1605
  ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \
1606
   (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL)))
1607
    &Curl_handler_ldaps,
1608
#else
1609
765k
    NULL,
1610
765k
#endif
1611
765k
#if !defined(CURL_DISABLE_WEBSOCKETS) &&                \
1612
765k
  defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
1613
765k
    &Curl_handler_wss,
1614
#else
1615
    NULL,
1616
#endif
1617
765k
#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
1618
765k
    &Curl_handler_https,
1619
#else
1620
    NULL,
1621
#endif
1622
765k
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1623
765k
#ifndef CURL_DISABLE_RTSP
1624
765k
    &Curl_handler_rtsp,
1625
#else
1626
    NULL,
1627
#endif
1628
765k
#if defined(USE_SSL) && !defined(CURL_DISABLE_SMB) && \
1629
765k
  defined(USE_CURL_NTLM_CORE) && (SIZEOF_CURL_OFF_T > 4)
1630
765k
    &Curl_handler_smbs,
1631
#else
1632
    NULL,
1633
#endif
1634
#if defined(USE_SSH) && !defined(USE_WOLFSSH)
1635
    &Curl_handler_scp,
1636
#else
1637
765k
    NULL,
1638
765k
#endif
1639
765k
    NULL, NULL, NULL,
1640
765k
#ifndef CURL_DISABLE_POP3
1641
765k
    &Curl_handler_pop3,
1642
#else
1643
    NULL,
1644
#endif
1645
765k
    NULL, NULL,
1646
#ifdef USE_LIBRTMP
1647
    &Curl_handler_rtmp,
1648
#else
1649
765k
    NULL,
1650
765k
#endif
1651
765k
    NULL, NULL, NULL,
1652
#ifdef USE_LIBRTMP
1653
    &Curl_handler_rtmpte,
1654
#else
1655
765k
    NULL,
1656
765k
#endif
1657
765k
    NULL, NULL, NULL,
1658
765k
#ifndef CURL_DISABLE_DICT
1659
765k
    &Curl_handler_dict,
1660
#else
1661
    NULL,
1662
#endif
1663
765k
    NULL, NULL, NULL,
1664
765k
#ifndef CURL_DISABLE_MQTT
1665
765k
    &Curl_handler_mqtt,
1666
#else
1667
    NULL,
1668
#endif
1669
765k
#if defined(USE_SSL) && !defined(CURL_DISABLE_POP3)
1670
765k
    &Curl_handler_pop3s,
1671
#else
1672
    NULL,
1673
#endif
1674
765k
#if defined(USE_SSL) && !defined(CURL_DISABLE_IMAP)
1675
765k
    &Curl_handler_imaps,
1676
#else
1677
    NULL,
1678
#endif
1679
765k
    NULL,
1680
765k
#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
1681
765k
    &Curl_handler_ws,
1682
#else
1683
    NULL,
1684
#endif
1685
765k
    NULL,
1686
#ifdef USE_LIBRTMP
1687
    &Curl_handler_rtmpts,
1688
#else
1689
765k
    NULL,
1690
765k
#endif
1691
#ifndef CURL_DISABLE_LDAP
1692
    &Curl_handler_ldap,
1693
#else
1694
765k
    NULL,
1695
765k
#endif
1696
765k
    NULL, NULL,
1697
765k
#ifndef CURL_DISABLE_FTP
1698
765k
    &Curl_handler_ftp,
1699
#else
1700
    NULL,
1701
#endif
1702
765k
  };
1703
1704
765k
  if(len && (len <= 7)) {
1705
765k
    const char *s = scheme;
1706
765k
    size_t l = len;
1707
765k
    const struct Curl_handler *h;
1708
765k
    unsigned int c = 978;
1709
3.91M
    while(l) {
1710
3.15M
      c <<= 5;
1711
3.15M
      c += (unsigned int)Curl_raw_tolower(*s);
1712
3.15M
      s++;
1713
3.15M
      l--;
1714
3.15M
    }
1715
1716
765k
    h = protocols[c % 67];
1717
765k
    if(h && curl_strnequal(scheme, h->scheme, len) && !h->scheme[len])
1718
758k
      return h;
1719
765k
  }
1720
6.58k
  return NULL;
1721
765k
}
1722
1723
static CURLcode findprotocol(struct Curl_easy *data,
1724
                             struct connectdata *conn,
1725
                             const char *protostr)
1726
117k
{
1727
117k
  const struct Curl_handler *p = Curl_get_scheme_handler(protostr);
1728
1729
117k
  if(p && /* Protocol found in table. Check if allowed */
1730
117k
     (data->set.allowed_protocols & p->protocol)) {
1731
1732
    /* it is allowed for "normal" request, now do an extra check if this is
1733
       the result of a redirect */
1734
110k
    if(data->state.this_is_a_follow &&
1735
110k
       !(data->set.redir_protocols & p->protocol))
1736
      /* nope, get out */
1737
76
      ;
1738
110k
    else {
1739
      /* Perform setup complement if some. */
1740
110k
      conn->handler = conn->given = p;
1741
      /* 'port' and 'remote_port' are set in setup_connection_internals() */
1742
110k
      return CURLE_OK;
1743
110k
    }
1744
110k
  }
1745
1746
  /* The protocol was not found in the table, but we do not have to assign it
1747
     to anything since it is already assigned to a dummy-struct in the
1748
     create_conn() function when the connectdata struct is allocated. */
1749
7.20k
  failf(data, "Protocol \"%s\" %s%s", protostr,
1750
7.20k
        p ? "disabled" : "not supported",
1751
7.20k
        data->state.this_is_a_follow ? " (in redirect)":"");
1752
1753
7.20k
  return CURLE_UNSUPPORTED_PROTOCOL;
1754
117k
}
1755
1756
1757
CURLcode Curl_uc_to_curlcode(CURLUcode uc)
1758
7.11k
{
1759
7.11k
  switch(uc) {
1760
7.08k
  default:
1761
7.08k
    return CURLE_URL_MALFORMAT;
1762
21
  case CURLUE_UNSUPPORTED_SCHEME:
1763
21
    return CURLE_UNSUPPORTED_PROTOCOL;
1764
0
  case CURLUE_OUT_OF_MEMORY:
1765
0
    return CURLE_OUT_OF_MEMORY;
1766
13
  case CURLUE_USER_NOT_ALLOWED:
1767
13
    return CURLE_LOGIN_DENIED;
1768
7.11k
  }
1769
7.11k
}
1770
1771
#ifdef USE_IPV6
1772
/*
1773
 * If the URL was set with an IPv6 numerical address with a zone id part, set
1774
 * the scope_id based on that!
1775
 */
1776
1777
static void zonefrom_url(CURLU *uh, struct Curl_easy *data,
1778
                         struct connectdata *conn)
1779
739
{
1780
739
  char *zoneid;
1781
739
  CURLUcode uc = curl_url_get(uh, CURLUPART_ZONEID, &zoneid, 0);
1782
#ifdef CURL_DISABLE_VERBOSE_STRINGS
1783
  (void)data;
1784
#endif
1785
1786
739
  if(!uc && zoneid) {
1787
481
    const char *p = zoneid;
1788
481
    curl_off_t scope;
1789
481
    if(!curlx_str_number(&p, &scope, UINT_MAX))
1790
      /* A plain number, use it directly as a scope id. */
1791
233
      conn->scope_id = (unsigned int)scope;
1792
248
#ifdef HAVE_IF_NAMETOINDEX
1793
248
    else {
1794
#elif defined(_WIN32)
1795
    else if(Curl_if_nametoindex) {
1796
#endif
1797
1798
248
#if defined(HAVE_IF_NAMETOINDEX) || defined(_WIN32)
1799
      /* Zone identifier is not numeric */
1800
248
      unsigned int scopeidx = 0;
1801
248
#ifdef HAVE_IF_NAMETOINDEX
1802
248
      scopeidx = if_nametoindex(zoneid);
1803
#else
1804
      scopeidx = Curl_if_nametoindex(zoneid);
1805
#endif
1806
248
      if(!scopeidx) {
1807
219
#ifndef CURL_DISABLE_VERBOSE_STRINGS
1808
219
        char buffer[STRERROR_LEN];
1809
219
        infof(data, "Invalid zoneid: %s; %s", zoneid,
1810
219
              Curl_strerror(errno, buffer, sizeof(buffer)));
1811
219
#endif
1812
219
      }
1813
29
      else
1814
29
        conn->scope_id = scopeidx;
1815
248
    }
1816
481
#endif /* HAVE_IF_NAMETOINDEX || _WIN32 */
1817
1818
481
    free(zoneid);
1819
481
  }
1820
739
}
1821
#else
1822
#define zonefrom_url(a,b,c) Curl_nop_stmt
1823
#endif
1824
1825
/*
1826
 * Parse URL and fill in the relevant members of the connection struct.
1827
 */
1828
static CURLcode parseurlandfillconn(struct Curl_easy *data,
1829
                                    struct connectdata *conn)
1830
126k
{
1831
126k
  CURLcode result;
1832
126k
  CURLU *uh;
1833
126k
  CURLUcode uc;
1834
126k
  char *hostname;
1835
126k
  bool use_set_uh = (data->set.uh && !data->state.this_is_a_follow);
1836
1837
126k
  up_free(data); /* cleanup previous leftovers first */
1838
1839
  /* parse the URL */
1840
126k
  if(use_set_uh) {
1841
0
    uh = data->state.uh = curl_url_dup(data->set.uh);
1842
0
  }
1843
126k
  else {
1844
126k
    uh = data->state.uh = curl_url();
1845
126k
  }
1846
1847
126k
  if(!uh)
1848
0
    return CURLE_OUT_OF_MEMORY;
1849
1850
126k
  if(data->set.str[STRING_DEFAULT_PROTOCOL] &&
1851
126k
     !Curl_is_absolute_url(data->state.url, NULL, 0, TRUE)) {
1852
6.67k
    char *url = aprintf("%s://%s", data->set.str[STRING_DEFAULT_PROTOCOL],
1853
6.67k
                        data->state.url);
1854
6.67k
    if(!url)
1855
0
      return CURLE_OUT_OF_MEMORY;
1856
6.67k
    if(data->state.url_alloc)
1857
0
      free(data->state.url);
1858
6.67k
    data->state.url = url;
1859
6.67k
    data->state.url_alloc = TRUE;
1860
6.67k
  }
1861
1862
126k
  if(!use_set_uh) {
1863
126k
    char *newurl;
1864
126k
    uc = curl_url_set(uh, CURLUPART_URL, data->state.url, (unsigned int)
1865
126k
                      (CURLU_GUESS_SCHEME |
1866
126k
                       CURLU_NON_SUPPORT_SCHEME |
1867
126k
                       (data->set.disallow_username_in_url ?
1868
126k
                        CURLU_DISALLOW_USER : 0) |
1869
126k
                       (data->set.path_as_is ? CURLU_PATH_AS_IS : 0)));
1870
126k
    if(uc) {
1871
7.08k
      failf(data, "URL rejected: %s", curl_url_strerror(uc));
1872
7.08k
      return Curl_uc_to_curlcode(uc);
1873
7.08k
    }
1874
1875
    /* after it was parsed, get the generated normalized version */
1876
119k
    uc = curl_url_get(uh, CURLUPART_URL, &newurl, 0);
1877
119k
    if(uc)
1878
0
      return Curl_uc_to_curlcode(uc);
1879
119k
    if(data->state.url_alloc)
1880
15.6k
      free(data->state.url);
1881
119k
    data->state.url = newurl;
1882
119k
    data->state.url_alloc = TRUE;
1883
119k
  }
1884
1885
119k
  uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0);
1886
119k
  if(uc)
1887
0
    return Curl_uc_to_curlcode(uc);
1888
1889
119k
  uc = curl_url_get(uh, CURLUPART_HOST, &data->state.up.hostname, 0);
1890
119k
  if(uc) {
1891
2.43k
    if(!curl_strequal("file", data->state.up.scheme))
1892
0
      return CURLE_OUT_OF_MEMORY;
1893
2.43k
  }
1894
116k
  else if(strlen(data->state.up.hostname) > MAX_URL_LEN) {
1895
23
    failf(data, "Too long hostname (maximum is %d)", MAX_URL_LEN);
1896
23
    return CURLE_URL_MALFORMAT;
1897
23
  }
1898
119k
  hostname = data->state.up.hostname;
1899
1900
119k
  if(hostname && hostname[0] == '[') {
1901
    /* This looks like an IPv6 address literal. See if there is an address
1902
       scope. */
1903
527
    size_t hlen;
1904
527
    conn->bits.ipv6_ip = TRUE;
1905
    /* cut off the brackets! */
1906
527
    hostname++;
1907
527
    hlen = strlen(hostname);
1908
527
    hostname[hlen - 1] = 0;
1909
1910
527
    zonefrom_url(uh, data, conn);
1911
527
  }
1912
1913
  /* make sure the connect struct gets its own copy of the hostname */
1914
119k
  conn->host.rawalloc = strdup(hostname ? hostname : "");
1915
119k
  if(!conn->host.rawalloc)
1916
0
    return CURLE_OUT_OF_MEMORY;
1917
119k
  conn->host.name = conn->host.rawalloc;
1918
1919
  /*************************************************************
1920
   * IDN-convert the hostnames
1921
   *************************************************************/
1922
119k
  result = Curl_idnconvert_hostname(&conn->host);
1923
119k
  if(result)
1924
1.82k
    return result;
1925
1926
117k
#ifndef CURL_DISABLE_HSTS
1927
  /* HSTS upgrade */
1928
117k
  if(data->hsts && curl_strequal("http", data->state.up.scheme)) {
1929
    /* This MUST use the IDN decoded name */
1930
32.1k
    if(Curl_hsts(data->hsts, conn->host.name, strlen(conn->host.name), TRUE)) {
1931
2
      char *url;
1932
2
      Curl_safefree(data->state.up.scheme);
1933
2
      uc = curl_url_set(uh, CURLUPART_SCHEME, "https", 0);
1934
2
      if(uc)
1935
0
        return Curl_uc_to_curlcode(uc);
1936
2
      if(data->state.url_alloc)
1937
2
        Curl_safefree(data->state.url);
1938
      /* after update, get the updated version */
1939
2
      uc = curl_url_get(uh, CURLUPART_URL, &url, 0);
1940
2
      if(uc)
1941
0
        return Curl_uc_to_curlcode(uc);
1942
2
      uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0);
1943
2
      if(uc) {
1944
0
        free(url);
1945
0
        return Curl_uc_to_curlcode(uc);
1946
0
      }
1947
2
      data->state.url = url;
1948
2
      data->state.url_alloc = TRUE;
1949
2
      infof(data, "Switched from HTTP to HTTPS due to HSTS => %s",
1950
2
            data->state.url);
1951
2
    }
1952
32.1k
  }
1953
117k
#endif
1954
1955
117k
  result = findprotocol(data, conn, data->state.up.scheme);
1956
117k
  if(result)
1957
7.20k
    return result;
1958
1959
  /*
1960
   * username and password set with their own options override the credentials
1961
   * possibly set in the URL, but netrc does not.
1962
   */
1963
110k
  if(!data->state.aptr.passwd || (data->state.creds_from != CREDS_OPTION)) {
1964
106k
    uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0);
1965
106k
    if(!uc) {
1966
3.15k
      char *decoded;
1967
3.15k
      result = Curl_urldecode(data->state.up.password, 0, &decoded, NULL,
1968
3.15k
                              conn->handler->flags&PROTOPT_USERPWDCTRL ?
1969
2.12k
                              REJECT_ZERO : REJECT_CTRL);
1970
3.15k
      if(result)
1971
34
        return result;
1972
3.11k
      conn->passwd = decoded;
1973
3.11k
      result = Curl_setstropt(&data->state.aptr.passwd, decoded);
1974
3.11k
      if(result)
1975
0
        return result;
1976
3.11k
      data->state.creds_from = CREDS_URL;
1977
3.11k
    }
1978
103k
    else if(uc != CURLUE_NO_PASSWORD)
1979
0
      return Curl_uc_to_curlcode(uc);
1980
106k
  }
1981
1982
110k
  if(!data->state.aptr.user || (data->state.creds_from != CREDS_OPTION)) {
1983
    /* we do not use the URL API's URL decoder option here since it rejects
1984
       control codes and we want to allow them for some schemes in the user
1985
       and password fields */
1986
106k
    uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user, 0);
1987
106k
    if(!uc) {
1988
18.8k
      char *decoded;
1989
18.8k
      result = Curl_urldecode(data->state.up.user, 0, &decoded, NULL,
1990
18.8k
                              conn->handler->flags&PROTOPT_USERPWDCTRL ?
1991
12.0k
                              REJECT_ZERO : REJECT_CTRL);
1992
18.8k
      if(result)
1993
40
        return result;
1994
18.8k
      conn->user = decoded;
1995
18.8k
      result = Curl_setstropt(&data->state.aptr.user, decoded);
1996
18.8k
      data->state.creds_from = CREDS_URL;
1997
18.8k
    }
1998
87.2k
    else if(uc != CURLUE_NO_USER)
1999
0
      return Curl_uc_to_curlcode(uc);
2000
106k
    if(result)
2001
0
      return result;
2002
106k
  }
2003
2004
110k
  uc = curl_url_get(uh, CURLUPART_OPTIONS, &data->state.up.options,
2005
110k
                    CURLU_URLDECODE);
2006
110k
  if(!uc) {
2007
248
    conn->options = strdup(data->state.up.options);
2008
248
    if(!conn->options)
2009
0
      return CURLE_OUT_OF_MEMORY;
2010
248
  }
2011
110k
  else if(uc != CURLUE_NO_OPTIONS)
2012
3
    return Curl_uc_to_curlcode(uc);
2013
2014
110k
  uc = curl_url_get(uh, CURLUPART_PATH, &data->state.up.path,
2015
110k
                    CURLU_URLENCODE);
2016
110k
  if(uc)
2017
0
    return Curl_uc_to_curlcode(uc);
2018
2019
110k
  uc = curl_url_get(uh, CURLUPART_PORT, &data->state.up.port,
2020
110k
                    CURLU_DEFAULT_PORT);
2021
110k
  if(uc) {
2022
0
    if(!curl_strequal("file", data->state.up.scheme))
2023
0
      return CURLE_OUT_OF_MEMORY;
2024
0
  }
2025
110k
  else {
2026
110k
    curl_off_t port;
2027
110k
    bool valid = TRUE;
2028
110k
    if(data->set.use_port && data->state.allow_port)
2029
425
      port = data->set.use_port;
2030
109k
    else {
2031
109k
      const char *p = data->state.up.port;
2032
109k
      if(curlx_str_number(&p, &port, 0xffff))
2033
0
        valid = FALSE;
2034
109k
    }
2035
110k
    if(valid)
2036
110k
      conn->primary.remote_port = conn->remote_port = (unsigned short)port;
2037
110k
  }
2038
2039
110k
  (void)curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query, 0);
2040
2041
110k
#ifdef USE_IPV6
2042
110k
  if(data->set.scope_id)
2043
    /* Override any scope that was set above.  */
2044
982
    conn->scope_id = data->set.scope_id;
2045
110k
#endif
2046
2047
110k
  return CURLE_OK;
2048
110k
}
2049
2050
2051
/*
2052
 * If we are doing a resumed transfer, we need to setup our stuff
2053
 * properly.
2054
 */
2055
static CURLcode setup_range(struct Curl_easy *data)
2056
107k
{
2057
107k
  struct UrlState *s = &data->state;
2058
107k
  s->resume_from = data->set.set_resume_from;
2059
107k
  if(s->resume_from || data->set.str[STRING_SET_RANGE]) {
2060
5.22k
    if(s->rangestringalloc)
2061
1.76k
      free(s->range);
2062
2063
5.22k
    if(s->resume_from)
2064
2.70k
      s->range = aprintf("%" FMT_OFF_T "-", s->resume_from);
2065
2.52k
    else
2066
2.52k
      s->range = strdup(data->set.str[STRING_SET_RANGE]);
2067
2068
5.22k
    if(!s->range)
2069
0
      return CURLE_OUT_OF_MEMORY;
2070
2071
5.22k
    s->rangestringalloc = TRUE;
2072
2073
    /* tell ourselves to fetch this range */
2074
5.22k
    s->use_range = TRUE;        /* enable range download */
2075
5.22k
  }
2076
102k
  else
2077
102k
    s->use_range = FALSE; /* disable range download */
2078
2079
107k
  return CURLE_OK;
2080
107k
}
2081
2082
2083
/*
2084
 * setup_connection_internals() -
2085
 *
2086
 * Setup connection internals specific to the requested protocol in the
2087
 * Curl_easy. This is inited and setup before the connection is made but
2088
 * is about the particular protocol that is to be used.
2089
 *
2090
 * This MUST get called after proxy magic has been figured out.
2091
 */
2092
static CURLcode setup_connection_internals(struct Curl_easy *data,
2093
                                           struct connectdata *conn)
2094
109k
{
2095
109k
  const struct Curl_handler *p;
2096
109k
  const char *hostname;
2097
109k
  int port;
2098
109k
  CURLcode result;
2099
2100
  /* Perform setup complement if some. */
2101
109k
  p = conn->handler;
2102
2103
109k
  if(p->setup_connection) {
2104
104k
    result = (*p->setup_connection)(data, conn);
2105
2106
104k
    if(result)
2107
244
      return result;
2108
2109
104k
    p = conn->handler;              /* May have changed. */
2110
104k
  }
2111
2112
109k
  if(conn->primary.remote_port < 0)
2113
    /* we check for -1 here since if proxy was detected already, this was
2114
       likely already set to the proxy port */
2115
0
    conn->primary.remote_port = p->defport;
2116
2117
  /* Now create the destination name */
2118
109k
#ifndef CURL_DISABLE_PROXY
2119
109k
  if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
2120
1.06k
    hostname = conn->http_proxy.host.name;
2121
1.06k
    port = conn->primary.remote_port;
2122
1.06k
  }
2123
108k
  else
2124
108k
#endif
2125
108k
  {
2126
108k
    port = conn->remote_port;
2127
108k
    if(conn->bits.conn_to_host)
2128
103k
      hostname = conn->conn_to_host.name;
2129
5.14k
    else
2130
5.14k
      hostname = conn->host.name;
2131
108k
  }
2132
2133
109k
#ifdef USE_IPV6
2134
109k
  conn->destination = aprintf("%u/%d/%s", conn->scope_id, port, hostname);
2135
#else
2136
  conn->destination = aprintf("%d/%s", port, hostname);
2137
#endif
2138
109k
  if(!conn->destination)
2139
0
    return CURLE_OUT_OF_MEMORY;
2140
2141
109k
  Curl_strntolower(conn->destination, conn->destination,
2142
109k
                   strlen(conn->destination));
2143
2144
109k
  return CURLE_OK;
2145
109k
}
2146
2147
2148
#ifndef CURL_DISABLE_PROXY
2149
2150
#ifndef CURL_DISABLE_HTTP
2151
/****************************************************************
2152
* Detect what (if any) proxy to use. Remember that this selects a host
2153
* name and is not limited to HTTP proxies only.
2154
* The returned pointer must be freed by the caller (unless NULL)
2155
****************************************************************/
2156
static char *detect_proxy(struct Curl_easy *data,
2157
                          struct connectdata *conn)
2158
72.8k
{
2159
72.8k
  char *proxy = NULL;
2160
2161
  /* If proxy was not specified, we check for default proxy environment
2162
   * variables, to enable i.e Lynx compliance:
2163
   *
2164
   * http_proxy=http://some.server.dom:port/
2165
   * https_proxy=http://some.server.dom:port/
2166
   * ftp_proxy=http://some.server.dom:port/
2167
   * no_proxy=domain1.dom,host.domain2.dom
2168
   *   (a comma-separated list of hosts which should
2169
   *   not be proxied, or an asterisk to override
2170
   *   all proxy variables)
2171
   * all_proxy=http://some.server.dom:port/
2172
   *   (seems to exist for the CERN www lib. Probably
2173
   *   the first to check for.)
2174
   *
2175
   * For compatibility, the all-uppercase versions of these variables are
2176
   * checked if the lowercase versions do not exist.
2177
   */
2178
72.8k
  char proxy_env[20];
2179
72.8k
  const char *envp = proxy_env;
2180
#ifdef CURL_DISABLE_VERBOSE_STRINGS
2181
  (void)data;
2182
#endif
2183
2184
72.8k
  msnprintf(proxy_env, sizeof(proxy_env), "%s_proxy", conn->handler->scheme);
2185
2186
  /* read the protocol proxy: */
2187
72.8k
  proxy = curl_getenv(proxy_env);
2188
2189
  /*
2190
   * We do not try the uppercase version of HTTP_PROXY because of
2191
   * security reasons:
2192
   *
2193
   * When curl is used in a webserver application
2194
   * environment (cgi or php), this environment variable can
2195
   * be controlled by the web server user by setting the
2196
   * http header 'Proxy:' to some value.
2197
   *
2198
   * This can cause 'internal' http/ftp requests to be
2199
   * arbitrarily redirected by any external attacker.
2200
   */
2201
72.8k
  if(!proxy && !curl_strequal("http_proxy", proxy_env)) {
2202
    /* There was no lowercase variable, try the uppercase version: */
2203
50.8k
    Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env));
2204
50.8k
    proxy = curl_getenv(proxy_env);
2205
50.8k
  }
2206
2207
72.8k
  if(!proxy) {
2208
72.8k
#ifndef CURL_DISABLE_WEBSOCKETS
2209
    /* websocket proxy fallbacks */
2210
72.8k
    if(curl_strequal("ws_proxy", proxy_env)) {
2211
496
      proxy = curl_getenv("http_proxy");
2212
496
    }
2213
72.3k
    else if(curl_strequal("wss_proxy", proxy_env)) {
2214
1.99k
      proxy = curl_getenv("https_proxy");
2215
1.99k
      if(!proxy)
2216
1.99k
        proxy = curl_getenv("HTTPS_PROXY");
2217
1.99k
    }
2218
72.8k
    if(!proxy) {
2219
72.8k
#endif
2220
72.8k
      envp = "all_proxy";
2221
72.8k
      proxy = curl_getenv(envp); /* default proxy to use */
2222
72.8k
      if(!proxy) {
2223
72.8k
        envp = "ALL_PROXY";
2224
72.8k
        proxy = curl_getenv(envp);
2225
72.8k
      }
2226
72.8k
#ifndef CURL_DISABLE_WEBSOCKETS
2227
72.8k
    }
2228
72.8k
#endif
2229
72.8k
  }
2230
72.8k
  if(proxy)
2231
0
    infof(data, "Uses proxy env variable %s == '%s'", envp, proxy);
2232
2233
72.8k
  return proxy;
2234
72.8k
}
2235
#endif /* CURL_DISABLE_HTTP */
2236
2237
/*
2238
 * If this is supposed to use a proxy, we need to figure out the proxy
2239
 * hostname, so that we can reuse an existing connection
2240
 * that may exist registered to the same proxy host.
2241
 */
2242
static CURLcode parse_proxy(struct Curl_easy *data,
2243
                            struct connectdata *conn, char *proxy,
2244
                            curl_proxytype proxytype)
2245
37.4k
{
2246
37.4k
  char *portptr = NULL;
2247
37.4k
  int port = -1;
2248
37.4k
  char *proxyuser = NULL;
2249
37.4k
  char *proxypasswd = NULL;
2250
37.4k
  char *host = NULL;
2251
37.4k
  bool sockstype;
2252
37.4k
  CURLUcode uc;
2253
37.4k
  struct proxy_info *proxyinfo;
2254
37.4k
  CURLU *uhp = curl_url();
2255
37.4k
  CURLcode result = CURLE_OK;
2256
37.4k
  char *scheme = NULL;
2257
37.4k
#ifdef USE_UNIX_SOCKETS
2258
37.4k
  char *path = NULL;
2259
37.4k
  bool is_unix_proxy = FALSE;
2260
37.4k
#endif
2261
2262
2263
37.4k
  if(!uhp) {
2264
0
    result = CURLE_OUT_OF_MEMORY;
2265
0
    goto error;
2266
0
  }
2267
2268
  /* When parsing the proxy, allowing non-supported schemes since we have
2269
     these made up ones for proxies. Guess scheme for URLs without it. */
2270
37.4k
  uc = curl_url_set(uhp, CURLUPART_URL, proxy,
2271
37.4k
                    CURLU_NON_SUPPORT_SCHEME|CURLU_GUESS_SCHEME);
2272
37.4k
  if(!uc) {
2273
    /* parsed okay as a URL */
2274
37.3k
    uc = curl_url_get(uhp, CURLUPART_SCHEME, &scheme, 0);
2275
37.3k
    if(uc) {
2276
0
      result = CURLE_OUT_OF_MEMORY;
2277
0
      goto error;
2278
0
    }
2279
2280
37.3k
    if(curl_strequal("https", scheme)) {
2281
747
      if(proxytype != CURLPROXY_HTTPS2)
2282
742
        proxytype = CURLPROXY_HTTPS;
2283
5
      else
2284
5
        proxytype = CURLPROXY_HTTPS2;
2285
747
    }
2286
36.5k
    else if(curl_strequal("socks5h", scheme))
2287
0
      proxytype = CURLPROXY_SOCKS5_HOSTNAME;
2288
36.5k
    else if(curl_strequal("socks5", scheme))
2289
0
      proxytype = CURLPROXY_SOCKS5;
2290
36.5k
    else if(curl_strequal("socks4a", scheme))
2291
0
      proxytype = CURLPROXY_SOCKS4A;
2292
36.5k
    else if(curl_strequal("socks4", scheme) ||
2293
36.5k
            curl_strequal("socks", scheme))
2294
0
      proxytype = CURLPROXY_SOCKS4;
2295
36.5k
    else if(curl_strequal("http", scheme))
2296
36.5k
      ; /* leave it as HTTP or HTTP/1.0 */
2297
33
    else {
2298
      /* Any other xxx:// reject! */
2299
33
      failf(data, "Unsupported proxy scheme for \'%s\'", proxy);
2300
33
      result = CURLE_COULDNT_CONNECT;
2301
33
      goto error;
2302
33
    }
2303
37.3k
  }
2304
96
  else {
2305
96
    failf(data, "Unsupported proxy syntax in \'%s\': %s", proxy,
2306
96
          curl_url_strerror(uc));
2307
96
    result = CURLE_COULDNT_RESOLVE_PROXY;
2308
96
    goto error;
2309
96
  }
2310
2311
37.2k
#ifdef USE_SSL
2312
37.2k
  if(!Curl_ssl_supports(data, SSLSUPP_HTTPS_PROXY))
2313
0
#endif
2314
0
    if(IS_HTTPS_PROXY(proxytype)) {
2315
0
      failf(data, "Unsupported proxy \'%s\', libcurl is built without the "
2316
0
            "HTTPS-proxy support.", proxy);
2317
0
      result = CURLE_NOT_BUILT_IN;
2318
0
      goto error;
2319
0
    }
2320
2321
37.2k
  sockstype =
2322
37.2k
    proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
2323
37.2k
    proxytype == CURLPROXY_SOCKS5 ||
2324
37.2k
    proxytype == CURLPROXY_SOCKS4A ||
2325
37.2k
    proxytype == CURLPROXY_SOCKS4;
2326
2327
37.2k
  proxyinfo = sockstype ? &conn->socks_proxy : &conn->http_proxy;
2328
37.2k
  proxyinfo->proxytype = (unsigned char)proxytype;
2329
2330
  /* Is there a username and password given in this proxy url? */
2331
37.2k
  uc = curl_url_get(uhp, CURLUPART_USER, &proxyuser, CURLU_URLDECODE);
2332
37.2k
  if(uc && (uc != CURLUE_NO_USER))
2333
60
    goto error;
2334
37.2k
  uc = curl_url_get(uhp, CURLUPART_PASSWORD, &proxypasswd, CURLU_URLDECODE);
2335
37.2k
  if(uc && (uc != CURLUE_NO_PASSWORD))
2336
24
    goto error;
2337
2338
37.1k
  if(proxyuser || proxypasswd) {
2339
13.7k
    free(proxyinfo->user);
2340
13.7k
    proxyinfo->user = proxyuser;
2341
13.7k
    result = Curl_setstropt(&data->state.aptr.proxyuser, proxyuser);
2342
13.7k
    proxyuser = NULL;
2343
13.7k
    if(result)
2344
0
      goto error;
2345
13.7k
    Curl_safefree(proxyinfo->passwd);
2346
13.7k
    if(!proxypasswd) {
2347
11.4k
      proxypasswd = strdup("");
2348
11.4k
      if(!proxypasswd) {
2349
0
        result = CURLE_OUT_OF_MEMORY;
2350
0
        goto error;
2351
0
      }
2352
11.4k
    }
2353
13.7k
    proxyinfo->passwd = proxypasswd;
2354
13.7k
    result = Curl_setstropt(&data->state.aptr.proxypasswd, proxypasswd);
2355
13.7k
    proxypasswd = NULL;
2356
13.7k
    if(result)
2357
0
      goto error;
2358
13.7k
    conn->bits.proxy_user_passwd = TRUE; /* enable it */
2359
13.7k
  }
2360
2361
37.1k
  (void)curl_url_get(uhp, CURLUPART_PORT, &portptr, 0);
2362
2363
37.1k
  if(portptr) {
2364
1.32k
    curl_off_t num;
2365
1.32k
    const char *p = portptr;
2366
1.32k
    if(!curlx_str_number(&p, &num, 0xffff))
2367
1.32k
      port = (int)num;
2368
1.32k
    free(portptr);
2369
1.32k
  }
2370
35.8k
  else {
2371
35.8k
    if(data->set.proxyport)
2372
      /* None given in the proxy string, then get the default one if it is
2373
         given */
2374
168
      port = (int)data->set.proxyport;
2375
35.6k
    else {
2376
35.6k
      if(IS_HTTPS_PROXY(proxytype))
2377
11.8k
        port = CURL_DEFAULT_HTTPS_PROXY_PORT;
2378
23.8k
      else
2379
23.8k
        port = CURL_DEFAULT_PROXY_PORT;
2380
35.6k
    }
2381
35.8k
  }
2382
37.1k
  if(port >= 0) {
2383
37.1k
    proxyinfo->port = port;
2384
37.1k
    if(conn->primary.remote_port < 0 || sockstype ||
2385
37.1k
       !conn->socks_proxy.host.rawalloc)
2386
37.1k
      conn->primary.remote_port = port;
2387
37.1k
  }
2388
2389
  /* now, clone the proxy hostname */
2390
37.1k
  uc = curl_url_get(uhp, CURLUPART_HOST, &host, CURLU_URLDECODE);
2391
37.1k
  if(uc) {
2392
0
    result = CURLE_OUT_OF_MEMORY;
2393
0
    goto error;
2394
0
  }
2395
37.1k
#ifdef USE_UNIX_SOCKETS
2396
37.1k
  if(sockstype && curl_strequal(UNIX_SOCKET_PREFIX, host)) {
2397
53
    uc = curl_url_get(uhp, CURLUPART_PATH, &path, CURLU_URLDECODE);
2398
53
    if(uc) {
2399
3
      result = CURLE_OUT_OF_MEMORY;
2400
3
      goto error;
2401
3
    }
2402
    /* path will be "/", if no path was found */
2403
50
    if(strcmp("/", path)) {
2404
20
      is_unix_proxy = TRUE;
2405
20
      free(host);
2406
20
      host = aprintf(UNIX_SOCKET_PREFIX"%s", path);
2407
20
      if(!host) {
2408
0
        result = CURLE_OUT_OF_MEMORY;
2409
0
        goto error;
2410
0
      }
2411
20
      free(proxyinfo->host.rawalloc);
2412
20
      proxyinfo->host.rawalloc = host;
2413
20
      proxyinfo->host.name = host;
2414
20
      host = NULL;
2415
20
    }
2416
50
  }
2417
2418
37.1k
  if(!is_unix_proxy) {
2419
37.1k
#endif
2420
37.1k
    free(proxyinfo->host.rawalloc);
2421
37.1k
    proxyinfo->host.rawalloc = host;
2422
37.1k
    if(host[0] == '[') {
2423
      /* this is a numerical IPv6, strip off the brackets */
2424
212
      size_t len = strlen(host);
2425
212
      host[len-1] = 0; /* clear the trailing bracket */
2426
212
      host++;
2427
212
      zonefrom_url(uhp, data, conn);
2428
212
    }
2429
37.1k
    proxyinfo->host.name = host;
2430
37.1k
    host = NULL;
2431
37.1k
#ifdef USE_UNIX_SOCKETS
2432
37.1k
  }
2433
37.1k
#endif
2434
2435
37.4k
error:
2436
37.4k
  free(proxyuser);
2437
37.4k
  free(proxypasswd);
2438
37.4k
  free(host);
2439
37.4k
  free(scheme);
2440
37.4k
#ifdef USE_UNIX_SOCKETS
2441
37.4k
  free(path);
2442
37.4k
#endif
2443
37.4k
  curl_url_cleanup(uhp);
2444
37.4k
  return result;
2445
37.1k
}
2446
2447
/*
2448
 * Extract the user and password from the authentication string
2449
 */
2450
static CURLcode parse_proxy_auth(struct Curl_easy *data,
2451
                                 struct connectdata *conn)
2452
2.54k
{
2453
2.54k
  const char *proxyuser = data->state.aptr.proxyuser ?
2454
2.54k
    data->state.aptr.proxyuser : "";
2455
2.54k
  const char *proxypasswd = data->state.aptr.proxypasswd ?
2456
1.68k
    data->state.aptr.proxypasswd : "";
2457
2.54k
  CURLcode result = CURLE_OUT_OF_MEMORY;
2458
2459
2.54k
  conn->http_proxy.user = strdup(proxyuser);
2460
2.54k
  if(conn->http_proxy.user) {
2461
2.54k
    conn->http_proxy.passwd = strdup(proxypasswd);
2462
2.54k
    if(conn->http_proxy.passwd)
2463
2.54k
      result = CURLE_OK;
2464
0
    else
2465
0
      Curl_safefree(conn->http_proxy.user);
2466
2.54k
  }
2467
2.54k
  return result;
2468
2.54k
}
2469
2470
/* create_conn helper to parse and init proxy values. to be called after Unix
2471
   socket init but before any proxy vars are evaluated. */
2472
static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
2473
                                              struct connectdata *conn)
2474
110k
{
2475
110k
  char *proxy = NULL;
2476
110k
  char *socksproxy = NULL;
2477
110k
  char *no_proxy = NULL;
2478
110k
  CURLcode result = CURLE_OK;
2479
2480
  /*************************************************************
2481
   * Extract the user and password from the authentication string
2482
   *************************************************************/
2483
110k
  if(conn->bits.proxy_user_passwd) {
2484
2.54k
    result = parse_proxy_auth(data, conn);
2485
2.54k
    if(result)
2486
0
      goto out;
2487
2.54k
  }
2488
2489
  /*************************************************************
2490
   * Detect what (if any) proxy to use
2491
   *************************************************************/
2492
110k
  if(data->set.str[STRING_PROXY]) {
2493
17.2k
    proxy = strdup(data->set.str[STRING_PROXY]);
2494
    /* if global proxy is set, this is it */
2495
17.2k
    if(!proxy) {
2496
0
      failf(data, "memory shortage");
2497
0
      result = CURLE_OUT_OF_MEMORY;
2498
0
      goto out;
2499
0
    }
2500
17.2k
  }
2501
2502
110k
  if(data->set.str[STRING_PRE_PROXY]) {
2503
20.9k
    socksproxy = strdup(data->set.str[STRING_PRE_PROXY]);
2504
    /* if global socks proxy is set, this is it */
2505
20.9k
    if(!socksproxy) {
2506
0
      failf(data, "memory shortage");
2507
0
      result = CURLE_OUT_OF_MEMORY;
2508
0
      goto out;
2509
0
    }
2510
20.9k
  }
2511
2512
110k
  if(!data->set.str[STRING_NOPROXY]) {
2513
107k
    const char *p = "no_proxy";
2514
107k
    no_proxy = curl_getenv(p);
2515
107k
    if(!no_proxy) {
2516
107k
      p = "NO_PROXY";
2517
107k
      no_proxy = curl_getenv(p);
2518
107k
    }
2519
107k
    if(no_proxy) {
2520
0
      infof(data, "Uses proxy env variable %s == '%s'", p, no_proxy);
2521
0
    }
2522
107k
  }
2523
2524
110k
  if(Curl_check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY] ?
2525
107k
                        data->set.str[STRING_NOPROXY] : no_proxy)) {
2526
124
    Curl_safefree(proxy);
2527
124
    Curl_safefree(socksproxy);
2528
124
  }
2529
110k
#ifndef CURL_DISABLE_HTTP
2530
110k
  else if(!proxy && !socksproxy)
2531
    /* if the host is not in the noproxy list, detect proxy. */
2532
72.8k
    proxy = detect_proxy(data, conn);
2533
110k
#endif /* CURL_DISABLE_HTTP */
2534
110k
  Curl_safefree(no_proxy);
2535
2536
110k
#ifdef USE_UNIX_SOCKETS
2537
  /* For the time being do not mix proxy and Unix domain sockets. See #1274 */
2538
110k
  if(proxy && conn->unix_domain_socket) {
2539
249
    free(proxy);
2540
249
    proxy = NULL;
2541
249
  }
2542
110k
#endif
2543
2544
110k
  if(proxy && (!*proxy || (conn->handler->flags & PROTOPT_NONETWORK))) {
2545
333
    free(proxy);  /* Do not bother with an empty proxy string or if the
2546
                     protocol does not work with network */
2547
333
    proxy = NULL;
2548
333
  }
2549
110k
  if(socksproxy && (!*socksproxy ||
2550
20.9k
                    (conn->handler->flags & PROTOPT_NONETWORK))) {
2551
205
    free(socksproxy);  /* Do not bother with an empty socks proxy string or if
2552
                          the protocol does not work with network */
2553
205
    socksproxy = NULL;
2554
205
  }
2555
2556
  /***********************************************************************
2557
   * If this is supposed to use a proxy, we need to figure out the proxy host
2558
   * name, proxy type and port number, so that we can reuse an existing
2559
   * connection that may exist registered to the same proxy host.
2560
   ***********************************************************************/
2561
110k
  if(proxy || socksproxy) {
2562
36.6k
    curl_proxytype ptype = (curl_proxytype)conn->http_proxy.proxytype;
2563
36.6k
    if(proxy) {
2564
16.6k
      result = parse_proxy(data, conn, proxy, ptype);
2565
16.6k
      Curl_safefree(proxy); /* parse_proxy copies the proxy string */
2566
16.6k
      if(result)
2567
36
        goto out;
2568
16.6k
    }
2569
2570
36.5k
    if(socksproxy) {
2571
20.7k
      result = parse_proxy(data, conn, socksproxy, ptype);
2572
      /* parse_proxy copies the socks proxy string */
2573
20.7k
      Curl_safefree(socksproxy);
2574
20.7k
      if(result)
2575
96
        goto out;
2576
20.7k
    }
2577
2578
36.4k
    if(conn->http_proxy.host.rawalloc) {
2579
#ifdef CURL_DISABLE_HTTP
2580
      /* asking for an HTTP proxy is a bit funny when HTTP is disabled... */
2581
      result = CURLE_UNSUPPORTED_PROTOCOL;
2582
      goto out;
2583
#else
2584
      /* force this connection's protocol to become HTTP if compatible */
2585
35.0k
      if(!(conn->handler->protocol & PROTO_FAMILY_HTTP)) {
2586
28.3k
        if((conn->handler->flags & PROTOPT_PROXY_AS_HTTP) &&
2587
28.3k
           !conn->bits.tunnel_proxy)
2588
7.87k
          conn->handler = &Curl_handler_http;
2589
20.4k
        else
2590
          /* if not converting to HTTP over the proxy, enforce tunneling */
2591
20.4k
          conn->bits.tunnel_proxy = TRUE;
2592
28.3k
      }
2593
35.0k
      conn->bits.httpproxy = TRUE;
2594
35.0k
#endif
2595
35.0k
    }
2596
1.48k
    else {
2597
1.48k
      conn->bits.httpproxy = FALSE; /* not an HTTP proxy */
2598
1.48k
      conn->bits.tunnel_proxy = FALSE; /* no tunneling if not HTTP */
2599
1.48k
    }
2600
2601
36.4k
    if(conn->socks_proxy.host.rawalloc) {
2602
1.55k
      if(!conn->http_proxy.host.rawalloc) {
2603
        /* once a socks proxy */
2604
1.42k
        if(!conn->socks_proxy.user) {
2605
1.10k
          conn->socks_proxy.user = conn->http_proxy.user;
2606
1.10k
          conn->http_proxy.user = NULL;
2607
1.10k
          free(conn->socks_proxy.passwd);
2608
1.10k
          conn->socks_proxy.passwd = conn->http_proxy.passwd;
2609
1.10k
          conn->http_proxy.passwd = NULL;
2610
1.10k
        }
2611
1.42k
      }
2612
1.55k
      conn->bits.socksproxy = TRUE;
2613
1.55k
    }
2614
34.9k
    else
2615
34.9k
      conn->bits.socksproxy = FALSE; /* not a socks proxy */
2616
36.4k
  }
2617
73.6k
  else {
2618
73.6k
    conn->bits.socksproxy = FALSE;
2619
73.6k
    conn->bits.httpproxy = FALSE;
2620
73.6k
  }
2621
110k
  conn->bits.proxy = conn->bits.httpproxy || conn->bits.socksproxy;
2622
2623
110k
  if(!conn->bits.proxy) {
2624
    /* we are not using the proxy after all... */
2625
73.7k
    conn->bits.proxy = FALSE;
2626
73.7k
    conn->bits.httpproxy = FALSE;
2627
73.7k
    conn->bits.socksproxy = FALSE;
2628
73.7k
    conn->bits.proxy_user_passwd = FALSE;
2629
73.7k
    conn->bits.tunnel_proxy = FALSE;
2630
    /* CURLPROXY_HTTPS does not have its own flag in conn->bits, yet we need
2631
       to signal that CURLPROXY_HTTPS is not used for this connection */
2632
73.7k
    conn->http_proxy.proxytype = CURLPROXY_HTTP;
2633
73.7k
  }
2634
2635
110k
out:
2636
2637
110k
  free(socksproxy);
2638
110k
  free(proxy);
2639
110k
  return result;
2640
110k
}
2641
#endif /* CURL_DISABLE_PROXY */
2642
2643
/*
2644
 * Curl_parse_login_details()
2645
 *
2646
 * This is used to parse a login string for username, password and options in
2647
 * the following formats:
2648
 *
2649
 *   user
2650
 *   user:password
2651
 *   user:password;options
2652
 *   user;options
2653
 *   user;options:password
2654
 *   :password
2655
 *   :password;options
2656
 *   ;options
2657
 *   ;options:password
2658
 *
2659
 * Parameters:
2660
 *
2661
 * login    [in]     - login string.
2662
 * len      [in]     - length of the login string.
2663
 * userp    [in/out] - address where a pointer to newly allocated memory
2664
 *                     holding the user will be stored upon completion.
2665
 * passwdp  [in/out] - address where a pointer to newly allocated memory
2666
 *                     holding the password will be stored upon completion.
2667
 * optionsp [in/out] - OPTIONAL address where a pointer to newly allocated
2668
 *                     memory holding the options will be stored upon
2669
 *                     completion.
2670
 *
2671
 * Returns CURLE_OK on success.
2672
 */
2673
CURLcode Curl_parse_login_details(const char *login, const size_t len,
2674
                                  char **userp, char **passwdp,
2675
                                  char **optionsp)
2676
40.6k
{
2677
40.6k
  char *ubuf = NULL;
2678
40.6k
  char *pbuf = NULL;
2679
40.6k
  const char *psep = NULL;
2680
40.6k
  const char *osep = NULL;
2681
40.6k
  size_t ulen;
2682
40.6k
  size_t plen;
2683
40.6k
  size_t olen;
2684
2685
40.6k
  DEBUGASSERT(userp);
2686
40.6k
  DEBUGASSERT(passwdp);
2687
2688
  /* Attempt to find the password separator */
2689
40.6k
  psep = memchr(login, ':', len);
2690
2691
  /* Attempt to find the options separator */
2692
40.6k
  if(optionsp)
2693
1.37k
    osep = memchr(login, ';', len);
2694
2695
  /* Calculate the portion lengths */
2696
40.6k
  ulen = (psep ?
2697
7.48k
          (size_t)(osep && psep > osep ? osep - login : psep - login) :
2698
40.6k
          (osep ? (size_t)(osep - login) : len));
2699
40.6k
  plen = (psep ?
2700
7.48k
          (osep && osep > psep ? (size_t)(osep - psep) :
2701
33.1k
           (size_t)(login + len - psep)) - 1 : 0);
2702
40.6k
  olen = (osep ?
2703
412
          (psep && psep > osep ? (size_t)(psep - osep) :
2704
40.2k
           (size_t)(login + len - osep)) - 1 : 0);
2705
2706
  /* Clone the user portion buffer, which can be zero length */
2707
40.6k
  ubuf = Curl_memdup0(login, ulen);
2708
40.6k
  if(!ubuf)
2709
0
    goto error;
2710
2711
  /* Clone the password portion buffer */
2712
40.6k
  if(psep) {
2713
7.48k
    pbuf = Curl_memdup0(&psep[1], plen);
2714
7.48k
    if(!pbuf)
2715
0
      goto error;
2716
7.48k
  }
2717
2718
  /* Allocate the options portion buffer */
2719
40.6k
  if(optionsp) {
2720
1.37k
    char *obuf = NULL;
2721
1.37k
    if(olen) {
2722
345
      obuf = Curl_memdup0(&osep[1], olen);
2723
345
      if(!obuf)
2724
0
        goto error;
2725
345
    }
2726
1.37k
    *optionsp = obuf;
2727
1.37k
  }
2728
40.6k
  *userp = ubuf;
2729
40.6k
  *passwdp = pbuf;
2730
40.6k
  return CURLE_OK;
2731
0
error:
2732
0
  free(ubuf);
2733
0
  free(pbuf);
2734
0
  return CURLE_OUT_OF_MEMORY;
2735
40.6k
}
2736
2737
/*************************************************************
2738
 * Figure out the remote port number and fix it in the URL
2739
 *
2740
 * No matter if we use a proxy or not, we have to figure out the remote
2741
 * port number of various reasons.
2742
 *
2743
 * The port number embedded in the URL is replaced, if necessary.
2744
 *************************************************************/
2745
static CURLcode parse_remote_port(struct Curl_easy *data,
2746
                                  struct connectdata *conn)
2747
110k
{
2748
2749
110k
  if(data->set.use_port && data->state.allow_port) {
2750
    /* if set, we use this instead of the port possibly given in the URL */
2751
424
    char portbuf[16];
2752
424
    CURLUcode uc;
2753
424
    conn->remote_port = data->set.use_port;
2754
424
    msnprintf(portbuf, sizeof(portbuf), "%d", conn->remote_port);
2755
424
    uc = curl_url_set(data->state.uh, CURLUPART_PORT, portbuf, 0);
2756
424
    if(uc)
2757
0
      return CURLE_OUT_OF_MEMORY;
2758
424
  }
2759
2760
110k
  return CURLE_OK;
2761
110k
}
2762
2763
#ifndef CURL_DISABLE_NETRC
2764
static bool str_has_ctrl(const char *input)
2765
0
{
2766
0
  if(input) {
2767
0
    const unsigned char *str = (const unsigned char *)input;
2768
0
    while(*str) {
2769
0
      if(*str < 0x20)
2770
0
        return TRUE;
2771
0
      str++;
2772
0
    }
2773
0
  }
2774
0
  return FALSE;
2775
0
}
2776
#endif
2777
2778
/*
2779
 * Override the login details from the URL with that in the CURLOPT_USERPWD
2780
 * option or a .netrc file, if applicable.
2781
 */
2782
static CURLcode override_login(struct Curl_easy *data,
2783
                               struct connectdata *conn)
2784
110k
{
2785
110k
  CURLUcode uc;
2786
110k
  char **userp = &conn->user;
2787
110k
  char **passwdp = &conn->passwd;
2788
110k
  char **optionsp = &conn->options;
2789
2790
110k
  if(data->set.str[STRING_OPTIONS]) {
2791
504
    free(*optionsp);
2792
504
    *optionsp = strdup(data->set.str[STRING_OPTIONS]);
2793
504
    if(!*optionsp)
2794
0
      return CURLE_OUT_OF_MEMORY;
2795
504
  }
2796
2797
110k
#ifndef CURL_DISABLE_NETRC
2798
110k
  if(data->set.use_netrc == CURL_NETRC_REQUIRED) {
2799
1.41k
    Curl_safefree(*userp);
2800
1.41k
    Curl_safefree(*passwdp);
2801
1.41k
  }
2802
110k
  conn->bits.netrc = FALSE;
2803
110k
  if(data->set.use_netrc && !data->set.str[STRING_USERNAME]) {
2804
1.37k
    bool url_provided = FALSE;
2805
2806
1.37k
    if(data->state.aptr.user &&
2807
1.37k
       (data->state.creds_from != CREDS_NETRC)) {
2808
      /* there was a username with a length in the URL. Use the URL decoded
2809
         version */
2810
149
      userp = &data->state.aptr.user;
2811
149
      url_provided = TRUE;
2812
149
    }
2813
2814
1.37k
    if(!*passwdp) {
2815
1.33k
      NETRCcode ret = Curl_parsenetrc(&data->state.netrc, conn->host.name,
2816
1.33k
                                      userp, passwdp,
2817
1.33k
                                      data->set.str[STRING_NETRC_FILE]);
2818
1.33k
      if(ret && ((ret == NETRC_NO_MATCH) ||
2819
1.33k
                 (data->set.use_netrc == CURL_NETRC_OPTIONAL))) {
2820
1.33k
        infof(data, "Couldn't find host %s in the %s file; using defaults",
2821
1.33k
              conn->host.name,
2822
1.33k
              (data->set.str[STRING_NETRC_FILE] ?
2823
1.33k
               data->set.str[STRING_NETRC_FILE] : ".netrc"));
2824
1.33k
      }
2825
0
      else if(ret) {
2826
0
        const char *m = Curl_netrc_strerror(ret);
2827
0
        failf(data, ".netrc error: %s", m);
2828
0
        return CURLE_READ_ERROR;
2829
0
      }
2830
0
      else {
2831
0
        if(!(conn->handler->flags&PROTOPT_USERPWDCTRL)) {
2832
          /* if the protocol can't handle control codes in credentials, make
2833
             sure there are none */
2834
0
          if(str_has_ctrl(*userp) || str_has_ctrl(*passwdp)) {
2835
0
            failf(data, "control code detected in .netrc credentials");
2836
0
            return CURLE_READ_ERROR;
2837
0
          }
2838
0
        }
2839
        /* set bits.netrc TRUE to remember that we got the name from a .netrc
2840
           file, so that it is safe to use even if we followed a Location: to a
2841
           different host or similar. */
2842
0
        conn->bits.netrc = TRUE;
2843
0
      }
2844
1.33k
    }
2845
1.37k
    if(url_provided) {
2846
149
      free(conn->user);
2847
149
      conn->user = strdup(*userp);
2848
149
      if(!conn->user)
2849
0
        return CURLE_OUT_OF_MEMORY;
2850
149
    }
2851
    /* no user was set but a password, set a blank user */
2852
1.37k
    if(!*userp && *passwdp) {
2853
0
      *userp = strdup("");
2854
0
      if(!*userp)
2855
0
        return CURLE_OUT_OF_MEMORY;
2856
0
    }
2857
1.37k
  }
2858
110k
#endif
2859
2860
  /* for updated strings, we update them in the URL */
2861
110k
  if(*userp) {
2862
18.8k
    CURLcode result;
2863
18.8k
    if(data->state.aptr.user != *userp) {
2864
      /* nothing to do then */
2865
18.6k
      result = Curl_setstropt(&data->state.aptr.user, *userp);
2866
18.6k
      if(result)
2867
0
        return result;
2868
18.6k
      data->state.creds_from = CREDS_NETRC;
2869
18.6k
    }
2870
18.8k
  }
2871
110k
  if(data->state.aptr.user) {
2872
23.3k
    uc = curl_url_set(data->state.uh, CURLUPART_USER, data->state.aptr.user,
2873
23.3k
                      CURLU_URLENCODE);
2874
23.3k
    if(uc)
2875
0
      return Curl_uc_to_curlcode(uc);
2876
23.3k
    if(!*userp) {
2877
4.53k
      *userp = strdup(data->state.aptr.user);
2878
4.53k
      if(!*userp)
2879
0
        return CURLE_OUT_OF_MEMORY;
2880
4.53k
    }
2881
23.3k
  }
2882
110k
  if(*passwdp) {
2883
3.10k
    CURLcode result = Curl_setstropt(&data->state.aptr.passwd, *passwdp);
2884
3.10k
    if(result)
2885
0
      return result;
2886
3.10k
    data->state.creds_from = CREDS_NETRC;
2887
3.10k
  }
2888
110k
  if(data->state.aptr.passwd) {
2889
7.63k
    uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD,
2890
7.63k
                      data->state.aptr.passwd, CURLU_URLENCODE);
2891
7.63k
    if(uc)
2892
0
      return Curl_uc_to_curlcode(uc);
2893
7.63k
    if(!*passwdp) {
2894
4.53k
      *passwdp = strdup(data->state.aptr.passwd);
2895
4.53k
      if(!*passwdp)
2896
0
        return CURLE_OUT_OF_MEMORY;
2897
4.53k
    }
2898
7.63k
  }
2899
2900
110k
  return CURLE_OK;
2901
110k
}
2902
2903
/*
2904
 * Set the login details so they are available in the connection
2905
 */
2906
static CURLcode set_login(struct Curl_easy *data,
2907
                          struct connectdata *conn)
2908
110k
{
2909
110k
  CURLcode result = CURLE_OK;
2910
110k
  const char *setuser = CURL_DEFAULT_USER;
2911
110k
  const char *setpasswd = CURL_DEFAULT_PASSWORD;
2912
2913
  /* If our protocol needs a password and we have none, use the defaults */
2914
110k
  if((conn->handler->flags & PROTOPT_NEEDSPWD) && !data->state.aptr.user)
2915
4.53k
    ;
2916
105k
  else {
2917
105k
    setuser = "";
2918
105k
    setpasswd = "";
2919
105k
  }
2920
  /* Store the default user */
2921
110k
  if(!conn->user) {
2922
86.8k
    conn->user = strdup(setuser);
2923
86.8k
    if(!conn->user)
2924
0
      return CURLE_OUT_OF_MEMORY;
2925
86.8k
  }
2926
2927
  /* Store the default password */
2928
110k
  if(!conn->passwd) {
2929
102k
    conn->passwd = strdup(setpasswd);
2930
102k
    if(!conn->passwd)
2931
0
      result = CURLE_OUT_OF_MEMORY;
2932
102k
  }
2933
2934
110k
  return result;
2935
110k
}
2936
2937
/*
2938
 * Parses a "host:port" string to connect to.
2939
 * The hostname and the port may be empty; in this case, NULL is returned for
2940
 * the hostname and -1 for the port.
2941
 */
2942
static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
2943
                                           const char *host,
2944
                                           char **hostname_result,
2945
                                           int *port_result)
2946
105k
{
2947
105k
  char *host_dup;
2948
105k
  char *hostptr;
2949
105k
  char *host_portno;
2950
105k
  char *portptr;
2951
105k
  int port = -1;
2952
105k
  CURLcode result = CURLE_OK;
2953
2954
#ifdef CURL_DISABLE_VERBOSE_STRINGS
2955
  (void) data;
2956
#endif
2957
2958
105k
  *hostname_result = NULL;
2959
105k
  *port_result = -1;
2960
2961
105k
  if(!host || !*host)
2962
0
    return CURLE_OK;
2963
2964
105k
  host_dup = strdup(host);
2965
105k
  if(!host_dup)
2966
0
    return CURLE_OUT_OF_MEMORY;
2967
2968
105k
  hostptr = host_dup;
2969
2970
  /* start scanning for port number at this point */
2971
105k
  portptr = hostptr;
2972
2973
  /* detect and extract RFC6874-style IPv6-addresses */
2974
105k
  if(*hostptr == '[') {
2975
0
#ifdef USE_IPV6
2976
0
    char *ptr = ++hostptr; /* advance beyond the initial bracket */
2977
0
    while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.')))
2978
0
      ptr++;
2979
0
    if(*ptr == '%') {
2980
      /* There might be a zone identifier */
2981
0
      if(strncmp("%25", ptr, 3))
2982
0
        infof(data, "Please URL encode %% as %%25, see RFC 6874.");
2983
0
      ptr++;
2984
      /* Allow unreserved characters as defined in RFC 3986 */
2985
0
      while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') ||
2986
0
                     (*ptr == '.') || (*ptr == '_') || (*ptr == '~')))
2987
0
        ptr++;
2988
0
    }
2989
0
    if(*ptr == ']')
2990
      /* yeps, it ended nicely with a bracket as well */
2991
0
      *ptr++ = '\0';
2992
0
    else
2993
0
      infof(data, "Invalid IPv6 address format");
2994
0
    portptr = ptr;
2995
    /* Note that if this did not end with a bracket, we still advanced the
2996
     * hostptr first, but I cannot see anything wrong with that as no host
2997
     * name nor a numeric can legally start with a bracket.
2998
     */
2999
#else
3000
    failf(data, "Use of IPv6 in *_CONNECT_TO without IPv6 support built-in");
3001
    result = CURLE_NOT_BUILT_IN;
3002
    goto error;
3003
#endif
3004
0
  }
3005
3006
  /* Get port number off server.com:1080 */
3007
105k
  host_portno = strchr(portptr, ':');
3008
105k
  if(host_portno) {
3009
105k
    *host_portno = '\0'; /* cut off number from hostname */
3010
105k
    host_portno++;
3011
105k
    if(*host_portno) {
3012
0
      curl_off_t portparse;
3013
0
      const char *p = host_portno;
3014
0
      if(curlx_str_number(&p, &portparse, 0xffff)) {
3015
0
        failf(data, "No valid port number in connect to host string (%s)",
3016
0
              host_portno);
3017
0
        result = CURLE_SETOPT_OPTION_SYNTAX;
3018
0
        goto error;
3019
0
      }
3020
0
      port = (int)portparse; /* we know it will fit */
3021
0
    }
3022
105k
  }
3023
3024
  /* now, clone the cleaned hostname */
3025
105k
  DEBUGASSERT(hostptr);
3026
105k
  *hostname_result = strdup(hostptr);
3027
105k
  if(!*hostname_result) {
3028
0
    result = CURLE_OUT_OF_MEMORY;
3029
0
    goto error;
3030
0
  }
3031
3032
105k
  *port_result = port;
3033
3034
105k
error:
3035
105k
  free(host_dup);
3036
105k
  return result;
3037
105k
}
3038
3039
/*
3040
 * Parses one "connect to" string in the form:
3041
 * "HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT".
3042
 */
3043
static CURLcode parse_connect_to_string(struct Curl_easy *data,
3044
                                        struct connectdata *conn,
3045
                                        const char *conn_to_host,
3046
                                        char **host_result,
3047
                                        int *port_result)
3048
105k
{
3049
105k
  CURLcode result = CURLE_OK;
3050
105k
  const char *ptr = conn_to_host;
3051
105k
  bool host_match = FALSE;
3052
105k
  bool port_match = FALSE;
3053
3054
105k
  *host_result = NULL;
3055
105k
  *port_result = -1;
3056
3057
105k
  if(*ptr == ':') {
3058
    /* an empty hostname always matches */
3059
105k
    host_match = TRUE;
3060
105k
    ptr++;
3061
105k
  }
3062
0
  else {
3063
    /* check whether the URL's hostname matches */
3064
0
    size_t hostname_to_match_len;
3065
0
    char *hostname_to_match = aprintf("%s%s%s",
3066
0
                                      conn->bits.ipv6_ip ? "[" : "",
3067
0
                                      conn->host.name,
3068
0
                                      conn->bits.ipv6_ip ? "]" : "");
3069
0
    if(!hostname_to_match)
3070
0
      return CURLE_OUT_OF_MEMORY;
3071
0
    hostname_to_match_len = strlen(hostname_to_match);
3072
0
    host_match = curl_strnequal(ptr, hostname_to_match,
3073
0
                                hostname_to_match_len);
3074
0
    free(hostname_to_match);
3075
0
    ptr += hostname_to_match_len;
3076
3077
0
    host_match = host_match && *ptr == ':';
3078
0
    ptr++;
3079
0
  }
3080
3081
105k
  if(host_match) {
3082
105k
    if(*ptr == ':') {
3083
      /* an empty port always matches */
3084
105k
      port_match = TRUE;
3085
105k
      ptr++;
3086
105k
    }
3087
0
    else {
3088
      /* check whether the URL's port matches */
3089
0
      char *ptr_next = strchr(ptr, ':');
3090
0
      if(ptr_next) {
3091
0
        curl_off_t port_to_match;
3092
0
        if(!curlx_str_number(&ptr, &port_to_match, 0xffff) &&
3093
0
           (port_to_match == (curl_off_t)conn->remote_port))
3094
0
          port_match = TRUE;
3095
0
        ptr = ptr_next + 1;
3096
0
      }
3097
0
    }
3098
105k
  }
3099
3100
105k
  if(host_match && port_match) {
3101
    /* parse the hostname and port to connect to */
3102
105k
    result = parse_connect_to_host_port(data, ptr, host_result, port_result);
3103
105k
  }
3104
3105
105k
  return result;
3106
105k
}
3107
3108
/*
3109
 * Processes all strings in the "connect to" slist, and uses the "connect
3110
 * to host" and "connect to port" of the first string that matches.
3111
 */
3112
static CURLcode parse_connect_to_slist(struct Curl_easy *data,
3113
                                       struct connectdata *conn,
3114
                                       struct curl_slist *conn_to_host)
3115
110k
{
3116
110k
  CURLcode result = CURLE_OK;
3117
110k
  char *host = NULL;
3118
110k
  int port = -1;
3119
3120
215k
  while(conn_to_host && !host && port == -1) {
3121
105k
    result = parse_connect_to_string(data, conn, conn_to_host->data,
3122
105k
                                     &host, &port);
3123
105k
    if(result)
3124
0
      return result;
3125
3126
105k
    if(host && *host) {
3127
105k
      conn->conn_to_host.rawalloc = host;
3128
105k
      conn->conn_to_host.name = host;
3129
105k
      conn->bits.conn_to_host = TRUE;
3130
3131
105k
      infof(data, "Connecting to hostname: %s", host);
3132
105k
    }
3133
0
    else {
3134
      /* no "connect to host" */
3135
0
      conn->bits.conn_to_host = FALSE;
3136
0
      Curl_safefree(host);
3137
0
    }
3138
3139
105k
    if(port >= 0) {
3140
0
      conn->conn_to_port = port;
3141
0
      conn->bits.conn_to_port = TRUE;
3142
0
      infof(data, "Connecting to port: %d", port);
3143
0
    }
3144
105k
    else {
3145
      /* no "connect to port" */
3146
105k
      conn->bits.conn_to_port = FALSE;
3147
105k
      port = -1;
3148
105k
    }
3149
3150
105k
    conn_to_host = conn_to_host->next;
3151
105k
  }
3152
3153
110k
#ifndef CURL_DISABLE_ALTSVC
3154
110k
  if(data->asi && !host && (port == -1) &&
3155
110k
     ((conn->handler->protocol == CURLPROTO_HTTPS) ||
3156
0
#ifdef DEBUGBUILD
3157
      /* allow debug builds to circumvent the HTTPS restriction */
3158
0
      getenv("CURL_ALTSVC_HTTP")
3159
#else
3160
      0
3161
#endif
3162
0
       )) {
3163
    /* no connect_to match, try alt-svc! */
3164
0
    enum alpnid srcalpnid = ALPN_none;
3165
0
    bool hit = FALSE;
3166
0
    struct altsvc *as = NULL;
3167
0
    int allowed_alpns = ALPN_none;
3168
0
    struct http_negotiation *neg = &data->state.http_neg;
3169
3170
0
    DEBUGF(infof(data, "Alt-svc check wanted=%x, allowed=%x",
3171
0
                 neg->wanted, neg->allowed));
3172
#ifdef USE_HTTP3
3173
    if(neg->allowed & CURL_HTTP_V3x)
3174
      allowed_alpns |= ALPN_h3;
3175
#endif
3176
0
#ifdef USE_HTTP2
3177
0
    if(neg->allowed & CURL_HTTP_V2x)
3178
0
      allowed_alpns |= ALPN_h2;
3179
0
#endif
3180
0
    if(neg->allowed & CURL_HTTP_V1x)
3181
0
      allowed_alpns |= ALPN_h1;
3182
0
    allowed_alpns &= (int)data->asi->flags;
3183
3184
0
    host = conn->host.rawalloc;
3185
0
    DEBUGF(infof(data, "check Alt-Svc for host %s", host));
3186
#ifdef USE_HTTP3
3187
    if(!hit && (neg->wanted & CURL_HTTP_V3x)) {
3188
      srcalpnid = ALPN_h3;
3189
      hit = Curl_altsvc_lookup(data->asi,
3190
                               ALPN_h3, host, conn->remote_port, /* from */
3191
                               &as /* to */,
3192
                               allowed_alpns);
3193
    }
3194
 #endif
3195
0
 #ifdef USE_HTTP2
3196
0
    if(!hit && (neg->wanted & CURL_HTTP_V2x) &&
3197
0
       !neg->h2_prior_knowledge) {
3198
0
      srcalpnid = ALPN_h2;
3199
0
      hit = Curl_altsvc_lookup(data->asi,
3200
0
                               ALPN_h2, host, conn->remote_port, /* from */
3201
0
                               &as /* to */,
3202
0
                               allowed_alpns);
3203
0
    }
3204
0
 #endif
3205
0
    if(!hit && (neg->wanted & CURL_HTTP_V1x) &&
3206
0
       !neg->only_10) {
3207
0
      srcalpnid = ALPN_h1;
3208
0
      hit = Curl_altsvc_lookup(data->asi,
3209
0
                               ALPN_h1, host, conn->remote_port, /* from */
3210
0
                               &as /* to */,
3211
0
                               allowed_alpns);
3212
0
    }
3213
3214
0
    if(hit) {
3215
0
      char *hostd = strdup((char *)as->dst.host);
3216
0
      if(!hostd)
3217
0
        return CURLE_OUT_OF_MEMORY;
3218
0
      conn->conn_to_host.rawalloc = hostd;
3219
0
      conn->conn_to_host.name = hostd;
3220
0
      conn->bits.conn_to_host = TRUE;
3221
0
      conn->conn_to_port = as->dst.port;
3222
0
      conn->bits.conn_to_port = TRUE;
3223
0
      conn->bits.altused = TRUE;
3224
0
      infof(data, "Alt-svc connecting from [%s]%s:%d to [%s]%s:%d",
3225
0
            Curl_alpnid2str(srcalpnid), host, conn->remote_port,
3226
0
            Curl_alpnid2str(as->dst.alpnid), hostd, as->dst.port);
3227
0
      if(srcalpnid != as->dst.alpnid) {
3228
        /* protocol version switch */
3229
0
        switch(as->dst.alpnid) {
3230
0
        case ALPN_h1:
3231
0
          neg->wanted = neg->allowed = CURL_HTTP_V1x;
3232
0
          neg->only_10 = FALSE;
3233
0
          break;
3234
0
        case ALPN_h2:
3235
0
          neg->wanted = neg->allowed = CURL_HTTP_V2x;
3236
0
          break;
3237
0
        case ALPN_h3:
3238
0
          conn->transport = TRNSPRT_QUIC;
3239
0
          neg->wanted = neg->allowed = CURL_HTTP_V3x;
3240
0
          break;
3241
0
        default: /* should not be possible */
3242
0
          break;
3243
0
        }
3244
0
      }
3245
0
    }
3246
0
  }
3247
110k
#endif
3248
3249
110k
  return result;
3250
110k
}
3251
3252
#ifdef USE_UNIX_SOCKETS
3253
static CURLcode resolve_unix(struct Curl_easy *data,
3254
                             struct connectdata *conn,
3255
                             char *unix_path,
3256
                             struct Curl_dns_entry **pdns)
3257
1.40k
{
3258
1.40k
  struct Curl_dns_entry *hostaddr;
3259
1.40k
  bool longpath = FALSE;
3260
3261
1.40k
  DEBUGASSERT(unix_path);
3262
1.40k
  *pdns = NULL;
3263
3264
  /* Unix domain sockets are local. The host gets ignored, just use the
3265
   * specified domain socket address. Do not cache "DNS entries". There is
3266
   * no DNS involved and we already have the filesystem path available. */
3267
1.40k
  hostaddr = calloc(1, sizeof(struct Curl_dns_entry));
3268
1.40k
  if(!hostaddr)
3269
0
    return CURLE_OUT_OF_MEMORY;
3270
3271
1.40k
  hostaddr->addr = Curl_unix2addr(unix_path, &longpath,
3272
1.40k
                                  conn->bits.abstract_unix_socket);
3273
1.40k
  if(!hostaddr->addr) {
3274
21
    if(longpath)
3275
      /* Long paths are not supported for now */
3276
21
      failf(data, "Unix socket path too long: '%s'", unix_path);
3277
21
    free(hostaddr);
3278
21
    return longpath ? CURLE_COULDNT_RESOLVE_HOST : CURLE_OUT_OF_MEMORY;
3279
21
  }
3280
3281
1.37k
  hostaddr->refcount = 1; /* connection is the only one holding this */
3282
1.37k
  *pdns = hostaddr;
3283
1.37k
  return CURLE_OK;
3284
1.40k
}
3285
#endif
3286
3287
/*************************************************************
3288
 * Resolve the address of the server or proxy
3289
 *************************************************************/
3290
static CURLcode resolve_server(struct Curl_easy *data,
3291
                               struct connectdata *conn,
3292
                               bool *async,
3293
                               struct Curl_dns_entry **pdns)
3294
98.7k
{
3295
98.7k
  struct hostname *ehost;
3296
98.7k
  timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
3297
98.7k
  const char *peertype = "host";
3298
98.7k
  CURLcode result;
3299
3300
98.7k
  *pdns = NULL;
3301
3302
98.7k
#ifdef USE_UNIX_SOCKETS
3303
98.7k
  {
3304
98.7k
    char *unix_path = conn->unix_domain_socket;
3305
3306
98.7k
#ifndef CURL_DISABLE_PROXY
3307
98.7k
    if(!unix_path && CONN_IS_PROXIED(conn) && conn->socks_proxy.host.name &&
3308
98.7k
       !strncmp(UNIX_SOCKET_PREFIX"/",
3309
1.50k
                conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX)))
3310
9
      unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1;
3311
98.7k
#endif
3312
3313
98.7k
    if(unix_path) {
3314
      /* This only works if previous transport is TRNSPRT_TCP. Check it? */
3315
1.40k
      conn->transport = TRNSPRT_UNIX;
3316
1.40k
      return resolve_unix(data, conn, unix_path, pdns);
3317
1.40k
    }
3318
98.7k
  }
3319
97.3k
#endif
3320
3321
97.3k
#ifndef CURL_DISABLE_PROXY
3322
97.3k
  if(CONN_IS_PROXIED(conn)) {
3323
35.5k
    ehost = conn->bits.socksproxy ? &conn->socks_proxy.host :
3324
35.5k
      &conn->http_proxy.host;
3325
35.5k
    peertype = "proxy";
3326
35.5k
  }
3327
61.8k
  else
3328
61.8k
#endif
3329
61.8k
  {
3330
61.8k
    ehost = conn->bits.conn_to_host ? &conn->conn_to_host : &conn->host;
3331
    /* If not connecting via a proxy, extract the port from the URL, if it is
3332
     * there, thus overriding any defaults that might have been set above. */
3333
61.8k
    conn->primary.remote_port = conn->bits.conn_to_port ? conn->conn_to_port :
3334
61.8k
      conn->remote_port;
3335
61.8k
  }
3336
3337
  /* Resolve target host right on */
3338
97.3k
  conn->hostname_resolve = strdup(ehost->name);
3339
97.3k
  if(!conn->hostname_resolve)
3340
0
    return CURLE_OUT_OF_MEMORY;
3341
3342
97.3k
  result = Curl_resolv_timeout(data, conn->hostname_resolve,
3343
97.3k
                               conn->primary.remote_port, conn->ip_version,
3344
97.3k
                               pdns, timeout_ms);
3345
97.3k
  DEBUGASSERT(!result || !*pdns);
3346
97.3k
  if(result == CURLE_AGAIN) {
3347
6.56k
    *async = TRUE;
3348
6.56k
    return CURLE_OK;
3349
6.56k
  }
3350
90.7k
  else if(result == CURLE_OPERATION_TIMEDOUT) {
3351
1
    failf(data, "Failed to resolve %s '%s' with timeout after %"
3352
1
          FMT_TIMEDIFF_T " ms", peertype, ehost->dispname,
3353
1
          curlx_timediff(curlx_now(), data->progress.t_startsingle));
3354
1
    return CURLE_OPERATION_TIMEDOUT;
3355
1
  }
3356
90.7k
  else if(result) {
3357
82
    failf(data, "Could not resolve %s: %s", peertype, ehost->dispname);
3358
82
    return result;
3359
82
  }
3360
90.7k
  DEBUGASSERT(*pdns);
3361
90.7k
  return CURLE_OK;
3362
90.7k
}
3363
3364
/*
3365
 * Cleanup the connection `temp`, just allocated for `data`, before using the
3366
 * previously `existing` one for `data`. All relevant info is copied over
3367
 * and `temp` is freed.
3368
 */
3369
static void reuse_conn(struct Curl_easy *data,
3370
                       struct connectdata *temp,
3371
                       struct connectdata *existing)
3372
7.13k
{
3373
  /* get the user+password information from the temp struct since it may
3374
   * be new for this request even when we reuse an existing connection */
3375
7.13k
  if(temp->user) {
3376
    /* use the new username and password though */
3377
7.13k
    free(existing->user);
3378
7.13k
    free(existing->passwd);
3379
7.13k
    existing->user = temp->user;
3380
7.13k
    existing->passwd = temp->passwd;
3381
7.13k
    temp->user = NULL;
3382
7.13k
    temp->passwd = NULL;
3383
7.13k
  }
3384
3385
7.13k
#ifndef CURL_DISABLE_PROXY
3386
7.13k
  existing->bits.proxy_user_passwd = temp->bits.proxy_user_passwd;
3387
7.13k
  if(existing->bits.proxy_user_passwd) {
3388
    /* use the new proxy username and proxy password though */
3389
507
    free(existing->http_proxy.user);
3390
507
    free(existing->socks_proxy.user);
3391
507
    free(existing->http_proxy.passwd);
3392
507
    free(existing->socks_proxy.passwd);
3393
507
    existing->http_proxy.user = temp->http_proxy.user;
3394
507
    existing->socks_proxy.user = temp->socks_proxy.user;
3395
507
    existing->http_proxy.passwd = temp->http_proxy.passwd;
3396
507
    existing->socks_proxy.passwd = temp->socks_proxy.passwd;
3397
507
    temp->http_proxy.user = NULL;
3398
507
    temp->socks_proxy.user = NULL;
3399
507
    temp->http_proxy.passwd = NULL;
3400
507
    temp->socks_proxy.passwd = NULL;
3401
507
  }
3402
7.13k
#endif
3403
3404
  /* Finding a connection for reuse in the cpool matches, among other
3405
   * things on the "remote-relevant" hostname. This is not necessarily
3406
   * the authority of the URL, e.g. conn->host. For example:
3407
   * - we use a proxy (not tunneling). we want to send all requests
3408
   *   that use the same proxy on this connection.
3409
   * - we have a "connect-to" setting that may redirect the hostname of
3410
   *   a new request to the same remote endpoint of an existing conn.
3411
   *   We want to reuse an existing conn to the remote endpoint.
3412
   * Since connection reuse does not match on conn->host necessarily, we
3413
   * switch `existing` conn to `temp` conn's host settings.
3414
   *       Is this correct in the case of TLS connections that have
3415
   *       used the original hostname in SNI to negotiate? Do we send
3416
   *       requests for another host through the different SNI?
3417
   */
3418
7.13k
  Curl_free_idnconverted_hostname(&existing->host);
3419
7.13k
  Curl_free_idnconverted_hostname(&existing->conn_to_host);
3420
7.13k
  Curl_safefree(existing->host.rawalloc);
3421
7.13k
  Curl_safefree(existing->conn_to_host.rawalloc);
3422
7.13k
  existing->host = temp->host;
3423
7.13k
  temp->host.rawalloc = NULL;
3424
7.13k
  temp->host.encalloc = NULL;
3425
7.13k
  existing->conn_to_host = temp->conn_to_host;
3426
7.13k
  temp->conn_to_host.rawalloc = NULL;
3427
7.13k
  existing->conn_to_port = temp->conn_to_port;
3428
7.13k
  existing->remote_port = temp->remote_port;
3429
7.13k
  free(existing->hostname_resolve);
3430
7.13k
  existing->hostname_resolve = temp->hostname_resolve;
3431
7.13k
  temp->hostname_resolve = NULL;
3432
3433
  /* reuse init */
3434
7.13k
  existing->bits.reuse = TRUE; /* yes, we are reusing here */
3435
3436
7.13k
  Curl_conn_free(data, temp);
3437
7.13k
}
3438
3439
static void conn_meta_freeentry(void *p)
3440
0
{
3441
0
  (void)p;
3442
  /* Will always be FALSE. Cannot use a 0 assert here since compilers
3443
   * are not in agreement if they then want a NORETURN attribute or
3444
   * not. *sigh* */
3445
0
  DEBUGASSERT(p == NULL);
3446
0
}
3447
3448
/**
3449
 * create_conn() sets up a new connectdata struct, or reuses an already
3450
 * existing one, and resolves hostname.
3451
 *
3452
 * if this function returns CURLE_OK and *async is set to TRUE, the resolve
3453
 * response will be coming asynchronously. If *async is FALSE, the name is
3454
 * already resolved.
3455
 *
3456
 * @param data The sessionhandle pointer
3457
 * @param in_connect is set to the next connection data pointer
3458
 * @param reusedp is set to to TRUE if connection was reused
3459
 * @see Curl_setup_conn()
3460
 *
3461
 */
3462
3463
static CURLcode create_conn(struct Curl_easy *data,
3464
                            struct connectdata **in_connect,
3465
                            bool *reusedp)
3466
126k
{
3467
126k
  CURLcode result = CURLE_OK;
3468
126k
  struct connectdata *conn;
3469
126k
  struct connectdata *existing = NULL;
3470
126k
  bool reuse;
3471
126k
  bool connections_available = TRUE;
3472
126k
  bool force_reuse = FALSE;
3473
126k
  bool waitpipe = FALSE;
3474
3475
126k
  *reusedp = FALSE;
3476
126k
  *in_connect = NULL;
3477
3478
  /*************************************************************
3479
   * Check input data
3480
   *************************************************************/
3481
126k
  if(!data->state.url) {
3482
0
    result = CURLE_URL_MALFORMAT;
3483
0
    goto out;
3484
0
  }
3485
3486
  /* First, split up the current URL in parts so that we can use the
3487
     parts for checking against the already present connections. In order
3488
     to not have to modify everything at once, we allocate a temporary
3489
     connection data struct and fill in for comparison purposes. */
3490
126k
  conn = allocate_conn(data);
3491
3492
126k
  if(!conn) {
3493
0
    result = CURLE_OUT_OF_MEMORY;
3494
0
    goto out;
3495
0
  }
3496
3497
  /* We must set the return variable as soon as possible, so that our
3498
     parent can cleanup any possible allocs we may have done before
3499
     any failure */
3500
126k
  *in_connect = conn;
3501
3502
  /* Do the unfailable inits first, before checks that may early return */
3503
126k
  Curl_hash_init(&conn->meta_hash, 23,
3504
126k
               Curl_hash_str, curlx_str_key_compare, conn_meta_freeentry);
3505
3506
  /* GSSAPI related inits */
3507
126k
  Curl_sec_conn_init(conn);
3508
3509
126k
  result = parseurlandfillconn(data, conn);
3510
126k
  if(result)
3511
16.2k
    goto out;
3512
3513
110k
  if(data->set.str[STRING_SASL_AUTHZID]) {
3514
349
    conn->sasl_authzid = strdup(data->set.str[STRING_SASL_AUTHZID]);
3515
349
    if(!conn->sasl_authzid) {
3516
0
      result = CURLE_OUT_OF_MEMORY;
3517
0
      goto out;
3518
0
    }
3519
349
  }
3520
3521
110k
  if(data->set.str[STRING_BEARER]) {
3522
6.58k
    conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]);
3523
6.58k
    if(!conn->oauth_bearer) {
3524
0
      result = CURLE_OUT_OF_MEMORY;
3525
0
      goto out;
3526
0
    }
3527
6.58k
  }
3528
3529
110k
#ifdef USE_UNIX_SOCKETS
3530
110k
  if(data->set.str[STRING_UNIX_SOCKET_PATH]) {
3531
2.53k
    conn->unix_domain_socket = strdup(data->set.str[STRING_UNIX_SOCKET_PATH]);
3532
2.53k
    if(!conn->unix_domain_socket) {
3533
0
      result = CURLE_OUT_OF_MEMORY;
3534
0
      goto out;
3535
0
    }
3536
2.53k
    conn->bits.abstract_unix_socket = data->set.abstract_unix_socket;
3537
2.53k
  }
3538
110k
#endif
3539
3540
  /* After the Unix socket init but before the proxy vars are used, parse and
3541
     initialize the proxy vars */
3542
110k
#ifndef CURL_DISABLE_PROXY
3543
110k
  result = create_conn_helper_init_proxy(data, conn);
3544
110k
  if(result)
3545
132
    goto out;
3546
3547
  /*************************************************************
3548
   * If the protocol is using SSL and HTTP proxy is used, we set
3549
   * the tunnel_proxy bit.
3550
   *************************************************************/
3551
110k
  if((conn->given->flags&PROTOPT_SSL) && conn->bits.httpproxy)
3552
3.62k
    conn->bits.tunnel_proxy = TRUE;
3553
110k
#endif
3554
3555
  /*************************************************************
3556
   * Figure out the remote port number and fix it in the URL
3557
   *************************************************************/
3558
110k
  result = parse_remote_port(data, conn);
3559
110k
  if(result)
3560
0
    goto out;
3561
3562
  /* Check for overridden login details and set them accordingly so that
3563
     they are known when protocol->setup_connection is called! */
3564
110k
  result = override_login(data, conn);
3565
110k
  if(result)
3566
0
    goto out;
3567
3568
110k
  result = set_login(data, conn); /* default credentials */
3569
110k
  if(result)
3570
0
    goto out;
3571
3572
  /*************************************************************
3573
   * Process the "connect to" linked list of hostname/port mappings.
3574
   * Do this after the remote port number has been fixed in the URL.
3575
   *************************************************************/
3576
110k
  result = parse_connect_to_slist(data, conn, data->set.connect_to);
3577
110k
  if(result)
3578
0
    goto out;
3579
3580
  /*************************************************************
3581
   * IDN-convert the proxy hostnames
3582
   *************************************************************/
3583
110k
#ifndef CURL_DISABLE_PROXY
3584
110k
  if(conn->bits.httpproxy) {
3585
35.0k
    result = Curl_idnconvert_hostname(&conn->http_proxy.host);
3586
35.0k
    if(result)
3587
143
      return result;
3588
35.0k
  }
3589
110k
  if(conn->bits.socksproxy) {
3590
1.55k
    result = Curl_idnconvert_hostname(&conn->socks_proxy.host);
3591
1.55k
    if(result)
3592
30
      return result;
3593
1.55k
  }
3594
109k
#endif
3595
109k
  if(conn->bits.conn_to_host) {
3596
104k
    result = Curl_idnconvert_hostname(&conn->conn_to_host);
3597
104k
    if(result)
3598
0
      return result;
3599
104k
  }
3600
3601
  /*************************************************************
3602
   * Check whether the host and the "connect to host" are equal.
3603
   * Do this after the hostnames have been IDN-converted.
3604
   *************************************************************/
3605
109k
  if(conn->bits.conn_to_host &&
3606
109k
     curl_strequal(conn->conn_to_host.name, conn->host.name)) {
3607
1.22k
    conn->bits.conn_to_host = FALSE;
3608
1.22k
  }
3609
3610
  /*************************************************************
3611
   * Check whether the port and the "connect to port" are equal.
3612
   * Do this after the remote port number has been fixed in the URL.
3613
   *************************************************************/
3614
109k
  if(conn->bits.conn_to_port && conn->conn_to_port == conn->remote_port) {
3615
0
    conn->bits.conn_to_port = FALSE;
3616
0
  }
3617
3618
109k
#ifndef CURL_DISABLE_PROXY
3619
  /*************************************************************
3620
   * If the "connect to" feature is used with an HTTP proxy,
3621
   * we set the tunnel_proxy bit.
3622
   *************************************************************/
3623
109k
  if((conn->bits.conn_to_host || conn->bits.conn_to_port) &&
3624
109k
      conn->bits.httpproxy)
3625
33.7k
    conn->bits.tunnel_proxy = TRUE;
3626
109k
#endif
3627
3628
  /*************************************************************
3629
   * Setup internals depending on protocol. Needs to be done after
3630
   * we figured out what/if proxy to use.
3631
   *************************************************************/
3632
109k
  result = setup_connection_internals(data, conn);
3633
109k
  if(result)
3634
244
    goto out;
3635
3636
  /***********************************************************************
3637
   * file: is a special case in that it does not need a network connection
3638
   ***********************************************************************/
3639
109k
#ifndef CURL_DISABLE_FILE
3640
109k
  if(conn->handler->flags & PROTOPT_NONETWORK) {
3641
1.86k
    bool done;
3642
    /* this is supposed to be the connect function so we better at least check
3643
       that the file is present here! */
3644
1.86k
    DEBUGASSERT(conn->handler->connect_it);
3645
1.86k
    data->info.conn_scheme = conn->handler->scheme;
3646
    /* conn_protocol can only provide "old" protocols */
3647
1.86k
    data->info.conn_protocol = (conn->handler->protocol) & CURLPROTO_MASK;
3648
1.86k
    result = conn->handler->connect_it(data, &done);
3649
1.86k
    if(result)
3650
224
      goto out;
3651
3652
    /* Setup a "faked" transfer that will do nothing */
3653
1.63k
    Curl_attach_connection(data, conn);
3654
1.63k
    result = Curl_cpool_add(data, conn);
3655
1.63k
    if(!result) {
3656
      /* Setup whatever necessary for a resumed transfer */
3657
1.63k
      result = setup_range(data);
3658
1.63k
      if(!result) {
3659
1.63k
        Curl_xfer_setup_nop(data);
3660
1.63k
        result = Curl_init_do(data, conn);
3661
1.63k
      }
3662
1.63k
    }
3663
3664
1.63k
    if(result) {
3665
0
      DEBUGASSERT(conn->handler->done);
3666
      /* we ignore the return code for the protocol-specific DONE */
3667
0
      (void)conn->handler->done(data, result, FALSE);
3668
0
    }
3669
1.63k
    goto out;
3670
1.63k
  }
3671
107k
#endif
3672
3673
  /* Setup filter for network connections */
3674
107k
  conn->recv[FIRSTSOCKET] = Curl_cf_recv;
3675
107k
  conn->send[FIRSTSOCKET] = Curl_cf_send;
3676
107k
  conn->recv[SECONDARYSOCKET] = Curl_cf_recv;
3677
107k
  conn->send[SECONDARYSOCKET] = Curl_cf_send;
3678
107k
  conn->bits.tcp_fastopen = data->set.tcp_fastopen;
3679
3680
  /* Complete the easy's SSL configuration for connection cache matching */
3681
107k
  result = Curl_ssl_easy_config_complete(data);
3682
107k
  if(result)
3683
0
    goto out;
3684
3685
107k
  Curl_cpool_prune_dead(data);
3686
3687
  /*************************************************************
3688
   * Check the current list of connections to see if we can
3689
   * reuse an already existing one or if we have to create a
3690
   * new one.
3691
   *************************************************************/
3692
3693
107k
  DEBUGASSERT(conn->user);
3694
107k
  DEBUGASSERT(conn->passwd);
3695
3696
  /* reuse_fresh is TRUE if we are told to use a new connection by force, but
3697
     we only acknowledge this option if this is not a reused connection
3698
     already (which happens due to follow-location or during an HTTP
3699
     authentication phase). CONNECT_ONLY transfers also refuse reuse. */
3700
107k
  if((data->set.reuse_fresh && !data->state.followlocation) ||
3701
107k
     data->set.connect_only)
3702
13.7k
    reuse = FALSE;
3703
94.1k
  else
3704
94.1k
    reuse = ConnectionExists(data, conn, &existing, &force_reuse, &waitpipe);
3705
3706
107k
  if(reuse) {
3707
    /*
3708
     * We already have a connection for this, we got the former connection in
3709
     * `existing` and thus we need to cleanup the one we just
3710
     * allocated before we can move along and use `existing`.
3711
     */
3712
7.13k
    bool tls_upgraded = (!(conn->given->flags & PROTOPT_SSL) &&
3713
7.13k
                         Curl_conn_is_ssl(conn, FIRSTSOCKET));
3714
3715
7.13k
    reuse_conn(data, conn, existing);
3716
7.13k
    conn = existing;
3717
7.13k
    *in_connect = conn;
3718
3719
7.13k
#ifndef CURL_DISABLE_PROXY
3720
7.13k
    infof(data, "Re-using existing %s: connection%s with %s %s",
3721
7.13k
          conn->given->scheme,
3722
7.13k
          tls_upgraded ? " (upgraded to SSL)" : "",
3723
7.13k
          conn->bits.proxy ? "proxy" : "host",
3724
7.13k
          conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname :
3725
7.13k
          conn->http_proxy.host.name ? conn->http_proxy.host.dispname :
3726
7.13k
          conn->host.dispname);
3727
#else
3728
    infof(data, "Re-using existing %s: connection%s with host %s",
3729
          conn->given->scheme,
3730
          tls_upgraded ? " (upgraded to SSL)" : "",
3731
          conn->host.dispname);
3732
#endif
3733
7.13k
  }
3734
100k
  else {
3735
    /* We have decided that we want a new connection. However, we may not
3736
       be able to do that if we have reached the limit of how many
3737
       connections we are allowed to open. */
3738
3739
100k
    if(conn->handler->flags & PROTOPT_ALPN) {
3740
      /* The protocol wants it, so set the bits if enabled in the easy handle
3741
         (default) */
3742
10.2k
      if(data->set.ssl_enable_alpn)
3743
10.1k
        conn->bits.tls_enable_alpn = TRUE;
3744
10.2k
    }
3745
3746
100k
    if(waitpipe) {
3747
      /* There is a connection that *might* become usable for multiplexing
3748
         "soon", and we wait for that */
3749
1.97k
      infof(data, "Waiting on connection to negotiate possible multiplexing.");
3750
1.97k
      connections_available = FALSE;
3751
1.97k
    }
3752
98.7k
    else {
3753
98.7k
      switch(Curl_cpool_check_limits(data, conn)) {
3754
0
      case CPOOL_LIMIT_DEST:
3755
0
        infof(data, "No more connections allowed to host");
3756
0
        connections_available = FALSE;
3757
0
        break;
3758
0
      case CPOOL_LIMIT_TOTAL:
3759
0
        if(data->master_mid != UINT_MAX)
3760
0
          CURL_TRC_M(data, "Allowing sub-requests (like DoH) to override "
3761
0
                     "max connection limit");
3762
0
        else {
3763
0
          infof(data, "No connections available, total of %ld reached.",
3764
0
                data->multi->max_total_connections);
3765
0
          connections_available = FALSE;
3766
0
        }
3767
0
        break;
3768
98.7k
      default:
3769
98.7k
        break;
3770
98.7k
      }
3771
98.7k
    }
3772
3773
100k
    if(!connections_available) {
3774
1.97k
      Curl_conn_free(data, conn);
3775
1.97k
      *in_connect = NULL;
3776
3777
1.97k
      result = CURLE_NO_CONNECTION_AVAILABLE;
3778
1.97k
      goto out;
3779
1.97k
    }
3780
98.7k
    else {
3781
      /*
3782
       * This is a brand new connection, so let's store it in the connection
3783
       * cache of ours!
3784
       */
3785
98.7k
      result = Curl_ssl_conn_config_init(data, conn);
3786
98.7k
      if(result) {
3787
0
        DEBUGF(fprintf(stderr, "Error: init connection ssl config\n"));
3788
0
        goto out;
3789
0
      }
3790
3791
98.7k
      Curl_attach_connection(data, conn);
3792
98.7k
      result = Curl_cpool_add(data, conn);
3793
98.7k
      if(result)
3794
0
        goto out;
3795
98.7k
    }
3796
3797
98.7k
#ifdef USE_NTLM
3798
    /* If NTLM is requested in a part of this connection, make sure we do not
3799
       assume the state is fine as this is a fresh connection and NTLM is
3800
       connection based. */
3801
98.7k
    if((data->state.authhost.picked & CURLAUTH_NTLM) &&
3802
98.7k
       data->state.authhost.done) {
3803
31
      infof(data, "NTLM picked AND auth done set, clear picked");
3804
31
      data->state.authhost.picked = CURLAUTH_NONE;
3805
31
      data->state.authhost.done = FALSE;
3806
31
    }
3807
3808
98.7k
    if((data->state.authproxy.picked & CURLAUTH_NTLM) &&
3809
98.7k
       data->state.authproxy.done) {
3810
53
      infof(data, "NTLM-proxy picked AND auth done set, clear picked");
3811
53
      data->state.authproxy.picked = CURLAUTH_NONE;
3812
53
      data->state.authproxy.done = FALSE;
3813
53
    }
3814
98.7k
#endif
3815
98.7k
  }
3816
3817
  /* Setup and init stuff before DO starts, in preparing for the transfer. */
3818
105k
  result = Curl_init_do(data, conn);
3819
105k
  if(result)
3820
0
    goto out;
3821
3822
  /*
3823
   * Setup whatever necessary for a resumed transfer
3824
   */
3825
105k
  result = setup_range(data);
3826
105k
  if(result)
3827
0
    goto out;
3828
3829
  /* Continue connectdata initialization here. */
3830
3831
105k
  if(conn->bits.reuse) {
3832
    /* We are reusing the connection - no need to resolve anything, and
3833
       idnconvert_hostname() was called already in create_conn() for the reuse
3834
       case. */
3835
7.13k
    *reusedp = TRUE;
3836
7.13k
  }
3837
3838
  /* persist the scheme and handler the transfer is using */
3839
105k
  data->info.conn_scheme = conn->handler->scheme;
3840
  /* conn_protocol can only provide "old" protocols */
3841
105k
  data->info.conn_protocol = (conn->handler->protocol) & CURLPROTO_MASK;
3842
105k
  data->info.used_proxy =
3843
#ifdef CURL_DISABLE_PROXY
3844
    0
3845
#else
3846
105k
    conn->bits.proxy
3847
105k
#endif
3848
105k
    ;
3849
3850
  /* Everything general done, inform filters that they need
3851
   * to prepare for a data transfer. */
3852
105k
  result = Curl_conn_ev_data_setup(data);
3853
3854
126k
out:
3855
126k
  return result;
3856
105k
}
3857
3858
/* Curl_setup_conn() is called after the name resolve initiated in
3859
 * create_conn() is all done.
3860
 *
3861
 * Curl_setup_conn() also handles reused connections
3862
 */
3863
CURLcode Curl_setup_conn(struct Curl_easy *data,
3864
                         struct Curl_dns_entry *dns,
3865
                         bool *protocol_done)
3866
92.3k
{
3867
92.3k
  CURLcode result = CURLE_OK;
3868
92.3k
  struct connectdata *conn = data->conn;
3869
3870
92.3k
  DEBUGASSERT(dns);
3871
92.3k
  Curl_pgrsTime(data, TIMER_NAMELOOKUP);
3872
3873
92.3k
  if(!conn->bits.reuse)
3874
92.3k
    result = Curl_conn_setup(data, conn, FIRSTSOCKET, dns,
3875
92.3k
                             CURL_CF_SSL_DEFAULT);
3876
92.3k
  if(!result)
3877
92.3k
    result = Curl_headers_init(data);
3878
3879
  /* not sure we need this flag to be passed around any more */
3880
92.3k
  *protocol_done = FALSE;
3881
92.3k
  return result;
3882
92.3k
}
3883
3884
CURLcode Curl_connect(struct Curl_easy *data,
3885
                      bool *asyncp,
3886
                      bool *protocol_done)
3887
126k
{
3888
126k
  CURLcode result;
3889
126k
  struct connectdata *conn;
3890
126k
  bool reused = FALSE;
3891
3892
126k
  *asyncp = FALSE; /* assume synchronous resolves by default */
3893
126k
  *protocol_done = FALSE;
3894
3895
  /* Set the request to virgin state based on transfer settings */
3896
126k
  Curl_req_hard_reset(&data->req, data);
3897
3898
  /* call the stuff that needs to be called */
3899
126k
  result = create_conn(data, &conn, &reused);
3900
3901
126k
  if(result == CURLE_NO_CONNECTION_AVAILABLE) {
3902
1.97k
    DEBUGASSERT(!conn);
3903
1.97k
    return result;
3904
1.97k
  }
3905
3906
124k
  if(!result) {
3907
107k
    DEBUGASSERT(conn);
3908
107k
    if(reused) {
3909
7.13k
      if(CONN_ATTACHED(conn) > 1)
3910
        /* multiplexed */
3911
0
        *protocol_done = TRUE;
3912
7.13k
    }
3913
100k
    else if(conn->handler->flags & PROTOPT_NONETWORK) {
3914
1.63k
      *asyncp = FALSE;
3915
1.63k
      Curl_pgrsTime(data, TIMER_NAMELOOKUP);
3916
1.63k
      *protocol_done = TRUE;
3917
1.63k
    }
3918
98.7k
    else {
3919
      /*************************************************************
3920
       * Resolve the address of the server or proxy
3921
       *************************************************************/
3922
98.7k
      struct Curl_dns_entry *dns;
3923
98.7k
      result = resolve_server(data, conn, asyncp, &dns);
3924
98.7k
      if(!result) {
3925
98.6k
        *asyncp = !dns;
3926
98.6k
        if(dns)
3927
          /* DNS resolution is done: that is either because this is a reused
3928
             connection, in which case DNS was unnecessary, or because DNS
3929
             really did finish already (synch resolver/fast async resolve) */
3930
92.0k
          result = Curl_setup_conn(data, dns, protocol_done);
3931
98.6k
      }
3932
98.7k
    }
3933
107k
  }
3934
3935
124k
  if(result && conn) {
3936
    /* We are not allowed to return failure with memory left allocated in the
3937
       connectdata struct, free those here */
3938
17.0k
    Curl_detach_connection(data);
3939
17.0k
    Curl_conn_terminate(data, conn, TRUE);
3940
17.0k
  }
3941
3942
124k
  return result;
3943
124k
}
3944
3945
/*
3946
 * Curl_init_do() inits the readwrite session. This is inited each time (in
3947
 * the DO function before the protocol-specific DO functions are invoked) for
3948
 * a transfer, sometimes multiple times on the same Curl_easy. Make sure
3949
 * nothing in here depends on stuff that are setup dynamically for the
3950
 * transfer.
3951
 *
3952
 * Allow this function to get called with 'conn' set to NULL.
3953
 */
3954
3955
CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
3956
107k
{
3957
  /* if this is a pushed stream, we need this: */
3958
107k
  CURLcode result;
3959
3960
107k
  if(conn) {
3961
107k
    conn->bits.do_more = FALSE; /* by default there is no curl_do_more() to
3962
                                   use */
3963
    /* if the protocol used does not support wildcards, switch it off */
3964
107k
    if(data->state.wildcardmatch &&
3965
107k
       !(conn->handler->flags & PROTOPT_WILDCARD))
3966
64
      data->state.wildcardmatch = FALSE;
3967
107k
  }
3968
3969
107k
  data->state.done = FALSE; /* *_done() is not called yet */
3970
3971
107k
  if(data->req.no_body)
3972
    /* in HTTP lingo, no body means using the HEAD request... */
3973
845
    data->state.httpreq = HTTPREQ_HEAD;
3974
3975
107k
  result = Curl_req_start(&data->req, data);
3976
107k
  if(!result) {
3977
107k
    Curl_speedinit(data);
3978
107k
    Curl_pgrsSetUploadCounter(data, 0);
3979
107k
    Curl_pgrsSetDownloadCounter(data, 0);
3980
107k
  }
3981
107k
  return result;
3982
107k
}
3983
3984
#if defined(USE_HTTP2) || defined(USE_HTTP3)
3985
3986
#ifdef USE_NGHTTP2
3987
3988
static void priority_remove_child(struct Curl_easy *parent,
3989
                                  struct Curl_easy *child)
3990
0
{
3991
0
  struct Curl_data_prio_node **pnext = &parent->set.priority.children;
3992
0
  struct Curl_data_prio_node *pnode = parent->set.priority.children;
3993
3994
0
  DEBUGASSERT(child->set.priority.parent == parent);
3995
0
  while(pnode && pnode->data != child) {
3996
0
    pnext = &pnode->next;
3997
0
    pnode = pnode->next;
3998
0
  }
3999
4000
0
  DEBUGASSERT(pnode);
4001
0
  if(pnode) {
4002
0
    *pnext = pnode->next;
4003
0
    free(pnode);
4004
0
  }
4005
4006
0
  child->set.priority.parent = 0;
4007
0
  child->set.priority.exclusive = FALSE;
4008
0
}
4009
4010
CURLcode Curl_data_priority_add_child(struct Curl_easy *parent,
4011
                                      struct Curl_easy *child,
4012
                                      bool exclusive)
4013
0
{
4014
0
  if(child->set.priority.parent) {
4015
0
    priority_remove_child(child->set.priority.parent, child);
4016
0
  }
4017
4018
0
  if(parent) {
4019
0
    struct Curl_data_prio_node **tail;
4020
0
    struct Curl_data_prio_node *pnode;
4021
4022
0
    pnode = calloc(1, sizeof(*pnode));
4023
0
    if(!pnode)
4024
0
      return CURLE_OUT_OF_MEMORY;
4025
0
    pnode->data = child;
4026
4027
0
    if(parent->set.priority.children && exclusive) {
4028
      /* exclusive: move all existing children underneath the new child */
4029
0
      struct Curl_data_prio_node *node = parent->set.priority.children;
4030
0
      while(node) {
4031
0
        node->data->set.priority.parent = child;
4032
0
        node = node->next;
4033
0
      }
4034
4035
0
      tail = &child->set.priority.children;
4036
0
      while(*tail)
4037
0
        tail = &(*tail)->next;
4038
4039
0
      DEBUGASSERT(!*tail);
4040
0
      *tail = parent->set.priority.children;
4041
0
      parent->set.priority.children = 0;
4042
0
    }
4043
4044
0
    tail = &parent->set.priority.children;
4045
0
    while(*tail) {
4046
0
      (*tail)->data->set.priority.exclusive = FALSE;
4047
0
      tail = &(*tail)->next;
4048
0
    }
4049
4050
0
    DEBUGASSERT(!*tail);
4051
0
    *tail = pnode;
4052
0
  }
4053
4054
0
  child->set.priority.parent = parent;
4055
0
  child->set.priority.exclusive = exclusive;
4056
0
  return CURLE_OK;
4057
0
}
4058
4059
#endif /* USE_NGHTTP2 */
4060
4061
#ifdef USE_NGHTTP2
4062
static void data_priority_cleanup(struct Curl_easy *data)
4063
311k
{
4064
311k
  while(data->set.priority.children) {
4065
0
    struct Curl_easy *tmp = data->set.priority.children->data;
4066
0
    priority_remove_child(data, tmp);
4067
0
    if(data->set.priority.parent)
4068
0
      Curl_data_priority_add_child(data->set.priority.parent, tmp, FALSE);
4069
0
  }
4070
4071
311k
  if(data->set.priority.parent)
4072
0
    priority_remove_child(data->set.priority.parent, data);
4073
311k
}
4074
#endif
4075
4076
void Curl_data_priority_clear_state(struct Curl_easy *data)
4077
115k
{
4078
115k
  memset(&data->state.priority, 0, sizeof(data->state.priority));
4079
115k
}
4080
4081
#endif /* defined(USE_HTTP2) || defined(USE_HTTP3) */
4082
4083
4084
CURLcode Curl_conn_meta_set(struct connectdata *conn, const char *key,
4085
                            void *meta_data, Curl_meta_dtor *meta_dtor)
4086
53.4k
{
4087
53.4k
  if(!Curl_hash_add2(&conn->meta_hash, CURL_UNCONST(key), strlen(key) + 1,
4088
53.4k
                     meta_data, meta_dtor)) {
4089
0
    meta_dtor(CURL_UNCONST(key), strlen(key) + 1, meta_data);
4090
0
    return CURLE_OUT_OF_MEMORY;
4091
0
  }
4092
53.4k
  return CURLE_OK;
4093
53.4k
}
4094
4095
void Curl_conn_meta_remove(struct connectdata *conn, const char *key)
4096
117k
{
4097
117k
  Curl_hash_delete(&conn->meta_hash, CURL_UNCONST(key), strlen(key) + 1);
4098
117k
}
4099
4100
void *Curl_conn_meta_get(struct connectdata *conn, const char *key)
4101
41.3M
{
4102
41.3M
  return Curl_hash_pick(&conn->meta_hash, CURL_UNCONST(key), strlen(key) + 1);
4103
41.3M
}
4104
4105
CURLcode Curl_1st_err(CURLcode r1, CURLcode r2)
4106
115k
{
4107
115k
  return r1 ? r1 : r2;
4108
115k
}
4109
4110
CURLcode Curl_1st_fatal(CURLcode r1, CURLcode r2)
4111
0
{
4112
0
  if(r1 && (r1 != CURLE_AGAIN))
4113
0
    return r1;
4114
0
  if(r2 && (r2 != CURLE_AGAIN))
4115
0
    return r2;
4116
0
  return r1;
4117
0
}