Coverage Report

Created: 2025-10-13 06:59

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
    /* If the protocol does not allow reuse of SSL connections OR
942
       is of another protocol family, not a match. */
943
0
    if(!(m->needle->handler->flags & PROTOPT_SSL_REUSE) ||
944
0
       (get_protocol_family(conn->handler) != m->needle->handler->protocol))
945
0
      return FALSE;
946
0
  }
947
0
  return TRUE;
948
0
}
949
950
#ifndef CURL_DISABLE_PROXY
951
static bool url_match_proxy_use(struct connectdata *conn,
952
                                struct url_conn_match *m)
953
0
{
954
0
  if(m->needle->bits.httpproxy != conn->bits.httpproxy ||
955
0
     m->needle->bits.socksproxy != conn->bits.socksproxy)
956
0
    return FALSE;
957
958
0
  if(m->needle->bits.socksproxy &&
959
0
    !socks_proxy_info_matches(&m->needle->socks_proxy,
960
0
                              &conn->socks_proxy))
961
0
    return FALSE;
962
963
0
  if(m->needle->bits.httpproxy) {
964
0
    if(m->needle->bits.tunnel_proxy != conn->bits.tunnel_proxy)
965
0
      return FALSE;
966
967
0
    if(!proxy_info_matches(&m->needle->http_proxy, &conn->http_proxy))
968
0
      return FALSE;
969
970
0
    if(IS_HTTPS_PROXY(m->needle->http_proxy.proxytype)) {
971
      /* https proxies come in different types, http/1.1, h2, ... */
972
0
      if(m->needle->http_proxy.proxytype != conn->http_proxy.proxytype)
973
0
        return FALSE;
974
      /* match SSL config to proxy */
975
0
      if(!Curl_ssl_conn_config_match(m->data, conn, TRUE)) {
976
0
        DEBUGF(infof(m->data,
977
0
          "Connection #%" FMT_OFF_T
978
0
          " has different SSL proxy parameters, cannot reuse",
979
0
          conn->connection_id));
980
0
        return FALSE;
981
0
      }
982
      /* the SSL config to the server, which may apply here is checked
983
       * further below */
984
0
    }
985
0
  }
986
0
  return TRUE;
987
0
}
988
#else
989
#define url_match_proxy_use(c,m)    ((void)c, (void)m, TRUE)
990
#endif
991
992
#ifndef CURL_DISABLE_HTTP
993
static bool url_match_http_multiplex(struct connectdata *conn,
994
                                     struct url_conn_match *m)
995
0
{
996
0
  if(m->may_multiplex &&
997
0
     (m->data->state.http_neg.allowed & (CURL_HTTP_V2x|CURL_HTTP_V3x)) &&
998
0
     (m->needle->handler->protocol & CURLPROTO_HTTP) &&
999
0
     !conn->httpversion_seen) {
1000
0
    if(m->data->set.pipewait) {
1001
0
      infof(m->data, "Server upgrade does not support multiplex yet, wait");
1002
0
      m->found = NULL;
1003
0
      m->wait_pipe = TRUE;
1004
0
      return TRUE; /* stop searching, we want to wait */
1005
0
    }
1006
0
    infof(m->data, "Server upgrade cannot be used");
1007
0
    return FALSE;
1008
0
  }
1009
0
  return TRUE;
1010
0
}
1011
1012
static bool url_match_http_version(struct connectdata *conn,
1013
                                   struct url_conn_match *m)
1014
0
{
1015
  /* If looking for HTTP and the HTTP versions allowed do not include
1016
   * the HTTP version of conn, continue looking. */
1017
0
  if((m->needle->handler->protocol & PROTO_FAMILY_HTTP)) {
1018
0
    switch(Curl_conn_http_version(m->data, conn)) {
1019
0
    case 30:
1020
0
      if(!(m->data->state.http_neg.allowed & CURL_HTTP_V3x)) {
1021
0
        DEBUGF(infof(m->data, "not reusing conn #%" CURL_FORMAT_CURL_OFF_T
1022
0
               ", we do not want h3", conn->connection_id));
1023
0
        return FALSE;
1024
0
      }
1025
0
      break;
1026
0
    case 20:
1027
0
      if(!(m->data->state.http_neg.allowed & CURL_HTTP_V2x)) {
1028
0
        DEBUGF(infof(m->data, "not reusing conn #%" CURL_FORMAT_CURL_OFF_T
1029
0
               ", we do not want h2", conn->connection_id));
1030
0
        return FALSE;
1031
0
      }
1032
0
      break;
1033
0
    default:
1034
0
      if(!(m->data->state.http_neg.allowed & CURL_HTTP_V1x)) {
1035
0
        DEBUGF(infof(m->data, "not reusing conn #%" CURL_FORMAT_CURL_OFF_T
1036
0
               ", we do not want h1", conn->connection_id));
1037
0
        return FALSE;
1038
0
      }
1039
0
      break;
1040
0
    }
1041
0
  }
1042
0
  return TRUE;
1043
0
}
1044
#else
1045
#define url_match_http_multiplex(c,m)    ((void)c, (void)m, TRUE)
1046
#define url_match_http_version(c,m)      ((void)c, (void)m, TRUE)
1047
#endif
1048
1049
static bool url_match_proto_config(struct connectdata *conn,
1050
                                   struct url_conn_match *m)
1051
0
{
1052
0
  if(!url_match_http_version(conn, m))
1053
0
    return FALSE;
1054
1055
#ifdef USE_SSH
1056
  if(get_protocol_family(m->needle->handler) & PROTO_FAMILY_SSH) {
1057
    if(!ssh_config_matches(m->needle, conn))
1058
      return FALSE;
1059
  }
1060
#endif
1061
0
#ifndef CURL_DISABLE_FTP
1062
0
  else if(get_protocol_family(m->needle->handler) & PROTO_FAMILY_FTP) {
1063
0
    if(!ftp_conns_match(m->needle, conn))
1064
0
      return FALSE;
1065
0
  }
1066
0
#endif
1067
0
  return TRUE;
1068
0
}
1069
1070
static bool url_match_auth(struct connectdata *conn,
1071
                           struct url_conn_match *m)
1072
0
{
1073
0
  if(!(m->needle->handler->flags & PROTOPT_CREDSPERREQUEST)) {
1074
    /* This protocol requires credentials per connection,
1075
       so verify that we are using the same name and password as well */
1076
0
    if(Curl_timestrcmp(m->needle->user, conn->user) ||
1077
0
       Curl_timestrcmp(m->needle->passwd, conn->passwd) ||
1078
0
       Curl_timestrcmp(m->needle->sasl_authzid, conn->sasl_authzid) ||
1079
0
       Curl_timestrcmp(m->needle->oauth_bearer, conn->oauth_bearer)) {
1080
      /* one of them was different */
1081
0
      return FALSE;
1082
0
    }
1083
0
  }
1084
#ifdef HAVE_GSSAPI
1085
  /* GSS delegation differences do not actually affect every connection
1086
     and auth method, but this check takes precaution before efficiency */
1087
  if(m->needle->gssapi_delegation != conn->gssapi_delegation)
1088
    return FALSE;
1089
#endif
1090
1091
0
  return TRUE;
1092
0
}
1093
1094
static bool url_match_destination(struct connectdata *conn,
1095
                                  struct url_conn_match *m)
1096
0
{
1097
  /* Additional match requirements if talking TLS OR
1098
   * not talking to an HTTP proxy OR using a tunnel through a proxy */
1099
0
  if((m->needle->handler->flags&PROTOPT_SSL)
1100
0
#ifndef CURL_DISABLE_PROXY
1101
0
     || !m->needle->bits.httpproxy || m->needle->bits.tunnel_proxy
1102
0
#endif
1103
0
    ) {
1104
0
    if(!curl_strequal(m->needle->handler->scheme, conn->handler->scheme)) {
1105
      /* `needle` and `conn` do not have the same scheme... */
1106
0
      if(get_protocol_family(conn->handler) != m->needle->handler->protocol) {
1107
        /* and `conn`s protocol family is not the protocol `needle` wants.
1108
         * IMAPS would work for IMAP, but no vice versa. */
1109
0
        return FALSE;
1110
0
      }
1111
      /* We are in an IMAPS vs IMAP like case. We expect `conn` to have SSL */
1112
0
      if(!Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
1113
0
        DEBUGF(infof(m->data,
1114
0
          "Connection #%" FMT_OFF_T " has compatible protocol family, "
1115
0
          "but no SSL, no match", conn->connection_id));
1116
0
        return FALSE;
1117
0
      }
1118
0
    }
1119
1120
    /* If needle has "conn_to_*" set, conn must match this */
1121
0
    if((m->needle->bits.conn_to_host && !curl_strequal(
1122
0
        m->needle->conn_to_host.name, conn->conn_to_host.name)) ||
1123
0
       (m->needle->bits.conn_to_port &&
1124
0
         m->needle->conn_to_port != conn->conn_to_port))
1125
0
      return FALSE;
1126
1127
    /* hostname and port must match */
1128
0
    if(!curl_strequal(m->needle->host.name, conn->host.name) ||
1129
0
       m->needle->remote_port != conn->remote_port)
1130
0
      return FALSE;
1131
0
  }
1132
0
  return TRUE;
1133
0
}
1134
1135
static bool url_match_ssl_config(struct connectdata *conn,
1136
                                 struct url_conn_match *m)
1137
0
{
1138
  /* If talking TLS, conn needs to use the same SSL options. */
1139
0
  if((m->needle->handler->flags & PROTOPT_SSL) &&
1140
0
     !Curl_ssl_conn_config_match(m->data, conn, FALSE)) {
1141
0
    DEBUGF(infof(m->data,
1142
0
                 "Connection #%" FMT_OFF_T
1143
0
                 " has different SSL parameters, cannot reuse",
1144
0
                 conn->connection_id));
1145
0
    return FALSE;
1146
0
  }
1147
0
  return TRUE;
1148
0
}
1149
1150
#ifdef USE_NTLM
1151
static bool url_match_auth_ntlm(struct connectdata *conn,
1152
                                struct url_conn_match *m)
1153
0
{
1154
  /* If we are looking for an HTTP+NTLM connection, check if this is
1155
     already authenticating with the right credentials. If not, keep
1156
     looking so that we can reuse NTLM connections if
1157
     possible. (Especially we must not reuse the same connection if
1158
     partway through a handshake!) */
1159
0
  if(m->want_ntlm_http) {
1160
0
    if(Curl_timestrcmp(m->needle->user, conn->user) ||
1161
0
       Curl_timestrcmp(m->needle->passwd, conn->passwd)) {
1162
1163
      /* we prefer a credential match, but this is at least a connection
1164
         that can be reused and "upgraded" to NTLM */
1165
0
      if(conn->http_ntlm_state == NTLMSTATE_NONE)
1166
0
        m->found = conn;
1167
0
      return FALSE;
1168
0
    }
1169
0
  }
1170
0
  else if(conn->http_ntlm_state != NTLMSTATE_NONE) {
1171
    /* Connection is using NTLM auth but we do not want NTLM */
1172
0
    return FALSE;
1173
0
  }
1174
1175
0
#ifndef CURL_DISABLE_PROXY
1176
  /* Same for Proxy NTLM authentication */
1177
0
  if(m->want_proxy_ntlm_http) {
1178
    /* Both conn->http_proxy.user and conn->http_proxy.passwd can be
1179
     * NULL */
1180
0
    if(!conn->http_proxy.user || !conn->http_proxy.passwd)
1181
0
      return FALSE;
1182
1183
0
    if(Curl_timestrcmp(m->needle->http_proxy.user,
1184
0
                       conn->http_proxy.user) ||
1185
0
       Curl_timestrcmp(m->needle->http_proxy.passwd,
1186
0
                       conn->http_proxy.passwd))
1187
0
      return FALSE;
1188
0
  }
1189
0
  else if(conn->proxy_ntlm_state != NTLMSTATE_NONE) {
1190
    /* Proxy connection is using NTLM auth but we do not want NTLM */
1191
0
    return FALSE;
1192
0
  }
1193
0
#endif
1194
0
  if(m->want_ntlm_http || m->want_proxy_ntlm_http) {
1195
    /* Credentials are already checked, we may use this connection.
1196
     * With NTLM being weird as it is, we MUST use a
1197
     * connection where it has already been fully negotiated.
1198
     * If it has not, we keep on looking for a better one. */
1199
0
    m->found = conn;
1200
1201
0
    if((m->want_ntlm_http &&
1202
0
       (conn->http_ntlm_state != NTLMSTATE_NONE)) ||
1203
0
        (m->want_proxy_ntlm_http &&
1204
0
         (conn->proxy_ntlm_state != NTLMSTATE_NONE))) {
1205
      /* We must use this connection, no other */
1206
0
      m->force_reuse = TRUE;
1207
0
      return TRUE;
1208
0
    }
1209
    /* Continue look up for a better connection */
1210
0
    return FALSE;
1211
0
  }
1212
0
  return TRUE;
1213
0
}
1214
#else
1215
#define url_match_auth_ntlm(c,m)    ((void)c, (void)m, TRUE)
1216
#endif
1217
1218
static bool url_match_conn(struct connectdata *conn, void *userdata)
1219
0
{
1220
0
  struct url_conn_match *m = userdata;
1221
  /* Check if `conn` can be used for transfer `m->data` */
1222
1223
  /* general connect config setting match? */
1224
0
  if(!url_match_connect_config(conn, m))
1225
0
    return FALSE;
1226
1227
  /* match for destination and protocol? */
1228
0
  if(!url_match_destination(conn, m))
1229
0
    return FALSE;
1230
1231
0
  if(!url_match_fully_connected(conn, m))
1232
0
    return FALSE;
1233
1234
0
  if(!url_match_multiplex_needs(conn, m))
1235
0
    return FALSE;
1236
1237
0
  if(!url_match_ssl_use(conn, m))
1238
0
    return FALSE;
1239
0
  if(!url_match_proxy_use(conn, m))
1240
0
    return FALSE;
1241
0
  if(!url_match_ssl_config(conn, m))
1242
0
    return FALSE;
1243
1244
0
  if(!url_match_http_multiplex(conn, m))
1245
0
    return FALSE;
1246
0
  else if(m->wait_pipe)
1247
    /* we decided to wait on PIPELINING */
1248
0
    return TRUE;
1249
1250
0
  if(!url_match_auth(conn, m))
1251
0
    return FALSE;
1252
1253
0
  if(!url_match_proto_config(conn, m))
1254
0
    return FALSE;
1255
1256
0
  if(!url_match_auth_ntlm(conn, m))
1257
0
    return FALSE;
1258
0
  else if(m->force_reuse)
1259
0
    return TRUE;
1260
1261
0
  if(!url_match_multiplex_limits(conn, m))
1262
0
    return FALSE;
1263
1264
0
  if(!CONN_INUSE(conn) && Curl_conn_seems_dead(conn, m->data, NULL)) {
1265
    /* remove and disconnect. */
1266
0
    Curl_conn_terminate(m->data, conn, FALSE);
1267
0
    return FALSE;
1268
0
  }
1269
1270
  /* conn matches our needs. */
1271
0
  m->found = conn;
1272
0
  return TRUE;
1273
0
}
1274
1275
static bool url_match_result(bool result, void *userdata)
1276
0
{
1277
0
  struct url_conn_match *match = userdata;
1278
0
  (void)result;
1279
0
  if(match->found) {
1280
    /* Attach it now while still under lock, so the connection does
1281
     * no longer appear idle and can be reaped. */
1282
0
    Curl_attach_connection(match->data, match->found);
1283
0
    return TRUE;
1284
0
  }
1285
0
  else if(match->seen_single_use_conn && !match->seen_multiplex_conn) {
1286
    /* We've seen a single-use, existing connection to the destination and
1287
     * no multiplexed one. It seems safe to assume that the server does
1288
     * not support multiplexing. */
1289
0
    match->wait_pipe = FALSE;
1290
0
  }
1291
0
  else if(match->seen_pending_conn && match->data->set.pipewait) {
1292
0
    infof(match->data,
1293
0
          "Found pending candidate for reuse and CURLOPT_PIPEWAIT is set");
1294
0
    match->wait_pipe = TRUE;
1295
0
  }
1296
0
  match->force_reuse = FALSE;
1297
0
  return FALSE;
1298
0
}
1299
1300
/*
1301
 * Given one filled in connection struct (named needle), this function should
1302
 * detect if there already is one that has all the significant details
1303
 * exactly the same and thus should be used instead.
1304
 *
1305
 * If there is a match, this function returns TRUE - and has marked the
1306
 * connection as 'in-use'. It must later be called with ConnectionDone() to
1307
 * return back to 'idle' (unused) state.
1308
 *
1309
 * The force_reuse flag is set if the connection must be used.
1310
 */
1311
static bool
1312
ConnectionExists(struct Curl_easy *data,
1313
                 struct connectdata *needle,
1314
                 struct connectdata **usethis,
1315
                 bool *force_reuse,
1316
                 bool *waitpipe)
1317
0
{
1318
0
  struct url_conn_match match;
1319
0
  bool result;
1320
1321
0
  memset(&match, 0, sizeof(match));
1322
0
  match.data = data;
1323
0
  match.needle = needle;
1324
0
  match.may_multiplex = xfer_may_multiplex(data, needle);
1325
1326
0
#ifdef USE_NTLM
1327
0
  match.want_ntlm_http = ((data->state.authhost.want & CURLAUTH_NTLM) &&
1328
0
                          (needle->handler->protocol & PROTO_FAMILY_HTTP));
1329
0
#ifndef CURL_DISABLE_PROXY
1330
0
  match.want_proxy_ntlm_http =
1331
0
    (needle->bits.proxy_user_passwd &&
1332
0
     (data->state.authproxy.want & CURLAUTH_NTLM) &&
1333
0
     (needle->handler->protocol & PROTO_FAMILY_HTTP));
1334
0
#endif
1335
0
#endif
1336
1337
  /* Find a connection in the pool that matches what "data + needle"
1338
   * requires. If a suitable candidate is found, it is attached to "data". */
1339
0
  result = Curl_cpool_find(data, needle->destination,
1340
0
                           url_match_conn, url_match_result, &match);
1341
1342
  /* wait_pipe is TRUE if we encounter a bundle that is undecided. There
1343
   * is no matching connection then, yet. */
1344
0
  *usethis = match.found;
1345
0
  *force_reuse = match.force_reuse;
1346
0
  *waitpipe = match.wait_pipe;
1347
0
  return result;
1348
0
}
1349
1350
/*
1351
 * Allocate and initialize a new connectdata object.
1352
 */
1353
static struct connectdata *allocate_conn(struct Curl_easy *data)
1354
0
{
1355
0
  struct connectdata *conn = calloc(1, sizeof(struct connectdata));
1356
0
  if(!conn)
1357
0
    return NULL;
1358
1359
  /* and we setup a few fields in case we end up actually using this struct */
1360
1361
0
  conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD;     /* no file descriptor */
1362
0
  conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
1363
0
  conn->recv_idx = 0; /* default for receiving transfer data */
1364
0
  conn->send_idx = 0; /* default for sending transfer data */
1365
0
  conn->connection_id = -1;    /* no ID */
1366
0
  conn->remote_port = -1; /* unknown at this point */
1367
1368
  /* Default protocol-independent behavior does not support persistent
1369
     connections, so we set this to force-close. Protocols that support
1370
     this need to set this to FALSE in their "curl_do" functions. */
1371
0
  connclose(conn, "Default to force-close");
1372
1373
  /* Store creation time to help future close decision making */
1374
0
  conn->created = curlx_now();
1375
1376
  /* Store current time to give a baseline to keepalive connection times. */
1377
0
  conn->keepalive = conn->created;
1378
1379
0
#ifndef CURL_DISABLE_PROXY
1380
0
  conn->http_proxy.proxytype = data->set.proxytype;
1381
0
  conn->socks_proxy.proxytype = CURLPROXY_SOCKS4;
1382
1383
  /* note that these two proxy bits are now just on what looks to be
1384
     requested, they may be altered down the road */
1385
0
  conn->bits.proxy = (data->set.str[STRING_PROXY] &&
1386
0
                      *data->set.str[STRING_PROXY]);
1387
0
  conn->bits.httpproxy = (conn->bits.proxy &&
1388
0
                          (conn->http_proxy.proxytype == CURLPROXY_HTTP ||
1389
0
                           conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0 ||
1390
0
                           IS_HTTPS_PROXY(conn->http_proxy.proxytype)));
1391
0
  conn->bits.socksproxy = (conn->bits.proxy && !conn->bits.httpproxy);
1392
1393
0
  if(data->set.str[STRING_PRE_PROXY] && *data->set.str[STRING_PRE_PROXY]) {
1394
0
    conn->bits.proxy = TRUE;
1395
0
    conn->bits.socksproxy = TRUE;
1396
0
  }
1397
1398
0
  conn->bits.proxy_user_passwd = !!data->state.aptr.proxyuser;
1399
0
  conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
1400
0
#endif /* CURL_DISABLE_PROXY */
1401
1402
0
#ifndef CURL_DISABLE_FTP
1403
0
  conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
1404
0
  conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
1405
0
#endif
1406
0
  conn->ip_version = data->set.ipver;
1407
0
  conn->connect_only = data->set.connect_only;
1408
0
  conn->transport_wanted = TRNSPRT_TCP; /* most of them are TCP streams */
1409
1410
  /* Initialize the attached xfers bitset */
1411
0
  Curl_uint_spbset_init(&conn->xfers_attached);
1412
1413
  /* Store the local bind parameters that will be used for this connection */
1414
0
  if(data->set.str[STRING_DEVICE]) {
1415
0
    conn->localdev = strdup(data->set.str[STRING_DEVICE]);
1416
0
    if(!conn->localdev)
1417
0
      goto error;
1418
0
  }
1419
0
#ifndef CURL_DISABLE_BINDLOCAL
1420
0
  conn->localportrange = data->set.localportrange;
1421
0
  conn->localport = data->set.localport;
1422
0
#endif
1423
1424
  /* the close socket stuff needs to be copied to the connection struct as
1425
     it may live on without (this specific) Curl_easy */
1426
0
  conn->fclosesocket = data->set.fclosesocket;
1427
0
  conn->closesocket_client = data->set.closesocket_client;
1428
0
  conn->lastused = conn->created;
1429
#ifdef HAVE_GSSAPI
1430
  conn->gssapi_delegation = data->set.gssapi_delegation;
1431
#endif
1432
0
  return conn;
1433
0
error:
1434
1435
0
  free(conn->localdev);
1436
0
  free(conn);
1437
0
  return NULL;
1438
0
}
1439
1440
const struct Curl_handler *Curl_get_scheme_handler(const char *scheme)
1441
0
{
1442
0
  return Curl_getn_scheme_handler(scheme, strlen(scheme));
1443
0
}
1444
1445
/* returns the handler if the given scheme is built-in */
1446
const struct Curl_handler *Curl_getn_scheme_handler(const char *scheme,
1447
                                                    size_t len)
1448
0
{
1449
  /* table generated by schemetable.c:
1450
     1. gcc schemetable.c && ./a.out
1451
     2. check how small the table gets
1452
     3. tweak the hash algorithm, then rerun from 1
1453
     4. when the table is good enough
1454
     5. copy the table into this source code
1455
     6. make sure this function uses the same hash function that worked for
1456
     schemetable.c
1457
     7. if needed, adjust the #ifdefs in schemetable.c and rerun
1458
     */
1459
0
  static const struct Curl_handler * const protocols[67] = {
1460
0
#ifndef CURL_DISABLE_FILE
1461
0
    &Curl_handler_file,
1462
#else
1463
    NULL,
1464
#endif
1465
0
    NULL, NULL,
1466
0
#if defined(USE_SSL) && !defined(CURL_DISABLE_GOPHER)
1467
0
    &Curl_handler_gophers,
1468
#else
1469
    NULL,
1470
#endif
1471
0
    NULL,
1472
#ifdef USE_LIBRTMP
1473
    &Curl_handler_rtmpe,
1474
#else
1475
0
    NULL,
1476
0
#endif
1477
0
#ifndef CURL_DISABLE_SMTP
1478
0
    &Curl_handler_smtp,
1479
#else
1480
    NULL,
1481
#endif
1482
#ifdef USE_SSH
1483
    &Curl_handler_sftp,
1484
#else
1485
0
    NULL,
1486
0
#endif
1487
0
#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \
1488
0
  (SIZEOF_CURL_OFF_T > 4)
1489
0
    &Curl_handler_smb,
1490
#else
1491
    NULL,
1492
#endif
1493
0
#if defined(USE_SSL) && !defined(CURL_DISABLE_SMTP)
1494
0
    &Curl_handler_smtps,
1495
#else
1496
    NULL,
1497
#endif
1498
0
#ifndef CURL_DISABLE_TELNET
1499
0
    &Curl_handler_telnet,
1500
#else
1501
    NULL,
1502
#endif
1503
0
#ifndef CURL_DISABLE_GOPHER
1504
0
    &Curl_handler_gopher,
1505
#else
1506
    NULL,
1507
#endif
1508
0
#ifndef CURL_DISABLE_TFTP
1509
0
    &Curl_handler_tftp,
1510
#else
1511
    NULL,
1512
#endif
1513
0
    NULL, NULL, NULL,
1514
0
#if defined(USE_SSL) && !defined(CURL_DISABLE_FTP)
1515
0
    &Curl_handler_ftps,
1516
#else
1517
    NULL,
1518
#endif
1519
0
#ifndef CURL_DISABLE_HTTP
1520
0
    &Curl_handler_http,
1521
#else
1522
    NULL,
1523
#endif
1524
0
#ifndef CURL_DISABLE_IMAP
1525
0
    &Curl_handler_imap,
1526
#else
1527
    NULL,
1528
#endif
1529
#ifdef USE_LIBRTMP
1530
    &Curl_handler_rtmps,
1531
#else
1532
0
    NULL,
1533
0
#endif
1534
#ifdef USE_LIBRTMP
1535
    &Curl_handler_rtmpt,
1536
#else
1537
0
    NULL,
1538
0
#endif
1539
0
    NULL, NULL, NULL,
1540
#if !defined(CURL_DISABLE_LDAP) && \
1541
  !defined(CURL_DISABLE_LDAPS) && \
1542
  ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \
1543
   (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL)))
1544
    &Curl_handler_ldaps,
1545
#else
1546
0
    NULL,
1547
0
#endif
1548
0
#if !defined(CURL_DISABLE_WEBSOCKETS) &&                \
1549
0
  defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
1550
0
    &Curl_handler_wss,
1551
#else
1552
    NULL,
1553
#endif
1554
0
#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
1555
0
    &Curl_handler_https,
1556
#else
1557
    NULL,
1558
#endif
1559
0
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1560
0
#ifndef CURL_DISABLE_RTSP
1561
0
    &Curl_handler_rtsp,
1562
#else
1563
    NULL,
1564
#endif
1565
0
#if defined(USE_SSL) && !defined(CURL_DISABLE_SMB) && \
1566
0
  defined(USE_CURL_NTLM_CORE) && (SIZEOF_CURL_OFF_T > 4)
1567
0
    &Curl_handler_smbs,
1568
#else
1569
    NULL,
1570
#endif
1571
#if defined(USE_SSH)
1572
    &Curl_handler_scp,
1573
#else
1574
0
    NULL,
1575
0
#endif
1576
0
    NULL, NULL, NULL,
1577
0
#ifndef CURL_DISABLE_POP3
1578
0
    &Curl_handler_pop3,
1579
#else
1580
    NULL,
1581
#endif
1582
0
    NULL, NULL,
1583
#ifdef USE_LIBRTMP
1584
    &Curl_handler_rtmp,
1585
#else
1586
0
    NULL,
1587
0
#endif
1588
0
    NULL, NULL, NULL,
1589
#ifdef USE_LIBRTMP
1590
    &Curl_handler_rtmpte,
1591
#else
1592
0
    NULL,
1593
0
#endif
1594
0
    NULL, NULL, NULL,
1595
0
#ifndef CURL_DISABLE_DICT
1596
0
    &Curl_handler_dict,
1597
#else
1598
    NULL,
1599
#endif
1600
0
    NULL, NULL, NULL,
1601
0
#ifndef CURL_DISABLE_MQTT
1602
0
    &Curl_handler_mqtt,
1603
#else
1604
    NULL,
1605
#endif
1606
0
#if defined(USE_SSL) && !defined(CURL_DISABLE_POP3)
1607
0
    &Curl_handler_pop3s,
1608
#else
1609
    NULL,
1610
#endif
1611
0
#if defined(USE_SSL) && !defined(CURL_DISABLE_IMAP)
1612
0
    &Curl_handler_imaps,
1613
#else
1614
    NULL,
1615
#endif
1616
0
    NULL,
1617
0
#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
1618
0
    &Curl_handler_ws,
1619
#else
1620
    NULL,
1621
#endif
1622
0
    NULL,
1623
#ifdef USE_LIBRTMP
1624
    &Curl_handler_rtmpts,
1625
#else
1626
0
    NULL,
1627
0
#endif
1628
#ifndef CURL_DISABLE_LDAP
1629
    &Curl_handler_ldap,
1630
#else
1631
0
    NULL,
1632
0
#endif
1633
0
    NULL, NULL,
1634
0
#ifndef CURL_DISABLE_FTP
1635
0
    &Curl_handler_ftp,
1636
#else
1637
    NULL,
1638
#endif
1639
0
  };
1640
1641
0
  if(len && (len <= 7)) {
1642
0
    const char *s = scheme;
1643
0
    size_t l = len;
1644
0
    const struct Curl_handler *h;
1645
0
    unsigned int c = 978;
1646
0
    while(l) {
1647
0
      c <<= 5;
1648
0
      c += (unsigned int)Curl_raw_tolower(*s);
1649
0
      s++;
1650
0
      l--;
1651
0
    }
1652
1653
0
    h = protocols[c % 67];
1654
0
    if(h && curl_strnequal(scheme, h->scheme, len) && !h->scheme[len])
1655
0
      return h;
1656
0
  }
1657
0
  return NULL;
1658
0
}
1659
1660
static CURLcode findprotocol(struct Curl_easy *data,
1661
                             struct connectdata *conn,
1662
                             const char *protostr)
1663
0
{
1664
0
  const struct Curl_handler *p = Curl_get_scheme_handler(protostr);
1665
1666
0
  if(p && /* Protocol found in table. Check if allowed */
1667
0
     (data->set.allowed_protocols & p->protocol)) {
1668
1669
    /* it is allowed for "normal" request, now do an extra check if this is
1670
       the result of a redirect */
1671
0
    if(data->state.this_is_a_follow &&
1672
0
       !(data->set.redir_protocols & p->protocol))
1673
      /* nope, get out */
1674
0
      ;
1675
0
    else {
1676
      /* Perform setup complement if some. */
1677
0
      conn->handler = conn->given = p;
1678
      /* 'port' and 'remote_port' are set in setup_connection_internals() */
1679
0
      return CURLE_OK;
1680
0
    }
1681
0
  }
1682
1683
  /* The protocol was not found in the table, but we do not have to assign it
1684
     to anything since it is already assigned to a dummy-struct in the
1685
     create_conn() function when the connectdata struct is allocated. */
1686
0
  failf(data, "Protocol \"%s\" %s%s", protostr,
1687
0
        p ? "disabled" : "not supported",
1688
0
        data->state.this_is_a_follow ? " (in redirect)":"");
1689
1690
0
  return CURLE_UNSUPPORTED_PROTOCOL;
1691
0
}
1692
1693
1694
CURLcode Curl_uc_to_curlcode(CURLUcode uc)
1695
0
{
1696
0
  switch(uc) {
1697
0
  default:
1698
0
    return CURLE_URL_MALFORMAT;
1699
0
  case CURLUE_UNSUPPORTED_SCHEME:
1700
0
    return CURLE_UNSUPPORTED_PROTOCOL;
1701
0
  case CURLUE_OUT_OF_MEMORY:
1702
0
    return CURLE_OUT_OF_MEMORY;
1703
0
  case CURLUE_USER_NOT_ALLOWED:
1704
0
    return CURLE_LOGIN_DENIED;
1705
0
  }
1706
0
}
1707
1708
#ifdef USE_IPV6
1709
/*
1710
 * If the URL was set with an IPv6 numerical address with a zone id part, set
1711
 * the scope_id based on that!
1712
 */
1713
1714
static void zonefrom_url(CURLU *uh, struct Curl_easy *data,
1715
                         struct connectdata *conn)
1716
0
{
1717
0
  char *zoneid;
1718
0
  CURLUcode uc = curl_url_get(uh, CURLUPART_ZONEID, &zoneid, 0);
1719
#ifdef CURL_DISABLE_VERBOSE_STRINGS
1720
  (void)data;
1721
#endif
1722
1723
0
  if(!uc && zoneid) {
1724
0
    const char *p = zoneid;
1725
0
    curl_off_t scope;
1726
0
    if(!curlx_str_number(&p, &scope, UINT_MAX))
1727
      /* A plain number, use it directly as a scope id. */
1728
0
      conn->scope_id = (unsigned int)scope;
1729
0
#ifdef HAVE_IF_NAMETOINDEX
1730
0
    else {
1731
#elif defined(_WIN32)
1732
    else if(Curl_if_nametoindex) {
1733
#endif
1734
1735
0
#if defined(HAVE_IF_NAMETOINDEX) || defined(_WIN32)
1736
      /* Zone identifier is not numeric */
1737
0
      unsigned int scopeidx = 0;
1738
0
#ifdef HAVE_IF_NAMETOINDEX
1739
0
      scopeidx = if_nametoindex(zoneid);
1740
#else
1741
      scopeidx = Curl_if_nametoindex(zoneid);
1742
#endif
1743
0
      if(!scopeidx) {
1744
0
#ifndef CURL_DISABLE_VERBOSE_STRINGS
1745
0
        char buffer[STRERROR_LEN];
1746
0
        infof(data, "Invalid zoneid: %s; %s", zoneid,
1747
0
              curlx_strerror(errno, buffer, sizeof(buffer)));
1748
0
#endif
1749
0
      }
1750
0
      else
1751
0
        conn->scope_id = scopeidx;
1752
0
    }
1753
0
#endif /* HAVE_IF_NAMETOINDEX || _WIN32 */
1754
1755
0
    free(zoneid);
1756
0
  }
1757
0
}
1758
#else
1759
#define zonefrom_url(a,b,c) Curl_nop_stmt
1760
#endif
1761
1762
/*
1763
 * Parse URL and fill in the relevant members of the connection struct.
1764
 */
1765
static CURLcode parseurlandfillconn(struct Curl_easy *data,
1766
                                    struct connectdata *conn)
1767
0
{
1768
0
  CURLcode result;
1769
0
  CURLU *uh;
1770
0
  CURLUcode uc;
1771
0
  char *hostname;
1772
0
  bool use_set_uh = (data->set.uh && !data->state.this_is_a_follow);
1773
1774
0
  up_free(data); /* cleanup previous leftovers first */
1775
1776
  /* parse the URL */
1777
0
  if(use_set_uh) {
1778
0
    uh = data->state.uh = curl_url_dup(data->set.uh);
1779
0
  }
1780
0
  else {
1781
0
    uh = data->state.uh = curl_url();
1782
0
  }
1783
1784
0
  if(!uh)
1785
0
    return CURLE_OUT_OF_MEMORY;
1786
1787
0
  if(data->set.str[STRING_DEFAULT_PROTOCOL] &&
1788
0
     !Curl_is_absolute_url(data->state.url, NULL, 0, TRUE)) {
1789
0
    char *url = curl_maprintf("%s://%s",
1790
0
                              data->set.str[STRING_DEFAULT_PROTOCOL],
1791
0
                              data->state.url);
1792
0
    if(!url)
1793
0
      return CURLE_OUT_OF_MEMORY;
1794
0
    if(data->state.url_alloc)
1795
0
      free(data->state.url);
1796
0
    data->state.url = url;
1797
0
    data->state.url_alloc = TRUE;
1798
0
  }
1799
1800
0
  if(!use_set_uh) {
1801
0
    char *newurl;
1802
0
    uc = curl_url_set(uh, CURLUPART_URL, data->state.url, (unsigned int)
1803
0
                      (CURLU_GUESS_SCHEME |
1804
0
                       CURLU_NON_SUPPORT_SCHEME |
1805
0
                       (data->set.disallow_username_in_url ?
1806
0
                        CURLU_DISALLOW_USER : 0) |
1807
0
                       (data->set.path_as_is ? CURLU_PATH_AS_IS : 0)));
1808
0
    if(uc) {
1809
0
      failf(data, "URL rejected: %s", curl_url_strerror(uc));
1810
0
      return Curl_uc_to_curlcode(uc);
1811
0
    }
1812
1813
    /* after it was parsed, get the generated normalized version */
1814
0
    uc = curl_url_get(uh, CURLUPART_URL, &newurl, 0);
1815
0
    if(uc)
1816
0
      return Curl_uc_to_curlcode(uc);
1817
0
    if(data->state.url_alloc)
1818
0
      free(data->state.url);
1819
0
    data->state.url = newurl;
1820
0
    data->state.url_alloc = TRUE;
1821
0
  }
1822
1823
0
  uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0);
1824
0
  if(uc)
1825
0
    return Curl_uc_to_curlcode(uc);
1826
1827
0
  uc = curl_url_get(uh, CURLUPART_HOST, &data->state.up.hostname, 0);
1828
0
  if(uc) {
1829
0
    if(!curl_strequal("file", data->state.up.scheme))
1830
0
      return CURLE_OUT_OF_MEMORY;
1831
0
  }
1832
0
  else if(strlen(data->state.up.hostname) > MAX_URL_LEN) {
1833
0
    failf(data, "Too long hostname (maximum is %d)", MAX_URL_LEN);
1834
0
    return CURLE_URL_MALFORMAT;
1835
0
  }
1836
0
  hostname = data->state.up.hostname;
1837
1838
0
  if(hostname && hostname[0] == '[') {
1839
    /* This looks like an IPv6 address literal. See if there is an address
1840
       scope. */
1841
0
    size_t hlen;
1842
0
    conn->bits.ipv6_ip = TRUE;
1843
    /* cut off the brackets! */
1844
0
    hostname++;
1845
0
    hlen = strlen(hostname);
1846
0
    hostname[hlen - 1] = 0;
1847
1848
0
    zonefrom_url(uh, data, conn);
1849
0
  }
1850
1851
  /* make sure the connect struct gets its own copy of the hostname */
1852
0
  conn->host.rawalloc = strdup(hostname ? hostname : "");
1853
0
  if(!conn->host.rawalloc)
1854
0
    return CURLE_OUT_OF_MEMORY;
1855
0
  conn->host.name = conn->host.rawalloc;
1856
1857
  /*************************************************************
1858
   * IDN-convert the hostnames
1859
   *************************************************************/
1860
0
  result = Curl_idnconvert_hostname(&conn->host);
1861
0
  if(result)
1862
0
    return result;
1863
1864
0
#ifndef CURL_DISABLE_HSTS
1865
  /* HSTS upgrade */
1866
0
  if(data->hsts && curl_strequal("http", data->state.up.scheme)) {
1867
    /* This MUST use the IDN decoded name */
1868
0
    if(Curl_hsts(data->hsts, conn->host.name, strlen(conn->host.name), TRUE)) {
1869
0
      char *url;
1870
0
      Curl_safefree(data->state.up.scheme);
1871
0
      uc = curl_url_set(uh, CURLUPART_SCHEME, "https", 0);
1872
0
      if(uc)
1873
0
        return Curl_uc_to_curlcode(uc);
1874
0
      if(data->state.url_alloc)
1875
0
        Curl_safefree(data->state.url);
1876
      /* after update, get the updated version */
1877
0
      uc = curl_url_get(uh, CURLUPART_URL, &url, 0);
1878
0
      if(uc)
1879
0
        return Curl_uc_to_curlcode(uc);
1880
0
      uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0);
1881
0
      if(uc) {
1882
0
        free(url);
1883
0
        return Curl_uc_to_curlcode(uc);
1884
0
      }
1885
0
      data->state.url = url;
1886
0
      data->state.url_alloc = TRUE;
1887
0
      infof(data, "Switched from HTTP to HTTPS due to HSTS => %s",
1888
0
            data->state.url);
1889
0
    }
1890
0
  }
1891
0
#endif
1892
1893
0
  result = findprotocol(data, conn, data->state.up.scheme);
1894
0
  if(result)
1895
0
    return result;
1896
1897
  /*
1898
   * username and password set with their own options override the credentials
1899
   * possibly set in the URL, but netrc does not.
1900
   */
1901
0
  if(!data->state.aptr.passwd || (data->state.creds_from != CREDS_OPTION)) {
1902
0
    uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0);
1903
0
    if(!uc) {
1904
0
      char *decoded;
1905
0
      result = Curl_urldecode(data->state.up.password, 0, &decoded, NULL,
1906
0
                              conn->handler->flags&PROTOPT_USERPWDCTRL ?
1907
0
                              REJECT_ZERO : REJECT_CTRL);
1908
0
      if(result)
1909
0
        return result;
1910
0
      conn->passwd = decoded;
1911
0
      result = Curl_setstropt(&data->state.aptr.passwd, decoded);
1912
0
      if(result)
1913
0
        return result;
1914
0
      data->state.creds_from = CREDS_URL;
1915
0
    }
1916
0
    else if(uc != CURLUE_NO_PASSWORD)
1917
0
      return Curl_uc_to_curlcode(uc);
1918
0
  }
1919
1920
0
  if(!data->state.aptr.user || (data->state.creds_from != CREDS_OPTION)) {
1921
    /* we do not use the URL API's URL decoder option here since it rejects
1922
       control codes and we want to allow them for some schemes in the user
1923
       and password fields */
1924
0
    uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user, 0);
1925
0
    if(!uc) {
1926
0
      char *decoded;
1927
0
      result = Curl_urldecode(data->state.up.user, 0, &decoded, NULL,
1928
0
                              conn->handler->flags&PROTOPT_USERPWDCTRL ?
1929
0
                              REJECT_ZERO : REJECT_CTRL);
1930
0
      if(result)
1931
0
        return result;
1932
0
      conn->user = decoded;
1933
0
      result = Curl_setstropt(&data->state.aptr.user, decoded);
1934
0
      data->state.creds_from = CREDS_URL;
1935
0
    }
1936
0
    else if(uc != CURLUE_NO_USER)
1937
0
      return Curl_uc_to_curlcode(uc);
1938
0
    if(result)
1939
0
      return result;
1940
0
  }
1941
1942
0
  uc = curl_url_get(uh, CURLUPART_OPTIONS, &data->state.up.options,
1943
0
                    CURLU_URLDECODE);
1944
0
  if(!uc) {
1945
0
    conn->options = strdup(data->state.up.options);
1946
0
    if(!conn->options)
1947
0
      return CURLE_OUT_OF_MEMORY;
1948
0
  }
1949
0
  else if(uc != CURLUE_NO_OPTIONS)
1950
0
    return Curl_uc_to_curlcode(uc);
1951
1952
0
  uc = curl_url_get(uh, CURLUPART_PATH, &data->state.up.path,
1953
0
                    CURLU_URLENCODE);
1954
0
  if(uc)
1955
0
    return Curl_uc_to_curlcode(uc);
1956
1957
0
  uc = curl_url_get(uh, CURLUPART_PORT, &data->state.up.port,
1958
0
                    CURLU_DEFAULT_PORT);
1959
0
  if(uc) {
1960
0
    if(!curl_strequal("file", data->state.up.scheme))
1961
0
      return CURLE_OUT_OF_MEMORY;
1962
0
  }
1963
0
  else {
1964
0
    curl_off_t port;
1965
0
    bool valid = TRUE;
1966
0
    if(data->set.use_port && data->state.allow_port)
1967
0
      port = data->set.use_port;
1968
0
    else {
1969
0
      const char *p = data->state.up.port;
1970
0
      if(curlx_str_number(&p, &port, 0xffff))
1971
0
        valid = FALSE;
1972
0
    }
1973
0
    if(valid)
1974
0
      conn->remote_port = (unsigned short)port;
1975
0
  }
1976
1977
0
  (void)curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query, 0);
1978
1979
0
#ifdef USE_IPV6
1980
0
  if(data->set.scope_id)
1981
    /* Override any scope that was set above.  */
1982
0
    conn->scope_id = data->set.scope_id;
1983
0
#endif
1984
1985
0
  return CURLE_OK;
1986
0
}
1987
1988
1989
/*
1990
 * If we are doing a resumed transfer, we need to setup our stuff
1991
 * properly.
1992
 */
1993
static CURLcode setup_range(struct Curl_easy *data)
1994
0
{
1995
0
  struct UrlState *s = &data->state;
1996
0
  s->resume_from = data->set.set_resume_from;
1997
0
  if(s->resume_from || data->set.str[STRING_SET_RANGE]) {
1998
0
    if(s->rangestringalloc)
1999
0
      free(s->range);
2000
2001
0
    if(s->resume_from)
2002
0
      s->range = curl_maprintf("%" FMT_OFF_T "-", s->resume_from);
2003
0
    else
2004
0
      s->range = strdup(data->set.str[STRING_SET_RANGE]);
2005
2006
0
    if(!s->range)
2007
0
      return CURLE_OUT_OF_MEMORY;
2008
2009
0
    s->rangestringalloc = TRUE;
2010
2011
    /* tell ourselves to fetch this range */
2012
0
    s->use_range = TRUE;        /* enable range download */
2013
0
  }
2014
0
  else
2015
0
    s->use_range = FALSE; /* disable range download */
2016
2017
0
  return CURLE_OK;
2018
0
}
2019
2020
2021
/*
2022
 * setup_connection_internals() -
2023
 *
2024
 * Setup connection internals specific to the requested protocol in the
2025
 * Curl_easy. This is inited and setup before the connection is made but
2026
 * is about the particular protocol that is to be used.
2027
 *
2028
 * This MUST get called after proxy magic has been figured out.
2029
 */
2030
static CURLcode setup_connection_internals(struct Curl_easy *data,
2031
                                           struct connectdata *conn)
2032
0
{
2033
0
  const char *hostname;
2034
0
  int port;
2035
0
  CURLcode result;
2036
2037
0
  if(conn->handler->setup_connection) {
2038
0
    result = conn->handler->setup_connection(data, conn);
2039
0
    if(result)
2040
0
      return result;
2041
0
  }
2042
2043
  /* Now create the destination name */
2044
0
#ifndef CURL_DISABLE_PROXY
2045
0
  if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
2046
0
    hostname = conn->http_proxy.host.name;
2047
0
    port = conn->http_proxy.port;
2048
0
  }
2049
0
  else
2050
0
#endif
2051
0
  {
2052
0
    port = conn->remote_port;
2053
0
    if(conn->bits.conn_to_host)
2054
0
      hostname = conn->conn_to_host.name;
2055
0
    else
2056
0
      hostname = conn->host.name;
2057
0
  }
2058
2059
0
#ifdef USE_IPV6
2060
0
  conn->destination = curl_maprintf("%u/%d/%s", conn->scope_id, port,
2061
0
                                    hostname);
2062
#else
2063
  conn->destination = curl_maprintf("%d/%s", port, hostname);
2064
#endif
2065
0
  if(!conn->destination)
2066
0
    return CURLE_OUT_OF_MEMORY;
2067
2068
0
  Curl_strntolower(conn->destination, conn->destination,
2069
0
                   strlen(conn->destination));
2070
2071
0
  return CURLE_OK;
2072
0
}
2073
2074
2075
#ifndef CURL_DISABLE_PROXY
2076
2077
#ifndef CURL_DISABLE_HTTP
2078
/****************************************************************
2079
* Detect what (if any) proxy to use. Remember that this selects a host
2080
* name and is not limited to HTTP proxies only.
2081
* The returned pointer must be freed by the caller (unless NULL)
2082
****************************************************************/
2083
static char *detect_proxy(struct Curl_easy *data,
2084
                          struct connectdata *conn)
2085
0
{
2086
0
  char *proxy = NULL;
2087
2088
  /* If proxy was not specified, we check for default proxy environment
2089
   * variables, to enable i.e Lynx compliance:
2090
   *
2091
   * http_proxy=http://some.server.dom:port/
2092
   * https_proxy=http://some.server.dom:port/
2093
   * ftp_proxy=http://some.server.dom:port/
2094
   * no_proxy=domain1.dom,host.domain2.dom
2095
   *   (a comma-separated list of hosts which should
2096
   *   not be proxied, or an asterisk to override
2097
   *   all proxy variables)
2098
   * all_proxy=http://some.server.dom:port/
2099
   *   (seems to exist for the CERN www lib. Probably
2100
   *   the first to check for.)
2101
   *
2102
   * For compatibility, the all-uppercase versions of these variables are
2103
   * checked if the lowercase versions do not exist.
2104
   */
2105
0
  char proxy_env[20];
2106
0
  const char *envp = proxy_env;
2107
#ifdef CURL_DISABLE_VERBOSE_STRINGS
2108
  (void)data;
2109
#endif
2110
2111
0
  curl_msnprintf(proxy_env, sizeof(proxy_env), "%s_proxy",
2112
0
                 conn->handler->scheme);
2113
2114
  /* read the protocol proxy: */
2115
0
  proxy = curl_getenv(proxy_env);
2116
2117
  /*
2118
   * We do not try the uppercase version of HTTP_PROXY because of
2119
   * security reasons:
2120
   *
2121
   * When curl is used in a webserver application
2122
   * environment (cgi or php), this environment variable can
2123
   * be controlled by the web server user by setting the
2124
   * http header 'Proxy:' to some value.
2125
   *
2126
   * This can cause 'internal' http/ftp requests to be
2127
   * arbitrarily redirected by any external attacker.
2128
   */
2129
0
  if(!proxy && !curl_strequal("http_proxy", proxy_env)) {
2130
    /* There was no lowercase variable, try the uppercase version: */
2131
0
    Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env));
2132
0
    proxy = curl_getenv(proxy_env);
2133
0
  }
2134
2135
0
  if(!proxy) {
2136
0
#ifndef CURL_DISABLE_WEBSOCKETS
2137
    /* websocket proxy fallbacks */
2138
0
    if(curl_strequal("ws_proxy", proxy_env)) {
2139
0
      proxy = curl_getenv("http_proxy");
2140
0
    }
2141
0
    else if(curl_strequal("wss_proxy", proxy_env)) {
2142
0
      proxy = curl_getenv("https_proxy");
2143
0
      if(!proxy)
2144
0
        proxy = curl_getenv("HTTPS_PROXY");
2145
0
    }
2146
0
    if(!proxy) {
2147
0
#endif
2148
0
      envp = "all_proxy";
2149
0
      proxy = curl_getenv(envp); /* default proxy to use */
2150
0
      if(!proxy) {
2151
0
        envp = "ALL_PROXY";
2152
0
        proxy = curl_getenv(envp);
2153
0
      }
2154
0
#ifndef CURL_DISABLE_WEBSOCKETS
2155
0
    }
2156
0
#endif
2157
0
  }
2158
0
  if(proxy)
2159
0
    infof(data, "Uses proxy env variable %s == '%s'", envp, proxy);
2160
2161
0
  return proxy;
2162
0
}
2163
#endif /* CURL_DISABLE_HTTP */
2164
2165
/*
2166
 * If this is supposed to use a proxy, we need to figure out the proxy
2167
 * hostname, so that we can reuse an existing connection
2168
 * that may exist registered to the same proxy host.
2169
 */
2170
static CURLcode parse_proxy(struct Curl_easy *data,
2171
                            struct connectdata *conn, char *proxy,
2172
                            long proxytype)
2173
0
{
2174
0
  char *portptr = NULL;
2175
0
  int port = -1;
2176
0
  char *proxyuser = NULL;
2177
0
  char *proxypasswd = NULL;
2178
0
  char *host = NULL;
2179
0
  bool sockstype;
2180
0
  CURLUcode uc;
2181
0
  struct proxy_info *proxyinfo;
2182
0
  CURLU *uhp = curl_url();
2183
0
  CURLcode result = CURLE_OK;
2184
0
  char *scheme = NULL;
2185
0
#ifdef USE_UNIX_SOCKETS
2186
0
  char *path = NULL;
2187
0
  bool is_unix_proxy = FALSE;
2188
0
#endif
2189
2190
2191
0
  if(!uhp) {
2192
0
    result = CURLE_OUT_OF_MEMORY;
2193
0
    goto error;
2194
0
  }
2195
2196
  /* When parsing the proxy, allowing non-supported schemes since we have
2197
     these made up ones for proxies. Guess scheme for URLs without it. */
2198
0
  uc = curl_url_set(uhp, CURLUPART_URL, proxy,
2199
0
                    CURLU_NON_SUPPORT_SCHEME|CURLU_GUESS_SCHEME);
2200
0
  if(!uc) {
2201
    /* parsed okay as a URL */
2202
0
    uc = curl_url_get(uhp, CURLUPART_SCHEME, &scheme, 0);
2203
0
    if(uc) {
2204
0
      result = CURLE_OUT_OF_MEMORY;
2205
0
      goto error;
2206
0
    }
2207
2208
0
    if(curl_strequal("https", scheme)) {
2209
0
      if(proxytype != CURLPROXY_HTTPS2)
2210
0
        proxytype = CURLPROXY_HTTPS;
2211
0
      else
2212
0
        proxytype = CURLPROXY_HTTPS2;
2213
0
    }
2214
0
    else if(curl_strequal("socks5h", scheme))
2215
0
      proxytype = CURLPROXY_SOCKS5_HOSTNAME;
2216
0
    else if(curl_strequal("socks5", scheme))
2217
0
      proxytype = CURLPROXY_SOCKS5;
2218
0
    else if(curl_strequal("socks4a", scheme))
2219
0
      proxytype = CURLPROXY_SOCKS4A;
2220
0
    else if(curl_strequal("socks4", scheme) ||
2221
0
            curl_strequal("socks", scheme))
2222
0
      proxytype = CURLPROXY_SOCKS4;
2223
0
    else if(curl_strequal("http", scheme))
2224
0
      ; /* leave it as HTTP or HTTP/1.0 */
2225
0
    else {
2226
      /* Any other xxx:// reject! */
2227
0
      failf(data, "Unsupported proxy scheme for \'%s\'", proxy);
2228
0
      result = CURLE_COULDNT_CONNECT;
2229
0
      goto error;
2230
0
    }
2231
0
  }
2232
0
  else {
2233
0
    failf(data, "Unsupported proxy syntax in \'%s\': %s", proxy,
2234
0
          curl_url_strerror(uc));
2235
0
    result = CURLE_COULDNT_RESOLVE_PROXY;
2236
0
    goto error;
2237
0
  }
2238
2239
0
#ifdef USE_SSL
2240
0
  if(!Curl_ssl_supports(data, SSLSUPP_HTTPS_PROXY))
2241
0
#endif
2242
0
    if(IS_HTTPS_PROXY(proxytype)) {
2243
0
      failf(data, "Unsupported proxy \'%s\', libcurl is built without the "
2244
0
            "HTTPS-proxy support.", proxy);
2245
0
      result = CURLE_NOT_BUILT_IN;
2246
0
      goto error;
2247
0
    }
2248
2249
0
  sockstype =
2250
0
    proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
2251
0
    proxytype == CURLPROXY_SOCKS5 ||
2252
0
    proxytype == CURLPROXY_SOCKS4A ||
2253
0
    proxytype == CURLPROXY_SOCKS4;
2254
2255
0
  proxyinfo = sockstype ? &conn->socks_proxy : &conn->http_proxy;
2256
0
  proxyinfo->proxytype = (unsigned char)proxytype;
2257
2258
  /* Is there a username and password given in this proxy url? */
2259
0
  uc = curl_url_get(uhp, CURLUPART_USER, &proxyuser, CURLU_URLDECODE);
2260
0
  if(uc && (uc != CURLUE_NO_USER))
2261
0
    goto error;
2262
0
  uc = curl_url_get(uhp, CURLUPART_PASSWORD, &proxypasswd, CURLU_URLDECODE);
2263
0
  if(uc && (uc != CURLUE_NO_PASSWORD))
2264
0
    goto error;
2265
2266
0
  if(proxyuser || proxypasswd) {
2267
0
    free(proxyinfo->user);
2268
0
    proxyinfo->user = proxyuser;
2269
0
    result = Curl_setstropt(&data->state.aptr.proxyuser, proxyuser);
2270
0
    proxyuser = NULL;
2271
0
    if(result)
2272
0
      goto error;
2273
0
    Curl_safefree(proxyinfo->passwd);
2274
0
    if(!proxypasswd) {
2275
0
      proxypasswd = strdup("");
2276
0
      if(!proxypasswd) {
2277
0
        result = CURLE_OUT_OF_MEMORY;
2278
0
        goto error;
2279
0
      }
2280
0
    }
2281
0
    proxyinfo->passwd = proxypasswd;
2282
0
    result = Curl_setstropt(&data->state.aptr.proxypasswd, proxypasswd);
2283
0
    proxypasswd = NULL;
2284
0
    if(result)
2285
0
      goto error;
2286
0
    conn->bits.proxy_user_passwd = TRUE; /* enable it */
2287
0
  }
2288
2289
0
  (void)curl_url_get(uhp, CURLUPART_PORT, &portptr, 0);
2290
2291
0
  if(portptr) {
2292
0
    curl_off_t num;
2293
0
    const char *p = portptr;
2294
0
    if(!curlx_str_number(&p, &num, 0xffff))
2295
0
      port = (int)num;
2296
0
    free(portptr);
2297
0
  }
2298
0
  else {
2299
0
    if(data->set.proxyport)
2300
      /* None given in the proxy string, then get the default one if it is
2301
         given */
2302
0
      port = (int)data->set.proxyport;
2303
0
    else {
2304
0
      if(IS_HTTPS_PROXY(proxytype))
2305
0
        port = CURL_DEFAULT_HTTPS_PROXY_PORT;
2306
0
      else
2307
0
        port = CURL_DEFAULT_PROXY_PORT;
2308
0
    }
2309
0
  }
2310
0
  if(port >= 0)
2311
0
    proxyinfo->port = port;
2312
2313
  /* now, clone the proxy hostname */
2314
0
  uc = curl_url_get(uhp, CURLUPART_HOST, &host, CURLU_URLDECODE);
2315
0
  if(uc) {
2316
0
    result = CURLE_OUT_OF_MEMORY;
2317
0
    goto error;
2318
0
  }
2319
0
#ifdef USE_UNIX_SOCKETS
2320
0
  if(sockstype && curl_strequal(UNIX_SOCKET_PREFIX, host)) {
2321
0
    uc = curl_url_get(uhp, CURLUPART_PATH, &path, CURLU_URLDECODE);
2322
0
    if(uc) {
2323
0
      result = CURLE_OUT_OF_MEMORY;
2324
0
      goto error;
2325
0
    }
2326
    /* path will be "/", if no path was found */
2327
0
    if(strcmp("/", path)) {
2328
0
      is_unix_proxy = TRUE;
2329
0
      free(host);
2330
0
      host = curl_maprintf(UNIX_SOCKET_PREFIX"%s", path);
2331
0
      if(!host) {
2332
0
        result = CURLE_OUT_OF_MEMORY;
2333
0
        goto error;
2334
0
      }
2335
0
      free(proxyinfo->host.rawalloc);
2336
0
      proxyinfo->host.rawalloc = host;
2337
0
      proxyinfo->host.name = host;
2338
0
      host = NULL;
2339
0
    }
2340
0
  }
2341
2342
0
  if(!is_unix_proxy) {
2343
0
#endif
2344
0
    free(proxyinfo->host.rawalloc);
2345
0
    proxyinfo->host.rawalloc = host;
2346
0
    if(host[0] == '[') {
2347
      /* this is a numerical IPv6, strip off the brackets */
2348
0
      size_t len = strlen(host);
2349
0
      host[len-1] = 0; /* clear the trailing bracket */
2350
0
      host++;
2351
0
      zonefrom_url(uhp, data, conn);
2352
0
    }
2353
0
    proxyinfo->host.name = host;
2354
0
    host = NULL;
2355
0
#ifdef USE_UNIX_SOCKETS
2356
0
  }
2357
0
#endif
2358
2359
0
error:
2360
0
  free(proxyuser);
2361
0
  free(proxypasswd);
2362
0
  free(host);
2363
0
  free(scheme);
2364
0
#ifdef USE_UNIX_SOCKETS
2365
0
  free(path);
2366
0
#endif
2367
0
  curl_url_cleanup(uhp);
2368
0
  return result;
2369
0
}
2370
2371
/*
2372
 * Extract the user and password from the authentication string
2373
 */
2374
static CURLcode parse_proxy_auth(struct Curl_easy *data,
2375
                                 struct connectdata *conn)
2376
0
{
2377
0
  const char *proxyuser = data->state.aptr.proxyuser ?
2378
0
    data->state.aptr.proxyuser : "";
2379
0
  const char *proxypasswd = data->state.aptr.proxypasswd ?
2380
0
    data->state.aptr.proxypasswd : "";
2381
0
  CURLcode result = CURLE_OUT_OF_MEMORY;
2382
2383
0
  conn->http_proxy.user = strdup(proxyuser);
2384
0
  if(conn->http_proxy.user) {
2385
0
    conn->http_proxy.passwd = strdup(proxypasswd);
2386
0
    if(conn->http_proxy.passwd)
2387
0
      result = CURLE_OK;
2388
0
    else
2389
0
      Curl_safefree(conn->http_proxy.user);
2390
0
  }
2391
0
  return result;
2392
0
}
2393
2394
/* create_conn helper to parse and init proxy values. to be called after Unix
2395
   socket init but before any proxy vars are evaluated. */
2396
static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
2397
                                              struct connectdata *conn)
2398
0
{
2399
0
  char *proxy = NULL;
2400
0
  char *socksproxy = NULL;
2401
0
  char *no_proxy = NULL;
2402
0
  CURLcode result = CURLE_OK;
2403
2404
  /*************************************************************
2405
   * Extract the user and password from the authentication string
2406
   *************************************************************/
2407
0
  if(conn->bits.proxy_user_passwd) {
2408
0
    result = parse_proxy_auth(data, conn);
2409
0
    if(result)
2410
0
      goto out;
2411
0
  }
2412
2413
  /*************************************************************
2414
   * Detect what (if any) proxy to use
2415
   *************************************************************/
2416
0
  if(data->set.str[STRING_PROXY]) {
2417
0
    proxy = strdup(data->set.str[STRING_PROXY]);
2418
    /* if global proxy is set, this is it */
2419
0
    if(!proxy) {
2420
0
      failf(data, "memory shortage");
2421
0
      result = CURLE_OUT_OF_MEMORY;
2422
0
      goto out;
2423
0
    }
2424
0
  }
2425
2426
0
  if(data->set.str[STRING_PRE_PROXY]) {
2427
0
    socksproxy = strdup(data->set.str[STRING_PRE_PROXY]);
2428
    /* if global socks proxy is set, this is it */
2429
0
    if(!socksproxy) {
2430
0
      failf(data, "memory shortage");
2431
0
      result = CURLE_OUT_OF_MEMORY;
2432
0
      goto out;
2433
0
    }
2434
0
  }
2435
2436
0
  if(!data->set.str[STRING_NOPROXY]) {
2437
0
    const char *p = "no_proxy";
2438
0
    no_proxy = curl_getenv(p);
2439
0
    if(!no_proxy) {
2440
0
      p = "NO_PROXY";
2441
0
      no_proxy = curl_getenv(p);
2442
0
    }
2443
0
    if(no_proxy) {
2444
0
      infof(data, "Uses proxy env variable %s == '%s'", p, no_proxy);
2445
0
    }
2446
0
  }
2447
2448
0
  if(Curl_check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY] ?
2449
0
                        data->set.str[STRING_NOPROXY] : no_proxy)) {
2450
0
    Curl_safefree(proxy);
2451
0
    Curl_safefree(socksproxy);
2452
0
  }
2453
0
#ifndef CURL_DISABLE_HTTP
2454
0
  else if(!proxy && !socksproxy)
2455
    /* if the host is not in the noproxy list, detect proxy. */
2456
0
    proxy = detect_proxy(data, conn);
2457
0
#endif /* CURL_DISABLE_HTTP */
2458
0
  Curl_safefree(no_proxy);
2459
2460
0
#ifdef USE_UNIX_SOCKETS
2461
  /* For the time being do not mix proxy and Unix domain sockets. See #1274 */
2462
0
  if(proxy && conn->unix_domain_socket) {
2463
0
    free(proxy);
2464
0
    proxy = NULL;
2465
0
  }
2466
0
#endif
2467
2468
0
  if(proxy && (!*proxy || (conn->handler->flags & PROTOPT_NONETWORK))) {
2469
0
    free(proxy);  /* Do not bother with an empty proxy string or if the
2470
                     protocol does not work with network */
2471
0
    proxy = NULL;
2472
0
  }
2473
0
  if(socksproxy && (!*socksproxy ||
2474
0
                    (conn->handler->flags & PROTOPT_NONETWORK))) {
2475
0
    free(socksproxy);  /* Do not bother with an empty socks proxy string or if
2476
                          the protocol does not work with network */
2477
0
    socksproxy = NULL;
2478
0
  }
2479
2480
  /***********************************************************************
2481
   * If this is supposed to use a proxy, we need to figure out the proxy host
2482
   * name, proxy type and port number, so that we can reuse an existing
2483
   * connection that may exist registered to the same proxy host.
2484
   ***********************************************************************/
2485
0
  if(proxy || socksproxy) {
2486
0
    long ptype = conn->http_proxy.proxytype;
2487
0
    if(proxy) {
2488
0
      result = parse_proxy(data, conn, proxy, ptype);
2489
0
      Curl_safefree(proxy); /* parse_proxy copies the proxy string */
2490
0
      if(result)
2491
0
        goto out;
2492
0
    }
2493
2494
0
    if(socksproxy) {
2495
0
      result = parse_proxy(data, conn, socksproxy, ptype);
2496
      /* parse_proxy copies the socks proxy string */
2497
0
      Curl_safefree(socksproxy);
2498
0
      if(result)
2499
0
        goto out;
2500
0
    }
2501
2502
0
    if(conn->http_proxy.host.rawalloc) {
2503
#ifdef CURL_DISABLE_HTTP
2504
      /* asking for an HTTP proxy is a bit funny when HTTP is disabled... */
2505
      result = CURLE_UNSUPPORTED_PROTOCOL;
2506
      goto out;
2507
#else
2508
      /* force this connection's protocol to become HTTP if compatible */
2509
0
      if(!(conn->handler->protocol & PROTO_FAMILY_HTTP)) {
2510
0
        if((conn->handler->flags & PROTOPT_PROXY_AS_HTTP) &&
2511
0
           !conn->bits.tunnel_proxy)
2512
0
          conn->handler = &Curl_handler_http;
2513
0
        else
2514
          /* if not converting to HTTP over the proxy, enforce tunneling */
2515
0
          conn->bits.tunnel_proxy = TRUE;
2516
0
      }
2517
0
      conn->bits.httpproxy = TRUE;
2518
0
#endif
2519
0
    }
2520
0
    else {
2521
0
      conn->bits.httpproxy = FALSE; /* not an HTTP proxy */
2522
0
      conn->bits.tunnel_proxy = FALSE; /* no tunneling if not HTTP */
2523
0
    }
2524
2525
0
    if(conn->socks_proxy.host.rawalloc) {
2526
0
      if(!conn->http_proxy.host.rawalloc) {
2527
        /* once a socks proxy */
2528
0
        if(!conn->socks_proxy.user) {
2529
0
          conn->socks_proxy.user = conn->http_proxy.user;
2530
0
          conn->http_proxy.user = NULL;
2531
0
          free(conn->socks_proxy.passwd);
2532
0
          conn->socks_proxy.passwd = conn->http_proxy.passwd;
2533
0
          conn->http_proxy.passwd = NULL;
2534
0
        }
2535
0
      }
2536
0
      conn->bits.socksproxy = TRUE;
2537
0
    }
2538
0
    else
2539
0
      conn->bits.socksproxy = FALSE; /* not a socks proxy */
2540
0
  }
2541
0
  else {
2542
0
    conn->bits.socksproxy = FALSE;
2543
0
    conn->bits.httpproxy = FALSE;
2544
0
  }
2545
0
  conn->bits.proxy = conn->bits.httpproxy || conn->bits.socksproxy;
2546
2547
0
  if(!conn->bits.proxy) {
2548
    /* we are not using the proxy after all... */
2549
0
    conn->bits.proxy = FALSE;
2550
0
    conn->bits.httpproxy = FALSE;
2551
0
    conn->bits.socksproxy = FALSE;
2552
0
    conn->bits.proxy_user_passwd = FALSE;
2553
0
    conn->bits.tunnel_proxy = FALSE;
2554
    /* CURLPROXY_HTTPS does not have its own flag in conn->bits, yet we need
2555
       to signal that CURLPROXY_HTTPS is not used for this connection */
2556
0
    conn->http_proxy.proxytype = CURLPROXY_HTTP;
2557
0
  }
2558
2559
0
out:
2560
2561
0
  free(socksproxy);
2562
0
  free(proxy);
2563
0
  return result;
2564
0
}
2565
#endif /* CURL_DISABLE_PROXY */
2566
2567
/*
2568
 * Curl_parse_login_details()
2569
 *
2570
 * This is used to parse a login string for username, password and options in
2571
 * the following formats:
2572
 *
2573
 *   user
2574
 *   user:password
2575
 *   user:password;options
2576
 *   user;options
2577
 *   user;options:password
2578
 *   :password
2579
 *   :password;options
2580
 *   ;options
2581
 *   ;options:password
2582
 *
2583
 * Parameters:
2584
 *
2585
 * login    [in]     - login string.
2586
 * len      [in]     - length of the login string.
2587
 * userp    [in/out] - address where a pointer to newly allocated memory
2588
 *                     holding the user will be stored upon completion.
2589
 * passwdp  [in/out] - address where a pointer to newly allocated memory
2590
 *                     holding the password will be stored upon completion.
2591
 * optionsp [in/out] - OPTIONAL address where a pointer to newly allocated
2592
 *                     memory holding the options will be stored upon
2593
 *                     completion.
2594
 *
2595
 * Returns CURLE_OK on success.
2596
 */
2597
CURLcode Curl_parse_login_details(const char *login, const size_t len,
2598
                                  char **userp, char **passwdp,
2599
                                  char **optionsp)
2600
0
{
2601
0
  char *ubuf = NULL;
2602
0
  char *pbuf = NULL;
2603
0
  const char *psep = NULL;
2604
0
  const char *osep = NULL;
2605
0
  size_t ulen;
2606
0
  size_t plen;
2607
0
  size_t olen;
2608
2609
0
  DEBUGASSERT(userp);
2610
0
  DEBUGASSERT(passwdp);
2611
2612
  /* Attempt to find the password separator */
2613
0
  psep = memchr(login, ':', len);
2614
2615
  /* Attempt to find the options separator */
2616
0
  if(optionsp)
2617
0
    osep = memchr(login, ';', len);
2618
2619
  /* Calculate the portion lengths */
2620
0
  ulen = (psep ?
2621
0
          (size_t)(osep && psep > osep ? osep - login : psep - login) :
2622
0
          (osep ? (size_t)(osep - login) : len));
2623
0
  plen = (psep ?
2624
0
          (osep && osep > psep ? (size_t)(osep - psep) :
2625
0
           (size_t)(login + len - psep)) - 1 : 0);
2626
0
  olen = (osep ?
2627
0
          (psep && psep > osep ? (size_t)(psep - osep) :
2628
0
           (size_t)(login + len - osep)) - 1 : 0);
2629
2630
  /* Clone the user portion buffer, which can be zero length */
2631
0
  ubuf = Curl_memdup0(login, ulen);
2632
0
  if(!ubuf)
2633
0
    goto error;
2634
2635
  /* Clone the password portion buffer */
2636
0
  if(psep) {
2637
0
    pbuf = Curl_memdup0(&psep[1], plen);
2638
0
    if(!pbuf)
2639
0
      goto error;
2640
0
  }
2641
2642
  /* Allocate the options portion buffer */
2643
0
  if(optionsp) {
2644
0
    char *obuf = NULL;
2645
0
    if(olen) {
2646
0
      obuf = Curl_memdup0(&osep[1], olen);
2647
0
      if(!obuf)
2648
0
        goto error;
2649
0
    }
2650
0
    *optionsp = obuf;
2651
0
  }
2652
0
  *userp = ubuf;
2653
0
  *passwdp = pbuf;
2654
0
  return CURLE_OK;
2655
0
error:
2656
0
  free(ubuf);
2657
0
  free(pbuf);
2658
0
  return CURLE_OUT_OF_MEMORY;
2659
0
}
2660
2661
/*************************************************************
2662
 * Figure out the remote port number and fix it in the URL
2663
 *
2664
 * No matter if we use a proxy or not, we have to figure out the remote
2665
 * port number of various reasons.
2666
 *
2667
 * The port number embedded in the URL is replaced, if necessary.
2668
 *************************************************************/
2669
static CURLcode parse_remote_port(struct Curl_easy *data,
2670
                                  struct connectdata *conn)
2671
0
{
2672
2673
0
  if(data->set.use_port && data->state.allow_port) {
2674
    /* if set, we use this instead of the port possibly given in the URL */
2675
0
    char portbuf[16];
2676
0
    CURLUcode uc;
2677
0
    conn->remote_port = data->set.use_port;
2678
0
    curl_msnprintf(portbuf, sizeof(portbuf), "%d", conn->remote_port);
2679
0
    uc = curl_url_set(data->state.uh, CURLUPART_PORT, portbuf, 0);
2680
0
    if(uc)
2681
0
      return CURLE_OUT_OF_MEMORY;
2682
0
  }
2683
2684
0
  return CURLE_OK;
2685
0
}
2686
2687
#ifndef CURL_DISABLE_NETRC
2688
static bool str_has_ctrl(const char *input)
2689
0
{
2690
0
  if(input) {
2691
0
    const unsigned char *str = (const unsigned char *)input;
2692
0
    while(*str) {
2693
0
      if(*str < 0x20)
2694
0
        return TRUE;
2695
0
      str++;
2696
0
    }
2697
0
  }
2698
0
  return FALSE;
2699
0
}
2700
#endif
2701
2702
/*
2703
 * Override the login details from the URL with that in the CURLOPT_USERPWD
2704
 * option or a .netrc file, if applicable.
2705
 */
2706
static CURLcode override_login(struct Curl_easy *data,
2707
                               struct connectdata *conn)
2708
0
{
2709
0
  CURLUcode uc;
2710
0
  char **userp = &conn->user;
2711
0
  char **passwdp = &conn->passwd;
2712
0
  char **optionsp = &conn->options;
2713
2714
0
  if(data->set.str[STRING_OPTIONS]) {
2715
0
    free(*optionsp);
2716
0
    *optionsp = strdup(data->set.str[STRING_OPTIONS]);
2717
0
    if(!*optionsp)
2718
0
      return CURLE_OUT_OF_MEMORY;
2719
0
  }
2720
2721
0
#ifndef CURL_DISABLE_NETRC
2722
0
  if(data->set.use_netrc == CURL_NETRC_REQUIRED) {
2723
0
    Curl_safefree(*userp);
2724
0
    Curl_safefree(*passwdp);
2725
0
  }
2726
0
  conn->bits.netrc = FALSE;
2727
0
  if(data->set.use_netrc && !data->set.str[STRING_USERNAME]) {
2728
0
    bool url_provided = FALSE;
2729
2730
0
    if(data->state.aptr.user &&
2731
0
       (data->state.creds_from != CREDS_NETRC)) {
2732
      /* there was a username with a length in the URL. Use the URL decoded
2733
         version */
2734
0
      userp = &data->state.aptr.user;
2735
0
      url_provided = TRUE;
2736
0
    }
2737
2738
0
    if(!*passwdp) {
2739
0
      NETRCcode ret = Curl_parsenetrc(&data->state.netrc, conn->host.name,
2740
0
                                      userp, passwdp,
2741
0
                                      data->set.str[STRING_NETRC_FILE]);
2742
0
      if(ret && ((ret == NETRC_NO_MATCH) ||
2743
0
                 (data->set.use_netrc == CURL_NETRC_OPTIONAL))) {
2744
0
        infof(data, "Couldn't find host %s in the %s file; using defaults",
2745
0
              conn->host.name,
2746
0
              (data->set.str[STRING_NETRC_FILE] ?
2747
0
               data->set.str[STRING_NETRC_FILE] : ".netrc"));
2748
0
      }
2749
0
      else if(ret) {
2750
0
        const char *m = Curl_netrc_strerror(ret);
2751
0
        failf(data, ".netrc error: %s", m);
2752
0
        return CURLE_READ_ERROR;
2753
0
      }
2754
0
      else {
2755
0
        if(!(conn->handler->flags&PROTOPT_USERPWDCTRL)) {
2756
          /* if the protocol can't handle control codes in credentials, make
2757
             sure there are none */
2758
0
          if(str_has_ctrl(*userp) || str_has_ctrl(*passwdp)) {
2759
0
            failf(data, "control code detected in .netrc credentials");
2760
0
            return CURLE_READ_ERROR;
2761
0
          }
2762
0
        }
2763
        /* set bits.netrc TRUE to remember that we got the name from a .netrc
2764
           file, so that it is safe to use even if we followed a Location: to a
2765
           different host or similar. */
2766
0
        conn->bits.netrc = TRUE;
2767
0
      }
2768
0
    }
2769
0
    if(url_provided) {
2770
0
      free(conn->user);
2771
0
      conn->user = strdup(*userp);
2772
0
      if(!conn->user)
2773
0
        return CURLE_OUT_OF_MEMORY;
2774
0
    }
2775
    /* no user was set but a password, set a blank user */
2776
0
    if(!*userp && *passwdp) {
2777
0
      *userp = strdup("");
2778
0
      if(!*userp)
2779
0
        return CURLE_OUT_OF_MEMORY;
2780
0
    }
2781
0
  }
2782
0
#endif
2783
2784
  /* for updated strings, we update them in the URL */
2785
0
  if(*userp) {
2786
0
    CURLcode result;
2787
0
    if(data->state.aptr.user != *userp) {
2788
      /* nothing to do then */
2789
0
      result = Curl_setstropt(&data->state.aptr.user, *userp);
2790
0
      if(result)
2791
0
        return result;
2792
0
      data->state.creds_from = CREDS_NETRC;
2793
0
    }
2794
0
  }
2795
0
  if(data->state.aptr.user) {
2796
0
    uc = curl_url_set(data->state.uh, CURLUPART_USER, data->state.aptr.user,
2797
0
                      CURLU_URLENCODE);
2798
0
    if(uc)
2799
0
      return Curl_uc_to_curlcode(uc);
2800
0
    if(!*userp) {
2801
0
      *userp = strdup(data->state.aptr.user);
2802
0
      if(!*userp)
2803
0
        return CURLE_OUT_OF_MEMORY;
2804
0
    }
2805
0
  }
2806
0
  if(*passwdp) {
2807
0
    CURLcode result = Curl_setstropt(&data->state.aptr.passwd, *passwdp);
2808
0
    if(result)
2809
0
      return result;
2810
0
    data->state.creds_from = CREDS_NETRC;
2811
0
  }
2812
0
  if(data->state.aptr.passwd) {
2813
0
    uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD,
2814
0
                      data->state.aptr.passwd, CURLU_URLENCODE);
2815
0
    if(uc)
2816
0
      return Curl_uc_to_curlcode(uc);
2817
0
    if(!*passwdp) {
2818
0
      *passwdp = strdup(data->state.aptr.passwd);
2819
0
      if(!*passwdp)
2820
0
        return CURLE_OUT_OF_MEMORY;
2821
0
    }
2822
0
  }
2823
2824
0
  return CURLE_OK;
2825
0
}
2826
2827
/*
2828
 * Set the login details so they are available in the connection
2829
 */
2830
static CURLcode set_login(struct Curl_easy *data,
2831
                          struct connectdata *conn)
2832
0
{
2833
0
  CURLcode result = CURLE_OK;
2834
0
  const char *setuser = CURL_DEFAULT_USER;
2835
0
  const char *setpasswd = CURL_DEFAULT_PASSWORD;
2836
2837
  /* If our protocol needs a password and we have none, use the defaults */
2838
0
  if((conn->handler->flags & PROTOPT_NEEDSPWD) && !data->state.aptr.user)
2839
0
    ;
2840
0
  else {
2841
0
    setuser = "";
2842
0
    setpasswd = "";
2843
0
  }
2844
  /* Store the default user */
2845
0
  if(!conn->user) {
2846
0
    conn->user = strdup(setuser);
2847
0
    if(!conn->user)
2848
0
      return CURLE_OUT_OF_MEMORY;
2849
0
  }
2850
2851
  /* Store the default password */
2852
0
  if(!conn->passwd) {
2853
0
    conn->passwd = strdup(setpasswd);
2854
0
    if(!conn->passwd)
2855
0
      result = CURLE_OUT_OF_MEMORY;
2856
0
  }
2857
2858
0
  return result;
2859
0
}
2860
2861
/*
2862
 * Parses a "host:port" string to connect to.
2863
 * The hostname and the port may be empty; in this case, NULL is returned for
2864
 * the hostname and -1 for the port.
2865
 */
2866
static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
2867
                                           const char *host,
2868
                                           char **hostname_result,
2869
                                           int *port_result)
2870
0
{
2871
0
  char *host_dup;
2872
0
  char *hostptr;
2873
0
  char *host_portno;
2874
0
  char *portptr;
2875
0
  int port = -1;
2876
0
  CURLcode result = CURLE_OK;
2877
2878
#ifdef CURL_DISABLE_VERBOSE_STRINGS
2879
  (void)data;
2880
#endif
2881
2882
0
  *hostname_result = NULL;
2883
0
  *port_result = -1;
2884
2885
0
  if(!host || !*host)
2886
0
    return CURLE_OK;
2887
2888
0
  host_dup = strdup(host);
2889
0
  if(!host_dup)
2890
0
    return CURLE_OUT_OF_MEMORY;
2891
2892
0
  hostptr = host_dup;
2893
2894
  /* start scanning for port number at this point */
2895
0
  portptr = hostptr;
2896
2897
  /* detect and extract RFC6874-style IPv6-addresses */
2898
0
  if(*hostptr == '[') {
2899
0
#ifdef USE_IPV6
2900
0
    char *ptr = ++hostptr; /* advance beyond the initial bracket */
2901
0
    while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.')))
2902
0
      ptr++;
2903
0
    if(*ptr == '%') {
2904
      /* There might be a zone identifier */
2905
0
      if(strncmp("%25", ptr, 3))
2906
0
        infof(data, "Please URL encode %% as %%25, see RFC 6874.");
2907
0
      ptr++;
2908
      /* Allow unreserved characters as defined in RFC 3986 */
2909
0
      while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') ||
2910
0
                     (*ptr == '.') || (*ptr == '_') || (*ptr == '~')))
2911
0
        ptr++;
2912
0
    }
2913
0
    if(*ptr == ']')
2914
      /* yeps, it ended nicely with a bracket as well */
2915
0
      *ptr++ = '\0';
2916
0
    else
2917
0
      infof(data, "Invalid IPv6 address format");
2918
0
    portptr = ptr;
2919
    /* Note that if this did not end with a bracket, we still advanced the
2920
     * hostptr first, but I cannot see anything wrong with that as no host
2921
     * name nor a numeric can legally start with a bracket.
2922
     */
2923
#else
2924
    failf(data, "Use of IPv6 in *_CONNECT_TO without IPv6 support built-in");
2925
    result = CURLE_NOT_BUILT_IN;
2926
    goto error;
2927
#endif
2928
0
  }
2929
2930
  /* Get port number off server.com:1080 */
2931
0
  host_portno = strchr(portptr, ':');
2932
0
  if(host_portno) {
2933
0
    *host_portno = '\0'; /* cut off number from hostname */
2934
0
    host_portno++;
2935
0
    if(*host_portno) {
2936
0
      curl_off_t portparse;
2937
0
      const char *p = host_portno;
2938
0
      if(curlx_str_number(&p, &portparse, 0xffff)) {
2939
0
        failf(data, "No valid port number in connect to host string (%s)",
2940
0
              host_portno);
2941
0
        result = CURLE_SETOPT_OPTION_SYNTAX;
2942
0
        goto error;
2943
0
      }
2944
0
      port = (int)portparse; /* we know it will fit */
2945
0
    }
2946
0
  }
2947
2948
  /* now, clone the cleaned hostname */
2949
0
  DEBUGASSERT(hostptr);
2950
0
  *hostname_result = strdup(hostptr);
2951
0
  if(!*hostname_result) {
2952
0
    result = CURLE_OUT_OF_MEMORY;
2953
0
    goto error;
2954
0
  }
2955
2956
0
  *port_result = port;
2957
2958
0
error:
2959
0
  free(host_dup);
2960
0
  return result;
2961
0
}
2962
2963
/*
2964
 * Parses one "connect to" string in the form:
2965
 * "HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT".
2966
 */
2967
static CURLcode parse_connect_to_string(struct Curl_easy *data,
2968
                                        struct connectdata *conn,
2969
                                        const char *conn_to_host,
2970
                                        char **host_result,
2971
                                        int *port_result)
2972
0
{
2973
0
  CURLcode result = CURLE_OK;
2974
0
  const char *ptr = conn_to_host;
2975
0
  bool host_match = FALSE;
2976
0
  bool port_match = FALSE;
2977
2978
0
  *host_result = NULL;
2979
0
  *port_result = -1;
2980
2981
0
  if(*ptr == ':') {
2982
    /* an empty hostname always matches */
2983
0
    host_match = TRUE;
2984
0
    ptr++;
2985
0
  }
2986
0
  else {
2987
    /* check whether the URL's hostname matches */
2988
0
    size_t hostname_to_match_len;
2989
0
    char *hostname_to_match = curl_maprintf("%s%s%s",
2990
0
                                            conn->bits.ipv6_ip ? "[" : "",
2991
0
                                            conn->host.name,
2992
0
                                            conn->bits.ipv6_ip ? "]" : "");
2993
0
    if(!hostname_to_match)
2994
0
      return CURLE_OUT_OF_MEMORY;
2995
0
    hostname_to_match_len = strlen(hostname_to_match);
2996
0
    host_match = curl_strnequal(ptr, hostname_to_match,
2997
0
                                hostname_to_match_len);
2998
0
    free(hostname_to_match);
2999
0
    ptr += hostname_to_match_len;
3000
3001
0
    host_match = host_match && *ptr == ':';
3002
0
    ptr++;
3003
0
  }
3004
3005
0
  if(host_match) {
3006
0
    if(*ptr == ':') {
3007
      /* an empty port always matches */
3008
0
      port_match = TRUE;
3009
0
      ptr++;
3010
0
    }
3011
0
    else {
3012
      /* check whether the URL's port matches */
3013
0
      char *ptr_next = strchr(ptr, ':');
3014
0
      if(ptr_next) {
3015
0
        curl_off_t port_to_match;
3016
0
        if(!curlx_str_number(&ptr, &port_to_match, 0xffff) &&
3017
0
           (port_to_match == (curl_off_t)conn->remote_port))
3018
0
          port_match = TRUE;
3019
0
        ptr = ptr_next + 1;
3020
0
      }
3021
0
    }
3022
0
  }
3023
3024
0
  if(host_match && port_match) {
3025
    /* parse the hostname and port to connect to */
3026
0
    result = parse_connect_to_host_port(data, ptr, host_result, port_result);
3027
0
  }
3028
3029
0
  return result;
3030
0
}
3031
3032
/*
3033
 * Processes all strings in the "connect to" slist, and uses the "connect
3034
 * to host" and "connect to port" of the first string that matches.
3035
 */
3036
static CURLcode parse_connect_to_slist(struct Curl_easy *data,
3037
                                       struct connectdata *conn,
3038
                                       struct curl_slist *conn_to_host)
3039
0
{
3040
0
  CURLcode result = CURLE_OK;
3041
0
  char *host = NULL;
3042
0
  int port = -1;
3043
3044
0
  while(conn_to_host && !host && port == -1) {
3045
0
    result = parse_connect_to_string(data, conn, conn_to_host->data,
3046
0
                                     &host, &port);
3047
0
    if(result)
3048
0
      return result;
3049
3050
0
    if(host && *host) {
3051
0
      conn->conn_to_host.rawalloc = host;
3052
0
      conn->conn_to_host.name = host;
3053
0
      conn->bits.conn_to_host = TRUE;
3054
3055
0
      infof(data, "Connecting to hostname: %s", host);
3056
0
    }
3057
0
    else {
3058
      /* no "connect to host" */
3059
0
      conn->bits.conn_to_host = FALSE;
3060
0
      Curl_safefree(host);
3061
0
    }
3062
3063
0
    if(port >= 0) {
3064
0
      conn->conn_to_port = port;
3065
0
      conn->bits.conn_to_port = TRUE;
3066
0
      infof(data, "Connecting to port: %d", port);
3067
0
    }
3068
0
    else {
3069
      /* no "connect to port" */
3070
0
      conn->bits.conn_to_port = FALSE;
3071
0
      port = -1;
3072
0
    }
3073
3074
0
    conn_to_host = conn_to_host->next;
3075
0
  }
3076
3077
0
#ifndef CURL_DISABLE_ALTSVC
3078
0
  if(data->asi && !host && (port == -1) &&
3079
0
     ((conn->handler->protocol == CURLPROTO_HTTPS) ||
3080
#ifdef DEBUGBUILD
3081
      /* allow debug builds to circumvent the HTTPS restriction */
3082
      getenv("CURL_ALTSVC_HTTP")
3083
#else
3084
0
      0
3085
0
#endif
3086
0
       )) {
3087
    /* no connect_to match, try alt-svc! */
3088
0
    enum alpnid srcalpnid = ALPN_none;
3089
0
    bool hit = FALSE;
3090
0
    struct altsvc *as = NULL;
3091
0
    int allowed_alpns = ALPN_none;
3092
0
    struct http_negotiation *neg = &data->state.http_neg;
3093
3094
0
    DEBUGF(infof(data, "Alt-svc check wanted=%x, allowed=%x",
3095
0
                 neg->wanted, neg->allowed));
3096
#ifdef USE_HTTP3
3097
    if(neg->allowed & CURL_HTTP_V3x)
3098
      allowed_alpns |= ALPN_h3;
3099
#endif
3100
#ifdef USE_HTTP2
3101
    if(neg->allowed & CURL_HTTP_V2x)
3102
      allowed_alpns |= ALPN_h2;
3103
#endif
3104
0
    if(neg->allowed & CURL_HTTP_V1x)
3105
0
      allowed_alpns |= ALPN_h1;
3106
0
    allowed_alpns &= (int)data->asi->flags;
3107
3108
0
    host = conn->host.rawalloc;
3109
0
    DEBUGF(infof(data, "check Alt-Svc for host %s", host));
3110
#ifdef USE_HTTP3
3111
    if(!hit && (neg->wanted & CURL_HTTP_V3x)) {
3112
      srcalpnid = ALPN_h3;
3113
      hit = Curl_altsvc_lookup(data->asi,
3114
                               ALPN_h3, host, conn->remote_port, /* from */
3115
                               &as /* to */,
3116
                               allowed_alpns);
3117
    }
3118
#endif
3119
#ifdef USE_HTTP2
3120
    if(!hit && (neg->wanted & CURL_HTTP_V2x) &&
3121
       !neg->h2_prior_knowledge) {
3122
      srcalpnid = ALPN_h2;
3123
      hit = Curl_altsvc_lookup(data->asi,
3124
                               ALPN_h2, host, conn->remote_port, /* from */
3125
                               &as /* to */,
3126
                               allowed_alpns);
3127
    }
3128
#endif
3129
0
    if(!hit && (neg->wanted & CURL_HTTP_V1x) &&
3130
0
       !neg->only_10) {
3131
0
      srcalpnid = ALPN_h1;
3132
0
      hit = Curl_altsvc_lookup(data->asi,
3133
0
                               ALPN_h1, host, conn->remote_port, /* from */
3134
0
                               &as /* to */,
3135
0
                               allowed_alpns);
3136
0
    }
3137
3138
0
    if(hit) {
3139
0
      char *hostd = strdup((char *)as->dst.host);
3140
0
      if(!hostd)
3141
0
        return CURLE_OUT_OF_MEMORY;
3142
0
      conn->conn_to_host.rawalloc = hostd;
3143
0
      conn->conn_to_host.name = hostd;
3144
0
      conn->bits.conn_to_host = TRUE;
3145
0
      conn->conn_to_port = as->dst.port;
3146
0
      conn->bits.conn_to_port = TRUE;
3147
0
      conn->bits.altused = TRUE;
3148
0
      infof(data, "Alt-svc connecting from [%s]%s:%d to [%s]%s:%d",
3149
0
            Curl_alpnid2str(srcalpnid), host, conn->remote_port,
3150
0
            Curl_alpnid2str(as->dst.alpnid), hostd, as->dst.port);
3151
0
      if(srcalpnid != as->dst.alpnid) {
3152
        /* protocol version switch */
3153
0
        switch(as->dst.alpnid) {
3154
0
        case ALPN_h1:
3155
0
          neg->wanted = neg->allowed = CURL_HTTP_V1x;
3156
0
          neg->only_10 = FALSE;
3157
0
          break;
3158
0
        case ALPN_h2:
3159
0
          neg->wanted = neg->allowed = CURL_HTTP_V2x;
3160
0
          break;
3161
0
        case ALPN_h3:
3162
0
          conn->transport_wanted = TRNSPRT_QUIC;
3163
0
          neg->wanted = neg->allowed = CURL_HTTP_V3x;
3164
0
          break;
3165
0
        default: /* should not be possible */
3166
0
          break;
3167
0
        }
3168
0
      }
3169
0
    }
3170
0
  }
3171
0
#endif
3172
3173
0
  return result;
3174
0
}
3175
3176
#ifdef USE_UNIX_SOCKETS
3177
static CURLcode resolve_unix(struct Curl_easy *data,
3178
                             struct connectdata *conn,
3179
                             char *unix_path,
3180
                             struct Curl_dns_entry **pdns)
3181
0
{
3182
0
  struct Curl_dns_entry *hostaddr;
3183
0
  bool longpath = FALSE;
3184
3185
0
  DEBUGASSERT(unix_path);
3186
0
  *pdns = NULL;
3187
3188
  /* Unix domain sockets are local. The host gets ignored, just use the
3189
   * specified domain socket address. Do not cache "DNS entries". There is
3190
   * no DNS involved and we already have the file system path available. */
3191
0
  hostaddr = calloc(1, sizeof(struct Curl_dns_entry));
3192
0
  if(!hostaddr)
3193
0
    return CURLE_OUT_OF_MEMORY;
3194
3195
0
  hostaddr->addr = Curl_unix2addr(unix_path, &longpath,
3196
0
                                  conn->bits.abstract_unix_socket);
3197
0
  if(!hostaddr->addr) {
3198
0
    if(longpath)
3199
      /* Long paths are not supported for now */
3200
0
      failf(data, "Unix socket path too long: '%s'", unix_path);
3201
0
    free(hostaddr);
3202
0
    return longpath ? CURLE_COULDNT_RESOLVE_HOST : CURLE_OUT_OF_MEMORY;
3203
0
  }
3204
3205
0
  hostaddr->refcount = 1; /* connection is the only one holding this */
3206
0
  *pdns = hostaddr;
3207
0
  return CURLE_OK;
3208
0
}
3209
#endif
3210
3211
/*************************************************************
3212
 * Resolve the address of the server or proxy
3213
 *************************************************************/
3214
static CURLcode resolve_server(struct Curl_easy *data,
3215
                               struct connectdata *conn,
3216
                               bool *async,
3217
                               struct Curl_dns_entry **pdns)
3218
0
{
3219
0
  struct hostname *ehost;
3220
0
  int eport;
3221
0
  timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
3222
0
  const char *peertype = "host";
3223
0
  CURLcode result;
3224
3225
0
  *pdns = NULL;
3226
3227
0
#ifdef USE_UNIX_SOCKETS
3228
0
  {
3229
0
    char *unix_path = conn->unix_domain_socket;
3230
3231
0
#ifndef CURL_DISABLE_PROXY
3232
0
    if(!unix_path && CONN_IS_PROXIED(conn) && conn->socks_proxy.host.name &&
3233
0
       !strncmp(UNIX_SOCKET_PREFIX"/",
3234
0
                conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX)))
3235
0
      unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1;
3236
0
#endif
3237
3238
0
    if(unix_path) {
3239
      /* This only works if previous transport is TRNSPRT_TCP. Check it? */
3240
0
      conn->transport_wanted = TRNSPRT_UNIX;
3241
0
      return resolve_unix(data, conn, unix_path, pdns);
3242
0
    }
3243
0
  }
3244
0
#endif
3245
3246
0
#ifndef CURL_DISABLE_PROXY
3247
0
  if(CONN_IS_PROXIED(conn)) {
3248
0
    ehost = conn->bits.socksproxy ? &conn->socks_proxy.host :
3249
0
      &conn->http_proxy.host;
3250
0
    eport = conn->bits.socksproxy ? conn->socks_proxy.port :
3251
0
      conn->http_proxy.port;
3252
0
    peertype = "proxy";
3253
0
  }
3254
0
  else
3255
0
#endif
3256
0
  {
3257
0
    ehost = conn->bits.conn_to_host ? &conn->conn_to_host : &conn->host;
3258
    /* If not connecting via a proxy, extract the port from the URL, if it is
3259
     * there, thus overriding any defaults that might have been set above. */
3260
0
    eport = conn->bits.conn_to_port ? conn->conn_to_port : conn->remote_port;
3261
0
  }
3262
3263
  /* Resolve target host right on */
3264
0
  conn->hostname_resolve = strdup(ehost->name);
3265
0
  if(!conn->hostname_resolve)
3266
0
    return CURLE_OUT_OF_MEMORY;
3267
3268
0
  result = Curl_resolv_timeout(data, conn->hostname_resolve,
3269
0
                               eport, conn->ip_version,
3270
0
                               pdns, timeout_ms);
3271
0
  DEBUGASSERT(!result || !*pdns);
3272
0
  if(result == CURLE_AGAIN) {
3273
0
    *async = TRUE;
3274
0
    return CURLE_OK;
3275
0
  }
3276
0
  else if(result == CURLE_OPERATION_TIMEDOUT) {
3277
0
    failf(data, "Failed to resolve %s '%s' with timeout after %"
3278
0
          FMT_TIMEDIFF_T " ms", peertype, ehost->dispname,
3279
0
          curlx_timediff(curlx_now(), data->progress.t_startsingle));
3280
0
    return CURLE_OPERATION_TIMEDOUT;
3281
0
  }
3282
0
  else if(result) {
3283
0
    failf(data, "Could not resolve %s: %s", peertype, ehost->dispname);
3284
0
    return result;
3285
0
  }
3286
0
  DEBUGASSERT(*pdns);
3287
0
  return CURLE_OK;
3288
0
}
3289
3290
static void url_move_hostname(struct hostname *dest, struct hostname *src)
3291
0
{
3292
0
  Curl_safefree(dest->rawalloc);
3293
0
  Curl_free_idnconverted_hostname(dest);
3294
0
  *dest = *src;
3295
0
  memset(src, 0, sizeof(*src));
3296
0
}
3297
3298
/*
3299
 * Cleanup the connection `temp`, just allocated for `data`, before using the
3300
 * previously `existing` one for `data`. All relevant info is copied over
3301
 * and `temp` is freed.
3302
 */
3303
static void reuse_conn(struct Curl_easy *data,
3304
                       struct connectdata *temp,
3305
                       struct connectdata *existing)
3306
0
{
3307
  /* get the user+password information from the temp struct since it may
3308
   * be new for this request even when we reuse an existing connection */
3309
0
  if(temp->user) {
3310
    /* use the new username and password though */
3311
0
    free(existing->user);
3312
0
    free(existing->passwd);
3313
0
    existing->user = temp->user;
3314
0
    existing->passwd = temp->passwd;
3315
0
    temp->user = NULL;
3316
0
    temp->passwd = NULL;
3317
0
  }
3318
3319
0
#ifndef CURL_DISABLE_PROXY
3320
0
  existing->bits.proxy_user_passwd = temp->bits.proxy_user_passwd;
3321
0
  if(existing->bits.proxy_user_passwd) {
3322
    /* use the new proxy username and proxy password though */
3323
0
    free(existing->http_proxy.user);
3324
0
    free(existing->socks_proxy.user);
3325
0
    free(existing->http_proxy.passwd);
3326
0
    free(existing->socks_proxy.passwd);
3327
0
    existing->http_proxy.user = temp->http_proxy.user;
3328
0
    existing->socks_proxy.user = temp->socks_proxy.user;
3329
0
    existing->http_proxy.passwd = temp->http_proxy.passwd;
3330
0
    existing->socks_proxy.passwd = temp->socks_proxy.passwd;
3331
0
    temp->http_proxy.user = NULL;
3332
0
    temp->socks_proxy.user = NULL;
3333
0
    temp->http_proxy.passwd = NULL;
3334
0
    temp->socks_proxy.passwd = NULL;
3335
0
  }
3336
0
#endif
3337
3338
  /* Finding a connection for reuse in the cpool matches, among other
3339
   * things on the "remote-relevant" hostname. This is not necessarily
3340
   * the authority of the URL, e.g. conn->host. For example:
3341
   * - we use a proxy (not tunneling). we want to send all requests
3342
   *   that use the same proxy on this connection.
3343
   * - we have a "connect-to" setting that may redirect the hostname of
3344
   *   a new request to the same remote endpoint of an existing conn.
3345
   *   We want to reuse an existing conn to the remote endpoint.
3346
   * Since connection reuse does not match on conn->host necessarily, we
3347
   * switch `existing` conn to `temp` conn's host settings.
3348
   *       Is this correct in the case of TLS connections that have
3349
   *       used the original hostname in SNI to negotiate? Do we send
3350
   *       requests for another host through the different SNI?
3351
   */
3352
0
  url_move_hostname(&existing->host, &temp->host);
3353
0
  url_move_hostname(&existing->conn_to_host, &temp->conn_to_host);
3354
3355
0
  existing->conn_to_port = temp->conn_to_port;
3356
0
  existing->remote_port = temp->remote_port;
3357
0
  free(existing->hostname_resolve);
3358
0
  existing->hostname_resolve = temp->hostname_resolve;
3359
0
  temp->hostname_resolve = NULL;
3360
3361
  /* reuse init */
3362
0
  existing->bits.reuse = TRUE; /* yes, we are reusing here */
3363
3364
0
  Curl_conn_free(data, temp);
3365
0
}
3366
3367
static void conn_meta_freeentry(void *p)
3368
0
{
3369
0
  (void)p;
3370
  /* Will always be FALSE. Cannot use a 0 assert here since compilers
3371
   * are not in agreement if they then want a NORETURN attribute or
3372
   * not. *sigh* */
3373
0
  DEBUGASSERT(p == NULL);
3374
0
}
3375
3376
/**
3377
 * create_conn() sets up a new connectdata struct, or reuses an already
3378
 * existing one, and resolves hostname.
3379
 *
3380
 * if this function returns CURLE_OK and *async is set to TRUE, the resolve
3381
 * response will be coming asynchronously. If *async is FALSE, the name is
3382
 * already resolved.
3383
 *
3384
 * @param data The sessionhandle pointer
3385
 * @param in_connect is set to the next connection data pointer
3386
 * @param reusedp is set to to TRUE if connection was reused
3387
 * @see Curl_setup_conn()
3388
 *
3389
 */
3390
3391
static CURLcode create_conn(struct Curl_easy *data,
3392
                            struct connectdata **in_connect,
3393
                            bool *reusedp)
3394
0
{
3395
0
  CURLcode result = CURLE_OK;
3396
0
  struct connectdata *conn;
3397
0
  struct connectdata *existing = NULL;
3398
0
  bool reuse;
3399
0
  bool connections_available = TRUE;
3400
0
  bool force_reuse = FALSE;
3401
0
  bool waitpipe = FALSE;
3402
3403
0
  *reusedp = FALSE;
3404
0
  *in_connect = NULL;
3405
3406
  /*************************************************************
3407
   * Check input data
3408
   *************************************************************/
3409
0
  if(!data->state.url) {
3410
0
    result = CURLE_URL_MALFORMAT;
3411
0
    goto out;
3412
0
  }
3413
3414
  /* First, split up the current URL in parts so that we can use the
3415
     parts for checking against the already present connections. In order
3416
     to not have to modify everything at once, we allocate a temporary
3417
     connection data struct and fill in for comparison purposes. */
3418
0
  conn = allocate_conn(data);
3419
3420
0
  if(!conn) {
3421
0
    result = CURLE_OUT_OF_MEMORY;
3422
0
    goto out;
3423
0
  }
3424
3425
  /* We must set the return variable as soon as possible, so that our
3426
     parent can cleanup any possible allocs we may have done before
3427
     any failure */
3428
0
  *in_connect = conn;
3429
3430
  /* Do the unfailable inits first, before checks that may early return */
3431
0
  Curl_hash_init(&conn->meta_hash, 23,
3432
0
                 Curl_hash_str, curlx_str_key_compare, conn_meta_freeentry);
3433
3434
0
  result = parseurlandfillconn(data, conn);
3435
0
  if(result)
3436
0
    goto out;
3437
3438
0
  if(data->set.str[STRING_SASL_AUTHZID]) {
3439
0
    conn->sasl_authzid = strdup(data->set.str[STRING_SASL_AUTHZID]);
3440
0
    if(!conn->sasl_authzid) {
3441
0
      result = CURLE_OUT_OF_MEMORY;
3442
0
      goto out;
3443
0
    }
3444
0
  }
3445
3446
0
  if(data->set.str[STRING_BEARER]) {
3447
0
    conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]);
3448
0
    if(!conn->oauth_bearer) {
3449
0
      result = CURLE_OUT_OF_MEMORY;
3450
0
      goto out;
3451
0
    }
3452
0
  }
3453
3454
0
#ifdef USE_UNIX_SOCKETS
3455
0
  if(data->set.str[STRING_UNIX_SOCKET_PATH]) {
3456
0
    conn->unix_domain_socket = strdup(data->set.str[STRING_UNIX_SOCKET_PATH]);
3457
0
    if(!conn->unix_domain_socket) {
3458
0
      result = CURLE_OUT_OF_MEMORY;
3459
0
      goto out;
3460
0
    }
3461
0
    conn->bits.abstract_unix_socket = data->set.abstract_unix_socket;
3462
0
  }
3463
0
#endif
3464
3465
  /* After the Unix socket init but before the proxy vars are used, parse and
3466
     initialize the proxy vars */
3467
0
#ifndef CURL_DISABLE_PROXY
3468
0
  result = create_conn_helper_init_proxy(data, conn);
3469
0
  if(result)
3470
0
    goto out;
3471
3472
  /*************************************************************
3473
   * If the protocol is using SSL and HTTP proxy is used, we set
3474
   * the tunnel_proxy bit.
3475
   *************************************************************/
3476
0
  if((conn->given->flags&PROTOPT_SSL) && conn->bits.httpproxy)
3477
0
    conn->bits.tunnel_proxy = TRUE;
3478
0
#endif
3479
3480
  /*************************************************************
3481
   * Figure out the remote port number and fix it in the URL
3482
   *************************************************************/
3483
0
  result = parse_remote_port(data, conn);
3484
0
  if(result)
3485
0
    goto out;
3486
3487
  /* Check for overridden login details and set them accordingly so that
3488
     they are known when protocol->setup_connection is called! */
3489
0
  result = override_login(data, conn);
3490
0
  if(result)
3491
0
    goto out;
3492
3493
0
  result = set_login(data, conn); /* default credentials */
3494
0
  if(result)
3495
0
    goto out;
3496
3497
  /*************************************************************
3498
   * Process the "connect to" linked list of hostname/port mappings.
3499
   * Do this after the remote port number has been fixed in the URL.
3500
   *************************************************************/
3501
0
  result = parse_connect_to_slist(data, conn, data->set.connect_to);
3502
0
  if(result)
3503
0
    goto out;
3504
3505
  /*************************************************************
3506
   * IDN-convert the proxy hostnames
3507
   *************************************************************/
3508
0
#ifndef CURL_DISABLE_PROXY
3509
0
  if(conn->bits.httpproxy) {
3510
0
    result = Curl_idnconvert_hostname(&conn->http_proxy.host);
3511
0
    if(result)
3512
0
      return result;
3513
0
  }
3514
0
  if(conn->bits.socksproxy) {
3515
0
    result = Curl_idnconvert_hostname(&conn->socks_proxy.host);
3516
0
    if(result)
3517
0
      return result;
3518
0
  }
3519
0
#endif
3520
0
  if(conn->bits.conn_to_host) {
3521
0
    result = Curl_idnconvert_hostname(&conn->conn_to_host);
3522
0
    if(result)
3523
0
      return result;
3524
0
  }
3525
3526
  /*************************************************************
3527
   * Check whether the host and the "connect to host" are equal.
3528
   * Do this after the hostnames have been IDN-converted.
3529
   *************************************************************/
3530
0
  if(conn->bits.conn_to_host &&
3531
0
     curl_strequal(conn->conn_to_host.name, conn->host.name)) {
3532
0
    conn->bits.conn_to_host = FALSE;
3533
0
  }
3534
3535
  /*************************************************************
3536
   * Check whether the port and the "connect to port" are equal.
3537
   * Do this after the remote port number has been fixed in the URL.
3538
   *************************************************************/
3539
0
  if(conn->bits.conn_to_port && conn->conn_to_port == conn->remote_port) {
3540
0
    conn->bits.conn_to_port = FALSE;
3541
0
  }
3542
3543
0
#ifndef CURL_DISABLE_PROXY
3544
  /*************************************************************
3545
   * If the "connect to" feature is used with an HTTP proxy,
3546
   * we set the tunnel_proxy bit.
3547
   *************************************************************/
3548
0
  if((conn->bits.conn_to_host || conn->bits.conn_to_port) &&
3549
0
      conn->bits.httpproxy)
3550
0
    conn->bits.tunnel_proxy = TRUE;
3551
0
#endif
3552
3553
  /*************************************************************
3554
   * Setup internals depending on protocol. Needs to be done after
3555
   * we figured out what/if proxy to use.
3556
   *************************************************************/
3557
0
  result = setup_connection_internals(data, conn);
3558
0
  if(result)
3559
0
    goto out;
3560
3561
  /***********************************************************************
3562
   * file: is a special case in that it does not need a network connection
3563
   ***********************************************************************/
3564
0
#ifndef CURL_DISABLE_FILE
3565
0
  if(conn->handler->flags & PROTOPT_NONETWORK) {
3566
0
    bool done;
3567
    /* this is supposed to be the connect function so we better at least check
3568
       that the file is present here! */
3569
0
    DEBUGASSERT(conn->handler->connect_it);
3570
0
    data->info.conn_scheme = conn->handler->scheme;
3571
    /* conn_protocol can only provide "old" protocols */
3572
0
    data->info.conn_protocol = (conn->handler->protocol) & CURLPROTO_MASK;
3573
0
    result = conn->handler->connect_it(data, &done);
3574
0
    if(result)
3575
0
      goto out;
3576
3577
    /* Setup a "faked" transfer that will do nothing */
3578
0
    Curl_attach_connection(data, conn);
3579
0
    result = Curl_cpool_add(data, conn);
3580
0
    if(!result) {
3581
      /* Setup whatever necessary for a resumed transfer */
3582
0
      result = setup_range(data);
3583
0
      if(!result) {
3584
0
        Curl_xfer_setup_nop(data);
3585
0
        result = Curl_init_do(data, conn);
3586
0
      }
3587
0
    }
3588
3589
0
    if(result) {
3590
0
      DEBUGASSERT(conn->handler->done);
3591
      /* we ignore the return code for the protocol-specific DONE */
3592
0
      (void)conn->handler->done(data, result, FALSE);
3593
0
    }
3594
0
    goto out;
3595
0
  }
3596
0
#endif
3597
3598
  /* Setup filter for network connections */
3599
0
  conn->recv[FIRSTSOCKET] = Curl_cf_recv;
3600
0
  conn->send[FIRSTSOCKET] = Curl_cf_send;
3601
0
  conn->recv[SECONDARYSOCKET] = Curl_cf_recv;
3602
0
  conn->send[SECONDARYSOCKET] = Curl_cf_send;
3603
0
  conn->bits.tcp_fastopen = data->set.tcp_fastopen;
3604
3605
  /* Complete the easy's SSL configuration for connection cache matching */
3606
0
  result = Curl_ssl_easy_config_complete(data);
3607
0
  if(result)
3608
0
    goto out;
3609
3610
0
  Curl_cpool_prune_dead(data);
3611
3612
  /*************************************************************
3613
   * Check the current list of connections to see if we can
3614
   * reuse an already existing one or if we have to create a
3615
   * new one.
3616
   *************************************************************/
3617
3618
0
  DEBUGASSERT(conn->user);
3619
0
  DEBUGASSERT(conn->passwd);
3620
3621
  /* reuse_fresh is TRUE if we are told to use a new connection by force, but
3622
     we only acknowledge this option if this is not a reused connection
3623
     already (which happens due to follow-location or during an HTTP
3624
     authentication phase). CONNECT_ONLY transfers also refuse reuse. */
3625
0
  if((data->set.reuse_fresh && !data->state.followlocation) ||
3626
0
     data->set.connect_only)
3627
0
    reuse = FALSE;
3628
0
  else
3629
0
    reuse = ConnectionExists(data, conn, &existing, &force_reuse, &waitpipe);
3630
3631
0
  if(reuse) {
3632
    /*
3633
     * We already have a connection for this, we got the former connection in
3634
     * `existing` and thus we need to cleanup the one we just
3635
     * allocated before we can move along and use `existing`.
3636
     */
3637
0
    bool tls_upgraded = (!(conn->given->flags & PROTOPT_SSL) &&
3638
0
                         Curl_conn_is_ssl(conn, FIRSTSOCKET));
3639
3640
0
    reuse_conn(data, conn, existing);
3641
0
    conn = existing;
3642
0
    *in_connect = conn;
3643
3644
0
#ifndef CURL_DISABLE_PROXY
3645
0
    infof(data, "Reusing existing %s: connection%s with %s %s",
3646
0
          conn->given->scheme,
3647
0
          tls_upgraded ? " (upgraded to SSL)" : "",
3648
0
          conn->bits.proxy ? "proxy" : "host",
3649
0
          conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname :
3650
0
          conn->http_proxy.host.name ? conn->http_proxy.host.dispname :
3651
0
          conn->host.dispname);
3652
#else
3653
    infof(data, "Reusing existing %s: connection%s with host %s",
3654
          conn->given->scheme,
3655
          tls_upgraded ? " (upgraded to SSL)" : "",
3656
          conn->host.dispname);
3657
#endif
3658
0
  }
3659
0
  else {
3660
    /* We have decided that we want a new connection. However, we may not
3661
       be able to do that if we have reached the limit of how many
3662
       connections we are allowed to open. */
3663
3664
0
    if(conn->handler->flags & PROTOPT_ALPN) {
3665
      /* The protocol wants it, so set the bits if enabled in the easy handle
3666
         (default) */
3667
0
      if(data->set.ssl_enable_alpn)
3668
0
        conn->bits.tls_enable_alpn = TRUE;
3669
0
    }
3670
3671
0
    if(waitpipe) {
3672
      /* There is a connection that *might* become usable for multiplexing
3673
         "soon", and we wait for that */
3674
0
      infof(data, "Waiting on connection to negotiate possible multiplexing.");
3675
0
      connections_available = FALSE;
3676
0
    }
3677
0
    else {
3678
0
      switch(Curl_cpool_check_limits(data, conn)) {
3679
0
      case CPOOL_LIMIT_DEST:
3680
0
        infof(data, "No more connections allowed to host");
3681
0
        connections_available = FALSE;
3682
0
        break;
3683
0
      case CPOOL_LIMIT_TOTAL:
3684
0
        if(data->master_mid != UINT_MAX)
3685
0
          CURL_TRC_M(data, "Allowing sub-requests (like DoH) to override "
3686
0
                     "max connection limit");
3687
0
        else {
3688
0
          infof(data, "No connections available, total of %ld reached.",
3689
0
                data->multi->max_total_connections);
3690
0
          connections_available = FALSE;
3691
0
        }
3692
0
        break;
3693
0
      default:
3694
0
        break;
3695
0
      }
3696
0
    }
3697
3698
0
    if(!connections_available) {
3699
0
      Curl_conn_free(data, conn);
3700
0
      *in_connect = NULL;
3701
3702
0
      result = CURLE_NO_CONNECTION_AVAILABLE;
3703
0
      goto out;
3704
0
    }
3705
0
    else {
3706
      /*
3707
       * This is a brand new connection, so let's store it in the connection
3708
       * cache of ours!
3709
       */
3710
0
      result = Curl_ssl_conn_config_init(data, conn);
3711
0
      if(result) {
3712
0
        DEBUGF(curl_mfprintf(stderr, "Error: init connection ssl config\n"));
3713
0
        goto out;
3714
0
      }
3715
3716
0
      Curl_attach_connection(data, conn);
3717
0
      result = Curl_cpool_add(data, conn);
3718
0
      if(result)
3719
0
        goto out;
3720
0
    }
3721
3722
0
#ifdef USE_NTLM
3723
    /* If NTLM is requested in a part of this connection, make sure we do not
3724
       assume the state is fine as this is a fresh connection and NTLM is
3725
       connection based. */
3726
0
    if((data->state.authhost.picked & CURLAUTH_NTLM) &&
3727
0
       data->state.authhost.done) {
3728
0
      infof(data, "NTLM picked AND auth done set, clear picked");
3729
0
      data->state.authhost.picked = CURLAUTH_NONE;
3730
0
      data->state.authhost.done = FALSE;
3731
0
    }
3732
3733
0
    if((data->state.authproxy.picked & CURLAUTH_NTLM) &&
3734
0
       data->state.authproxy.done) {
3735
0
      infof(data, "NTLM-proxy picked AND auth done set, clear picked");
3736
0
      data->state.authproxy.picked = CURLAUTH_NONE;
3737
0
      data->state.authproxy.done = FALSE;
3738
0
    }
3739
0
#endif
3740
0
  }
3741
3742
  /* Setup and init stuff before DO starts, in preparing for the transfer. */
3743
0
  result = Curl_init_do(data, conn);
3744
0
  if(result)
3745
0
    goto out;
3746
3747
  /*
3748
   * Setup whatever necessary for a resumed transfer
3749
   */
3750
0
  result = setup_range(data);
3751
0
  if(result)
3752
0
    goto out;
3753
3754
  /* Continue connectdata initialization here. */
3755
3756
0
  if(conn->bits.reuse) {
3757
    /* We are reusing the connection - no need to resolve anything, and
3758
       idnconvert_hostname() was called already in create_conn() for the reuse
3759
       case. */
3760
0
    *reusedp = TRUE;
3761
0
  }
3762
3763
  /* persist the scheme and handler the transfer is using */
3764
0
  data->info.conn_scheme = conn->handler->scheme;
3765
  /* conn_protocol can only provide "old" protocols */
3766
0
  data->info.conn_protocol = (conn->handler->protocol) & CURLPROTO_MASK;
3767
0
  data->info.used_proxy =
3768
#ifdef CURL_DISABLE_PROXY
3769
    0
3770
#else
3771
0
    conn->bits.proxy
3772
0
#endif
3773
0
    ;
3774
3775
  /* Everything general done, inform filters that they need
3776
   * to prepare for a data transfer. */
3777
0
  result = Curl_conn_ev_data_setup(data);
3778
3779
0
out:
3780
0
  return result;
3781
0
}
3782
3783
/* Curl_setup_conn() is called after the name resolve initiated in
3784
 * create_conn() is all done.
3785
 *
3786
 * Curl_setup_conn() also handles reused connections
3787
 */
3788
CURLcode Curl_setup_conn(struct Curl_easy *data,
3789
                         struct Curl_dns_entry *dns,
3790
                         bool *protocol_done)
3791
0
{
3792
0
  CURLcode result = CURLE_OK;
3793
0
  struct connectdata *conn = data->conn;
3794
3795
0
  DEBUGASSERT(dns);
3796
0
  Curl_pgrsTime(data, TIMER_NAMELOOKUP);
3797
3798
0
  if(!conn->bits.reuse)
3799
0
    result = Curl_conn_setup(data, conn, FIRSTSOCKET, dns,
3800
0
                             CURL_CF_SSL_DEFAULT);
3801
0
  if(!result)
3802
0
    result = Curl_headers_init(data);
3803
3804
  /* not sure we need this flag to be passed around any more */
3805
0
  *protocol_done = FALSE;
3806
0
  return result;
3807
0
}
3808
3809
CURLcode Curl_connect(struct Curl_easy *data,
3810
                      bool *asyncp,
3811
                      bool *protocol_done)
3812
0
{
3813
0
  CURLcode result;
3814
0
  struct connectdata *conn;
3815
0
  bool reused = FALSE;
3816
3817
0
  *asyncp = FALSE; /* assume synchronous resolves by default */
3818
0
  *protocol_done = FALSE;
3819
3820
  /* Set the request to virgin state based on transfer settings */
3821
0
  Curl_req_hard_reset(&data->req, data);
3822
3823
  /* call the stuff that needs to be called */
3824
0
  result = create_conn(data, &conn, &reused);
3825
3826
0
  if(result == CURLE_NO_CONNECTION_AVAILABLE) {
3827
0
    DEBUGASSERT(!conn);
3828
0
    return result;
3829
0
  }
3830
3831
0
  if(!result) {
3832
0
    DEBUGASSERT(conn);
3833
0
    if(reused) {
3834
0
      if(CONN_ATTACHED(conn) > 1)
3835
        /* multiplexed */
3836
0
        *protocol_done = TRUE;
3837
0
    }
3838
0
    else if(conn->handler->flags & PROTOPT_NONETWORK) {
3839
0
      *asyncp = FALSE;
3840
0
      Curl_pgrsTime(data, TIMER_NAMELOOKUP);
3841
0
      *protocol_done = TRUE;
3842
0
    }
3843
0
    else {
3844
      /*************************************************************
3845
       * Resolve the address of the server or proxy
3846
       *************************************************************/
3847
0
      struct Curl_dns_entry *dns;
3848
0
      result = resolve_server(data, conn, asyncp, &dns);
3849
0
      if(!result) {
3850
0
        *asyncp = !dns;
3851
0
        if(dns)
3852
          /* DNS resolution is done: that is either because this is a reused
3853
             connection, in which case DNS was unnecessary, or because DNS
3854
             really did finish already (synch resolver/fast async resolve) */
3855
0
          result = Curl_setup_conn(data, dns, protocol_done);
3856
0
      }
3857
0
    }
3858
0
  }
3859
3860
0
  if(result && conn) {
3861
    /* We are not allowed to return failure with memory left allocated in the
3862
       connectdata struct, free those here */
3863
0
    Curl_detach_connection(data);
3864
0
    Curl_conn_terminate(data, conn, TRUE);
3865
0
  }
3866
3867
0
  return result;
3868
0
}
3869
3870
/*
3871
 * Curl_init_do() inits the readwrite session. This is inited each time (in
3872
 * the DO function before the protocol-specific DO functions are invoked) for
3873
 * a transfer, sometimes multiple times on the same Curl_easy. Make sure
3874
 * nothing in here depends on stuff that are setup dynamically for the
3875
 * transfer.
3876
 *
3877
 * Allow this function to get called with 'conn' set to NULL.
3878
 */
3879
3880
CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
3881
0
{
3882
  /* if this is a pushed stream, we need this: */
3883
0
  CURLcode result;
3884
3885
0
  if(conn) {
3886
0
    conn->bits.do_more = FALSE; /* by default there is no curl_do_more() to
3887
                                   use */
3888
    /* if the protocol used does not support wildcards, switch it off */
3889
0
    if(data->state.wildcardmatch &&
3890
0
       !(conn->handler->flags & PROTOPT_WILDCARD))
3891
0
      data->state.wildcardmatch = FALSE;
3892
0
  }
3893
3894
0
  data->state.done = FALSE; /* *_done() is not called yet */
3895
3896
0
  if(data->req.no_body)
3897
    /* in HTTP lingo, no body means using the HEAD request... */
3898
0
    data->state.httpreq = HTTPREQ_HEAD;
3899
3900
0
  result = Curl_req_start(&data->req, data);
3901
0
  if(!result) {
3902
0
    Curl_speedinit(data);
3903
0
    Curl_pgrsSetUploadCounter(data, 0);
3904
0
    Curl_pgrsSetDownloadCounter(data, 0);
3905
0
  }
3906
0
  return result;
3907
0
}
3908
3909
#if defined(USE_HTTP2) || defined(USE_HTTP3)
3910
3911
#ifdef USE_NGHTTP2
3912
3913
static void priority_remove_child(struct Curl_easy *parent,
3914
                                  struct Curl_easy *child)
3915
{
3916
  struct Curl_data_prio_node **pnext = &parent->set.priority.children;
3917
  struct Curl_data_prio_node *pnode = parent->set.priority.children;
3918
3919
  DEBUGASSERT(child->set.priority.parent == parent);
3920
  while(pnode && pnode->data != child) {
3921
    pnext = &pnode->next;
3922
    pnode = pnode->next;
3923
  }
3924
3925
  DEBUGASSERT(pnode);
3926
  if(pnode) {
3927
    *pnext = pnode->next;
3928
    free(pnode);
3929
  }
3930
3931
  child->set.priority.parent = 0;
3932
  child->set.priority.exclusive = FALSE;
3933
}
3934
3935
CURLcode Curl_data_priority_add_child(struct Curl_easy *parent,
3936
                                      struct Curl_easy *child,
3937
                                      bool exclusive)
3938
{
3939
  if(child->set.priority.parent) {
3940
    priority_remove_child(child->set.priority.parent, child);
3941
  }
3942
3943
  if(parent) {
3944
    struct Curl_data_prio_node **tail;
3945
    struct Curl_data_prio_node *pnode;
3946
3947
    pnode = calloc(1, sizeof(*pnode));
3948
    if(!pnode)
3949
      return CURLE_OUT_OF_MEMORY;
3950
    pnode->data = child;
3951
3952
    if(parent->set.priority.children && exclusive) {
3953
      /* exclusive: move all existing children underneath the new child */
3954
      struct Curl_data_prio_node *node = parent->set.priority.children;
3955
      while(node) {
3956
        node->data->set.priority.parent = child;
3957
        node = node->next;
3958
      }
3959
3960
      tail = &child->set.priority.children;
3961
      while(*tail)
3962
        tail = &(*tail)->next;
3963
3964
      DEBUGASSERT(!*tail);
3965
      *tail = parent->set.priority.children;
3966
      parent->set.priority.children = 0;
3967
    }
3968
3969
    tail = &parent->set.priority.children;
3970
    while(*tail) {
3971
      (*tail)->data->set.priority.exclusive = FALSE;
3972
      tail = &(*tail)->next;
3973
    }
3974
3975
    DEBUGASSERT(!*tail);
3976
    *tail = pnode;
3977
  }
3978
3979
  child->set.priority.parent = parent;
3980
  child->set.priority.exclusive = exclusive;
3981
  return CURLE_OK;
3982
}
3983
3984
#endif /* USE_NGHTTP2 */
3985
3986
#ifdef USE_NGHTTP2
3987
static void data_priority_cleanup(struct Curl_easy *data)
3988
{
3989
  while(data->set.priority.children) {
3990
    struct Curl_easy *tmp = data->set.priority.children->data;
3991
    priority_remove_child(data, tmp);
3992
    if(data->set.priority.parent)
3993
      Curl_data_priority_add_child(data->set.priority.parent, tmp, FALSE);
3994
  }
3995
3996
  if(data->set.priority.parent)
3997
    priority_remove_child(data->set.priority.parent, data);
3998
}
3999
#endif
4000
4001
void Curl_data_priority_clear_state(struct Curl_easy *data)
4002
{
4003
  memset(&data->state.priority, 0, sizeof(data->state.priority));
4004
}
4005
4006
#endif /* USE_HTTP2 || USE_HTTP3 */
4007
4008
4009
CURLcode Curl_conn_meta_set(struct connectdata *conn, const char *key,
4010
                            void *meta_data, Curl_meta_dtor *meta_dtor)
4011
0
{
4012
0
  if(!Curl_hash_add2(&conn->meta_hash, CURL_UNCONST(key), strlen(key) + 1,
4013
0
                     meta_data, meta_dtor)) {
4014
0
    meta_dtor(CURL_UNCONST(key), strlen(key) + 1, meta_data);
4015
0
    return CURLE_OUT_OF_MEMORY;
4016
0
  }
4017
0
  return CURLE_OK;
4018
0
}
4019
4020
void Curl_conn_meta_remove(struct connectdata *conn, const char *key)
4021
0
{
4022
0
  Curl_hash_delete(&conn->meta_hash, CURL_UNCONST(key), strlen(key) + 1);
4023
0
}
4024
4025
void *Curl_conn_meta_get(struct connectdata *conn, const char *key)
4026
0
{
4027
0
  return Curl_hash_pick(&conn->meta_hash, CURL_UNCONST(key), strlen(key) + 1);
4028
0
}
4029
4030
CURLcode Curl_1st_err(CURLcode r1, CURLcode r2)
4031
0
{
4032
0
  return r1 ? r1 : r2;
4033
0
}
4034
4035
CURLcode Curl_1st_fatal(CURLcode r1, CURLcode r2)
4036
0
{
4037
0
  if(r1 && (r1 != CURLE_AGAIN))
4038
0
    return r1;
4039
0
  if(r2 && (r2 != CURLE_AGAIN))
4040
0
    return r2;
4041
0
  return r1;
4042
0
}