Coverage Report

Created: 2023-06-07 07:02

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