Coverage Report

Created: 2025-07-11 06:33

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