Coverage Report

Created: 2026-06-15 07:03

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