Coverage Report

Created: 2025-11-09 06:25

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
3.89k
#define UNIX_SOCKET_PREFIX "localhost"
150
#endif
151
152
/* Reject URLs exceeding this length */
153
136k
#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
13.6k
{
168
13.6k
  DEBUGASSERT(h);
169
13.6k
  DEBUGASSERT(h->family);
170
13.6k
  return h->family;
171
13.6k
}
172
173
void Curl_freeset(struct Curl_easy *data)
174
360k
{
175
  /* Free all dynamic strings stored in the data->set substructure. */
176
360k
  enum dupstring i;
177
360k
  enum dupblob j;
178
179
27.3M
  for(i = (enum dupstring)0; i < STRING_LAST; i++) {
180
27.0M
    Curl_safefree(data->set.str[i]);
181
27.0M
  }
182
183
3.24M
  for(j = (enum dupblob)0; j < BLOB_LAST; j++) {
184
2.88M
    Curl_safefree(data->set.blobs[j]);
185
2.88M
  }
186
187
360k
  if(data->state.referer_alloc) {
188
0
    Curl_safefree(data->state.referer);
189
0
    data->state.referer_alloc = FALSE;
190
0
  }
191
360k
  data->state.referer = NULL;
192
360k
  if(data->state.url_alloc) {
193
122k
    Curl_safefree(data->state.url);
194
122k
    data->state.url_alloc = FALSE;
195
122k
  }
196
360k
  data->state.url = NULL;
197
198
360k
  Curl_mime_cleanpart(&data->set.mimepost);
199
200
360k
#ifndef CURL_DISABLE_COOKIES
201
360k
  curl_slist_free_all(data->state.cookielist);
202
360k
  data->state.cookielist = NULL;
203
360k
#endif
204
360k
}
205
206
/* free the URL pieces */
207
static void up_free(struct Curl_easy *data)
208
508k
{
209
508k
  struct urlpieces *up = &data->state.up;
210
508k
  Curl_safefree(up->scheme);
211
508k
  Curl_safefree(up->hostname);
212
508k
  Curl_safefree(up->port);
213
508k
  Curl_safefree(up->user);
214
508k
  Curl_safefree(up->password);
215
508k
  Curl_safefree(up->options);
216
508k
  Curl_safefree(up->path);
217
508k
  Curl_safefree(up->query);
218
508k
  curl_url_cleanup(data->state.uh);
219
508k
  data->state.uh = NULL;
220
508k
}
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
360k
{
231
360k
  struct Curl_easy *data;
232
233
360k
  if(!datap || !*datap)
234
106
    return CURLE_OK;
235
236
360k
  data = *datap;
237
360k
  *datap = NULL;
238
239
360k
  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
360k
  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
360k
    Curl_detach_connection(data);
249
360k
    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
360k
  }
256
360k
  DEBUGASSERT(!data->conn || data->state.internal);
257
258
360k
  Curl_expire_clear(data); /* shut off any timers left */
259
260
360k
  if(data->state.rangestringalloc)
261
3.35k
    free(data->state.range);
262
263
  /* release any resolve information this transfer kept */
264
360k
  Curl_async_destroy(data);
265
360k
  Curl_resolv_unlink(data, &data->state.dns[0]); /* done with this */
266
360k
  Curl_resolv_unlink(data, &data->state.dns[1]);
267
268
360k
  data->set.verbose = FALSE; /* no more calls to DEBUGFUNCTION */
269
360k
  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
360k
  Curl_req_free(&data->req, data);
276
277
  /* Close down all open SSL info and sessions */
278
360k
  Curl_ssl_close_all(data);
279
360k
  Curl_safefree(data->state.first_host);
280
360k
  Curl_ssl_free_certinfo(data);
281
282
360k
  if(data->state.referer_alloc) {
283
332
    Curl_safefree(data->state.referer);
284
332
    data->state.referer_alloc = FALSE;
285
332
  }
286
360k
  data->state.referer = NULL;
287
288
360k
  up_free(data);
289
360k
  curlx_dyn_free(&data->state.headerb);
290
360k
  Curl_flush_cookies(data, TRUE);
291
360k
#ifndef CURL_DISABLE_ALTSVC
292
360k
  Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]);
293
360k
  Curl_altsvc_cleanup(&data->asi);
294
360k
#endif
295
360k
#ifndef CURL_DISABLE_HSTS
296
360k
  Curl_hsts_save(data, data->hsts, data->set.str[STRING_HSTS]);
297
360k
  if(!data->share || !data->share->hsts)
298
360k
    Curl_hsts_cleanup(&data->hsts);
299
360k
  curl_slist_free_all(data->state.hstslist); /* clean up list */
300
360k
#endif
301
360k
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH)
302
360k
  Curl_http_auth_cleanup_digest(data);
303
360k
#endif
304
360k
  Curl_safefree(data->state.most_recent_ftp_entrypath);
305
360k
  Curl_safefree(data->info.contenttype);
306
360k
  Curl_safefree(data->info.wouldredirect);
307
308
360k
  data_priority_cleanup(data);
309
310
  /* No longer a dirty share, if it exists */
311
360k
  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
360k
  Curl_hash_destroy(&data->meta_hash);
318
360k
#ifndef CURL_DISABLE_PROXY
319
360k
  Curl_safefree(data->state.aptr.proxyuserpwd);
320
360k
#endif
321
360k
  Curl_safefree(data->state.aptr.uagent);
322
360k
  Curl_safefree(data->state.aptr.userpwd);
323
360k
  Curl_safefree(data->state.aptr.accept_encoding);
324
360k
  Curl_safefree(data->state.aptr.rangeline);
325
360k
  Curl_safefree(data->state.aptr.ref);
326
360k
  Curl_safefree(data->state.aptr.host);
327
360k
#ifndef CURL_DISABLE_COOKIES
328
360k
  Curl_safefree(data->state.aptr.cookiehost);
329
360k
#endif
330
360k
#ifndef CURL_DISABLE_RTSP
331
360k
  Curl_safefree(data->state.aptr.rtsp_transport);
332
360k
#endif
333
360k
  Curl_safefree(data->state.aptr.user);
334
360k
  Curl_safefree(data->state.aptr.passwd);
335
360k
#ifndef CURL_DISABLE_PROXY
336
360k
  Curl_safefree(data->state.aptr.proxyuser);
337
360k
  Curl_safefree(data->state.aptr.proxypasswd);
338
360k
#endif
339
340
360k
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_FORM_API)
341
360k
  Curl_mime_cleanpart(data->state.formp);
342
360k
  Curl_safefree(data->state.formp);
343
360k
#endif
344
345
  /* destruct wildcard structures if it is needed */
346
360k
  Curl_wildcard_dtor(&data->wildcard);
347
360k
  Curl_freeset(data);
348
360k
  Curl_headers_cleanup(data);
349
360k
  Curl_netrc_cleanup(&data->state.netrc);
350
360k
  free(data);
351
360k
  return CURLE_OK;
352
360k
}
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
360k
{
360
360k
  struct UserDefined *set = &data->set;
361
362
360k
  set->out = stdout;  /* default output to stdout */
363
360k
  set->in_set = stdin;  /* default input from stdin */
364
360k
  set->err = stderr;  /* default stderr to stderr */
365
366
360k
#if defined(__clang__) && __clang_major__ >= 16
367
360k
#pragma clang diagnostic push
368
360k
#pragma clang diagnostic ignored "-Wcast-function-type-strict"
369
360k
#endif
370
  /* use fwrite as default function to store output */
371
360k
  set->fwrite_func = (curl_write_callback)fwrite;
372
373
  /* use fread as default function to read input */
374
360k
  set->fread_func_set = (curl_read_callback)fread;
375
360k
#if defined(__clang__) && __clang_major__ >= 16
376
360k
#pragma clang diagnostic pop
377
360k
#endif
378
360k
  set->is_fread_set = 0;
379
380
360k
  set->seek_client = ZERO_NULL;
381
382
360k
  set->filesize = -1;        /* we do not know the size */
383
360k
  set->postfieldsize = -1;   /* unknown size */
384
360k
  set->maxredirs = 30;       /* sensible default */
385
386
360k
  set->method = HTTPREQ_GET; /* Default HTTP request */
387
360k
#ifndef CURL_DISABLE_RTSP
388
360k
  set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */
389
360k
#endif
390
360k
#ifndef CURL_DISABLE_FTP
391
360k
  set->ftp_use_epsv = TRUE;   /* FTP defaults to EPSV operations */
392
360k
  set->ftp_use_eprt = TRUE;   /* FTP defaults to EPRT operations */
393
360k
  set->ftp_use_pret = FALSE;  /* mainly useful for drftpd servers */
394
360k
  set->ftp_filemethod = FTPFILE_MULTICWD;
395
360k
  set->ftp_skip_ip = TRUE;    /* skip PASV IP by default */
396
360k
#endif
397
360k
  set->dns_cache_timeout_ms = 60000; /* Timeout every 60 seconds by default */
398
399
  /* Timeout every 24 hours by default */
400
360k
  set->general_ssl.ca_cache_timeout = 24 * 60 * 60;
401
402
360k
  set->httpauth = CURLAUTH_BASIC;  /* defaults to basic */
403
404
360k
#ifndef CURL_DISABLE_PROXY
405
360k
  set->proxyport = 0;
406
360k
  set->proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */
407
360k
  set->proxyauth = CURLAUTH_BASIC; /* defaults to basic */
408
  /* SOCKS5 proxy auth defaults to username/password + GSS-API */
409
360k
  set->socks5auth = CURLAUTH_BASIC | CURLAUTH_GSSAPI;
410
360k
#endif
411
412
360k
  Curl_mime_initpart(&set->mimepost);
413
414
360k
  Curl_ssl_easy_config_init(data);
415
360k
#ifndef CURL_DISABLE_DOH
416
360k
  set->doh_verifyhost = TRUE;
417
360k
  set->doh_verifypeer = TRUE;
418
360k
#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
360k
  set->new_file_perms = 0644;    /* Default permissions */
426
360k
  set->allowed_protocols = (curl_prot_t) CURLPROTO_ALL;
427
360k
  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
360k
#ifdef USE_SSL
439
360k
  Curl_setopt_SSLVERSION(data, CURLOPT_SSLVERSION, CURL_SSLVERSION_DEFAULT);
440
360k
#ifndef CURL_DISABLE_PROXY
441
360k
  Curl_setopt_SSLVERSION(data, CURLOPT_PROXY_SSLVERSION,
442
360k
                         CURL_SSLVERSION_DEFAULT);
443
360k
#endif
444
360k
#endif
445
360k
#ifndef CURL_DISABLE_FTP
446
360k
  set->wildcard_enabled = FALSE;
447
360k
  set->chunk_bgn      = ZERO_NULL;
448
360k
  set->chunk_end      = ZERO_NULL;
449
360k
  set->fnmatch = ZERO_NULL;
450
360k
#endif
451
360k
  set->tcp_keepalive = FALSE;
452
360k
  set->tcp_keepintvl = 60;
453
360k
  set->tcp_keepidle = 60;
454
360k
  set->tcp_keepcnt = 9;
455
360k
  set->tcp_fastopen = FALSE;
456
360k
  set->tcp_nodelay = TRUE;
457
360k
  set->ssl_enable_alpn = TRUE;
458
360k
  set->expect_100_timeout = 1000L; /* Wait for a second by default. */
459
360k
  set->sep_headers = TRUE; /* separated header lists by default */
460
360k
  set->buffer_size = READBUFFER_SIZE;
461
360k
  set->upload_buffer_size = UPLOADBUFFER_DEFAULT;
462
360k
  set->happy_eyeballs_timeout = CURL_HET_DEFAULT;
463
360k
  set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT;
464
360k
  set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
465
360k
  set->conn_max_idle_ms = 118 * 1000;
466
360k
  set->conn_max_age_ms = 24 * 3600 * 1000;
467
360k
  set->http09_allowed = FALSE;
468
360k
  set->httpwant = CURL_HTTP_VERSION_NONE
469
360k
    ;
470
360k
#if defined(USE_HTTP2) || defined(USE_HTTP3)
471
360k
  memset(&set->priority, 0, sizeof(set->priority));
472
360k
#endif
473
360k
  set->quick_exit = 0L;
474
360k
#ifndef CURL_DISABLE_WEBSOCKETS
475
360k
  set->ws_raw_mode = FALSE;
476
360k
  set->ws_no_auto_pong = FALSE;
477
360k
#endif
478
360k
}
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
360k
{
501
360k
  struct Curl_easy *data;
502
503
  /* simple start-up: alloc the struct, init it with zeroes and return */
504
360k
  data = calloc(1, sizeof(struct Curl_easy));
505
360k
  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
360k
  data->magic = CURLEASY_MAGIC_NUMBER;
512
  /* most recent connection is not yet defined */
513
360k
  data->state.lastconnect_id = -1;
514
360k
  data->state.recent_conn_id = -1;
515
  /* and not assigned an id yet */
516
360k
  data->id = -1;
517
360k
  data->mid = UINT_MAX;
518
360k
  data->master_mid = UINT_MAX;
519
360k
  data->progress.hide = TRUE;
520
360k
  data->state.current_speed = -1; /* init to negative == impossible */
521
522
360k
  Curl_hash_init(&data->meta_hash, 23,
523
360k
                 Curl_hash_str, curlx_str_key_compare, easy_meta_freeentry);
524
360k
  curlx_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER);
525
360k
  Curl_req_init(&data->req);
526
360k
  Curl_initinfo(data);
527
360k
#ifndef CURL_DISABLE_HTTP
528
360k
  Curl_llist_init(&data->state.httphdrs, NULL);
529
360k
#endif
530
360k
  Curl_netrc_init(&data->state.netrc);
531
360k
  Curl_init_userdefined(data);
532
533
360k
  *curl = data;
534
360k
  return CURLE_OK;
535
360k
}
536
537
void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn)
538
148k
{
539
148k
  size_t i;
540
541
148k
  DEBUGASSERT(conn);
542
543
148k
  if(conn->handler && conn->handler->disconnect &&
544
32.3k
     !conn->bits.shutdown_handler)
545
14
    conn->handler->disconnect(data, conn, TRUE);
546
547
445k
  for(i = 0; i < CURL_ARRAYSIZE(conn->cfilter); ++i) {
548
296k
    Curl_conn_cf_discard_all(data, conn, (int)i);
549
296k
  }
550
551
148k
  Curl_free_idnconverted_hostname(&conn->host);
552
148k
  Curl_free_idnconverted_hostname(&conn->conn_to_host);
553
148k
#ifndef CURL_DISABLE_PROXY
554
148k
  Curl_free_idnconverted_hostname(&conn->http_proxy.host);
555
148k
  Curl_free_idnconverted_hostname(&conn->socks_proxy.host);
556
148k
  Curl_safefree(conn->http_proxy.user);
557
148k
  Curl_safefree(conn->socks_proxy.user);
558
148k
  Curl_safefree(conn->http_proxy.passwd);
559
148k
  Curl_safefree(conn->socks_proxy.passwd);
560
148k
  Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */
561
148k
  Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */
562
148k
#endif
563
148k
  Curl_safefree(conn->user);
564
148k
  Curl_safefree(conn->passwd);
565
148k
  Curl_safefree(conn->sasl_authzid);
566
148k
  Curl_safefree(conn->options);
567
148k
  Curl_safefree(conn->oauth_bearer);
568
148k
  Curl_safefree(conn->host.rawalloc); /* hostname buffer */
569
148k
  Curl_safefree(conn->conn_to_host.rawalloc); /* hostname buffer */
570
148k
  Curl_safefree(conn->hostname_resolve);
571
148k
  Curl_safefree(conn->secondaryhostname);
572
148k
  Curl_safefree(conn->localdev);
573
148k
  Curl_ssl_conn_config_cleanup(conn);
574
575
148k
#ifdef USE_UNIX_SOCKETS
576
148k
  Curl_safefree(conn->unix_domain_socket);
577
148k
#endif
578
148k
  Curl_safefree(conn->destination);
579
148k
  Curl_uint_spbset_destroy(&conn->xfers_attached);
580
148k
  Curl_hash_destroy(&conn->meta_hash);
581
582
148k
  free(conn); /* free all the connection oriented data */
583
148k
}
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
42.6k
     (!conn->bits.protoconnstart || !conn->bits.close)) {
598
599
42.6k
    if(Curl_multiplex_wanted(data->multi) &&
600
42.6k
       (data->state.http_neg.allowed & (CURL_HTTP_V2x|CURL_HTTP_V3x)))
601
      /* allows HTTP/2 or newer */
602
42.3k
      return TRUE;
603
42.6k
  }
604
#else
605
  (void)data;
606
  (void)conn;
607
#endif
608
70.5k
  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
3.95k
{
616
3.95k
  if((data->proxytype == needle->proxytype) &&
617
3.95k
     (data->port == needle->port) &&
618
3.95k
     curl_strequal(data->host.name, needle->host.name))
619
3.95k
    return TRUE;
620
621
0
  return FALSE;
622
3.95k
}
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
9.76k
{
655
9.76k
  timediff_t age_ms;
656
657
9.76k
  if(data->set.conn_max_idle_ms) {
658
9.69k
    age_ms = curlx_timediff(now, conn->lastused);
659
9.69k
    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.69k
  }
666
667
9.76k
  if(data->set.conn_max_age_ms) {
668
9.71k
    age_ms = curlx_timediff(now, conn->created);
669
9.71k
    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
9.71k
  }
677
678
9.76k
  return FALSE;
679
9.76k
}
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
9.76k
{
688
9.76k
  DEBUGASSERT(!data->conn);
689
9.76k
  if(!CONN_INUSE(conn)) {
690
    /* The check for a dead socket makes sense only if the connection is not in
691
       use */
692
9.76k
    bool dead;
693
9.76k
    struct curltime now;
694
9.76k
    if(!pnow) {
695
9.76k
      now = curlx_now();
696
9.76k
      pnow = &now;
697
9.76k
    }
698
699
9.76k
    if(conn_maxage(data, conn, *pnow)) {
700
      /* avoid check if already too old */
701
0
      dead = TRUE;
702
0
    }
703
9.76k
    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.34k
      unsigned int state;
707
708
      /* briefly attach the connection to this transfer for the purpose of
709
         checking it */
710
9.34k
      Curl_attach_connection(data, conn);
711
712
9.34k
      state = conn->handler->connection_check(data, conn, CONNCHECK_ISDEAD);
713
9.34k
      dead = (state & CONNRESULT_DEAD);
714
      /* detach the connection again */
715
9.34k
      Curl_detach_connection(data);
716
717
9.34k
    }
718
422
    else {
719
422
      bool input_pending = FALSE;
720
721
422
      Curl_attach_connection(data, conn);
722
422
      dead = !Curl_conn_is_alive(data, conn, &input_pending);
723
422
      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
246
        DEBUGF(infof(data, "connection has input pending, not reusable"));
733
246
        dead = TRUE;
734
246
      }
735
422
      Curl_detach_connection(data);
736
422
    }
737
738
9.76k
    if(dead) {
739
      /* remove connection from cpool */
740
246
      infof(data, "Connection %" FMT_OFF_T " seems to be dead",
741
246
            conn->connection_id);
742
246
      return TRUE;
743
246
    }
744
9.76k
  }
745
9.51k
  return FALSE;
746
9.76k
}
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(*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
16.5k
{
806
  /* connect-only or to-be-closed connections will not be reused */
807
16.5k
  if(conn->connect_only || conn->bits.close || conn->bits.no_reuse)
808
0
    return FALSE;
809
810
  /* ip_version must match */
811
16.5k
  if(m->data->set.ipver != CURL_IPRESOLVE_WHATEVER
812
101
     && m->data->set.ipver != conn->ip_version)
813
0
    return FALSE;
814
815
16.5k
  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.32k
    if((conn->localport != m->needle->localport) ||
828
1.32k
       (conn->localportrange != m->needle->localportrange) ||
829
1.32k
       (m->needle->localdev &&
830
129
        (!conn->localdev || strcmp(conn->localdev, m->needle->localdev))))
831
0
      return FALSE;
832
1.32k
  }
833
834
16.5k
  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
16.5k
  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
16.5k
#ifdef USE_UNIX_SOCKETS
846
16.5k
  if(m->needle->unix_domain_socket) {
847
3.95k
    if(!conn->unix_domain_socket)
848
0
      return FALSE;
849
3.95k
    if(strcmp(m->needle->unix_domain_socket, conn->unix_domain_socket))
850
0
      return FALSE;
851
3.95k
    if(m->needle->bits.abstract_unix_socket != conn->bits.abstract_unix_socket)
852
0
      return FALSE;
853
3.95k
  }
854
12.6k
  else if(conn->unix_domain_socket)
855
0
    return FALSE;
856
16.5k
#endif
857
858
16.5k
  return TRUE;
859
16.5k
}
860
861
static bool url_match_fully_connected(struct connectdata *conn,
862
                                      struct url_conn_match *m)
863
16.5k
{
864
16.5k
  if(!Curl_conn_is_connected(conn, FIRSTSOCKET) ||
865
13.7k
     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.75k
    if(m->may_multiplex) {
869
2.75k
      m->seen_pending_conn = TRUE;
870
      /* Do not pick a connection that has not connected yet */
871
2.75k
      infof(m->data, "Connection #%" FMT_OFF_T
872
2.75k
            " is not open enough, cannot reuse", conn->connection_id);
873
2.75k
    }
874
    /* Do not pick a connection that has not connected yet */
875
2.75k
    return FALSE;
876
2.75k
  }
877
13.7k
  return TRUE;
878
16.5k
}
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
13.7k
{
894
13.7k
  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
13.7k
  return TRUE;
906
13.7k
}
907
908
static bool url_match_multiplex_limits(struct connectdata *conn,
909
                                       struct url_conn_match *m)
910
9.76k
{
911
9.76k
  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
9.76k
  return TRUE;
930
9.76k
}
931
932
static bool url_match_ssl_use(struct connectdata *conn,
933
                              struct url_conn_match *m)
934
13.7k
{
935
13.7k
  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
13.7k
  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
13.7k
  return TRUE;
948
13.7k
}
949
950
#ifndef CURL_DISABLE_PROXY
951
static bool url_match_proxy_use(struct connectdata *conn,
952
                                struct url_conn_match *m)
953
13.7k
{
954
13.7k
  if(m->needle->bits.httpproxy != conn->bits.httpproxy ||
955
13.7k
     m->needle->bits.socksproxy != conn->bits.socksproxy)
956
0
    return FALSE;
957
958
13.7k
  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
13.7k
  if(m->needle->bits.httpproxy) {
964
3.94k
    if(m->needle->bits.tunnel_proxy != conn->bits.tunnel_proxy)
965
0
      return FALSE;
966
967
3.94k
    if(!proxy_info_matches(&m->needle->http_proxy, &conn->http_proxy))
968
0
      return FALSE;
969
970
3.94k
    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
3.94k
  }
986
13.7k
  return TRUE;
987
13.7k
}
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
13.7k
{
996
13.7k
  if(m->may_multiplex &&
997
4.11k
     (m->data->state.http_neg.allowed & (CURL_HTTP_V2x|CURL_HTTP_V3x)) &&
998
4.11k
     (m->needle->handler->protocol & CURLPROTO_HTTP) &&
999
4.11k
     !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
13.7k
  return TRUE;
1010
13.7k
}
1011
1012
static bool url_match_http_version(struct connectdata *conn,
1013
                                   struct url_conn_match *m)
1014
13.7k
{
1015
  /* If looking for HTTP and the HTTP versions allowed do not include
1016
   * the HTTP version of conn, continue looking. */
1017
13.7k
  if((m->needle->handler->protocol & PROTO_FAMILY_HTTP)) {
1018
4.26k
    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
270
    case 20:
1027
270
      if(!(m->data->state.http_neg.allowed & CURL_HTTP_V2x)) {
1028
127
        DEBUGF(infof(m->data, "not reusing conn #%" CURL_FORMAT_CURL_OFF_T
1029
127
               ", we do not want h2", conn->connection_id));
1030
127
        return FALSE;
1031
127
      }
1032
143
      break;
1033
3.99k
    default:
1034
3.99k
      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
3.99k
      break;
1040
4.26k
    }
1041
4.26k
  }
1042
13.6k
  return TRUE;
1043
13.7k
}
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
13.7k
{
1052
13.7k
  if(!url_match_http_version(conn, m))
1053
133
    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
13.6k
#ifndef CURL_DISABLE_FTP
1062
13.6k
  else if(get_protocol_family(m->needle->handler) & PROTO_FAMILY_FTP) {
1063
80
    if(!ftp_conns_match(m->needle, conn))
1064
0
      return FALSE;
1065
80
  }
1066
13.6k
#endif
1067
13.6k
  return TRUE;
1068
13.7k
}
1069
1070
static bool url_match_auth(struct connectdata *conn,
1071
                           struct url_conn_match *m)
1072
13.7k
{
1073
13.7k
  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.48k
    if(Curl_timestrcmp(m->needle->user, conn->user) ||
1077
9.47k
       Curl_timestrcmp(m->needle->passwd, conn->passwd) ||
1078
9.47k
       Curl_timestrcmp(m->needle->sasl_authzid, conn->sasl_authzid) ||
1079
9.47k
       Curl_timestrcmp(m->needle->oauth_bearer, conn->oauth_bearer)) {
1080
      /* one of them was different */
1081
15
      return FALSE;
1082
15
    }
1083
9.48k
  }
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
13.7k
  return TRUE;
1092
13.7k
}
1093
1094
static bool url_match_destination(struct connectdata *conn,
1095
                                  struct url_conn_match *m)
1096
16.5k
{
1097
  /* Additional match requirements if talking TLS OR
1098
   * not talking to an HTTP proxy OR using a tunnel through a proxy */
1099
16.5k
  if((m->needle->handler->flags&PROTOPT_SSL)
1100
13.8k
#ifndef CURL_DISABLE_PROXY
1101
13.8k
     || !m->needle->bits.httpproxy || m->needle->bits.tunnel_proxy
1102
16.5k
#endif
1103
16.5k
    ) {
1104
16.2k
    if(!curl_strequal(m->needle->handler->scheme, conn->handler->scheme)) {
1105
      /* `needle` and `conn` do not have the same scheme... */
1106
0
      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
0
        return FALSE;
1110
0
      }
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
16.2k
    if((m->needle->bits.conn_to_host && !curl_strequal(
1122
13.5k
        m->needle->conn_to_host.name, conn->conn_to_host.name)) ||
1123
16.2k
       (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
16.2k
    if(!curl_strequal(m->needle->host.name, conn->host.name) ||
1129
16.2k
       m->needle->remote_port != conn->remote_port)
1130
47
      return FALSE;
1131
16.2k
  }
1132
16.5k
  return TRUE;
1133
16.5k
}
1134
1135
static bool url_match_ssl_config(struct connectdata *conn,
1136
                                 struct url_conn_match *m)
1137
13.7k
{
1138
  /* If talking TLS, conn needs to use the same SSL options. */
1139
13.7k
  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
13.7k
  return TRUE;
1148
13.7k
}
1149
1150
#ifdef USE_NTLM
1151
static bool url_match_auth_ntlm(struct connectdata *conn,
1152
                                struct url_conn_match *m)
1153
13.6k
{
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
13.6k
  if(m->want_ntlm_http) {
1160
3.64k
    if(Curl_timestrcmp(m->needle->user, conn->user) ||
1161
3.63k
       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
10
      if(conn->http_ntlm_state == NTLMSTATE_NONE)
1166
10
        m->found = conn;
1167
10
      return FALSE;
1168
10
    }
1169
3.64k
  }
1170
9.96k
  else if(conn->http_ntlm_state != NTLMSTATE_NONE) {
1171
    /* Connection is using NTLM auth but we do not want NTLM */
1172
51
    return FALSE;
1173
51
  }
1174
1175
13.5k
#ifndef CURL_DISABLE_PROXY
1176
  /* Same for Proxy NTLM authentication */
1177
13.5k
  if(m->want_proxy_ntlm_http) {
1178
    /* Both conn->http_proxy.user and conn->http_proxy.passwd can be
1179
     * NULL */
1180
153
    if(!conn->http_proxy.user || !conn->http_proxy.passwd)
1181
0
      return FALSE;
1182
1183
153
    if(Curl_timestrcmp(m->needle->http_proxy.user,
1184
153
                       conn->http_proxy.user) ||
1185
153
       Curl_timestrcmp(m->needle->http_proxy.passwd,
1186
153
                       conn->http_proxy.passwd))
1187
0
      return FALSE;
1188
153
  }
1189
13.3k
  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
13.5k
#endif
1194
13.5k
  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
3.78k
    m->found = conn;
1200
1201
3.78k
    if((m->want_ntlm_http &&
1202
3.63k
       (conn->http_ntlm_state != NTLMSTATE_NONE)) ||
1203
3.78k
        (m->want_proxy_ntlm_http &&
1204
153
         (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
3.78k
    return FALSE;
1211
3.78k
  }
1212
9.76k
  return TRUE;
1213
13.5k
}
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
16.5k
{
1220
16.5k
  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
16.5k
  if(!url_match_connect_config(conn, m))
1225
3
    return FALSE;
1226
1227
  /* match for destination and protocol? */
1228
16.5k
  if(!url_match_destination(conn, m))
1229
47
    return FALSE;
1230
1231
16.5k
  if(!url_match_fully_connected(conn, m))
1232
2.75k
    return FALSE;
1233
1234
13.7k
  if(!url_match_multiplex_needs(conn, m))
1235
0
    return FALSE;
1236
1237
13.7k
  if(!url_match_ssl_use(conn, m))
1238
0
    return FALSE;
1239
13.7k
  if(!url_match_proxy_use(conn, m))
1240
0
    return FALSE;
1241
13.7k
  if(!url_match_ssl_config(conn, m))
1242
0
    return FALSE;
1243
1244
13.7k
  if(!url_match_http_multiplex(conn, m))
1245
0
    return FALSE;
1246
13.7k
  else if(m->wait_pipe)
1247
    /* we decided to wait on PIPELINING */
1248
0
    return TRUE;
1249
1250
13.7k
  if(!url_match_auth(conn, m))
1251
15
    return FALSE;
1252
1253
13.7k
  if(!url_match_proto_config(conn, m))
1254
133
    return FALSE;
1255
1256
13.6k
  if(!url_match_auth_ntlm(conn, m))
1257
3.84k
    return FALSE;
1258
9.76k
  else if(m->force_reuse)
1259
1
    return TRUE;
1260
1261
9.76k
  if(!url_match_multiplex_limits(conn, m))
1262
0
    return FALSE;
1263
1264
9.76k
  if(!CONN_INUSE(conn) && Curl_conn_seems_dead(conn, m->data, NULL)) {
1265
    /* remove and disconnect. */
1266
246
    Curl_conn_terminate(m->data, conn, FALSE);
1267
246
    return FALSE;
1268
246
  }
1269
1270
  /* conn matches our needs. */
1271
9.51k
  m->found = conn;
1272
9.51k
  return TRUE;
1273
9.76k
}
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
13.3k
    Curl_attach_connection(match->data, match->found);
1283
13.3k
    return TRUE;
1284
13.3k
  }
1285
99.6k
  else if(match->seen_single_use_conn && !match->seen_multiplex_conn) {
1286
    /* We've 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
99.6k
  else if(match->seen_pending_conn && match->data->set.pipewait) {
1292
2.74k
    infof(match->data,
1293
2.74k
          "Found pending candidate for reuse and CURLOPT_PIPEWAIT is set");
1294
2.74k
    match->wait_pipe = TRUE;
1295
2.74k
  }
1296
99.6k
  match->force_reuse = FALSE;
1297
99.6k
  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.4k
                          (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.0k
     (data->state.authproxy.want & CURLAUTH_NTLM) &&
1333
919
     (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
148k
{
1355
148k
  struct connectdata *conn = calloc(1, sizeof(struct connectdata));
1356
148k
  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
148k
  conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD;     /* no file descriptor */
1362
148k
  conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
1363
148k
  conn->recv_idx = 0; /* default for receiving transfer data */
1364
148k
  conn->send_idx = 0; /* default for sending transfer data */
1365
148k
  conn->connection_id = -1;    /* no ID */
1366
148k
  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
148k
  connclose(conn, "Default to force-close");
1372
1373
  /* Store creation time to help future close decision making */
1374
148k
  conn->created = curlx_now();
1375
1376
  /* Store current time to give a baseline to keepalive connection times. */
1377
148k
  conn->keepalive = conn->created;
1378
1379
148k
#ifndef CURL_DISABLE_PROXY
1380
148k
  conn->http_proxy.proxytype = data->set.proxytype;
1381
148k
  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
148k
  conn->bits.proxy = (data->set.str[STRING_PROXY] &&
1386
19.7k
                      *data->set.str[STRING_PROXY]);
1387
148k
  conn->bits.httpproxy = (conn->bits.proxy &&
1388
19.4k
                          (conn->http_proxy.proxytype == CURLPROXY_HTTP ||
1389
8.19k
                           conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0 ||
1390
8.13k
                           IS_HTTPS_PROXY(conn->http_proxy.proxytype)));
1391
148k
  conn->bits.socksproxy = (conn->bits.proxy && !conn->bits.httpproxy);
1392
1393
148k
  if(data->set.str[STRING_PRE_PROXY] && *data->set.str[STRING_PRE_PROXY]) {
1394
26.2k
    conn->bits.proxy = TRUE;
1395
26.2k
    conn->bits.socksproxy = TRUE;
1396
26.2k
  }
1397
1398
148k
  conn->bits.proxy_user_passwd = !!data->state.aptr.proxyuser;
1399
148k
  conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
1400
148k
#endif /* CURL_DISABLE_PROXY */
1401
1402
148k
#ifndef CURL_DISABLE_FTP
1403
148k
  conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
1404
148k
  conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
1405
148k
#endif
1406
148k
  conn->ip_version = data->set.ipver;
1407
148k
  conn->connect_only = data->set.connect_only;
1408
148k
  conn->transport_wanted = TRNSPRT_TCP; /* most of them are TCP streams */
1409
1410
  /* Initialize the attached xfers bitset */
1411
148k
  Curl_uint_spbset_init(&conn->xfers_attached);
1412
1413
  /* Store the local bind parameters that will be used for this connection */
1414
148k
  if(data->set.str[STRING_DEVICE]) {
1415
1.01k
    conn->localdev = strdup(data->set.str[STRING_DEVICE]);
1416
1.01k
    if(!conn->localdev)
1417
0
      goto error;
1418
1.01k
  }
1419
148k
#ifndef CURL_DISABLE_BINDLOCAL
1420
148k
  conn->localportrange = data->set.localportrange;
1421
148k
  conn->localport = data->set.localport;
1422
148k
#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
148k
  conn->fclosesocket = data->set.fclosesocket;
1427
148k
  conn->closesocket_client = data->set.closesocket_client;
1428
148k
  conn->lastused = conn->created;
1429
#ifdef HAVE_GSSAPI
1430
  conn->gssapi_delegation = data->set.gssapi_delegation;
1431
#endif
1432
148k
  return conn;
1433
0
error:
1434
1435
0
  free(conn->localdev);
1436
0
  free(conn);
1437
0
  return NULL;
1438
148k
}
1439
1440
const struct Curl_handler *Curl_get_scheme_handler(const char *scheme)
1441
597k
{
1442
597k
  return Curl_getn_scheme_handler(scheme, strlen(scheme));
1443
597k
}
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
935k
{
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
935k
  static const struct Curl_handler * const protocols[67] = {
1460
935k
#ifndef CURL_DISABLE_FILE
1461
935k
    &Curl_handler_file,
1462
#else
1463
    NULL,
1464
#endif
1465
935k
    NULL, NULL,
1466
935k
#if defined(USE_SSL) && !defined(CURL_DISABLE_GOPHER)
1467
935k
    &Curl_handler_gophers,
1468
#else
1469
    NULL,
1470
#endif
1471
935k
    NULL,
1472
#ifdef USE_LIBRTMP
1473
    &Curl_handler_rtmpe,
1474
#else
1475
935k
    NULL,
1476
935k
#endif
1477
935k
#ifndef CURL_DISABLE_SMTP
1478
935k
    &Curl_handler_smtp,
1479
#else
1480
    NULL,
1481
#endif
1482
#ifdef USE_SSH
1483
    &Curl_handler_sftp,
1484
#else
1485
935k
    NULL,
1486
935k
#endif
1487
935k
#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \
1488
935k
  (SIZEOF_CURL_OFF_T > 4)
1489
935k
    &Curl_handler_smb,
1490
#else
1491
    NULL,
1492
#endif
1493
935k
#if defined(USE_SSL) && !defined(CURL_DISABLE_SMTP)
1494
935k
    &Curl_handler_smtps,
1495
#else
1496
    NULL,
1497
#endif
1498
935k
#ifndef CURL_DISABLE_TELNET
1499
935k
    &Curl_handler_telnet,
1500
#else
1501
    NULL,
1502
#endif
1503
935k
#ifndef CURL_DISABLE_GOPHER
1504
935k
    &Curl_handler_gopher,
1505
#else
1506
    NULL,
1507
#endif
1508
935k
#ifndef CURL_DISABLE_TFTP
1509
935k
    &Curl_handler_tftp,
1510
#else
1511
    NULL,
1512
#endif
1513
935k
    NULL, NULL, NULL,
1514
935k
#if defined(USE_SSL) && !defined(CURL_DISABLE_FTP)
1515
935k
    &Curl_handler_ftps,
1516
#else
1517
    NULL,
1518
#endif
1519
935k
#ifndef CURL_DISABLE_HTTP
1520
935k
    &Curl_handler_http,
1521
#else
1522
    NULL,
1523
#endif
1524
935k
#ifndef CURL_DISABLE_IMAP
1525
935k
    &Curl_handler_imap,
1526
#else
1527
    NULL,
1528
#endif
1529
#ifdef USE_LIBRTMP
1530
    &Curl_handler_rtmps,
1531
#else
1532
935k
    NULL,
1533
935k
#endif
1534
#ifdef USE_LIBRTMP
1535
    &Curl_handler_rtmpt,
1536
#else
1537
935k
    NULL,
1538
935k
#endif
1539
935k
    NULL, NULL, NULL,
1540
935k
#if !defined(CURL_DISABLE_LDAP) && \
1541
935k
  !defined(CURL_DISABLE_LDAPS) && \
1542
935k
  ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \
1543
935k
   (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL)))
1544
935k
    &Curl_handler_ldaps,
1545
#else
1546
    NULL,
1547
#endif
1548
935k
#if !defined(CURL_DISABLE_WEBSOCKETS) &&                \
1549
935k
  defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
1550
935k
    &Curl_handler_wss,
1551
#else
1552
    NULL,
1553
#endif
1554
935k
#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
1555
935k
    &Curl_handler_https,
1556
#else
1557
    NULL,
1558
#endif
1559
935k
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1560
935k
#ifndef CURL_DISABLE_RTSP
1561
935k
    &Curl_handler_rtsp,
1562
#else
1563
    NULL,
1564
#endif
1565
935k
#if defined(USE_SSL) && !defined(CURL_DISABLE_SMB) && \
1566
935k
  defined(USE_CURL_NTLM_CORE) && (SIZEOF_CURL_OFF_T > 4)
1567
935k
    &Curl_handler_smbs,
1568
#else
1569
    NULL,
1570
#endif
1571
#if defined(USE_SSH)
1572
    &Curl_handler_scp,
1573
#else
1574
935k
    NULL,
1575
935k
#endif
1576
935k
    NULL, NULL, NULL,
1577
935k
#ifndef CURL_DISABLE_POP3
1578
935k
    &Curl_handler_pop3,
1579
#else
1580
    NULL,
1581
#endif
1582
935k
    NULL, NULL,
1583
#ifdef USE_LIBRTMP
1584
    &Curl_handler_rtmp,
1585
#else
1586
935k
    NULL,
1587
935k
#endif
1588
935k
    NULL, NULL, NULL,
1589
#ifdef USE_LIBRTMP
1590
    &Curl_handler_rtmpte,
1591
#else
1592
935k
    NULL,
1593
935k
#endif
1594
935k
    NULL, NULL, NULL,
1595
935k
#ifndef CURL_DISABLE_DICT
1596
935k
    &Curl_handler_dict,
1597
#else
1598
    NULL,
1599
#endif
1600
935k
    NULL, NULL, NULL,
1601
935k
#ifndef CURL_DISABLE_MQTT
1602
935k
    &Curl_handler_mqtt,
1603
#else
1604
    NULL,
1605
#endif
1606
935k
#if defined(USE_SSL) && !defined(CURL_DISABLE_POP3)
1607
935k
    &Curl_handler_pop3s,
1608
#else
1609
    NULL,
1610
#endif
1611
935k
#if defined(USE_SSL) && !defined(CURL_DISABLE_IMAP)
1612
935k
    &Curl_handler_imaps,
1613
#else
1614
    NULL,
1615
#endif
1616
935k
    NULL,
1617
935k
#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
1618
935k
    &Curl_handler_ws,
1619
#else
1620
    NULL,
1621
#endif
1622
935k
    NULL,
1623
#ifdef USE_LIBRTMP
1624
    &Curl_handler_rtmpts,
1625
#else
1626
935k
    NULL,
1627
935k
#endif
1628
935k
#ifndef CURL_DISABLE_LDAP
1629
935k
    &Curl_handler_ldap,
1630
#else
1631
    NULL,
1632
#endif
1633
935k
    NULL, NULL,
1634
935k
#ifndef CURL_DISABLE_FTP
1635
935k
    &Curl_handler_ftp,
1636
#else
1637
    NULL,
1638
#endif
1639
935k
  };
1640
1641
935k
  if(len && (len <= 7)) {
1642
935k
    const char *s = scheme;
1643
935k
    size_t l = len;
1644
935k
    const struct Curl_handler *h;
1645
935k
    unsigned int c = 978;
1646
4.78M
    while(l) {
1647
3.85M
      c <<= 5;
1648
3.85M
      c += (unsigned int)Curl_raw_tolower(*s);
1649
3.85M
      s++;
1650
3.85M
      l--;
1651
3.85M
    }
1652
1653
935k
    h = protocols[c % 67];
1654
935k
    if(h && curl_strnequal(scheme, h->scheme, len) && !h->scheme[len])
1655
928k
      return h;
1656
935k
  }
1657
6.93k
  return NULL;
1658
935k
}
1659
1660
static CURLcode findprotocol(struct Curl_easy *data,
1661
                             struct connectdata *conn,
1662
                             const char *protostr)
1663
136k
{
1664
136k
  const struct Curl_handler *p = Curl_get_scheme_handler(protostr);
1665
1666
136k
  if(p && /* Protocol found in table. Check if allowed */
1667
136k
     (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
129k
    if(data->state.this_is_a_follow &&
1672
10.8k
       !(data->set.redir_protocols & p->protocol))
1673
      /* nope, get out */
1674
70
      ;
1675
129k
    else {
1676
      /* Perform setup complement if some. */
1677
129k
      conn->handler = conn->given = p;
1678
      /* 'port' and 'remote_port' are set in setup_connection_internals() */
1679
129k
      return CURLE_OK;
1680
129k
    }
1681
129k
  }
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.14k
  failf(data, "Protocol \"%s\" %s%s", protostr,
1687
7.14k
        p ? "disabled" : "not supported",
1688
7.14k
        data->state.this_is_a_follow ? " (in redirect)":"");
1689
1690
7.14k
  return CURLE_UNSUPPORTED_PROTOCOL;
1691
136k
}
1692
1693
1694
CURLcode Curl_uc_to_curlcode(CURLUcode uc)
1695
9.85k
{
1696
9.85k
  switch(uc) {
1697
9.83k
  default:
1698
9.83k
    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.85k
  }
1706
9.85k
}
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
943
{
1717
943
  char *zoneid;
1718
943
  CURLUcode uc = curl_url_get(uh, CURLUPART_ZONEID, &zoneid, 0);
1719
#ifdef CURL_DISABLE_VERBOSE_STRINGS
1720
  (void)data;
1721
#endif
1722
1723
943
  if(!uc && zoneid) {
1724
695
    const char *p = zoneid;
1725
695
    curl_off_t scope;
1726
695
    if(!curlx_str_number(&p, &scope, UINT_MAX))
1727
      /* A plain number, use it directly as a scope id. */
1728
273
      conn->scope_id = (unsigned int)scope;
1729
422
#ifdef HAVE_IF_NAMETOINDEX
1730
422
    else {
1731
#elif defined(_WIN32)
1732
    else if(Curl_if_nametoindex) {
1733
#endif
1734
1735
422
#if defined(HAVE_IF_NAMETOINDEX) || defined(_WIN32)
1736
      /* Zone identifier is not numeric */
1737
422
      unsigned int scopeidx = 0;
1738
422
#ifdef HAVE_IF_NAMETOINDEX
1739
422
      scopeidx = if_nametoindex(zoneid);
1740
#else
1741
      scopeidx = Curl_if_nametoindex(zoneid);
1742
#endif
1743
422
      if(!scopeidx) {
1744
399
#ifndef CURL_DISABLE_VERBOSE_STRINGS
1745
399
        char buffer[STRERROR_LEN];
1746
399
        infof(data, "Invalid zoneid: %s; %s", zoneid,
1747
399
              curlx_strerror(errno, buffer, sizeof(buffer)));
1748
399
#endif
1749
399
      }
1750
23
      else
1751
23
        conn->scope_id = scopeidx;
1752
422
    }
1753
695
#endif /* HAVE_IF_NAMETOINDEX || _WIN32 */
1754
1755
695
    free(zoneid);
1756
695
  }
1757
943
}
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
148k
{
1768
148k
  CURLcode result;
1769
148k
  CURLU *uh;
1770
148k
  CURLUcode uc;
1771
148k
  char *hostname;
1772
148k
  bool use_set_uh = (data->set.uh && !data->state.this_is_a_follow);
1773
1774
148k
  up_free(data); /* cleanup previous leftovers first */
1775
1776
  /* parse the URL */
1777
148k
  if(use_set_uh) {
1778
0
    uh = data->state.uh = curl_url_dup(data->set.uh);
1779
0
  }
1780
148k
  else {
1781
148k
    uh = data->state.uh = curl_url();
1782
148k
  }
1783
1784
148k
  if(!uh)
1785
0
    return CURLE_OUT_OF_MEMORY;
1786
1787
148k
  if(data->set.str[STRING_DEFAULT_PROTOCOL] &&
1788
15.0k
     !Curl_is_absolute_url(data->state.url, NULL, 0, TRUE)) {
1789
8.66k
    char *url = curl_maprintf("%s://%s",
1790
8.66k
                              data->set.str[STRING_DEFAULT_PROTOCOL],
1791
8.66k
                              data->state.url);
1792
8.66k
    if(!url)
1793
0
      return CURLE_OUT_OF_MEMORY;
1794
8.66k
    if(data->state.url_alloc)
1795
0
      free(data->state.url);
1796
8.66k
    data->state.url = url;
1797
8.66k
    data->state.url_alloc = TRUE;
1798
8.66k
  }
1799
1800
148k
  if(!use_set_uh) {
1801
148k
    char *newurl;
1802
148k
    uc = curl_url_set(uh, CURLUPART_URL, data->state.url, (unsigned int)
1803
148k
                      (CURLU_GUESS_SCHEME |
1804
148k
                       CURLU_NON_SUPPORT_SCHEME |
1805
148k
                       (data->set.disallow_username_in_url ?
1806
148k
                        CURLU_DISALLOW_USER : 0) |
1807
148k
                       (data->set.path_as_is ? CURLU_PATH_AS_IS : 0)));
1808
148k
    if(uc) {
1809
9.83k
      failf(data, "URL rejected: %s", curl_url_strerror(uc));
1810
9.83k
      return Curl_uc_to_curlcode(uc);
1811
9.83k
    }
1812
1813
    /* after it was parsed, get the generated normalized version */
1814
138k
    uc = curl_url_get(uh, CURLUPART_URL, &newurl, 0);
1815
138k
    if(uc)
1816
0
      return Curl_uc_to_curlcode(uc);
1817
138k
    if(data->state.url_alloc)
1818
24.6k
      free(data->state.url);
1819
138k
    data->state.url = newurl;
1820
138k
    data->state.url_alloc = TRUE;
1821
138k
  }
1822
1823
138k
  uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0);
1824
138k
  if(uc)
1825
0
    return Curl_uc_to_curlcode(uc);
1826
1827
138k
  uc = curl_url_get(uh, CURLUPART_HOST, &data->state.up.hostname, 0);
1828
138k
  if(uc) {
1829
2.25k
    if(!curl_strequal("file", data->state.up.scheme))
1830
0
      return CURLE_OUT_OF_MEMORY;
1831
2.25k
  }
1832
136k
  else if(strlen(data->state.up.hostname) > MAX_URL_LEN) {
1833
13
    failf(data, "Too long hostname (maximum is %d)", MAX_URL_LEN);
1834
13
    return CURLE_URL_MALFORMAT;
1835
13
  }
1836
138k
  hostname = data->state.up.hostname;
1837
1838
138k
  if(hostname && hostname[0] == '[') {
1839
    /* This looks like an IPv6 address literal. See if there is an address
1840
       scope. */
1841
641
    size_t hlen;
1842
641
    conn->bits.ipv6_ip = TRUE;
1843
    /* cut off the brackets! */
1844
641
    hostname++;
1845
641
    hlen = strlen(hostname);
1846
641
    hostname[hlen - 1] = 0;
1847
1848
641
    zonefrom_url(uh, data, conn);
1849
641
  }
1850
1851
  /* make sure the connect struct gets its own copy of the hostname */
1852
138k
  conn->host.rawalloc = strdup(hostname ? hostname : "");
1853
138k
  if(!conn->host.rawalloc)
1854
0
    return CURLE_OUT_OF_MEMORY;
1855
138k
  conn->host.name = conn->host.rawalloc;
1856
1857
  /*************************************************************
1858
   * IDN-convert the hostnames
1859
   *************************************************************/
1860
138k
  result = Curl_idnconvert_hostname(&conn->host);
1861
138k
  if(result)
1862
1.77k
    return result;
1863
1864
136k
#ifndef CURL_DISABLE_HSTS
1865
  /* HSTS upgrade */
1866
136k
  if(data->hsts && curl_strequal("http", data->state.up.scheme)) {
1867
    /* This MUST use the IDN decoded name */
1868
34.7k
    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
34.7k
  }
1891
136k
#endif
1892
1893
136k
  result = findprotocol(data, conn, data->state.up.scheme);
1894
136k
  if(result)
1895
7.14k
    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
129k
  if(!data->state.aptr.passwd || (data->state.creds_from != CREDS_OPTION)) {
1902
125k
    uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0);
1903
125k
    if(!uc) {
1904
4.66k
      char *decoded;
1905
4.66k
      result = Curl_urldecode(data->state.up.password, 0, &decoded, NULL,
1906
4.66k
                              conn->handler->flags&PROTOPT_USERPWDCTRL ?
1907
3.58k
                              REJECT_ZERO : REJECT_CTRL);
1908
4.66k
      if(result)
1909
39
        return result;
1910
4.62k
      conn->passwd = decoded;
1911
4.62k
      result = Curl_setstropt(&data->state.aptr.passwd, decoded);
1912
4.62k
      if(result)
1913
0
        return result;
1914
4.62k
      data->state.creds_from = CREDS_URL;
1915
4.62k
    }
1916
120k
    else if(uc != CURLUE_NO_PASSWORD)
1917
0
      return Curl_uc_to_curlcode(uc);
1918
125k
  }
1919
1920
129k
  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
124k
    uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user, 0);
1925
124k
    if(!uc) {
1926
19.7k
      char *decoded;
1927
19.7k
      result = Curl_urldecode(data->state.up.user, 0, &decoded, NULL,
1928
19.7k
                              conn->handler->flags&PROTOPT_USERPWDCTRL ?
1929
12.7k
                              REJECT_ZERO : REJECT_CTRL);
1930
19.7k
      if(result)
1931
69
        return result;
1932
19.6k
      conn->user = decoded;
1933
19.6k
      result = Curl_setstropt(&data->state.aptr.user, decoded);
1934
19.6k
      data->state.creds_from = CREDS_URL;
1935
19.6k
    }
1936
105k
    else if(uc != CURLUE_NO_USER)
1937
0
      return Curl_uc_to_curlcode(uc);
1938
124k
    if(result)
1939
0
      return result;
1940
124k
  }
1941
1942
129k
  uc = curl_url_get(uh, CURLUPART_OPTIONS, &data->state.up.options,
1943
129k
                    CURLU_URLDECODE);
1944
129k
  if(!uc) {
1945
99
    conn->options = strdup(data->state.up.options);
1946
99
    if(!conn->options)
1947
0
      return CURLE_OUT_OF_MEMORY;
1948
99
  }
1949
129k
  else if(uc != CURLUE_NO_OPTIONS)
1950
3
    return Curl_uc_to_curlcode(uc);
1951
1952
129k
  uc = curl_url_get(uh, CURLUPART_PATH, &data->state.up.path,
1953
129k
                    CURLU_URLENCODE);
1954
129k
  if(uc)
1955
0
    return Curl_uc_to_curlcode(uc);
1956
1957
129k
  uc = curl_url_get(uh, CURLUPART_PORT, &data->state.up.port,
1958
129k
                    CURLU_DEFAULT_PORT);
1959
129k
  if(uc) {
1960
0
    if(!curl_strequal("file", data->state.up.scheme))
1961
0
      return CURLE_OUT_OF_MEMORY;
1962
0
  }
1963
129k
  else {
1964
129k
    curl_off_t port;
1965
129k
    bool valid = TRUE;
1966
129k
    if(data->set.use_port && data->state.allow_port)
1967
728
      port = data->set.use_port;
1968
128k
    else {
1969
128k
      const char *p = data->state.up.port;
1970
128k
      if(curlx_str_number(&p, &port, 0xffff))
1971
0
        valid = FALSE;
1972
128k
    }
1973
129k
    if(valid)
1974
129k
      conn->remote_port = (unsigned short)port;
1975
129k
  }
1976
1977
129k
  (void)curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query, 0);
1978
1979
129k
#ifdef USE_IPV6
1980
129k
  if(data->set.scope_id)
1981
    /* Override any scope that was set above.  */
1982
1.88k
    conn->scope_id = data->set.scope_id;
1983
129k
#endif
1984
1985
129k
  return CURLE_OK;
1986
129k
}
1987
1988
1989
/*
1990
 * If we are doing a resumed transfer, we need to setup our stuff
1991
 * properly.
1992
 */
1993
static CURLcode setup_range(struct Curl_easy *data)
1994
125k
{
1995
125k
  struct UrlState *s = &data->state;
1996
125k
  s->resume_from = data->set.set_resume_from;
1997
125k
  if(s->resume_from || data->set.str[STRING_SET_RANGE]) {
1998
5.67k
    if(s->rangestringalloc)
1999
2.31k
      free(s->range);
2000
2001
5.67k
    if(s->resume_from)
2002
2.99k
      s->range = curl_maprintf("%" FMT_OFF_T "-", s->resume_from);
2003
2.67k
    else
2004
2.67k
      s->range = strdup(data->set.str[STRING_SET_RANGE]);
2005
2006
5.67k
    if(!s->range)
2007
0
      return CURLE_OUT_OF_MEMORY;
2008
2009
5.67k
    s->rangestringalloc = TRUE;
2010
2011
    /* tell ourselves to fetch this range */
2012
5.67k
    s->use_range = TRUE;        /* enable range download */
2013
5.67k
  }
2014
120k
  else
2015
120k
    s->use_range = FALSE; /* disable range download */
2016
2017
125k
  return CURLE_OK;
2018
125k
}
2019
2020
2021
/*
2022
 * setup_connection_internals() -
2023
 *
2024
 * Setup connection internals specific to the requested protocol in the
2025
 * Curl_easy. This is inited and setup before the connection is made but
2026
 * is about the particular protocol that is to be used.
2027
 *
2028
 * This MUST get called after proxy magic has been figured out.
2029
 */
2030
static CURLcode setup_connection_internals(struct Curl_easy *data,
2031
                                           struct connectdata *conn)
2032
129k
{
2033
129k
  const char *hostname;
2034
129k
  int port;
2035
129k
  CURLcode result;
2036
2037
129k
  if(conn->handler->setup_connection) {
2038
123k
    result = conn->handler->setup_connection(data, conn);
2039
123k
    if(result)
2040
419
      return result;
2041
123k
  }
2042
2043
  /* Now create the destination name */
2044
128k
#ifndef CURL_DISABLE_PROXY
2045
128k
  if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
2046
1.22k
    hostname = conn->http_proxy.host.name;
2047
1.22k
    port = conn->http_proxy.port;
2048
1.22k
  }
2049
127k
  else
2050
127k
#endif
2051
127k
  {
2052
127k
    port = conn->remote_port;
2053
127k
    if(conn->bits.conn_to_host)
2054
120k
      hostname = conn->conn_to_host.name;
2055
7.17k
    else
2056
7.17k
      hostname = conn->host.name;
2057
127k
  }
2058
2059
128k
#ifdef USE_IPV6
2060
128k
  conn->destination = curl_maprintf("%u/%d/%s", conn->scope_id, port,
2061
128k
                                    hostname);
2062
#else
2063
  conn->destination = curl_maprintf("%d/%s", port, hostname);
2064
#endif
2065
128k
  if(!conn->destination)
2066
0
    return CURLE_OUT_OF_MEMORY;
2067
2068
128k
  Curl_strntolower(conn->destination, conn->destination,
2069
128k
                   strlen(conn->destination));
2070
2071
128k
  return CURLE_OK;
2072
128k
}
2073
2074
2075
#ifndef CURL_DISABLE_PROXY
2076
2077
#ifndef CURL_DISABLE_HTTP
2078
/****************************************************************
2079
* Detect what (if any) proxy to use. Remember that this selects a host
2080
* name and is not limited to HTTP proxies only.
2081
* The returned pointer must be freed by the caller (unless NULL)
2082
****************************************************************/
2083
static char *detect_proxy(struct Curl_easy *data,
2084
                          struct connectdata *conn)
2085
84.3k
{
2086
84.3k
  char *proxy = NULL;
2087
2088
  /* If proxy was not specified, we check for default proxy environment
2089
   * variables, to enable i.e Lynx compliance:
2090
   *
2091
   * http_proxy=http://some.server.dom:port/
2092
   * https_proxy=http://some.server.dom:port/
2093
   * ftp_proxy=http://some.server.dom:port/
2094
   * no_proxy=domain1.dom,host.domain2.dom
2095
   *   (a comma-separated list of hosts which should
2096
   *   not be proxied, or an asterisk to override
2097
   *   all proxy variables)
2098
   * all_proxy=http://some.server.dom:port/
2099
   *   (seems to exist for the CERN www lib. Probably
2100
   *   the first to check for.)
2101
   *
2102
   * For compatibility, the all-uppercase versions of these variables are
2103
   * checked if the lowercase versions do not exist.
2104
   */
2105
84.3k
  char proxy_env[20];
2106
84.3k
  const char *envp = proxy_env;
2107
#ifdef CURL_DISABLE_VERBOSE_STRINGS
2108
  (void)data;
2109
#endif
2110
2111
84.3k
  curl_msnprintf(proxy_env, sizeof(proxy_env), "%s_proxy",
2112
84.3k
                 conn->handler->scheme);
2113
2114
  /* read the protocol proxy: */
2115
84.3k
  proxy = curl_getenv(proxy_env);
2116
2117
  /*
2118
   * We do not try the uppercase version of HTTP_PROXY because of
2119
   * security reasons:
2120
   *
2121
   * When curl is used in a webserver application
2122
   * environment (cgi or php), this environment variable can
2123
   * be controlled by the web server user by setting the
2124
   * http header 'Proxy:' to some value.
2125
   *
2126
   * This can cause 'internal' http/ftp requests to be
2127
   * arbitrarily redirected by any external attacker.
2128
   */
2129
84.3k
  if(!proxy && !curl_strequal("http_proxy", proxy_env)) {
2130
    /* There was no lowercase variable, try the uppercase version: */
2131
60.3k
    Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env));
2132
60.3k
    proxy = curl_getenv(proxy_env);
2133
60.3k
  }
2134
2135
84.3k
  if(!proxy) {
2136
84.3k
#ifndef CURL_DISABLE_WEBSOCKETS
2137
    /* websocket proxy fallbacks */
2138
84.3k
    if(curl_strequal("ws_proxy", proxy_env)) {
2139
243
      proxy = curl_getenv("http_proxy");
2140
243
    }
2141
84.1k
    else if(curl_strequal("wss_proxy", proxy_env)) {
2142
2.23k
      proxy = curl_getenv("https_proxy");
2143
2.23k
      if(!proxy)
2144
2.23k
        proxy = curl_getenv("HTTPS_PROXY");
2145
2.23k
    }
2146
84.3k
    if(!proxy) {
2147
84.3k
#endif
2148
84.3k
      envp = "all_proxy";
2149
84.3k
      proxy = curl_getenv(envp); /* default proxy to use */
2150
84.3k
      if(!proxy) {
2151
84.3k
        envp = "ALL_PROXY";
2152
84.3k
        proxy = curl_getenv(envp);
2153
84.3k
      }
2154
84.3k
#ifndef CURL_DISABLE_WEBSOCKETS
2155
84.3k
    }
2156
84.3k
#endif
2157
84.3k
  }
2158
84.3k
  if(proxy)
2159
0
    infof(data, "Uses proxy env variable %s == '%s'", envp, proxy);
2160
2161
84.3k
  return proxy;
2162
84.3k
}
2163
#endif /* CURL_DISABLE_HTTP */
2164
2165
/*
2166
 * If this is supposed to use a proxy, we need to figure out the proxy
2167
 * hostname, so that we can reuse an existing connection
2168
 * that may exist registered to the same proxy host.
2169
 */
2170
static CURLcode parse_proxy(struct Curl_easy *data,
2171
                            struct connectdata *conn, char *proxy,
2172
                            long proxytype)
2173
45.0k
{
2174
45.0k
  char *portptr = NULL;
2175
45.0k
  int port = -1;
2176
45.0k
  char *proxyuser = NULL;
2177
45.0k
  char *proxypasswd = NULL;
2178
45.0k
  char *host = NULL;
2179
45.0k
  bool sockstype;
2180
45.0k
  CURLUcode uc;
2181
45.0k
  struct proxy_info *proxyinfo;
2182
45.0k
  CURLU *uhp = curl_url();
2183
45.0k
  CURLcode result = CURLE_OK;
2184
45.0k
  char *scheme = NULL;
2185
45.0k
#ifdef USE_UNIX_SOCKETS
2186
45.0k
  char *path = NULL;
2187
45.0k
  bool is_unix_proxy = FALSE;
2188
45.0k
#endif
2189
2190
45.0k
  if(!uhp) {
2191
0
    result = CURLE_OUT_OF_MEMORY;
2192
0
    goto error;
2193
0
  }
2194
2195
  /* When parsing the proxy, allowing non-supported schemes since we have
2196
     these made up ones for proxies. Guess scheme for URLs without it. */
2197
45.0k
  uc = curl_url_set(uhp, CURLUPART_URL, proxy,
2198
45.0k
                    CURLU_NON_SUPPORT_SCHEME|CURLU_GUESS_SCHEME);
2199
45.0k
  if(!uc) {
2200
    /* parsed okay as a URL */
2201
44.9k
    uc = curl_url_get(uhp, CURLUPART_SCHEME, &scheme, 0);
2202
44.9k
    if(uc) {
2203
0
      result = CURLE_OUT_OF_MEMORY;
2204
0
      goto error;
2205
0
    }
2206
2207
44.9k
    if(curl_strequal("https", scheme)) {
2208
1.03k
      if(proxytype != CURLPROXY_HTTPS2)
2209
1.03k
        proxytype = CURLPROXY_HTTPS;
2210
6
      else
2211
6
        proxytype = CURLPROXY_HTTPS2;
2212
1.03k
    }
2213
43.9k
    else if(curl_strequal("socks5h", scheme))
2214
0
      proxytype = CURLPROXY_SOCKS5_HOSTNAME;
2215
43.9k
    else if(curl_strequal("socks5", scheme))
2216
0
      proxytype = CURLPROXY_SOCKS5;
2217
43.9k
    else if(curl_strequal("socks4a", scheme))
2218
0
      proxytype = CURLPROXY_SOCKS4A;
2219
43.9k
    else if(curl_strequal("socks4", scheme) ||
2220
43.9k
            curl_strequal("socks", scheme))
2221
0
      proxytype = CURLPROXY_SOCKS4;
2222
43.9k
    else if(curl_strequal("http", scheme))
2223
43.9k
      ; /* leave it as HTTP or HTTP/1.0 */
2224
24
    else {
2225
      /* Any other xxx:// reject! */
2226
24
      failf(data, "Unsupported proxy scheme for \'%s\'", proxy);
2227
24
      result = CURLE_COULDNT_CONNECT;
2228
24
      goto error;
2229
24
    }
2230
44.9k
  }
2231
107
  else {
2232
107
    failf(data, "Unsupported proxy syntax in \'%s\': %s", proxy,
2233
107
          curl_url_strerror(uc));
2234
107
    result = CURLE_COULDNT_RESOLVE_PROXY;
2235
107
    goto error;
2236
107
  }
2237
2238
44.9k
#ifdef USE_SSL
2239
44.9k
  if(!Curl_ssl_supports(data, SSLSUPP_HTTPS_PROXY))
2240
0
#endif
2241
0
    if(IS_HTTPS_PROXY(proxytype)) {
2242
0
      failf(data, "Unsupported proxy \'%s\', libcurl is built without the "
2243
0
            "HTTPS-proxy support.", proxy);
2244
0
      result = CURLE_NOT_BUILT_IN;
2245
0
      goto error;
2246
0
    }
2247
2248
44.9k
  sockstype =
2249
44.9k
    proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
2250
44.5k
    proxytype == CURLPROXY_SOCKS5 ||
2251
44.1k
    proxytype == CURLPROXY_SOCKS4A ||
2252
43.8k
    proxytype == CURLPROXY_SOCKS4;
2253
2254
44.9k
  proxyinfo = sockstype ? &conn->socks_proxy : &conn->http_proxy;
2255
44.9k
  proxyinfo->proxytype = (unsigned char)proxytype;
2256
2257
  /* Is there a username and password given in this proxy url? */
2258
44.9k
  uc = curl_url_get(uhp, CURLUPART_USER, &proxyuser, CURLU_URLDECODE);
2259
44.9k
  if(uc && (uc != CURLUE_NO_USER))
2260
90
    goto error;
2261
44.8k
  uc = curl_url_get(uhp, CURLUPART_PASSWORD, &proxypasswd, CURLU_URLDECODE);
2262
44.8k
  if(uc && (uc != CURLUE_NO_PASSWORD))
2263
57
    goto error;
2264
2265
44.8k
  if(proxyuser || proxypasswd) {
2266
18.3k
    free(proxyinfo->user);
2267
18.3k
    proxyinfo->user = proxyuser;
2268
18.3k
    result = Curl_setstropt(&data->state.aptr.proxyuser, proxyuser);
2269
18.3k
    proxyuser = NULL;
2270
18.3k
    if(result)
2271
0
      goto error;
2272
18.3k
    Curl_safefree(proxyinfo->passwd);
2273
18.3k
    if(!proxypasswd) {
2274
14.8k
      proxypasswd = strdup("");
2275
14.8k
      if(!proxypasswd) {
2276
0
        result = CURLE_OUT_OF_MEMORY;
2277
0
        goto error;
2278
0
      }
2279
14.8k
    }
2280
18.3k
    proxyinfo->passwd = proxypasswd;
2281
18.3k
    result = Curl_setstropt(&data->state.aptr.proxypasswd, proxypasswd);
2282
18.3k
    proxypasswd = NULL;
2283
18.3k
    if(result)
2284
0
      goto error;
2285
18.3k
    conn->bits.proxy_user_passwd = TRUE; /* enable it */
2286
18.3k
  }
2287
2288
44.8k
  (void)curl_url_get(uhp, CURLUPART_PORT, &portptr, 0);
2289
2290
44.8k
  if(portptr) {
2291
1.19k
    curl_off_t num;
2292
1.19k
    const char *p = portptr;
2293
1.19k
    if(!curlx_str_number(&p, &num, 0xffff))
2294
1.19k
      port = (int)num;
2295
1.19k
    free(portptr);
2296
1.19k
  }
2297
43.6k
  else {
2298
43.6k
    if(data->set.proxyport)
2299
      /* None given in the proxy string, then get the default one if it is
2300
         given */
2301
312
      port = (int)data->set.proxyport;
2302
43.2k
    else {
2303
43.2k
      if(IS_HTTPS_PROXY(proxytype))
2304
12.4k
        port = CURL_DEFAULT_HTTPS_PROXY_PORT;
2305
30.8k
      else
2306
30.8k
        port = CURL_DEFAULT_PROXY_PORT;
2307
43.2k
    }
2308
43.6k
  }
2309
44.8k
  if(port >= 0)
2310
44.8k
    proxyinfo->port = port;
2311
2312
  /* now, clone the proxy hostname */
2313
44.8k
  uc = curl_url_get(uhp, CURLUPART_HOST, &host, CURLU_URLDECODE);
2314
44.8k
  if(uc) {
2315
0
    result = CURLE_OUT_OF_MEMORY;
2316
0
    goto error;
2317
0
  }
2318
44.8k
#ifdef USE_UNIX_SOCKETS
2319
44.8k
  if(sockstype && curl_strequal(UNIX_SOCKET_PREFIX, host)) {
2320
51
    uc = curl_url_get(uhp, CURLUPART_PATH, &path, CURLU_URLDECODE);
2321
51
    if(uc) {
2322
6
      result = CURLE_OUT_OF_MEMORY;
2323
6
      goto error;
2324
6
    }
2325
    /* path will be "/", if no path was found */
2326
45
    if(strcmp("/", path)) {
2327
19
      is_unix_proxy = TRUE;
2328
19
      free(host);
2329
19
      host = curl_maprintf(UNIX_SOCKET_PREFIX"%s", path);
2330
19
      if(!host) {
2331
0
        result = CURLE_OUT_OF_MEMORY;
2332
0
        goto error;
2333
0
      }
2334
19
      free(proxyinfo->host.rawalloc);
2335
19
      proxyinfo->host.rawalloc = host;
2336
19
      proxyinfo->host.name = host;
2337
19
      host = NULL;
2338
19
    }
2339
45
  }
2340
2341
44.7k
  if(!is_unix_proxy) {
2342
44.7k
#endif
2343
44.7k
    free(proxyinfo->host.rawalloc);
2344
44.7k
    proxyinfo->host.rawalloc = host;
2345
44.7k
    if(host[0] == '[') {
2346
      /* this is a numerical IPv6, strip off the brackets */
2347
302
      size_t len = strlen(host);
2348
302
      host[len-1] = 0; /* clear the trailing bracket */
2349
302
      host++;
2350
302
      zonefrom_url(uhp, data, conn);
2351
302
    }
2352
44.7k
    proxyinfo->host.name = host;
2353
44.7k
    host = NULL;
2354
44.7k
#ifdef USE_UNIX_SOCKETS
2355
44.7k
  }
2356
44.7k
#endif
2357
2358
45.0k
error:
2359
45.0k
  free(proxyuser);
2360
45.0k
  free(proxypasswd);
2361
45.0k
  free(host);
2362
45.0k
  free(scheme);
2363
45.0k
#ifdef USE_UNIX_SOCKETS
2364
45.0k
  free(path);
2365
45.0k
#endif
2366
45.0k
  curl_url_cleanup(uhp);
2367
45.0k
  return result;
2368
44.7k
}
2369
2370
/*
2371
 * Extract the user and password from the authentication string
2372
 */
2373
static CURLcode parse_proxy_auth(struct Curl_easy *data,
2374
                                 struct connectdata *conn)
2375
5.80k
{
2376
5.80k
  const char *proxyuser = data->state.aptr.proxyuser ?
2377
5.80k
    data->state.aptr.proxyuser : "";
2378
5.80k
  const char *proxypasswd = data->state.aptr.proxypasswd ?
2379
4.31k
    data->state.aptr.proxypasswd : "";
2380
5.80k
  CURLcode result = CURLE_OUT_OF_MEMORY;
2381
2382
5.80k
  conn->http_proxy.user = strdup(proxyuser);
2383
5.80k
  if(conn->http_proxy.user) {
2384
5.80k
    conn->http_proxy.passwd = strdup(proxypasswd);
2385
5.80k
    if(conn->http_proxy.passwd)
2386
5.80k
      result = CURLE_OK;
2387
0
    else
2388
0
      Curl_safefree(conn->http_proxy.user);
2389
5.80k
  }
2390
5.80k
  return result;
2391
5.80k
}
2392
2393
/* create_conn helper to parse and init proxy values. to be called after Unix
2394
   socket init but before any proxy vars are evaluated. */
2395
static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
2396
                                              struct connectdata *conn)
2397
129k
{
2398
129k
  char *proxy = NULL;
2399
129k
  char *socksproxy = NULL;
2400
129k
  char *no_proxy = NULL;
2401
129k
  CURLcode result = CURLE_OK;
2402
2403
  /*************************************************************
2404
   * Extract the user and password from the authentication string
2405
   *************************************************************/
2406
129k
  if(conn->bits.proxy_user_passwd) {
2407
5.80k
    result = parse_proxy_auth(data, conn);
2408
5.80k
    if(result)
2409
0
      goto out;
2410
5.80k
  }
2411
2412
  /*************************************************************
2413
   * Detect what (if any) proxy to use
2414
   *************************************************************/
2415
129k
  if(data->set.str[STRING_PROXY]) {
2416
19.6k
    proxy = strdup(data->set.str[STRING_PROXY]);
2417
    /* if global proxy is set, this is it */
2418
19.6k
    if(!proxy) {
2419
0
      failf(data, "memory shortage");
2420
0
      result = CURLE_OUT_OF_MEMORY;
2421
0
      goto out;
2422
0
    }
2423
19.6k
  }
2424
2425
129k
  if(data->set.str[STRING_PRE_PROXY]) {
2426
26.5k
    socksproxy = strdup(data->set.str[STRING_PRE_PROXY]);
2427
    /* if global socks proxy is set, this is it */
2428
26.5k
    if(!socksproxy) {
2429
0
      failf(data, "memory shortage");
2430
0
      result = CURLE_OUT_OF_MEMORY;
2431
0
      goto out;
2432
0
    }
2433
26.5k
  }
2434
2435
129k
  if(!data->set.str[STRING_NOPROXY]) {
2436
125k
    const char *p = "no_proxy";
2437
125k
    no_proxy = curl_getenv(p);
2438
125k
    if(!no_proxy) {
2439
125k
      p = "NO_PROXY";
2440
125k
      no_proxy = curl_getenv(p);
2441
125k
    }
2442
125k
    if(no_proxy) {
2443
0
      infof(data, "Uses proxy env variable %s == '%s'", p, no_proxy);
2444
0
    }
2445
125k
  }
2446
2447
129k
  if(Curl_check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY] ?
2448
125k
                        data->set.str[STRING_NOPROXY] : no_proxy)) {
2449
191
    Curl_safefree(proxy);
2450
191
    Curl_safefree(socksproxy);
2451
191
  }
2452
129k
#ifndef CURL_DISABLE_HTTP
2453
129k
  else if(!proxy && !socksproxy)
2454
    /* if the host is not in the noproxy list, detect proxy. */
2455
84.3k
    proxy = detect_proxy(data, conn);
2456
129k
#endif /* CURL_DISABLE_HTTP */
2457
129k
  Curl_safefree(no_proxy);
2458
2459
129k
#ifdef USE_UNIX_SOCKETS
2460
  /* For the time being do not mix proxy and Unix domain sockets. See #1274 */
2461
129k
  if(proxy && conn->unix_domain_socket) {
2462
419
    free(proxy);
2463
419
    proxy = NULL;
2464
419
  }
2465
129k
#endif
2466
2467
129k
  if(proxy && (!*proxy || (conn->handler->flags & PROTOPT_NONETWORK))) {
2468
327
    free(proxy);  /* Do not bother with an empty proxy string or if the
2469
                     protocol does not work with network */
2470
327
    proxy = NULL;
2471
327
  }
2472
129k
  if(socksproxy && (!*socksproxy ||
2473
26.1k
                    (conn->handler->flags & PROTOPT_NONETWORK))) {
2474
356
    free(socksproxy);  /* Do not bother with an empty socks proxy string or if
2475
                          the protocol does not work with network */
2476
356
    socksproxy = NULL;
2477
356
  }
2478
2479
  /***********************************************************************
2480
   * If this is supposed to use a proxy, we need to figure out the proxy host
2481
   * name, proxy type and port number, so that we can reuse an existing
2482
   * connection that may exist registered to the same proxy host.
2483
   ***********************************************************************/
2484
129k
  if(proxy || socksproxy) {
2485
44.1k
    long ptype = conn->http_proxy.proxytype;
2486
44.1k
    if(proxy) {
2487
18.9k
      result = parse_proxy(data, conn, proxy, ptype);
2488
18.9k
      Curl_safefree(proxy); /* parse_proxy copies the proxy string */
2489
18.9k
      if(result)
2490
37
        goto out;
2491
18.9k
    }
2492
2493
44.1k
    if(socksproxy) {
2494
26.1k
      result = parse_proxy(data, conn, socksproxy, ptype);
2495
      /* parse_proxy copies the socks proxy string */
2496
26.1k
      Curl_safefree(socksproxy);
2497
26.1k
      if(result)
2498
100
        goto out;
2499
26.1k
    }
2500
2501
44.0k
    if(conn->http_proxy.host.rawalloc) {
2502
#ifdef CURL_DISABLE_HTTP
2503
      /* asking for an HTTP proxy is a bit funny when HTTP is disabled... */
2504
      result = CURLE_UNSUPPORTED_PROTOCOL;
2505
      goto out;
2506
#else
2507
      /* force this connection's protocol to become HTTP if compatible */
2508
42.7k
      if(!(conn->handler->protocol & PROTO_FAMILY_HTTP)) {
2509
35.3k
        if((conn->handler->flags & PROTOPT_PROXY_AS_HTTP) &&
2510
12.4k
           !conn->bits.tunnel_proxy)
2511
12.4k
          conn->handler = &Curl_handler_http;
2512
22.9k
        else
2513
          /* if not converting to HTTP over the proxy, enforce tunneling */
2514
22.9k
          conn->bits.tunnel_proxy = TRUE;
2515
35.3k
      }
2516
42.7k
      conn->bits.httpproxy = TRUE;
2517
42.7k
#endif
2518
42.7k
    }
2519
1.26k
    else {
2520
1.26k
      conn->bits.httpproxy = FALSE; /* not an HTTP proxy */
2521
1.26k
      conn->bits.tunnel_proxy = FALSE; /* no tunneling if not HTTP */
2522
1.26k
    }
2523
2524
44.0k
    if(conn->socks_proxy.host.rawalloc) {
2525
1.29k
      if(!conn->http_proxy.host.rawalloc) {
2526
        /* once a socks proxy */
2527
1.14k
        if(!conn->socks_proxy.user) {
2528
882
          conn->socks_proxy.user = conn->http_proxy.user;
2529
882
          conn->http_proxy.user = NULL;
2530
882
          free(conn->socks_proxy.passwd);
2531
882
          conn->socks_proxy.passwd = conn->http_proxy.passwd;
2532
882
          conn->http_proxy.passwd = NULL;
2533
882
        }
2534
1.14k
      }
2535
1.29k
      conn->bits.socksproxy = TRUE;
2536
1.29k
    }
2537
42.7k
    else
2538
42.7k
      conn->bits.socksproxy = FALSE; /* not a socks proxy */
2539
44.0k
  }
2540
85.3k
  else {
2541
85.3k
    conn->bits.socksproxy = FALSE;
2542
85.3k
    conn->bits.httpproxy = FALSE;
2543
85.3k
  }
2544
129k
  conn->bits.proxy = conn->bits.httpproxy || conn->bits.socksproxy;
2545
2546
129k
  if(!conn->bits.proxy) {
2547
    /* we are not using the proxy after all... */
2548
85.5k
    conn->bits.proxy = FALSE;
2549
85.5k
    conn->bits.httpproxy = FALSE;
2550
85.5k
    conn->bits.socksproxy = FALSE;
2551
85.5k
    conn->bits.proxy_user_passwd = FALSE;
2552
85.5k
    conn->bits.tunnel_proxy = FALSE;
2553
    /* CURLPROXY_HTTPS does not have its own flag in conn->bits, yet we need
2554
       to signal that CURLPROXY_HTTPS is not used for this connection */
2555
85.5k
    conn->http_proxy.proxytype = CURLPROXY_HTTP;
2556
85.5k
  }
2557
2558
129k
out:
2559
2560
129k
  free(socksproxy);
2561
129k
  free(proxy);
2562
129k
  return result;
2563
129k
}
2564
#endif /* CURL_DISABLE_PROXY */
2565
2566
/*
2567
 * Curl_parse_login_details()
2568
 *
2569
 * This is used to parse a login string for username, password and options in
2570
 * the following formats:
2571
 *
2572
 *   user
2573
 *   user:password
2574
 *   user:password;options
2575
 *   user;options
2576
 *   user;options:password
2577
 *   :password
2578
 *   :password;options
2579
 *   ;options
2580
 *   ;options:password
2581
 *
2582
 * Parameters:
2583
 *
2584
 * login    [in]     - login string.
2585
 * len      [in]     - length of the login string.
2586
 * userp    [in/out] - address where a pointer to newly allocated memory
2587
 *                     holding the user will be stored upon completion.
2588
 * passwdp  [in/out] - address where a pointer to newly allocated memory
2589
 *                     holding the password will be stored upon completion.
2590
 * optionsp [in/out] - OPTIONAL address where a pointer to newly allocated
2591
 *                     memory holding the options will be stored upon
2592
 *                     completion.
2593
 *
2594
 * Returns CURLE_OK on success.
2595
 */
2596
CURLcode Curl_parse_login_details(const char *login, const size_t len,
2597
                                  char **userp, char **passwdp,
2598
                                  char **optionsp)
2599
52.3k
{
2600
52.3k
  char *ubuf = NULL;
2601
52.3k
  char *pbuf = NULL;
2602
52.3k
  const char *psep = NULL;
2603
52.3k
  const char *osep = NULL;
2604
52.3k
  size_t ulen;
2605
52.3k
  size_t plen;
2606
52.3k
  size_t olen;
2607
2608
52.3k
  DEBUGASSERT(userp);
2609
52.3k
  DEBUGASSERT(passwdp);
2610
2611
  /* Attempt to find the password separator */
2612
52.3k
  psep = memchr(login, ':', len);
2613
2614
  /* Attempt to find the options separator */
2615
52.3k
  if(optionsp)
2616
1.07k
    osep = memchr(login, ';', len);
2617
2618
  /* Calculate the portion lengths */
2619
52.3k
  ulen = (psep ?
2620
15.6k
          (size_t)(osep && psep > osep ? osep - login : psep - login) :
2621
52.3k
          (osep ? (size_t)(osep - login) : len));
2622
52.3k
  plen = (psep ?
2623
15.6k
          (osep && osep > psep ? (size_t)(osep - psep) :
2624
36.6k
           (size_t)(login + len - psep)) - 1 : 0);
2625
52.3k
  olen = (osep ?
2626
301
          (psep && psep > osep ? (size_t)(psep - osep) :
2627
52.0k
           (size_t)(login + len - osep)) - 1 : 0);
2628
2629
  /* Clone the user portion buffer, which can be zero length */
2630
52.3k
  ubuf = Curl_memdup0(login, ulen);
2631
52.3k
  if(!ubuf)
2632
0
    goto error;
2633
2634
  /* Clone the password portion buffer */
2635
52.3k
  if(psep) {
2636
15.6k
    pbuf = Curl_memdup0(&psep[1], plen);
2637
15.6k
    if(!pbuf)
2638
0
      goto error;
2639
15.6k
  }
2640
2641
  /* Allocate the options portion buffer */
2642
52.3k
  if(optionsp) {
2643
1.07k
    char *obuf = NULL;
2644
1.07k
    if(olen) {
2645
212
      obuf = Curl_memdup0(&osep[1], olen);
2646
212
      if(!obuf)
2647
0
        goto error;
2648
212
    }
2649
1.07k
    *optionsp = obuf;
2650
1.07k
  }
2651
52.3k
  *userp = ubuf;
2652
52.3k
  *passwdp = pbuf;
2653
52.3k
  return CURLE_OK;
2654
0
error:
2655
0
  free(ubuf);
2656
0
  free(pbuf);
2657
0
  return CURLE_OUT_OF_MEMORY;
2658
52.3k
}
2659
2660
/*************************************************************
2661
 * Figure out the remote port number and fix it in the URL
2662
 *
2663
 * No matter if we use a proxy or not, we have to figure out the remote
2664
 * port number of various reasons.
2665
 *
2666
 * The port number embedded in the URL is replaced, if necessary.
2667
 *************************************************************/
2668
static CURLcode parse_remote_port(struct Curl_easy *data,
2669
                                  struct connectdata *conn)
2670
129k
{
2671
2672
129k
  if(data->set.use_port && data->state.allow_port) {
2673
    /* if set, we use this instead of the port possibly given in the URL */
2674
728
    char portbuf[16];
2675
728
    CURLUcode uc;
2676
728
    conn->remote_port = data->set.use_port;
2677
728
    curl_msnprintf(portbuf, sizeof(portbuf), "%d", conn->remote_port);
2678
728
    uc = curl_url_set(data->state.uh, CURLUPART_PORT, portbuf, 0);
2679
728
    if(uc)
2680
0
      return CURLE_OUT_OF_MEMORY;
2681
728
  }
2682
2683
129k
  return CURLE_OK;
2684
129k
}
2685
2686
#ifndef CURL_DISABLE_NETRC
2687
static bool str_has_ctrl(const char *input)
2688
0
{
2689
0
  if(input) {
2690
0
    const unsigned char *str = (const unsigned char *)input;
2691
0
    while(*str) {
2692
0
      if(*str < 0x20)
2693
0
        return TRUE;
2694
0
      str++;
2695
0
    }
2696
0
  }
2697
0
  return FALSE;
2698
0
}
2699
#endif
2700
2701
/*
2702
 * Override the login details from the URL with that in the CURLOPT_USERPWD
2703
 * option or a .netrc file, if applicable.
2704
 */
2705
static CURLcode override_login(struct Curl_easy *data,
2706
                               struct connectdata *conn)
2707
129k
{
2708
129k
  CURLUcode uc;
2709
129k
  char **userp = &conn->user;
2710
129k
  char **passwdp = &conn->passwd;
2711
129k
  char **optionsp = &conn->options;
2712
2713
129k
  if(data->set.str[STRING_OPTIONS]) {
2714
1.45k
    free(*optionsp);
2715
1.45k
    *optionsp = strdup(data->set.str[STRING_OPTIONS]);
2716
1.45k
    if(!*optionsp)
2717
0
      return CURLE_OUT_OF_MEMORY;
2718
1.45k
  }
2719
2720
129k
#ifndef CURL_DISABLE_NETRC
2721
129k
  if(data->set.use_netrc == CURL_NETRC_REQUIRED) {
2722
1.09k
    Curl_safefree(*userp);
2723
1.09k
    Curl_safefree(*passwdp);
2724
1.09k
  }
2725
129k
  conn->bits.netrc = FALSE;
2726
129k
  if(data->set.use_netrc && !data->set.str[STRING_USERNAME]) {
2727
1.15k
    bool url_provided = FALSE;
2728
2729
1.15k
    if(data->state.aptr.user &&
2730
296
       (data->state.creds_from != CREDS_NETRC)) {
2731
      /* there was a username with a length in the URL. Use the URL decoded
2732
         version */
2733
294
      userp = &data->state.aptr.user;
2734
294
      url_provided = TRUE;
2735
294
    }
2736
2737
1.15k
    if(!*passwdp) {
2738
1.07k
      NETRCcode ret = Curl_parsenetrc(&data->state.netrc, conn->host.name,
2739
1.07k
                                      userp, passwdp,
2740
1.07k
                                      data->set.str[STRING_NETRC_FILE]);
2741
1.07k
      if(ret && ((ret == NETRC_NO_MATCH) ||
2742
1.07k
                 (data->set.use_netrc == CURL_NETRC_OPTIONAL))) {
2743
1.07k
        infof(data, "Couldn't find host %s in the %s file; using defaults",
2744
1.07k
              conn->host.name,
2745
1.07k
              (data->set.str[STRING_NETRC_FILE] ?
2746
1.07k
               data->set.str[STRING_NETRC_FILE] : ".netrc"));
2747
1.07k
      }
2748
0
      else if(ret) {
2749
0
        const char *m = Curl_netrc_strerror(ret);
2750
0
        failf(data, ".netrc error: %s", m);
2751
0
        return CURLE_READ_ERROR;
2752
0
      }
2753
0
      else {
2754
0
        if(!(conn->handler->flags&PROTOPT_USERPWDCTRL)) {
2755
          /* if the protocol can't handle control codes in credentials, make
2756
             sure there are none */
2757
0
          if(str_has_ctrl(*userp) || str_has_ctrl(*passwdp)) {
2758
0
            failf(data, "control code detected in .netrc credentials");
2759
0
            return CURLE_READ_ERROR;
2760
0
          }
2761
0
        }
2762
        /* set bits.netrc TRUE to remember that we got the name from a .netrc
2763
           file, so that it is safe to use even if we followed a Location: to a
2764
           different host or similar. */
2765
0
        conn->bits.netrc = TRUE;
2766
0
      }
2767
1.07k
    }
2768
1.15k
    if(url_provided) {
2769
294
      free(conn->user);
2770
294
      conn->user = strdup(*userp);
2771
294
      if(!conn->user)
2772
0
        return CURLE_OUT_OF_MEMORY;
2773
294
    }
2774
    /* no user was set but a password, set a blank user */
2775
1.15k
    if(!*userp && *passwdp) {
2776
0
      *userp = strdup("");
2777
0
      if(!*userp)
2778
0
        return CURLE_OUT_OF_MEMORY;
2779
0
    }
2780
1.15k
  }
2781
129k
#endif
2782
2783
  /* for updated strings, we update them in the URL */
2784
129k
  if(*userp) {
2785
19.6k
    CURLcode result;
2786
19.6k
    if(data->state.aptr.user != *userp) {
2787
      /* nothing to do then */
2788
19.3k
      result = Curl_setstropt(&data->state.aptr.user, *userp);
2789
19.3k
      if(result)
2790
0
        return result;
2791
19.3k
      data->state.creds_from = CREDS_NETRC;
2792
19.3k
    }
2793
19.6k
  }
2794
129k
  if(data->state.aptr.user) {
2795
24.5k
    uc = curl_url_set(data->state.uh, CURLUPART_USER, data->state.aptr.user,
2796
24.5k
                      CURLU_URLENCODE);
2797
24.5k
    if(uc)
2798
0
      return Curl_uc_to_curlcode(uc);
2799
24.5k
    if(!*userp) {
2800
4.95k
      *userp = strdup(data->state.aptr.user);
2801
4.95k
      if(!*userp)
2802
0
        return CURLE_OUT_OF_MEMORY;
2803
4.95k
    }
2804
24.5k
  }
2805
129k
  if(*passwdp) {
2806
4.49k
    CURLcode result = Curl_setstropt(&data->state.aptr.passwd, *passwdp);
2807
4.49k
    if(result)
2808
0
      return result;
2809
4.49k
    data->state.creds_from = CREDS_NETRC;
2810
4.49k
  }
2811
129k
  if(data->state.aptr.passwd) {
2812
9.32k
    uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD,
2813
9.32k
                      data->state.aptr.passwd, CURLU_URLENCODE);
2814
9.32k
    if(uc)
2815
0
      return Curl_uc_to_curlcode(uc);
2816
9.32k
    if(!*passwdp) {
2817
4.83k
      *passwdp = strdup(data->state.aptr.passwd);
2818
4.83k
      if(!*passwdp)
2819
0
        return CURLE_OUT_OF_MEMORY;
2820
4.83k
    }
2821
9.32k
  }
2822
2823
129k
  return CURLE_OK;
2824
129k
}
2825
2826
/*
2827
 * Set the login details so they are available in the connection
2828
 */
2829
static CURLcode set_login(struct Curl_easy *data,
2830
                          struct connectdata *conn)
2831
129k
{
2832
129k
  CURLcode result = CURLE_OK;
2833
129k
  const char *setuser = CURL_DEFAULT_USER;
2834
129k
  const char *setpasswd = CURL_DEFAULT_PASSWORD;
2835
2836
  /* If our protocol needs a password and we have none, use the defaults */
2837
129k
  if((conn->handler->flags & PROTOPT_NEEDSPWD) && !data->state.aptr.user)
2838
4.68k
    ;
2839
124k
  else {
2840
124k
    setuser = "";
2841
124k
    setpasswd = "";
2842
124k
  }
2843
  /* Store the default user */
2844
129k
  if(!conn->user) {
2845
104k
    conn->user = strdup(setuser);
2846
104k
    if(!conn->user)
2847
0
      return CURLE_OUT_OF_MEMORY;
2848
104k
  }
2849
2850
  /* Store the default password */
2851
129k
  if(!conn->passwd) {
2852
120k
    conn->passwd = strdup(setpasswd);
2853
120k
    if(!conn->passwd)
2854
0
      result = CURLE_OUT_OF_MEMORY;
2855
120k
  }
2856
2857
129k
  return result;
2858
129k
}
2859
2860
/*
2861
 * Parses a "host:port" string to connect to.
2862
 * The hostname and the port may be empty; in this case, NULL is returned for
2863
 * the hostname and -1 for the port.
2864
 */
2865
static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
2866
                                           const char *host,
2867
                                           char **hostname_result,
2868
                                           int *port_result)
2869
122k
{
2870
122k
  char *host_dup;
2871
122k
  char *hostptr;
2872
122k
  char *host_portno;
2873
122k
  char *portptr;
2874
122k
  int port = -1;
2875
122k
  CURLcode result = CURLE_OK;
2876
2877
#ifdef CURL_DISABLE_VERBOSE_STRINGS
2878
  (void)data;
2879
#endif
2880
2881
122k
  *hostname_result = NULL;
2882
122k
  *port_result = -1;
2883
2884
122k
  if(!host || !*host)
2885
0
    return CURLE_OK;
2886
2887
122k
  host_dup = strdup(host);
2888
122k
  if(!host_dup)
2889
0
    return CURLE_OUT_OF_MEMORY;
2890
2891
122k
  hostptr = host_dup;
2892
2893
  /* start scanning for port number at this point */
2894
122k
  portptr = hostptr;
2895
2896
  /* detect and extract RFC6874-style IPv6-addresses */
2897
122k
  if(*hostptr == '[') {
2898
0
#ifdef USE_IPV6
2899
0
    char *ptr = ++hostptr; /* advance beyond the initial bracket */
2900
0
    while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.')))
2901
0
      ptr++;
2902
0
    if(*ptr == '%') {
2903
      /* There might be a zone identifier */
2904
0
      if(strncmp("%25", ptr, 3))
2905
0
        infof(data, "Please URL encode %% as %%25, see RFC 6874.");
2906
0
      ptr++;
2907
      /* Allow unreserved characters as defined in RFC 3986 */
2908
0
      while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') ||
2909
0
                     (*ptr == '.') || (*ptr == '_') || (*ptr == '~')))
2910
0
        ptr++;
2911
0
    }
2912
0
    if(*ptr == ']')
2913
      /* yeps, it ended nicely with a bracket as well */
2914
0
      *ptr++ = '\0';
2915
0
    else
2916
0
      infof(data, "Invalid IPv6 address format");
2917
0
    portptr = ptr;
2918
    /* Note that if this did not end with a bracket, we still advanced the
2919
     * hostptr first, but I cannot see anything wrong with that as no host
2920
     * name nor a numeric can legally start with a bracket.
2921
     */
2922
#else
2923
    failf(data, "Use of IPv6 in *_CONNECT_TO without IPv6 support built-in");
2924
    result = CURLE_NOT_BUILT_IN;
2925
    goto error;
2926
#endif
2927
0
  }
2928
2929
  /* Get port number off server.com:1080 */
2930
122k
  host_portno = strchr(portptr, ':');
2931
122k
  if(host_portno) {
2932
122k
    *host_portno = '\0'; /* cut off number from hostname */
2933
122k
    host_portno++;
2934
122k
    if(*host_portno) {
2935
0
      curl_off_t portparse;
2936
0
      const char *p = host_portno;
2937
0
      if(curlx_str_number(&p, &portparse, 0xffff)) {
2938
0
        failf(data, "No valid port number in connect to host string (%s)",
2939
0
              host_portno);
2940
0
        result = CURLE_SETOPT_OPTION_SYNTAX;
2941
0
        goto error;
2942
0
      }
2943
0
      port = (int)portparse; /* we know it will fit */
2944
0
    }
2945
122k
  }
2946
2947
  /* now, clone the cleaned hostname */
2948
122k
  DEBUGASSERT(hostptr);
2949
122k
  *hostname_result = strdup(hostptr);
2950
122k
  if(!*hostname_result) {
2951
0
    result = CURLE_OUT_OF_MEMORY;
2952
0
    goto error;
2953
0
  }
2954
2955
122k
  *port_result = port;
2956
2957
122k
error:
2958
122k
  free(host_dup);
2959
122k
  return result;
2960
122k
}
2961
2962
/*
2963
 * Parses one "connect to" string in the form:
2964
 * "HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT".
2965
 */
2966
static CURLcode parse_connect_to_string(struct Curl_easy *data,
2967
                                        struct connectdata *conn,
2968
                                        const char *conn_to_host,
2969
                                        char **host_result,
2970
                                        int *port_result)
2971
122k
{
2972
122k
  CURLcode result = CURLE_OK;
2973
122k
  const char *ptr = conn_to_host;
2974
122k
  bool host_match = FALSE;
2975
122k
  bool port_match = FALSE;
2976
2977
122k
  *host_result = NULL;
2978
122k
  *port_result = -1;
2979
2980
122k
  if(*ptr == ':') {
2981
    /* an empty hostname always matches */
2982
122k
    host_match = TRUE;
2983
122k
    ptr++;
2984
122k
  }
2985
0
  else {
2986
    /* check whether the URL's hostname matches */
2987
0
    size_t hostname_to_match_len;
2988
0
    char *hostname_to_match = curl_maprintf("%s%s%s",
2989
0
                                            conn->bits.ipv6_ip ? "[" : "",
2990
0
                                            conn->host.name,
2991
0
                                            conn->bits.ipv6_ip ? "]" : "");
2992
0
    if(!hostname_to_match)
2993
0
      return CURLE_OUT_OF_MEMORY;
2994
0
    hostname_to_match_len = strlen(hostname_to_match);
2995
0
    host_match = curl_strnequal(ptr, hostname_to_match,
2996
0
                                hostname_to_match_len);
2997
0
    free(hostname_to_match);
2998
0
    ptr += hostname_to_match_len;
2999
3000
0
    host_match = host_match && *ptr == ':';
3001
0
    ptr++;
3002
0
  }
3003
3004
122k
  if(host_match) {
3005
122k
    if(*ptr == ':') {
3006
      /* an empty port always matches */
3007
122k
      port_match = TRUE;
3008
122k
      ptr++;
3009
122k
    }
3010
0
    else {
3011
      /* check whether the URL's port matches */
3012
0
      char *ptr_next = strchr(ptr, ':');
3013
0
      if(ptr_next) {
3014
0
        curl_off_t port_to_match;
3015
0
        if(!curlx_str_number(&ptr, &port_to_match, 0xffff) &&
3016
0
           (port_to_match == (curl_off_t)conn->remote_port))
3017
0
          port_match = TRUE;
3018
0
        ptr = ptr_next + 1;
3019
0
      }
3020
0
    }
3021
122k
  }
3022
3023
122k
  if(host_match && port_match) {
3024
    /* parse the hostname and port to connect to */
3025
122k
    result = parse_connect_to_host_port(data, ptr, host_result, port_result);
3026
122k
  }
3027
3028
122k
  return result;
3029
122k
}
3030
3031
/*
3032
 * Processes all strings in the "connect to" slist, and uses the "connect
3033
 * to host" and "connect to port" of the first string that matches.
3034
 */
3035
static CURLcode parse_connect_to_slist(struct Curl_easy *data,
3036
                                       struct connectdata *conn,
3037
                                       struct curl_slist *conn_to_host)
3038
129k
{
3039
129k
  CURLcode result = CURLE_OK;
3040
129k
  char *host = NULL;
3041
129k
  int port = -1;
3042
3043
251k
  while(conn_to_host && !host && port == -1) {
3044
122k
    result = parse_connect_to_string(data, conn, conn_to_host->data,
3045
122k
                                     &host, &port);
3046
122k
    if(result)
3047
0
      return result;
3048
3049
122k
    if(host && *host) {
3050
122k
      conn->conn_to_host.rawalloc = host;
3051
122k
      conn->conn_to_host.name = host;
3052
122k
      conn->bits.conn_to_host = TRUE;
3053
3054
122k
      infof(data, "Connecting to hostname: %s", host);
3055
122k
    }
3056
0
    else {
3057
      /* no "connect to host" */
3058
0
      conn->bits.conn_to_host = FALSE;
3059
0
      Curl_safefree(host);
3060
0
    }
3061
3062
122k
    if(port >= 0) {
3063
0
      conn->conn_to_port = port;
3064
0
      conn->bits.conn_to_port = TRUE;
3065
0
      infof(data, "Connecting to port: %d", port);
3066
0
    }
3067
122k
    else {
3068
      /* no "connect to port" */
3069
122k
      conn->bits.conn_to_port = FALSE;
3070
122k
      port = -1;
3071
122k
    }
3072
3073
122k
    conn_to_host = conn_to_host->next;
3074
122k
  }
3075
3076
129k
#ifndef CURL_DISABLE_ALTSVC
3077
129k
  if(data->asi && !host && (port == -1) &&
3078
0
     ((conn->handler->protocol == CURLPROTO_HTTPS) ||
3079
0
#ifdef DEBUGBUILD
3080
      /* allow debug builds to circumvent the HTTPS restriction */
3081
0
      getenv("CURL_ALTSVC_HTTP")
3082
#else
3083
      0
3084
#endif
3085
0
       )) {
3086
    /* no connect_to match, try alt-svc! */
3087
0
    enum alpnid srcalpnid = ALPN_none;
3088
0
    bool hit = FALSE;
3089
0
    struct altsvc *as = NULL;
3090
0
    int allowed_alpns = ALPN_none;
3091
0
    struct http_negotiation *neg = &data->state.http_neg;
3092
3093
0
    DEBUGF(infof(data, "Alt-svc check wanted=%x, allowed=%x",
3094
0
                 neg->wanted, neg->allowed));
3095
#ifdef USE_HTTP3
3096
    if(neg->allowed & CURL_HTTP_V3x)
3097
      allowed_alpns |= ALPN_h3;
3098
#endif
3099
0
#ifdef USE_HTTP2
3100
0
    if(neg->allowed & CURL_HTTP_V2x)
3101
0
      allowed_alpns |= ALPN_h2;
3102
0
#endif
3103
0
    if(neg->allowed & CURL_HTTP_V1x)
3104
0
      allowed_alpns |= ALPN_h1;
3105
0
    allowed_alpns &= (int)data->asi->flags;
3106
3107
0
    host = conn->host.rawalloc;
3108
0
    DEBUGF(infof(data, "check Alt-Svc for host %s", host));
3109
#ifdef USE_HTTP3
3110
    if(!hit && (neg->wanted & CURL_HTTP_V3x)) {
3111
      srcalpnid = ALPN_h3;
3112
      hit = Curl_altsvc_lookup(data->asi,
3113
                               ALPN_h3, host, conn->remote_port, /* from */
3114
                               &as /* to */,
3115
                               allowed_alpns);
3116
    }
3117
#endif
3118
0
#ifdef USE_HTTP2
3119
0
    if(!hit && (neg->wanted & CURL_HTTP_V2x) &&
3120
0
       !neg->h2_prior_knowledge) {
3121
0
      srcalpnid = ALPN_h2;
3122
0
      hit = Curl_altsvc_lookup(data->asi,
3123
0
                               ALPN_h2, host, conn->remote_port, /* from */
3124
0
                               &as /* to */,
3125
0
                               allowed_alpns);
3126
0
    }
3127
0
#endif
3128
0
    if(!hit && (neg->wanted & CURL_HTTP_V1x) &&
3129
0
       !neg->only_10) {
3130
0
      srcalpnid = ALPN_h1;
3131
0
      hit = Curl_altsvc_lookup(data->asi,
3132
0
                               ALPN_h1, host, conn->remote_port, /* from */
3133
0
                               &as /* to */,
3134
0
                               allowed_alpns);
3135
0
    }
3136
3137
0
    if(hit) {
3138
0
      char *hostd = strdup((char *)as->dst.host);
3139
0
      if(!hostd)
3140
0
        return CURLE_OUT_OF_MEMORY;
3141
0
      conn->conn_to_host.rawalloc = hostd;
3142
0
      conn->conn_to_host.name = hostd;
3143
0
      conn->bits.conn_to_host = TRUE;
3144
0
      conn->conn_to_port = as->dst.port;
3145
0
      conn->bits.conn_to_port = TRUE;
3146
0
      conn->bits.altused = TRUE;
3147
0
      infof(data, "Alt-svc connecting from [%s]%s:%d to [%s]%s:%d",
3148
0
            Curl_alpnid2str(srcalpnid), host, conn->remote_port,
3149
0
            Curl_alpnid2str(as->dst.alpnid), hostd, as->dst.port);
3150
0
      if(srcalpnid != as->dst.alpnid) {
3151
        /* protocol version switch */
3152
0
        switch(as->dst.alpnid) {
3153
0
        case ALPN_h1:
3154
0
          neg->wanted = neg->allowed = CURL_HTTP_V1x;
3155
0
          neg->only_10 = FALSE;
3156
0
          break;
3157
0
        case ALPN_h2:
3158
0
          neg->wanted = neg->allowed = CURL_HTTP_V2x;
3159
0
          break;
3160
0
        case ALPN_h3:
3161
0
          conn->transport_wanted = TRNSPRT_QUIC;
3162
0
          neg->wanted = neg->allowed = CURL_HTTP_V3x;
3163
0
          break;
3164
0
        default: /* should not be possible */
3165
0
          break;
3166
0
        }
3167
0
      }
3168
0
    }
3169
0
  }
3170
129k
#endif
3171
3172
129k
  return result;
3173
129k
}
3174
3175
#ifdef USE_UNIX_SOCKETS
3176
static CURLcode resolve_unix(struct Curl_easy *data,
3177
                             struct connectdata *conn,
3178
                             char *unix_path,
3179
                             struct Curl_dns_entry **pdns)
3180
1.23k
{
3181
1.23k
  struct Curl_dns_entry *hostaddr;
3182
1.23k
  bool longpath = FALSE;
3183
3184
1.23k
  DEBUGASSERT(unix_path);
3185
1.23k
  *pdns = NULL;
3186
3187
  /* Unix domain sockets are local. The host gets ignored, just use the
3188
   * specified domain socket address. Do not cache "DNS entries". There is
3189
   * no DNS involved and we already have the file system path available. */
3190
1.23k
  hostaddr = calloc(1, sizeof(struct Curl_dns_entry));
3191
1.23k
  if(!hostaddr)
3192
0
    return CURLE_OUT_OF_MEMORY;
3193
3194
1.23k
  hostaddr->addr = Curl_unix2addr(unix_path, &longpath,
3195
1.23k
                                  conn->bits.abstract_unix_socket);
3196
1.23k
  if(!hostaddr->addr) {
3197
20
    if(longpath)
3198
      /* Long paths are not supported for now */
3199
20
      failf(data, "Unix socket path too long: '%s'", unix_path);
3200
20
    free(hostaddr);
3201
20
    return longpath ? CURLE_COULDNT_RESOLVE_HOST : CURLE_OUT_OF_MEMORY;
3202
20
  }
3203
3204
1.21k
  hostaddr->refcount = 1; /* connection is the only one holding this */
3205
1.21k
  *pdns = hostaddr;
3206
1.21k
  return CURLE_OK;
3207
1.23k
}
3208
#endif
3209
3210
/*************************************************************
3211
 * Resolve the address of the server or proxy
3212
 *************************************************************/
3213
static CURLcode resolve_server(struct Curl_easy *data,
3214
                               struct connectdata *conn,
3215
                               bool *async,
3216
                               struct Curl_dns_entry **pdns)
3217
111k
{
3218
111k
  struct hostname *ehost;
3219
111k
  int eport;
3220
111k
  timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
3221
111k
  const char *peertype = "host";
3222
111k
  CURLcode result;
3223
3224
111k
  *pdns = NULL;
3225
3226
111k
#ifdef USE_UNIX_SOCKETS
3227
111k
  {
3228
111k
    char *unix_path = conn->unix_domain_socket;
3229
3230
111k
#ifndef CURL_DISABLE_PROXY
3231
111k
    if(!unix_path && CONN_IS_PROXIED(conn) && conn->socks_proxy.host.name &&
3232
1.25k
       !strncmp(UNIX_SOCKET_PREFIX"/",
3233
1.25k
                conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX)))
3234
13
      unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1;
3235
111k
#endif
3236
3237
111k
    if(unix_path) {
3238
      /* This only works if previous transport is TRNSPRT_TCP. Check it? */
3239
1.23k
      conn->transport_wanted = TRNSPRT_UNIX;
3240
1.23k
      return resolve_unix(data, conn, unix_path, pdns);
3241
1.23k
    }
3242
111k
  }
3243
109k
#endif
3244
3245
109k
#ifndef CURL_DISABLE_PROXY
3246
109k
  if(CONN_IS_PROXIED(conn)) {
3247
39.5k
    ehost = conn->bits.socksproxy ? &conn->socks_proxy.host :
3248
39.5k
      &conn->http_proxy.host;
3249
39.5k
    eport = conn->bits.socksproxy ? conn->socks_proxy.port :
3250
39.5k
      conn->http_proxy.port;
3251
39.5k
    peertype = "proxy";
3252
39.5k
  }
3253
70.1k
  else
3254
70.1k
#endif
3255
70.1k
  {
3256
70.1k
    ehost = conn->bits.conn_to_host ? &conn->conn_to_host : &conn->host;
3257
    /* If not connecting via a proxy, extract the port from the URL, if it is
3258
     * there, thus overriding any defaults that might have been set above. */
3259
70.1k
    eport = conn->bits.conn_to_port ? conn->conn_to_port : conn->remote_port;
3260
70.1k
  }
3261
3262
  /* Resolve target host right on */
3263
109k
  conn->hostname_resolve = strdup(ehost->name);
3264
109k
  if(!conn->hostname_resolve)
3265
0
    return CURLE_OUT_OF_MEMORY;
3266
3267
109k
  result = Curl_resolv_timeout(data, conn->hostname_resolve,
3268
109k
                               eport, conn->ip_version,
3269
109k
                               pdns, timeout_ms);
3270
109k
  DEBUGASSERT(!result || !*pdns);
3271
109k
  if(result == CURLE_AGAIN) {
3272
7.66k
    *async = TRUE;
3273
7.66k
    return CURLE_OK;
3274
7.66k
  }
3275
102k
  else if(result == CURLE_OPERATION_TIMEDOUT) {
3276
0
    failf(data, "Failed to resolve %s '%s' with timeout after %"
3277
0
          FMT_TIMEDIFF_T " ms", peertype, ehost->dispname,
3278
0
          curlx_timediff(curlx_now(), data->progress.t_startsingle));
3279
0
    return CURLE_OPERATION_TIMEDOUT;
3280
0
  }
3281
102k
  else if(result) {
3282
1.25k
    failf(data, "Could not resolve %s: %s", peertype, ehost->dispname);
3283
1.25k
    return result;
3284
1.25k
  }
3285
100k
  DEBUGASSERT(*pdns);
3286
100k
  return CURLE_OK;
3287
100k
}
3288
3289
static void url_move_hostname(struct hostname *dest, struct hostname *src)
3290
26.6k
{
3291
26.6k
  Curl_safefree(dest->rawalloc);
3292
26.6k
  Curl_free_idnconverted_hostname(dest);
3293
26.6k
  *dest = *src;
3294
26.6k
  memset(src, 0, sizeof(*src));
3295
26.6k
}
3296
3297
/*
3298
 * Cleanup the connection `temp`, just allocated for `data`, before using the
3299
 * previously `existing` one for `data`. All relevant info is copied over
3300
 * and `temp` is freed.
3301
 */
3302
static void reuse_conn(struct Curl_easy *data,
3303
                       struct connectdata *temp,
3304
                       struct connectdata *existing)
3305
13.3k
{
3306
  /* get the user+password information from the temp struct since it may
3307
   * be new for this request even when we reuse an existing connection */
3308
13.3k
  if(temp->user) {
3309
    /* use the new username and password though */
3310
13.3k
    free(existing->user);
3311
13.3k
    free(existing->passwd);
3312
13.3k
    existing->user = temp->user;
3313
13.3k
    existing->passwd = temp->passwd;
3314
13.3k
    temp->user = NULL;
3315
13.3k
    temp->passwd = NULL;
3316
13.3k
  }
3317
3318
13.3k
#ifndef CURL_DISABLE_PROXY
3319
13.3k
  existing->bits.proxy_user_passwd = temp->bits.proxy_user_passwd;
3320
13.3k
  if(existing->bits.proxy_user_passwd) {
3321
    /* use the new proxy username and proxy password though */
3322
3.68k
    free(existing->http_proxy.user);
3323
3.68k
    free(existing->socks_proxy.user);
3324
3.68k
    free(existing->http_proxy.passwd);
3325
3.68k
    free(existing->socks_proxy.passwd);
3326
3.68k
    existing->http_proxy.user = temp->http_proxy.user;
3327
3.68k
    existing->socks_proxy.user = temp->socks_proxy.user;
3328
3.68k
    existing->http_proxy.passwd = temp->http_proxy.passwd;
3329
3.68k
    existing->socks_proxy.passwd = temp->socks_proxy.passwd;
3330
3.68k
    temp->http_proxy.user = NULL;
3331
3.68k
    temp->socks_proxy.user = NULL;
3332
3.68k
    temp->http_proxy.passwd = NULL;
3333
3.68k
    temp->socks_proxy.passwd = NULL;
3334
3.68k
  }
3335
13.3k
#endif
3336
3337
  /* Finding a connection for reuse in the cpool matches, among other
3338
   * things on the "remote-relevant" hostname. This is not necessarily
3339
   * the authority of the URL, e.g. conn->host. For example:
3340
   * - we use a proxy (not tunneling). we want to send all requests
3341
   *   that use the same proxy on this connection.
3342
   * - we have a "connect-to" setting that may redirect the hostname of
3343
   *   a new request to the same remote endpoint of an existing conn.
3344
   *   We want to reuse an existing conn to the remote endpoint.
3345
   * Since connection reuse does not match on conn->host necessarily, we
3346
   * switch `existing` conn to `temp` conn's host settings.
3347
   *       Is this correct in the case of TLS connections that have
3348
   *       used the original hostname in SNI to negotiate? Do we send
3349
   *       requests for another host through the different SNI?
3350
   */
3351
13.3k
  url_move_hostname(&existing->host, &temp->host);
3352
13.3k
  url_move_hostname(&existing->conn_to_host, &temp->conn_to_host);
3353
3354
13.3k
  existing->conn_to_port = temp->conn_to_port;
3355
13.3k
  existing->remote_port = temp->remote_port;
3356
13.3k
  free(existing->hostname_resolve);
3357
13.3k
  existing->hostname_resolve = temp->hostname_resolve;
3358
13.3k
  temp->hostname_resolve = NULL;
3359
3360
  /* reuse init */
3361
13.3k
  existing->bits.reuse = TRUE; /* yes, we are reusing here */
3362
3363
13.3k
  Curl_conn_free(data, temp);
3364
13.3k
}
3365
3366
static void conn_meta_freeentry(void *p)
3367
0
{
3368
0
  (void)p;
3369
  /* Will always be FALSE. Cannot use a 0 assert here since compilers
3370
   * are not in agreement if they then want a NORETURN attribute or
3371
   * not. *sigh* */
3372
0
  DEBUGASSERT(p == NULL);
3373
0
}
3374
3375
/**
3376
 * create_conn() sets up a new connectdata struct, or reuses an already
3377
 * existing one, and resolves hostname.
3378
 *
3379
 * if this function returns CURLE_OK and *async is set to TRUE, the resolve
3380
 * response will be coming asynchronously. If *async is FALSE, the name is
3381
 * already resolved.
3382
 *
3383
 * @param data The sessionhandle pointer
3384
 * @param in_connect is set to the next connection data pointer
3385
 * @param reusedp is set to to TRUE if connection was reused
3386
 * @see Curl_setup_conn()
3387
 *
3388
 */
3389
3390
static CURLcode create_conn(struct Curl_easy *data,
3391
                            struct connectdata **in_connect,
3392
                            bool *reusedp)
3393
148k
{
3394
148k
  CURLcode result = CURLE_OK;
3395
148k
  struct connectdata *conn;
3396
148k
  struct connectdata *existing = NULL;
3397
148k
  bool reuse;
3398
148k
  bool connections_available = TRUE;
3399
148k
  bool force_reuse = FALSE;
3400
148k
  bool waitpipe = FALSE;
3401
3402
148k
  *reusedp = FALSE;
3403
148k
  *in_connect = NULL;
3404
3405
  /*************************************************************
3406
   * Check input data
3407
   *************************************************************/
3408
148k
  if(!data->state.url) {
3409
0
    result = CURLE_URL_MALFORMAT;
3410
0
    goto out;
3411
0
  }
3412
3413
  /* First, split up the current URL in parts so that we can use the
3414
     parts for checking against the already present connections. In order
3415
     to not have to modify everything at once, we allocate a temporary
3416
     connection data struct and fill in for comparison purposes. */
3417
148k
  conn = allocate_conn(data);
3418
3419
148k
  if(!conn) {
3420
0
    result = CURLE_OUT_OF_MEMORY;
3421
0
    goto out;
3422
0
  }
3423
3424
  /* We must set the return variable as soon as possible, so that our
3425
     parent can cleanup any possible allocs we may have done before
3426
     any failure */
3427
148k
  *in_connect = conn;
3428
3429
  /* Do the unfailable inits first, before checks that may early return */
3430
148k
  Curl_hash_init(&conn->meta_hash, 23,
3431
148k
                 Curl_hash_str, curlx_str_key_compare, conn_meta_freeentry);
3432
3433
148k
  result = parseurlandfillconn(data, conn);
3434
148k
  if(result)
3435
18.8k
    goto out;
3436
3437
129k
  if(data->set.str[STRING_SASL_AUTHZID]) {
3438
508
    conn->sasl_authzid = strdup(data->set.str[STRING_SASL_AUTHZID]);
3439
508
    if(!conn->sasl_authzid) {
3440
0
      result = CURLE_OUT_OF_MEMORY;
3441
0
      goto out;
3442
0
    }
3443
508
  }
3444
3445
129k
  if(data->set.str[STRING_BEARER]) {
3446
8.78k
    conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]);
3447
8.78k
    if(!conn->oauth_bearer) {
3448
0
      result = CURLE_OUT_OF_MEMORY;
3449
0
      goto out;
3450
0
    }
3451
8.78k
  }
3452
3453
129k
#ifdef USE_UNIX_SOCKETS
3454
129k
  if(data->set.str[STRING_UNIX_SOCKET_PATH]) {
3455
5.12k
    conn->unix_domain_socket = strdup(data->set.str[STRING_UNIX_SOCKET_PATH]);
3456
5.12k
    if(!conn->unix_domain_socket) {
3457
0
      result = CURLE_OUT_OF_MEMORY;
3458
0
      goto out;
3459
0
    }
3460
5.12k
    conn->bits.abstract_unix_socket = data->set.abstract_unix_socket;
3461
5.12k
  }
3462
129k
#endif
3463
3464
  /* After the Unix socket init but before the proxy vars are used, parse and
3465
     initialize the proxy vars */
3466
129k
#ifndef CURL_DISABLE_PROXY
3467
129k
  result = create_conn_helper_init_proxy(data, conn);
3468
129k
  if(result)
3469
137
    goto out;
3470
3471
  /*************************************************************
3472
   * If the protocol is using SSL and HTTP proxy is used, we set
3473
   * the tunnel_proxy bit.
3474
   *************************************************************/
3475
129k
  if((conn->given->flags&PROTOPT_SSL) && conn->bits.httpproxy)
3476
4.23k
    conn->bits.tunnel_proxy = TRUE;
3477
129k
#endif
3478
3479
  /*************************************************************
3480
   * Figure out the remote port number and fix it in the URL
3481
   *************************************************************/
3482
129k
  result = parse_remote_port(data, conn);
3483
129k
  if(result)
3484
0
    goto out;
3485
3486
  /* Check for overridden login details and set them accordingly so that
3487
     they are known when protocol->setup_connection is called! */
3488
129k
  result = override_login(data, conn);
3489
129k
  if(result)
3490
0
    goto out;
3491
3492
129k
  result = set_login(data, conn); /* default credentials */
3493
129k
  if(result)
3494
0
    goto out;
3495
3496
  /*************************************************************
3497
   * Process the "connect to" linked list of hostname/port mappings.
3498
   * Do this after the remote port number has been fixed in the URL.
3499
   *************************************************************/
3500
129k
  result = parse_connect_to_slist(data, conn, data->set.connect_to);
3501
129k
  if(result)
3502
0
    goto out;
3503
3504
  /*************************************************************
3505
   * IDN-convert the proxy hostnames
3506
   *************************************************************/
3507
129k
#ifndef CURL_DISABLE_PROXY
3508
129k
  if(conn->bits.httpproxy) {
3509
42.7k
    result = Curl_idnconvert_hostname(&conn->http_proxy.host);
3510
42.7k
    if(result)
3511
141
      return result;
3512
42.7k
  }
3513
129k
  if(conn->bits.socksproxy) {
3514
1.29k
    result = Curl_idnconvert_hostname(&conn->socks_proxy.host);
3515
1.29k
    if(result)
3516
38
      return result;
3517
1.29k
  }
3518
129k
#endif
3519
129k
  if(conn->bits.conn_to_host) {
3520
122k
    result = Curl_idnconvert_hostname(&conn->conn_to_host);
3521
122k
    if(result)
3522
0
      return result;
3523
122k
  }
3524
3525
  /*************************************************************
3526
   * Check whether the host and the "connect to host" are equal.
3527
   * Do this after the hostnames have been IDN-converted.
3528
   *************************************************************/
3529
129k
  if(conn->bits.conn_to_host &&
3530
122k
     curl_strequal(conn->conn_to_host.name, conn->host.name)) {
3531
1.30k
    conn->bits.conn_to_host = FALSE;
3532
1.30k
  }
3533
3534
  /*************************************************************
3535
   * Check whether the port and the "connect to port" are equal.
3536
   * Do this after the remote port number has been fixed in the URL.
3537
   *************************************************************/
3538
129k
  if(conn->bits.conn_to_port && conn->conn_to_port == conn->remote_port) {
3539
0
    conn->bits.conn_to_port = FALSE;
3540
0
  }
3541
3542
129k
#ifndef CURL_DISABLE_PROXY
3543
  /*************************************************************
3544
   * If the "connect to" feature is used with an HTTP proxy,
3545
   * we set the tunnel_proxy bit.
3546
   *************************************************************/
3547
129k
  if((conn->bits.conn_to_host || conn->bits.conn_to_port) &&
3548
120k
      conn->bits.httpproxy)
3549
41.3k
    conn->bits.tunnel_proxy = TRUE;
3550
129k
#endif
3551
3552
  /*************************************************************
3553
   * Setup internals depending on protocol. Needs to be done after
3554
   * we figured out what/if proxy to use.
3555
   *************************************************************/
3556
129k
  result = setup_connection_internals(data, conn);
3557
129k
  if(result)
3558
419
    goto out;
3559
3560
  /***********************************************************************
3561
   * file: is a special case in that it does not need a network connection
3562
   ***********************************************************************/
3563
128k
#ifndef CURL_DISABLE_FILE
3564
128k
  if(conn->handler->flags & PROTOPT_NONETWORK) {
3565
1.72k
    bool done;
3566
    /* this is supposed to be the connect function so we better at least check
3567
       that the file is present here! */
3568
1.72k
    DEBUGASSERT(conn->handler->connect_it);
3569
1.72k
    data->info.conn_scheme = conn->handler->scheme;
3570
    /* conn_protocol can only provide "old" protocols */
3571
1.72k
    data->info.conn_protocol = (conn->handler->protocol) & CURLPROTO_MASK;
3572
1.72k
    result = conn->handler->connect_it(data, &done);
3573
1.72k
    if(result)
3574
250
      goto out;
3575
3576
    /* Setup a "faked" transfer that will do nothing */
3577
1.47k
    Curl_attach_connection(data, conn);
3578
1.47k
    result = Curl_cpool_add(data, conn);
3579
1.47k
    if(!result) {
3580
      /* Setup whatever necessary for a resumed transfer */
3581
1.47k
      result = setup_range(data);
3582
1.47k
      if(!result) {
3583
1.47k
        Curl_xfer_setup_nop(data);
3584
1.47k
        result = Curl_init_do(data, conn);
3585
1.47k
      }
3586
1.47k
    }
3587
3588
1.47k
    if(result) {
3589
0
      DEBUGASSERT(conn->handler->done);
3590
      /* we ignore the return code for the protocol-specific DONE */
3591
0
      (void)conn->handler->done(data, result, FALSE);
3592
0
    }
3593
1.47k
    goto out;
3594
1.47k
  }
3595
127k
#endif
3596
3597
  /* Setup filter for network connections */
3598
127k
  conn->recv[FIRSTSOCKET] = Curl_cf_recv;
3599
127k
  conn->send[FIRSTSOCKET] = Curl_cf_send;
3600
127k
  conn->recv[SECONDARYSOCKET] = Curl_cf_recv;
3601
127k
  conn->send[SECONDARYSOCKET] = Curl_cf_send;
3602
127k
  conn->bits.tcp_fastopen = data->set.tcp_fastopen;
3603
3604
  /* Complete the easy's SSL configuration for connection cache matching */
3605
127k
  result = Curl_ssl_easy_config_complete(data);
3606
127k
  if(result)
3607
0
    goto out;
3608
3609
127k
  Curl_cpool_prune_dead(data);
3610
3611
  /*************************************************************
3612
   * Check the current list of connections to see if we can
3613
   * reuse an already existing one or if we have to create a
3614
   * new one.
3615
   *************************************************************/
3616
3617
127k
  DEBUGASSERT(conn->user);
3618
127k
  DEBUGASSERT(conn->passwd);
3619
3620
  /* reuse_fresh is TRUE if we are told to use a new connection by force, but
3621
     we only acknowledge this option if this is not a reused connection
3622
     already (which happens due to follow-location or during an HTTP
3623
     authentication phase). CONNECT_ONLY transfers also refuse reuse. */
3624
127k
  if((data->set.reuse_fresh && !data->state.followlocation) ||
3625
126k
     data->set.connect_only)
3626
14.1k
    reuse = FALSE;
3627
112k
  else
3628
112k
    reuse = ConnectionExists(data, conn, &existing, &force_reuse, &waitpipe);
3629
3630
127k
  if(reuse) {
3631
    /*
3632
     * We already have a connection for this, we got the former connection in
3633
     * `existing` and thus we need to cleanup the one we just
3634
     * allocated before we can move along and use `existing`.
3635
     */
3636
13.3k
    bool tls_upgraded = (!(conn->given->flags & PROTOPT_SSL) &&
3637
13.3k
                         Curl_conn_is_ssl(conn, FIRSTSOCKET));
3638
3639
13.3k
    reuse_conn(data, conn, existing);
3640
13.3k
    conn = existing;
3641
13.3k
    *in_connect = conn;
3642
3643
13.3k
#ifndef CURL_DISABLE_PROXY
3644
13.3k
    infof(data, "Reusing existing %s: connection%s with %s %s",
3645
13.3k
          conn->given->scheme,
3646
13.3k
          tls_upgraded ? " (upgraded to SSL)" : "",
3647
13.3k
          conn->bits.proxy ? "proxy" : "host",
3648
13.3k
          conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname :
3649
13.3k
          conn->http_proxy.host.name ? conn->http_proxy.host.dispname :
3650
13.3k
          conn->host.dispname);
3651
#else
3652
    infof(data, "Reusing existing %s: connection%s with host %s",
3653
          conn->given->scheme,
3654
          tls_upgraded ? " (upgraded to SSL)" : "",
3655
          conn->host.dispname);
3656
#endif
3657
13.3k
  }
3658
113k
  else {
3659
    /* We have decided that we want a new connection. However, we may not
3660
       be able to do that if we have reached the limit of how many
3661
       connections we are allowed to open. */
3662
3663
113k
    if(conn->handler->flags & PROTOPT_ALPN) {
3664
      /* The protocol wants it, so set the bits if enabled in the easy handle
3665
         (default) */
3666
12.6k
      if(data->set.ssl_enable_alpn)
3667
12.6k
        conn->bits.tls_enable_alpn = TRUE;
3668
12.6k
    }
3669
3670
113k
    if(waitpipe) {
3671
      /* There is a connection that *might* become usable for multiplexing
3672
         "soon", and we wait for that */
3673
2.74k
      infof(data, "Waiting on connection to negotiate possible multiplexing.");
3674
2.74k
      connections_available = FALSE;
3675
2.74k
    }
3676
111k
    else {
3677
111k
      switch(Curl_cpool_check_limits(data, conn)) {
3678
0
      case CPOOL_LIMIT_DEST:
3679
0
        infof(data, "No more connections allowed to host");
3680
0
        connections_available = FALSE;
3681
0
        break;
3682
0
      case CPOOL_LIMIT_TOTAL:
3683
0
        if(data->master_mid != UINT_MAX)
3684
0
          CURL_TRC_M(data, "Allowing sub-requests (like DoH) to override "
3685
0
                     "max connection limit");
3686
0
        else {
3687
0
          infof(data, "No connections available, total of %ld reached.",
3688
0
                data->multi->max_total_connections);
3689
0
          connections_available = FALSE;
3690
0
        }
3691
0
        break;
3692
111k
      default:
3693
111k
        break;
3694
111k
      }
3695
111k
    }
3696
3697
113k
    if(!connections_available) {
3698
2.74k
      Curl_conn_free(data, conn);
3699
2.74k
      *in_connect = NULL;
3700
3701
2.74k
      result = CURLE_NO_CONNECTION_AVAILABLE;
3702
2.74k
      goto out;
3703
2.74k
    }
3704
111k
    else {
3705
      /*
3706
       * This is a brand new connection, so let's store it in the connection
3707
       * cache of ours!
3708
       */
3709
111k
      result = Curl_ssl_conn_config_init(data, conn);
3710
111k
      if(result) {
3711
0
        DEBUGF(curl_mfprintf(stderr, "Error: init connection ssl config\n"));
3712
0
        goto out;
3713
0
      }
3714
3715
111k
      Curl_attach_connection(data, conn);
3716
111k
      result = Curl_cpool_add(data, conn);
3717
111k
      if(result)
3718
0
        goto out;
3719
111k
    }
3720
3721
111k
#ifdef USE_NTLM
3722
    /* If NTLM is requested in a part of this connection, make sure we do not
3723
       assume the state is fine as this is a fresh connection and NTLM is
3724
       connection based. */
3725
111k
    if((data->state.authhost.picked & CURLAUTH_NTLM) &&
3726
565
       data->state.authhost.done) {
3727
36
      infof(data, "NTLM picked AND auth done set, clear picked");
3728
36
      data->state.authhost.picked = CURLAUTH_NONE;
3729
36
      data->state.authhost.done = FALSE;
3730
36
    }
3731
3732
111k
    if((data->state.authproxy.picked & CURLAUTH_NTLM) &&
3733
184
       data->state.authproxy.done) {
3734
39
      infof(data, "NTLM-proxy picked AND auth done set, clear picked");
3735
39
      data->state.authproxy.picked = CURLAUTH_NONE;
3736
39
      data->state.authproxy.done = FALSE;
3737
39
    }
3738
111k
#endif
3739
111k
  }
3740
3741
  /* Setup and init stuff before DO starts, in preparing for the transfer. */
3742
124k
  result = Curl_init_do(data, conn);
3743
124k
  if(result)
3744
0
    goto out;
3745
3746
  /*
3747
   * Setup whatever necessary for a resumed transfer
3748
   */
3749
124k
  result = setup_range(data);
3750
124k
  if(result)
3751
0
    goto out;
3752
3753
  /* Continue connectdata initialization here. */
3754
3755
124k
  if(conn->bits.reuse) {
3756
    /* We are reusing the connection - no need to resolve anything, and
3757
       idnconvert_hostname() was called already in create_conn() for the reuse
3758
       case. */
3759
13.3k
    *reusedp = TRUE;
3760
13.3k
  }
3761
3762
  /* persist the scheme and handler the transfer is using */
3763
124k
  data->info.conn_scheme = conn->handler->scheme;
3764
  /* conn_protocol can only provide "old" protocols */
3765
124k
  data->info.conn_protocol = (conn->handler->protocol) & CURLPROTO_MASK;
3766
124k
  data->info.used_proxy =
3767
#ifdef CURL_DISABLE_PROXY
3768
    0
3769
#else
3770
124k
    conn->bits.proxy
3771
124k
#endif
3772
124k
    ;
3773
3774
  /* Everything general done, inform filters that they need
3775
   * to prepare for a data transfer. */
3776
124k
  result = Curl_conn_ev_data_setup(data);
3777
3778
148k
out:
3779
148k
  return result;
3780
124k
}
3781
3782
/* Curl_setup_conn() is called after the name resolve initiated in
3783
 * create_conn() is all done.
3784
 *
3785
 * Curl_setup_conn() also handles reused connections
3786
 */
3787
CURLcode Curl_setup_conn(struct Curl_easy *data,
3788
                         struct Curl_dns_entry *dns,
3789
                         bool *protocol_done)
3790
102k
{
3791
102k
  CURLcode result = CURLE_OK;
3792
102k
  struct connectdata *conn = data->conn;
3793
3794
102k
  DEBUGASSERT(dns);
3795
102k
  Curl_pgrsTime(data, TIMER_NAMELOOKUP);
3796
3797
102k
  if(!conn->bits.reuse)
3798
102k
    result = Curl_conn_setup(data, conn, FIRSTSOCKET, dns,
3799
102k
                             CURL_CF_SSL_DEFAULT);
3800
102k
  if(!result)
3801
102k
    result = Curl_headers_init(data);
3802
3803
  /* not sure we need this flag to be passed around any more */
3804
102k
  *protocol_done = FALSE;
3805
102k
  return result;
3806
102k
}
3807
3808
CURLcode Curl_connect(struct Curl_easy *data,
3809
                      bool *asyncp,
3810
                      bool *protocol_done)
3811
148k
{
3812
148k
  CURLcode result;
3813
148k
  struct connectdata *conn;
3814
148k
  bool reused = FALSE;
3815
3816
148k
  *asyncp = FALSE; /* assume synchronous resolves by default */
3817
148k
  *protocol_done = FALSE;
3818
3819
  /* Set the request to virgin state based on transfer settings */
3820
148k
  Curl_req_hard_reset(&data->req, data);
3821
3822
  /* call the stuff that needs to be called */
3823
148k
  result = create_conn(data, &conn, &reused);
3824
3825
148k
  if(result == CURLE_NO_CONNECTION_AVAILABLE) {
3826
2.74k
    DEBUGASSERT(!conn);
3827
2.74k
    return result;
3828
2.74k
  }
3829
3830
145k
  if(!result) {
3831
125k
    DEBUGASSERT(conn);
3832
125k
    if(reused) {
3833
13.3k
      if(CONN_ATTACHED(conn) > 1)
3834
        /* multiplexed */
3835
0
        *protocol_done = TRUE;
3836
13.3k
    }
3837
112k
    else if(conn->handler->flags & PROTOPT_NONETWORK) {
3838
1.47k
      *asyncp = FALSE;
3839
1.47k
      Curl_pgrsTime(data, TIMER_NAMELOOKUP);
3840
1.47k
      *protocol_done = TRUE;
3841
1.47k
    }
3842
111k
    else {
3843
      /*************************************************************
3844
       * Resolve the address of the server or proxy
3845
       *************************************************************/
3846
111k
      struct Curl_dns_entry *dns;
3847
111k
      result = resolve_server(data, conn, asyncp, &dns);
3848
111k
      if(!result) {
3849
109k
        *asyncp = !dns;
3850
109k
        if(dns)
3851
          /* DNS resolution is done: that is either because this is a reused
3852
             connection, in which case DNS was unnecessary, or because DNS
3853
             really did finish already (synch resolver/fast async resolve) */
3854
102k
          result = Curl_setup_conn(data, dns, protocol_done);
3855
109k
      }
3856
111k
    }
3857
125k
  }
3858
3859
145k
  if(result && conn) {
3860
    /* We are not allowed to return failure with memory left allocated in the
3861
       connectdata struct, free those here */
3862
21.1k
    Curl_detach_connection(data);
3863
21.1k
    Curl_conn_terminate(data, conn, TRUE);
3864
21.1k
  }
3865
3866
145k
  return result;
3867
145k
}
3868
3869
/*
3870
 * Curl_init_do() inits the readwrite session. This is inited each time (in
3871
 * the DO function before the protocol-specific DO functions are invoked) for
3872
 * a transfer, sometimes multiple times on the same Curl_easy. Make sure
3873
 * nothing in here depends on stuff that are setup dynamically for the
3874
 * transfer.
3875
 *
3876
 * Allow this function to get called with 'conn' set to NULL.
3877
 */
3878
3879
CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
3880
125k
{
3881
  /* if this is a pushed stream, we need this: */
3882
125k
  CURLcode result;
3883
3884
125k
  if(conn) {
3885
125k
    conn->bits.do_more = FALSE; /* by default there is no curl_do_more() to
3886
                                   use */
3887
    /* if the protocol used does not support wildcards, switch it off */
3888
125k
    if(data->state.wildcardmatch &&
3889
552
       !(conn->handler->flags & PROTOPT_WILDCARD))
3890
46
      data->state.wildcardmatch = FALSE;
3891
125k
  }
3892
3893
125k
  data->state.done = FALSE; /* *_done() is not called yet */
3894
3895
125k
  if(data->req.no_body)
3896
    /* in HTTP lingo, no body means using the HEAD request... */
3897
1.94k
    data->state.httpreq = HTTPREQ_HEAD;
3898
3899
125k
  result = Curl_req_start(&data->req, data);
3900
125k
  if(!result) {
3901
125k
    Curl_speedinit(data);
3902
125k
    Curl_pgrsSetUploadCounter(data, 0);
3903
125k
    Curl_pgrsSetDownloadCounter(data, 0);
3904
125k
  }
3905
125k
  return result;
3906
125k
}
3907
3908
#if defined(USE_HTTP2) || defined(USE_HTTP3)
3909
3910
#ifdef USE_NGHTTP2
3911
3912
static void priority_remove_child(struct Curl_easy *parent,
3913
                                  struct Curl_easy *child)
3914
0
{
3915
0
  struct Curl_data_prio_node **pnext = &parent->set.priority.children;
3916
0
  struct Curl_data_prio_node *pnode = parent->set.priority.children;
3917
3918
0
  DEBUGASSERT(child->set.priority.parent == parent);
3919
0
  while(pnode && pnode->data != child) {
3920
0
    pnext = &pnode->next;
3921
0
    pnode = pnode->next;
3922
0
  }
3923
3924
0
  DEBUGASSERT(pnode);
3925
0
  if(pnode) {
3926
0
    *pnext = pnode->next;
3927
0
    free(pnode);
3928
0
  }
3929
3930
0
  child->set.priority.parent = 0;
3931
0
  child->set.priority.exclusive = FALSE;
3932
0
}
3933
3934
CURLcode Curl_data_priority_add_child(struct Curl_easy *parent,
3935
                                      struct Curl_easy *child,
3936
                                      bool exclusive)
3937
0
{
3938
0
  if(child->set.priority.parent) {
3939
0
    priority_remove_child(child->set.priority.parent, child);
3940
0
  }
3941
3942
0
  if(parent) {
3943
0
    struct Curl_data_prio_node **tail;
3944
0
    struct Curl_data_prio_node *pnode;
3945
3946
0
    pnode = calloc(1, sizeof(*pnode));
3947
0
    if(!pnode)
3948
0
      return CURLE_OUT_OF_MEMORY;
3949
0
    pnode->data = child;
3950
3951
0
    if(parent->set.priority.children && exclusive) {
3952
      /* exclusive: move all existing children underneath the new child */
3953
0
      struct Curl_data_prio_node *node = parent->set.priority.children;
3954
0
      while(node) {
3955
0
        node->data->set.priority.parent = child;
3956
0
        node = node->next;
3957
0
      }
3958
3959
0
      tail = &child->set.priority.children;
3960
0
      while(*tail)
3961
0
        tail = &(*tail)->next;
3962
3963
0
      DEBUGASSERT(!*tail);
3964
0
      *tail = parent->set.priority.children;
3965
0
      parent->set.priority.children = 0;
3966
0
    }
3967
3968
0
    tail = &parent->set.priority.children;
3969
0
    while(*tail) {
3970
0
      (*tail)->data->set.priority.exclusive = FALSE;
3971
0
      tail = &(*tail)->next;
3972
0
    }
3973
3974
0
    DEBUGASSERT(!*tail);
3975
0
    *tail = pnode;
3976
0
  }
3977
3978
0
  child->set.priority.parent = parent;
3979
0
  child->set.priority.exclusive = exclusive;
3980
0
  return CURLE_OK;
3981
0
}
3982
3983
#endif /* USE_NGHTTP2 */
3984
3985
#ifdef USE_NGHTTP2
3986
static void data_priority_cleanup(struct Curl_easy *data)
3987
360k
{
3988
360k
  while(data->set.priority.children) {
3989
0
    struct Curl_easy *tmp = data->set.priority.children->data;
3990
0
    priority_remove_child(data, tmp);
3991
0
    if(data->set.priority.parent)
3992
0
      Curl_data_priority_add_child(data->set.priority.parent, tmp, FALSE);
3993
0
  }
3994
3995
360k
  if(data->set.priority.parent)
3996
0
    priority_remove_child(data->set.priority.parent, data);
3997
360k
}
3998
#endif
3999
4000
void Curl_data_priority_clear_state(struct Curl_easy *data)
4001
130k
{
4002
130k
  memset(&data->state.priority, 0, sizeof(data->state.priority));
4003
130k
}
4004
4005
#endif /* USE_HTTP2 || USE_HTTP3 */
4006
4007
4008
CURLcode Curl_conn_meta_set(struct connectdata *conn, const char *key,
4009
                            void *meta_data, Curl_meta_dtor *meta_dtor)
4010
60.4k
{
4011
60.4k
  if(!Curl_hash_add2(&conn->meta_hash, CURL_UNCONST(key), strlen(key) + 1,
4012
60.4k
                     meta_data, meta_dtor)) {
4013
0
    meta_dtor(CURL_UNCONST(key), strlen(key) + 1, meta_data);
4014
0
    return CURLE_OUT_OF_MEMORY;
4015
0
  }
4016
60.4k
  return CURLE_OK;
4017
60.4k
}
4018
4019
void Curl_conn_meta_remove(struct connectdata *conn, const char *key)
4020
132k
{
4021
132k
  Curl_hash_delete(&conn->meta_hash, CURL_UNCONST(key), strlen(key) + 1);
4022
132k
}
4023
4024
void *Curl_conn_meta_get(struct connectdata *conn, const char *key)
4025
50.5M
{
4026
50.5M
  return Curl_hash_pick(&conn->meta_hash, CURL_UNCONST(key), strlen(key) + 1);
4027
50.5M
}
4028
4029
CURLcode Curl_1st_err(CURLcode r1, CURLcode r2)
4030
138k
{
4031
138k
  return r1 ? r1 : r2;
4032
138k
}
4033
4034
CURLcode Curl_1st_fatal(CURLcode r1, CURLcode r2)
4035
0
{
4036
0
  if(r1 && (r1 != CURLE_AGAIN))
4037
0
    return r1;
4038
0
  if(r2 && (r2 != CURLE_AGAIN))
4039
0
    return r2;
4040
0
  return r1;
4041
0
}