Coverage Report

Created: 2026-03-12 06:35

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