Coverage Report

Created: 2025-10-10 06:31

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