Coverage Report

Created: 2025-11-11 06:17

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