Coverage Report

Created: 2025-11-23 06:22

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