Coverage Report

Created: 2025-06-09 07:42

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