Coverage Report

Created: 2025-08-26 07:08

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