Coverage Report

Created: 2026-05-30 06:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/curl/lib/url.c
Line
Count
Source
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9
 *
10
 * This software is licensed as described in the file COPYING, which
11
 * you should have received as part of this distribution. The terms
12
 * are also available at https://curl.se/docs/copyright.html.
13
 *
14
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15
 * copies of the Software, and permit persons to whom the Software is
16
 * furnished to do so, under the terms of the COPYING file.
17
 *
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
 * KIND, either express or implied.
20
 *
21
 * SPDX-License-Identifier: curl
22
 *
23
 ***************************************************************************/
24
#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
#include "peer.h"
103
104
/* Now for the protocols */
105
#include "ftp.h"
106
#include "dict.h"
107
#include "telnet.h"
108
#include "tftp.h"
109
#include "http.h"
110
#include "vauth/vauth.h"
111
#include "file.h"
112
#include "curl_ldap.h"
113
#include "vssh/ssh.h"
114
#include "imap.h"
115
#include "url.h"
116
#include "connect.h"
117
#include "gopher.h"
118
#include "mqtt.h"
119
#include "rtsp.h"
120
#include "smtp.h"
121
#include "ws.h"
122
123
/* Some parts of the code (e.g. chunked encoding) assume this buffer has more
124
 * than a few bytes to play with. Do not let it become too small or bad things
125
 * will happen.
126
 */
127
#if READBUFFER_SIZE < READBUFFER_MIN
128
# error READBUFFER_SIZE is too small
129
#endif
130
131
/*
132
 * get_protocol_family()
133
 *
134
 * This is used to return the protocol family for a given protocol.
135
 *
136
 * Parameters:
137
 *
138
 * 's'  [in]  - struct Curl_scheme pointer.
139
 *
140
 * Returns the family as a single bit protocol identifier.
141
 */
142
static curl_prot_t get_protocol_family(const struct Curl_scheme *s)
143
0
{
144
0
  DEBUGASSERT(s);
145
0
  DEBUGASSERT(s->family);
146
0
  return s->family;
147
0
}
148
149
void Curl_freeset(struct Curl_easy *data)
150
0
{
151
  /* Free all dynamic strings stored in the data->set substructure. */
152
0
  enum dupstring i;
153
0
  enum dupblob j;
154
155
0
  for(i = (enum dupstring)0; i < STRING_LAST; i++) {
156
0
    curlx_safefree(data->set.str[i]);
157
0
  }
158
159
0
  for(j = (enum dupblob)0; j < BLOB_LAST; j++) {
160
0
    curlx_safefree(data->set.blobs[j]);
161
0
  }
162
163
0
  Curl_bufref_free(&data->state.referer);
164
0
  Curl_bufref_free(&data->state.url);
165
166
0
#if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
167
0
  Curl_mime_cleanpart(data->set.mimepostp);
168
0
  curlx_safefree(data->set.mimepostp);
169
0
#endif
170
171
0
#ifndef CURL_DISABLE_COOKIES
172
0
  curl_slist_free_all(data->state.cookielist);
173
0
  data->state.cookielist = NULL;
174
0
#endif
175
0
}
176
177
/* free the URL pieces */
178
static void up_free(struct Curl_easy *data)
179
0
{
180
0
  struct urlpieces *up = &data->state.up;
181
0
  curlx_safefree(up->scheme);
182
0
  curlx_safefree(up->hostname);
183
0
  curlx_safefree(up->port);
184
0
  curlx_safefree(up->user);
185
0
  curlx_safefree(up->password);
186
0
  curlx_safefree(up->options);
187
0
  curlx_safefree(up->path);
188
0
  curlx_safefree(up->query);
189
0
  curl_url_cleanup(data->state.uh);
190
0
  data->state.uh = NULL;
191
0
}
192
193
/*
194
 * This is the internal function curl_easy_cleanup() calls. This should
195
 * cleanup and free all resources associated with this sessionhandle.
196
 *
197
 * We ignore SIGPIPE when this is called from curl_easy_cleanup.
198
 */
199
200
CURLcode Curl_close(struct Curl_easy **datap)
201
0
{
202
0
  struct Curl_easy *data;
203
204
0
  if(!datap || !*datap)
205
0
    return CURLE_OK;
206
207
0
  data = *datap;
208
0
  *datap = NULL;
209
210
0
  if(!data->state.internal && data->multi) {
211
    /* This handle is still part of a multi handle, take care of this first
212
       and detach this handle from there.
213
       This detaches the connection. */
214
0
    curl_multi_remove_handle(data->multi, data);
215
0
  }
216
0
  else {
217
    /* Detach connection if any is left. This should not be normal, but can be
218
       the case for example with CONNECT_ONLY + recv/send (test 556) */
219
0
    Curl_detach_connection(data);
220
0
    if(!data->state.internal && data->multi_easy) {
221
      /* when curl_easy_perform() is used, it creates its own multi handle to
222
         use and this is the one */
223
0
      curl_multi_cleanup(data->multi_easy);
224
0
      data->multi_easy = NULL;
225
0
    }
226
0
  }
227
0
  DEBUGASSERT(!data->conn || data->state.internal);
228
229
0
  Curl_expire_clear(data); /* shut off any timers left */
230
231
0
  if(data->state.rangestringalloc)
232
0
    curlx_free(data->state.range);
233
234
  /* release any resolve information this transfer kept */
235
0
  Curl_resolv_destroy_all(data);
236
237
0
  data->set.verbose = FALSE; /* no more calls to DEBUGFUNCTION */
238
0
  data->magic = 0; /* force a clear AFTER the possibly enforced removal from
239
                    * the multi handle and async dns shutdown. The multi
240
                    * handle might check the magic and so might any
241
                    * DEBUGFUNCTION invoked for tracing */
242
243
  /* freed here in case DONE was not called */
244
0
  Curl_req_free(&data->req, data);
245
246
  /* Close down all open SSL info and sessions */
247
0
  Curl_ssl_close_all(data);
248
0
  Curl_peer_unlink(&data->state.initial_origin);
249
0
  Curl_ssl_free_certinfo(data);
250
251
0
  Curl_bufref_free(&data->state.referer);
252
253
0
  up_free(data);
254
0
  curlx_dyn_free(&data->state.headerb);
255
0
  Curl_flush_cookies(data, TRUE);
256
0
#ifndef CURL_DISABLE_ALTSVC
257
0
  Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]);
258
0
  Curl_altsvc_cleanup(&data->asi);
259
0
#endif
260
0
#ifndef CURL_DISABLE_HSTS
261
0
  Curl_hsts_save(data, data->hsts, data->set.str[STRING_HSTS]);
262
0
  if(!data->share || !data->share->hsts)
263
0
    Curl_hsts_cleanup(&data->hsts);
264
0
  curl_slist_free_all(data->state.hstslist); /* clean up list */
265
0
#endif
266
0
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH)
267
0
  Curl_http_auth_cleanup_digest(data);
268
0
#endif
269
0
  curlx_safefree(data->state.most_recent_ftp_entrypath);
270
0
  curlx_safefree(data->info.contenttype);
271
0
  curlx_safefree(data->info.wouldredirect);
272
273
  /* No longer a dirty share, if it exists */
274
0
  if(Curl_share_easy_unlink(data))
275
0
    DEBUGASSERT(0);
276
277
0
  Curl_hash_destroy(&data->meta_hash);
278
0
  Curl_creds_unlink(&data->state.creds);
279
0
  curlx_safefree(data->state.aptr.uagent);
280
0
  curlx_safefree(data->state.aptr.accept_encoding);
281
0
  curlx_safefree(data->state.aptr.rangeline);
282
0
  curlx_safefree(data->state.aptr.ref);
283
0
  curlx_safefree(data->state.aptr.host);
284
0
#ifndef CURL_DISABLE_COOKIES
285
0
  curlx_safefree(data->req.cookiehost);
286
0
#endif
287
0
#ifndef CURL_DISABLE_RTSP
288
0
  curlx_safefree(data->state.aptr.rtsp_transport);
289
0
#endif
290
291
0
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_FORM_API)
292
0
  Curl_mime_cleanpart(data->state.formp);
293
0
  curlx_safefree(data->state.formp);
294
0
#endif
295
296
  /* destruct wildcard structures if it is needed */
297
0
  Curl_wildcard_dtor(&data->wildcard);
298
0
  Curl_freeset(data);
299
0
  Curl_headers_cleanup(data);
300
0
  Curl_netrc_cleanup(&data->state.netrc);
301
0
#ifndef CURL_DISABLE_DIGEST_AUTH
302
0
  curlx_free(data->state.envproxy);
303
0
#endif
304
0
  curlx_free(data);
305
0
  return CURLE_OK;
306
0
}
307
308
/*
309
 * Initialize the UserDefined fields within a Curl_easy.
310
 * This may be safely called on a new or existing Curl_easy.
311
 */
312
void Curl_init_userdefined(struct Curl_easy *data)
313
0
{
314
0
  struct UserDefined *set = &data->set;
315
316
0
  set->out = stdout;  /* default output to stdout */
317
0
  set->in_set = stdin;  /* default input from stdin */
318
0
  set->err = stderr;  /* default stderr to stderr */
319
320
0
#if defined(__clang__) && __clang_major__ >= 16
321
0
#pragma clang diagnostic push
322
0
#pragma clang diagnostic ignored "-Wcast-function-type-strict"
323
0
#endif
324
  /* use fwrite as default function to store output */
325
0
  set->fwrite_func = (curl_write_callback)fwrite;
326
327
  /* use fread as default function to read input */
328
0
  set->fread_func_set = (curl_read_callback)fread;
329
0
#if defined(__clang__) && __clang_major__ >= 16
330
0
#pragma clang diagnostic pop
331
0
#endif
332
0
  set->is_fread_set = 0;
333
334
0
  set->seek_client = ZERO_NULL;
335
336
0
  set->filesize = -1;        /* we do not know the size */
337
0
  set->postfieldsize = -1;   /* unknown size */
338
0
  set->maxredirs = 30;       /* sensible default */
339
340
0
  set->method = HTTPREQ_GET; /* Default HTTP request */
341
0
#ifndef CURL_DISABLE_RTSP
342
0
  set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */
343
0
#endif
344
0
#ifndef CURL_DISABLE_FTP
345
0
  set->ftp_use_epsv = TRUE;   /* FTP defaults to EPSV operations */
346
0
  set->ftp_use_eprt = TRUE;   /* FTP defaults to EPRT operations */
347
0
  set->ftp_use_pret = FALSE;  /* mainly useful for drftpd servers */
348
0
  set->ftp_filemethod = FTPFILE_MULTICWD;
349
0
  set->ftp_skip_ip = TRUE;    /* skip PASV IP by default */
350
0
#endif
351
0
  set->dns_cache_timeout_ms = 60000; /* Timeout every 60 seconds by default */
352
353
  /* Timeout every 24 hours by default */
354
0
  set->general_ssl.ca_cache_timeout = 24 * 60 * 60;
355
356
0
  set->httpauth = CURLAUTH_BASIC;  /* defaults to basic */
357
358
0
#ifndef CURL_DISABLE_PROXY
359
0
  set->proxyport = 0;
360
0
  set->proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */
361
0
  set->proxyauth = CURLAUTH_BASIC; /* defaults to basic */
362
  /* SOCKS5 proxy auth defaults to username/password + GSS-API */
363
0
  set->socks5auth = CURLAUTH_BASIC | CURLAUTH_GSSAPI;
364
0
#endif
365
366
0
  Curl_ssl_easy_config_init(data);
367
0
#ifndef CURL_DISABLE_DOH
368
0
  set->doh_verifyhost = TRUE;
369
0
  set->doh_verifypeer = TRUE;
370
0
#endif
371
#ifdef USE_SSH
372
  /* defaults to any auth type */
373
  set->ssh_auth_types = CURLSSH_AUTH_DEFAULT;
374
  set->new_directory_perms = 0755; /* Default permissions */
375
#endif
376
377
0
  set->new_file_perms = 0644;    /* Default permissions */
378
0
  set->allowed_protocols = (curl_prot_t)CURLPROTO_64ALL;
379
0
  set->redir_protocols = CURLPROTO_REDIR;
380
381
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
382
  /*
383
   * disallow unprotected protection negotiation NEC reference implementation
384
   * seem not to follow rfc1961 section 4.3/4.4
385
   */
386
  set->socks5_gssapi_nec = FALSE;
387
#endif
388
389
  /* set default minimum TLS version */
390
0
#ifdef USE_SSL
391
0
  Curl_setopt_SSLVERSION(data, CURLOPT_SSLVERSION, CURL_SSLVERSION_DEFAULT);
392
0
#ifndef CURL_DISABLE_PROXY
393
0
  Curl_setopt_SSLVERSION(data, CURLOPT_PROXY_SSLVERSION,
394
0
                         CURL_SSLVERSION_DEFAULT);
395
0
#endif
396
0
#endif
397
0
#ifndef CURL_DISABLE_FTP
398
0
  set->wildcard_enabled = FALSE;
399
0
  set->chunk_bgn = ZERO_NULL;
400
0
  set->chunk_end = ZERO_NULL;
401
0
  set->fnmatch = ZERO_NULL;
402
0
#endif
403
0
  set->tcp_keepalive = FALSE;
404
0
  set->tcp_keepintvl = 60;
405
0
  set->tcp_keepidle = 60;
406
0
  set->tcp_keepcnt = 9;
407
0
  set->tcp_fastopen = FALSE;
408
0
  set->tcp_nodelay = TRUE;
409
0
  set->ssl_enable_alpn = TRUE;
410
0
  set->expect_100_timeout = 1000L; /* Wait for a second by default. */
411
0
  set->sep_headers = TRUE; /* separated header lists by default */
412
0
  set->buffer_size = READBUFFER_SIZE;
413
0
  set->upload_buffer_size = UPLOADBUFFER_DEFAULT;
414
0
  set->upload_flags = CURLULFLAG_SEEN;
415
0
  set->happy_eyeballs_timeout = CURL_HET_DEFAULT;
416
0
  set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT;
417
0
  set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
418
0
  set->conn_max_idle_ms = 118 * 1000;
419
0
  set->conn_max_age_ms = 24 * 3600 * 1000;
420
0
  set->http09_allowed = FALSE;
421
0
  set->httpwant = CURL_HTTP_VERSION_NONE;
422
0
#if defined(USE_HTTP2) || defined(USE_HTTP3)
423
0
  memset(&set->priority, 0, sizeof(set->priority));
424
0
#endif
425
0
  set->quick_exit = 0L;
426
0
#ifndef CURL_DISABLE_WEBSOCKETS
427
0
  set->ws_raw_mode = FALSE;
428
0
  set->ws_no_auto_pong = FALSE;
429
0
#endif
430
0
}
431
432
/* easy->meta_hash destructor. Should never be called as elements
433
 * MUST be added with their own destructor */
434
static void easy_meta_freeentry(void *p)
435
0
{
436
0
  (void)p;
437
  /* Always FALSE. Cannot use a 0 assert here since compilers
438
   * are not in agreement if they then want a NORETURN attribute or
439
   * not. *sigh* */
440
0
  DEBUGASSERT(p == NULL);
441
0
}
442
443
/**
444
 * Curl_open()
445
 *
446
 * @param curl is a pointer to a sessionhandle pointer that gets set by this
447
 * function.
448
 * @return CURLcode
449
 */
450
451
CURLcode Curl_open(struct Curl_easy **curl)
452
0
{
453
0
  struct Curl_easy *data;
454
455
  /* simple start-up: alloc the struct, init it with zeroes and return */
456
0
  data = curlx_calloc(1, sizeof(struct Curl_easy));
457
0
  if(!data) {
458
    /* this is a serious error */
459
0
    DEBUGF(curl_mfprintf(stderr, "Error: calloc of Curl_easy failed\n"));
460
0
    return CURLE_OUT_OF_MEMORY;
461
0
  }
462
463
0
  data->magic = CURLEASY_MAGIC_NUMBER;
464
  /* most recent connection is not yet defined */
465
0
  data->state.lastconnect_id = -1;
466
0
  data->state.recent_conn_id = -1;
467
  /* and not assigned an id yet */
468
0
  data->id = -1;
469
0
  data->mid = UINT32_MAX;
470
0
  data->master_mid = UINT32_MAX;
471
0
  data->progress.hide = TRUE;
472
0
  data->state.current_speed = -1; /* init to negative == impossible */
473
474
0
  Curl_hash_init(&data->meta_hash, 23,
475
0
                 Curl_hash_str, curlx_str_key_compare, easy_meta_freeentry);
476
0
  curlx_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER);
477
0
  Curl_bufref_init(&data->state.url);
478
0
  Curl_bufref_init(&data->state.referer);
479
0
  Curl_req_init(&data->req);
480
0
  Curl_initinfo(data);
481
0
#ifndef CURL_DISABLE_HTTP
482
0
  Curl_llist_init(&data->state.httphdrs, NULL);
483
0
#endif
484
0
  Curl_netrc_init(&data->state.netrc);
485
0
  Curl_init_userdefined(data);
486
487
0
  *curl = data;
488
0
  return CURLE_OK;
489
0
}
490
491
void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn)
492
0
{
493
0
  size_t i;
494
495
0
  DEBUGASSERT(conn);
496
497
0
  if(conn->scheme && conn->scheme->run->disconnect &&
498
0
     !conn->bits.shutdown_handler)
499
0
    conn->scheme->run->disconnect(data, conn, TRUE);
500
501
0
  for(i = 0; i < CURL_ARRAYSIZE(conn->cfilter); ++i) {
502
0
    Curl_conn_cf_discard_all(data, conn, (int)i);
503
0
  }
504
505
0
#ifndef CURL_DISABLE_PROXY
506
0
  Curl_peer_unlink(&conn->http_proxy.peer);
507
0
  Curl_peer_unlink(&conn->socks_proxy.peer);
508
0
  Curl_creds_unlink(&conn->http_proxy.creds);
509
0
  Curl_creds_unlink(&conn->socks_proxy.creds);
510
0
#endif
511
0
  Curl_creds_unlink(&conn->creds);
512
0
  curlx_safefree(conn->options);
513
0
  curlx_safefree(conn->localdev);
514
0
  Curl_ssl_conn_config_cleanup(conn);
515
516
0
  curlx_safefree(conn->destination);
517
0
  Curl_hash_destroy(&conn->meta_hash);
518
0
  Curl_peer_unlink(&conn->origin);
519
0
  Curl_peer_unlink(&conn->via_peer);
520
0
  Curl_peer_unlink(&conn->origin2);
521
0
  Curl_peer_unlink(&conn->via_peer2);
522
523
0
  curlx_free(conn); /* free all the connection oriented data */
524
0
}
525
526
/*
527
 * xfer_may_multiplex()
528
 *
529
 * Return a TRUE, iff the transfer can be done over an (appropriate)
530
 * multiplexed connection.
531
 */
532
static bool xfer_may_multiplex(const struct Curl_easy *data,
533
                               const struct connectdata *conn)
534
0
{
535
0
#ifndef CURL_DISABLE_HTTP
536
  /* If an HTTP protocol and multiplexing is enabled */
537
0
  if((conn->scheme->protocol & PROTO_FAMILY_HTTP) &&
538
0
     (!conn->bits.protoconnstart || !conn->bits.close)) {
539
540
0
    if(Curl_multiplex_wanted(data->multi) &&
541
0
       (data->state.http_neg.allowed & (CURL_HTTP_V2x | CURL_HTTP_V3x)))
542
      /* allows HTTP/2 or newer */
543
0
      return TRUE;
544
0
  }
545
#else
546
  (void)data;
547
  (void)conn;
548
#endif
549
0
  return FALSE;
550
0
}
551
552
#ifndef CURL_DISABLE_PROXY
553
static bool proxy_info_matches(const struct proxy_info *data,
554
                               const struct proxy_info *needle)
555
0
{
556
0
  if((data->proxytype == needle->proxytype) &&
557
0
     Curl_peer_same_destination(data->peer, needle->peer) &&
558
0
     Curl_creds_same(data->creds, needle->creds)) {
559
0
    return TRUE;
560
0
  }
561
0
  return FALSE;
562
0
}
563
#endif
564
565
/* A connection has to have been idle for less than 'conn_max_idle_ms'
566
   (the success rate is too low after this), or created less than
567
   'conn_max_age_ms' ago, to be subject for reuse. */
568
static bool conn_maxage(struct Curl_easy *data,
569
                        struct connectdata *conn,
570
                        struct curltime now)
571
0
{
572
0
  timediff_t age_ms;
573
574
0
  if(data->set.conn_max_idle_ms) {
575
0
    age_ms = curlx_ptimediff_ms(&now, &conn->lastused);
576
0
    if(age_ms > data->set.conn_max_idle_ms) {
577
0
      infof(data, "Too old connection (%" FMT_TIMEDIFF_T
578
0
            " ms idle, max idle is %" FMT_TIMEDIFF_T " ms), disconnect it",
579
0
            age_ms, data->set.conn_max_idle_ms);
580
0
      return TRUE;
581
0
    }
582
0
  }
583
584
0
  if(data->set.conn_max_age_ms) {
585
0
    age_ms = curlx_ptimediff_ms(&now, &conn->created);
586
0
    if(age_ms > data->set.conn_max_age_ms) {
587
0
      infof(data,
588
0
            "Too old connection (created %" FMT_TIMEDIFF_T
589
0
            " ms ago, max lifetime is %" FMT_TIMEDIFF_T " ms), disconnect it",
590
0
            age_ms, data->set.conn_max_age_ms);
591
0
      return TRUE;
592
0
    }
593
0
  }
594
595
0
  return FALSE;
596
0
}
597
598
/*
599
 * Return TRUE iff the given connection is considered dead.
600
 */
601
bool Curl_conn_seems_dead(struct connectdata *conn,
602
                          struct Curl_easy *data)
603
0
{
604
0
  DEBUGASSERT(!data->conn);
605
0
  if(!CONN_INUSE(conn)) {
606
    /* The check for a dead socket makes sense only if the connection is not in
607
       use */
608
0
    bool dead;
609
610
0
    if(conn_maxage(data, conn, *Curl_pgrs_now(data))) {
611
      /* avoid check if already too old */
612
0
      dead = TRUE;
613
0
    }
614
0
    else if(conn->scheme->run->connection_is_dead) {
615
      /* The protocol has a special method for checking the state of the
616
         connection. Use it to check if the connection is dead. */
617
      /* briefly attach the connection for the check */
618
0
      Curl_attach_connection(data, conn);
619
0
      dead = conn->scheme->run->connection_is_dead(data, conn);
620
0
      Curl_detach_connection(data);
621
0
    }
622
0
    else {
623
0
      bool input_pending = FALSE;
624
625
0
      Curl_attach_connection(data, conn);
626
0
      dead = !Curl_conn_is_alive(data, conn, &input_pending);
627
0
      if(input_pending) {
628
        /* For reuse, we want a "clean" connection state. This includes
629
         * that we expect - in general - no waiting input data. Input
630
         * waiting might be a TLS Notify Close, for example. We reject
631
         * that.
632
         * For protocols where data from other end may arrive at
633
         * any time (HTTP/2 PING for example), the protocol handler needs
634
         * to install its own `connection_check` callback.
635
         */
636
0
        DEBUGF(infof(data, "connection has input pending, not reusable"));
637
0
        dead = TRUE;
638
0
      }
639
0
      Curl_detach_connection(data);
640
0
    }
641
642
0
    if(dead) {
643
      /* remove connection from cpool */
644
0
      infof(data, "Connection %" FMT_OFF_T " seems to be dead",
645
0
            conn->connection_id);
646
0
      return TRUE;
647
0
    }
648
0
  }
649
0
  return FALSE;
650
0
}
651
652
CURLcode Curl_conn_upkeep(struct Curl_easy *data,
653
                          struct connectdata *conn)
654
0
{
655
0
  CURLcode result = CURLE_OK;
656
0
  if(curlx_ptimediff_ms(Curl_pgrs_now(data), &conn->keepalive) <=
657
0
     data->set.upkeep_interval_ms)
658
0
    return result;
659
660
  /* briefly attach for action */
661
0
  Curl_attach_connection(data, conn);
662
0
  result = Curl_conn_keep_alive(data, conn, FIRSTSOCKET);
663
0
  Curl_detach_connection(data);
664
665
0
  conn->keepalive = *Curl_pgrs_now(data);
666
0
  return result;
667
0
}
668
669
struct url_conn_match {
670
  struct connectdata *found;
671
  struct Curl_easy *data;
672
  struct connectdata *needle;
673
  BIT(may_multiplex);
674
  BIT(want_ntlm_http);
675
  BIT(want_proxy_ntlm_http);
676
  BIT(want_nego_http);
677
  BIT(want_proxy_nego_http);
678
  BIT(may_tls); /* May upgrade clear-text connection to TLS, can only reuse
679
                 * connections that have matching TLS configuration.
680
                 * Always TRUE if `req_tls` is TRUE. */
681
  BIT(require_tls); /* Requires TLS use from a clear-text start, can only
682
                 * reuse connections that have TLS. */
683
  BIT(wait_pipe);
684
  BIT(force_reuse);
685
  BIT(seen_pending_conn);
686
  BIT(seen_single_use_conn);
687
  BIT(seen_multiplex_conn);
688
};
689
690
static bool url_match_connect_config(struct connectdata *conn,
691
                                     struct url_conn_match *m)
692
0
{
693
  /* connect-only or to-be-closed connections will not be reused */
694
0
  if(conn->bits.connect_only || conn->bits.close || conn->bits.no_reuse)
695
0
    return FALSE;
696
697
  /* ip_version must match */
698
0
  if(m->data->set.ipver != CURL_IPRESOLVE_WHATEVER &&
699
0
     m->data->set.ipver != conn->ip_version)
700
0
    return FALSE;
701
702
0
  if(m->needle->localdev || m->needle->localport) {
703
    /* If we are bound to a specific local end (IP+port), we must not reuse a
704
       random other one, although if we did not ask for a particular one we
705
       can reuse one that was bound.
706
707
       This comparison is a bit rough and too strict. Since the input
708
       parameters can be specified in numerous ways and still end up the same
709
       it would take a lot of processing to make it really accurate. Instead,
710
       this matching will assume that reuses of bound connections will most
711
       likely also reuse the exact same binding parameters and missing out a
712
       few edge cases should not hurt anyone much.
713
    */
714
0
    if((conn->localport != m->needle->localport) ||
715
0
       (conn->localportrange != m->needle->localportrange) ||
716
0
       (m->needle->localdev &&
717
0
        (!conn->localdev || strcmp(conn->localdev, m->needle->localdev))))
718
0
      return FALSE;
719
0
  }
720
721
0
  if(!m->needle->via_peer != !conn->via_peer)
722
    /* do not mix connections that use the "connect to host" feature and
723
     * connections that do not use this feature */
724
0
    return FALSE;
725
726
0
  return TRUE;
727
0
}
728
729
static bool url_match_fully_connected(struct connectdata *conn,
730
                                      struct url_conn_match *m)
731
0
{
732
0
  if(!Curl_conn_is_connected(conn, FIRSTSOCKET) ||
733
0
     conn->bits.upgrade_in_progress) {
734
    /* Not yet connected, or a protocol upgrade is in progress. The later
735
     * happens for HTTP/2 Upgrade: requests that need a response. */
736
0
    if(m->may_multiplex) {
737
0
      m->seen_pending_conn = TRUE;
738
      /* Do not pick a connection that has not connected yet */
739
0
      infof(m->data, "Connection #%" FMT_OFF_T
740
0
            " is not open enough, cannot reuse", conn->connection_id);
741
0
    }
742
    /* Do not pick a connection that has not connected yet */
743
0
    return FALSE;
744
0
  }
745
0
  return TRUE;
746
0
}
747
748
static bool url_match_multi(struct connectdata *conn,
749
                            struct url_conn_match *m)
750
0
{
751
0
  if(CONN_INUSE(conn)) {
752
0
    DEBUGASSERT(conn->attached_multi);
753
0
    if(conn->attached_multi != m->data->multi)
754
0
      return FALSE;
755
0
  }
756
0
  return TRUE;
757
0
}
758
759
static bool url_match_multiplex_needs(struct connectdata *conn,
760
                                      struct url_conn_match *m)
761
0
{
762
0
  if(CONN_INUSE(conn)) {
763
0
    if(!conn->bits.multiplex) {
764
      /* conn busy and conn cannot take more transfers */
765
0
      m->seen_single_use_conn = TRUE;
766
0
      return FALSE;
767
0
    }
768
0
    m->seen_multiplex_conn = TRUE;
769
0
    if(!m->may_multiplex || !url_match_multi(conn, m))
770
      /* conn busy and transfer cannot be multiplexed */
771
0
      return FALSE;
772
0
  }
773
0
  return TRUE;
774
0
}
775
776
static bool url_match_multiplex_limits(struct connectdata *conn,
777
                                       struct url_conn_match *m)
778
0
{
779
0
  if(CONN_INUSE(conn) && m->may_multiplex) {
780
0
    DEBUGASSERT(conn->bits.multiplex);
781
    /* If multiplexed, make sure we do not go over concurrency limit */
782
0
    if(conn->attached_xfers >=
783
0
            Curl_multi_max_concurrent_streams(m->data->multi)) {
784
0
      infof(m->data, "client side MAX_CONCURRENT_STREAMS reached"
785
0
            ", skip (%u)", conn->attached_xfers);
786
0
      return FALSE;
787
0
    }
788
0
    if(conn->attached_xfers >=
789
0
       Curl_conn_get_max_concurrent(m->data, conn, FIRSTSOCKET)) {
790
0
      infof(m->data, "MAX_CONCURRENT_STREAMS reached, skip (%u)",
791
0
            conn->attached_xfers);
792
0
      return FALSE;
793
0
    }
794
    /* When not multiplexed, we have a match here! */
795
0
    infof(m->data, "Multiplexed connection found");
796
0
  }
797
0
  return TRUE;
798
0
}
799
800
static bool url_match_ssl_use(struct connectdata *conn,
801
                              struct url_conn_match *m)
802
0
{
803
0
  if(m->needle->scheme->flags & PROTOPT_SSL) {
804
    /* We are looking for SSL, if `conn` does not do it, not a match. */
805
0
    if(!Curl_conn_is_ssl(conn, FIRSTSOCKET))
806
0
      return FALSE;
807
0
  }
808
0
  else if(Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
809
    /* If the protocol does not allow reuse of SSL connections OR
810
       is of another protocol family, not a match. */
811
0
    if(!(m->needle->scheme->flags & PROTOPT_SSL_REUSE) ||
812
0
       (get_protocol_family(conn->scheme) != m->needle->scheme->protocol))
813
0
      return FALSE;
814
0
  }
815
0
  else if(m->require_tls)
816
    /* a clear-text STARTTLS protocol with required TLS */
817
0
    return FALSE;
818
0
  return TRUE;
819
0
}
820
821
#ifndef CURL_DISABLE_PROXY
822
static bool url_match_proxy_use(struct connectdata *conn,
823
                                struct url_conn_match *m)
824
0
{
825
0
  if(m->needle->bits.httpproxy != conn->bits.httpproxy ||
826
0
     m->needle->bits.socksproxy != conn->bits.socksproxy)
827
0
    return FALSE;
828
829
0
  if(m->needle->bits.socksproxy &&
830
0
     !proxy_info_matches(&m->needle->socks_proxy, &conn->socks_proxy))
831
0
    return FALSE;
832
833
0
  if(m->needle->bits.httpproxy) {
834
0
    if(m->needle->bits.tunnel_proxy != conn->bits.tunnel_proxy)
835
0
      return FALSE;
836
837
0
    if(!proxy_info_matches(&m->needle->http_proxy, &conn->http_proxy))
838
0
      return FALSE;
839
840
0
    if(IS_HTTPS_PROXY(m->needle->http_proxy.proxytype)) {
841
      /* https proxies come in different types, http/1.1, h2, ... */
842
0
      if(m->needle->http_proxy.proxytype != conn->http_proxy.proxytype)
843
0
        return FALSE;
844
      /* match SSL config to proxy */
845
0
      if(!Curl_ssl_conn_config_match(m->data, conn, TRUE)) {
846
0
        DEBUGF(infof(m->data,
847
0
                     "Connection #%" FMT_OFF_T
848
0
                     " has different SSL proxy parameters, cannot reuse",
849
0
                     conn->connection_id));
850
0
        return FALSE;
851
0
      }
852
      /* the SSL config to the server, which may apply here is checked
853
       * further below */
854
0
    }
855
0
  }
856
0
  return TRUE;
857
0
}
858
#else
859
#define url_match_proxy_use(c, m) ((void)(c), (void)(m), TRUE)
860
#endif
861
862
#ifndef CURL_DISABLE_HTTP
863
static bool url_match_http_multiplex(struct connectdata *conn,
864
                                     struct url_conn_match *m)
865
0
{
866
0
  if(m->may_multiplex &&
867
0
     (m->data->state.http_neg.allowed & (CURL_HTTP_V2x | CURL_HTTP_V3x)) &&
868
0
     (m->needle->scheme->protocol & CURLPROTO_HTTP) &&
869
0
     !conn->httpversion_seen) {
870
0
    if(m->data->set.pipewait) {
871
0
      infof(m->data, "Server upgrade does not support multiplex yet, wait");
872
0
      m->found = NULL;
873
0
      m->wait_pipe = TRUE;
874
0
      return TRUE; /* stop searching, we want to wait */
875
0
    }
876
0
    infof(m->data, "Server upgrade cannot be used");
877
0
    return FALSE;
878
0
  }
879
0
  return TRUE;
880
0
}
881
882
static bool url_match_http_version(struct connectdata *conn,
883
                                   struct url_conn_match *m)
884
0
{
885
  /* If looking for HTTP and the HTTP versions allowed do not include
886
   * the HTTP version of conn, continue looking. */
887
0
  if((m->needle->scheme->protocol & PROTO_FAMILY_HTTP)) {
888
0
    switch(Curl_conn_http_version(m->data, conn)) {
889
0
    case 30:
890
0
      if(!(m->data->state.http_neg.allowed & CURL_HTTP_V3x)) {
891
0
        DEBUGF(infof(m->data, "not reusing conn #%" CURL_FORMAT_CURL_OFF_T
892
0
                     ", we do not want h3", conn->connection_id));
893
0
        return FALSE;
894
0
      }
895
0
      break;
896
0
    case 20:
897
0
      if(!(m->data->state.http_neg.allowed & CURL_HTTP_V2x)) {
898
0
        DEBUGF(infof(m->data, "not reusing conn #%" CURL_FORMAT_CURL_OFF_T
899
0
                     ", we do not want h2", conn->connection_id));
900
0
        return FALSE;
901
0
      }
902
0
      break;
903
0
    default:
904
0
      if(!(m->data->state.http_neg.allowed & CURL_HTTP_V1x)) {
905
0
        DEBUGF(infof(m->data, "not reusing conn #%" CURL_FORMAT_CURL_OFF_T
906
0
                     ", we do not want h1", conn->connection_id));
907
0
        return FALSE;
908
0
      }
909
0
      break;
910
0
    }
911
0
  }
912
0
  return TRUE;
913
0
}
914
#else
915
#define url_match_http_multiplex(c, m) ((void)(c), (void)(m), TRUE)
916
#define url_match_http_version(c, m)   ((void)(c), (void)(m), TRUE)
917
#endif
918
919
static bool url_match_proto_config(struct connectdata *conn,
920
                                   struct url_conn_match *m)
921
0
{
922
0
  if(!url_match_http_version(conn, m))
923
0
    return FALSE;
924
925
0
#ifndef CURL_DISABLE_FTP
926
0
  else if(get_protocol_family(m->needle->scheme) & PROTO_FAMILY_FTP) {
927
0
    if(!ftp_conns_match(m->needle, conn))
928
0
      return FALSE;
929
0
  }
930
0
#endif
931
0
  return TRUE;
932
0
}
933
934
static bool url_match_auth(struct connectdata *conn,
935
                           struct url_conn_match *m)
936
0
{
937
0
  if(!Curl_creds_same(m->needle->creds, conn->creds)) {
938
0
    if(m->needle->creds)
939
0
      return FALSE;
940
0
    if(!Curl_creds_same(m->data->state.creds, conn->creds))
941
0
      return FALSE;
942
0
  }
943
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
944
  /* GSS delegation differences do not actually affect every connection and
945
     auth method, but this check takes precaution before efficiency */
946
  if(m->needle->gssapi_delegation != conn->gssapi_delegation)
947
    return FALSE;
948
#endif
949
950
0
  return TRUE;
951
0
}
952
953
static bool url_match_destination(struct connectdata *conn,
954
                                  struct url_conn_match *m)
955
0
{
956
  /* Different connect-to peers never match */
957
0
  if(!Curl_peer_same_destination(m->needle->via_peer, conn->via_peer))
958
0
    return FALSE;
959
960
0
#ifndef CURL_DISABLE_PROXY
961
0
  if(m->needle->bits.httpproxy && !m->needle->bits.tunnel_proxy) {
962
    /* Talking to a non-tunneling HTTP proxy matches on proxy peers. */
963
0
    return Curl_peer_equal(m->needle->http_proxy.peer,
964
0
                           conn->http_proxy.peer);
965
0
  }
966
0
#endif
967
968
0
  if(m->needle->origin->scheme != conn->origin->scheme) {
969
    /* `needle` and `conn` not having the same scheme.
970
     * This is allowed for the same family *if* conn is using TLS.
971
     * - IMAP+STARTTLS works for IMAPS.
972
     * - IMAPS works for IMAP. */
973
0
    if(get_protocol_family(conn->origin->scheme) !=
974
0
       m->needle->scheme->protocol) {
975
0
      return FALSE;
976
0
    }
977
0
    if(!url_match_ssl_use(conn, m)) {
978
0
      DEBUGF(infof(m->data, "Connection #%" FMT_OFF_T
979
0
                   " has compatible protocol family, but no SSL, no match",
980
0
                   conn->connection_id));
981
0
      return FALSE;
982
0
    }
983
0
  }
984
  /* Scheme mismatch is acceptable, just compare hostname/port */
985
0
  return Curl_peer_same_destination(m->needle->origin, conn->origin);
986
0
}
987
988
static bool url_match_ssl_config(struct connectdata *conn,
989
                                 struct url_conn_match *m)
990
0
{
991
  /* If talking/upgrading to TLS, conn needs to use the same SSL options. */
992
0
  if(((m->needle->scheme->flags & PROTOPT_SSL) || m->may_tls) &&
993
0
     !Curl_ssl_conn_config_match(m->data, conn, FALSE)) {
994
0
    DEBUGF(infof(m->data, "Connection #%" FMT_OFF_T
995
0
                 " has different SSL parameters, cannot reuse",
996
0
                 conn->connection_id));
997
0
    return FALSE;
998
0
  }
999
0
  return TRUE;
1000
0
}
1001
1002
#ifdef USE_NTLM
1003
static bool url_match_auth_ntlm(struct connectdata *conn,
1004
                                struct url_conn_match *m)
1005
{
1006
  /* If we are looking for an HTTP+NTLM connection, check if this is
1007
     already authenticating with the right credentials. If not, keep
1008
     looking so that we can reuse NTLM connections if
1009
     possible. (Especially we must not reuse the same connection if
1010
     partway through a handshake!) */
1011
  if(m->want_ntlm_http) {
1012
    if(!Curl_creds_same(m->data->state.creds, conn->creds)) {
1013
      /* we prefer a credential match, but this is at least a connection
1014
         that can be reused and "upgraded" to NTLM if it does
1015
         not have any auth ongoing. */
1016
#ifdef USE_SPNEGO
1017
      if((conn->http_ntlm_state == NTLMSTATE_NONE) &&
1018
         (conn->http_negotiate_state == GSS_AUTHNONE)) {
1019
#else
1020
      if(conn->http_ntlm_state == NTLMSTATE_NONE) {
1021
#endif
1022
        m->found = conn;
1023
      }
1024
      return FALSE;
1025
    }
1026
  }
1027
  else if(conn->http_ntlm_state != NTLMSTATE_NONE) {
1028
    /* Connection is using NTLM auth but we do not want NTLM */
1029
    return FALSE;
1030
  }
1031
1032
#ifndef CURL_DISABLE_PROXY
1033
  /* Same for Proxy NTLM authentication */
1034
  if(m->want_proxy_ntlm_http) {
1035
    /* Both conn->http_proxy.user and conn->http_proxy.passwd can be
1036
     * NULL */
1037
    if(!conn->http_proxy.creds)
1038
      return FALSE;
1039
1040
    if(!Curl_creds_same(m->needle->http_proxy.creds, conn->http_proxy.creds))
1041
      return FALSE;
1042
  }
1043
  else if(conn->proxy_ntlm_state != NTLMSTATE_NONE) {
1044
    /* Proxy connection is using NTLM auth but we do not want NTLM */
1045
    return FALSE;
1046
  }
1047
#endif
1048
  if(m->want_ntlm_http || m->want_proxy_ntlm_http) {
1049
    /* Credentials are already checked, we may use this connection.
1050
     * With NTLM being weird as it is, we MUST use a
1051
     * connection where it has already been fully negotiated.
1052
     * If it has not, we keep on looking for a better one. */
1053
    m->found = conn;
1054
1055
    if((m->want_ntlm_http &&
1056
       (conn->http_ntlm_state != NTLMSTATE_NONE)) ||
1057
        (m->want_proxy_ntlm_http &&
1058
         (conn->proxy_ntlm_state != NTLMSTATE_NONE))) {
1059
      /* We must use this connection, no other */
1060
      m->force_reuse = TRUE;
1061
      return TRUE;
1062
    }
1063
    /* Continue look up for a better connection */
1064
    return FALSE;
1065
  }
1066
  return TRUE;
1067
}
1068
#else
1069
0
#define url_match_auth_ntlm(c, m) ((void)(c), (void)(m), TRUE)
1070
#endif
1071
1072
#ifdef USE_SPNEGO
1073
static bool url_match_auth_nego(struct connectdata *conn,
1074
                                struct url_conn_match *m)
1075
{
1076
  /* If we are looking for an HTTP+Negotiate connection, check if this is
1077
     already authenticating with the right credentials. If not, keep looking
1078
     so that we can reuse Negotiate connections if possible. */
1079
  if(m->want_nego_http) {
1080
    if(!Curl_creds_same(m->needle->creds, conn->creds))
1081
      return FALSE;
1082
  }
1083
  else if(conn->http_negotiate_state != GSS_AUTHNONE) {
1084
    /* Connection is using Negotiate auth but we do not want Negotiate */
1085
    return FALSE;
1086
  }
1087
1088
#ifndef CURL_DISABLE_PROXY
1089
  /* Same for Proxy Negotiate authentication */
1090
  if(m->want_proxy_nego_http) {
1091
    /* Both conn->http_proxy.user and conn->http_proxy.passwd can be
1092
     * NULL */
1093
    if(!conn->http_proxy.creds)
1094
      return FALSE;
1095
1096
    if(!Curl_creds_same(m->needle->http_proxy.creds, conn->http_proxy.creds))
1097
      return FALSE;
1098
  }
1099
  else if(conn->proxy_negotiate_state != GSS_AUTHNONE) {
1100
    /* Proxy connection is using Negotiate auth but we do not want Negotiate */
1101
    return FALSE;
1102
  }
1103
#endif
1104
  if(m->want_nego_http || m->want_proxy_nego_http) {
1105
    /* Credentials are already checked, we may use this connection. We MUST
1106
     * use a connection where it has already been fully negotiated. If it has
1107
     * not, we keep on looking for a better one. */
1108
    m->found = conn;
1109
    if((m->want_nego_http &&
1110
        (conn->http_negotiate_state != GSS_AUTHNONE)) ||
1111
       (m->want_proxy_nego_http &&
1112
        (conn->proxy_negotiate_state != GSS_AUTHNONE))) {
1113
      /* We must use this connection, no other */
1114
      m->force_reuse = TRUE;
1115
      return TRUE;
1116
    }
1117
    return FALSE; /* get another */
1118
  }
1119
  return TRUE;
1120
}
1121
#else
1122
0
#define url_match_auth_nego(c, m) ((void)(c), (void)(m), TRUE)
1123
#endif
1124
1125
static bool url_match_conn(struct connectdata *conn, void *userdata)
1126
0
{
1127
0
  struct url_conn_match *m = userdata;
1128
  /* Check if `conn` can be used for transfer `m->data` */
1129
1130
  /* general connect config setting match? */
1131
0
  if(!url_match_connect_config(conn, m))
1132
0
    return FALSE;
1133
1134
  /* match for destination and protocol? */
1135
0
  if(!url_match_destination(conn, m))
1136
0
    return FALSE;
1137
1138
0
  if(!url_match_fully_connected(conn, m))
1139
0
    return FALSE;
1140
1141
0
  if(!url_match_multiplex_needs(conn, m))
1142
0
    return FALSE;
1143
1144
0
  if(!url_match_proxy_use(conn, m))
1145
0
    return FALSE;
1146
0
  if(!url_match_ssl_config(conn, m))
1147
0
    return FALSE;
1148
1149
0
  if(!url_match_http_multiplex(conn, m))
1150
0
    return FALSE;
1151
0
  else if(m->wait_pipe)
1152
    /* we decided to wait on PIPELINING */
1153
0
    return TRUE;
1154
1155
0
  if(!url_match_auth(conn, m))
1156
0
    return FALSE;
1157
1158
0
  if(!url_match_proto_config(conn, m))
1159
0
    return FALSE;
1160
1161
0
  if(!url_match_auth_ntlm(conn, m))
1162
0
    return FALSE;
1163
0
  else if(m->force_reuse)
1164
0
    return TRUE;
1165
1166
0
  if(!url_match_auth_nego(conn, m))
1167
0
    return FALSE;
1168
0
  else if(m->force_reuse)
1169
0
    return TRUE;
1170
1171
0
  if(!url_match_multiplex_limits(conn, m))
1172
0
    return FALSE;
1173
1174
0
  if(!CONN_INUSE(conn) && Curl_conn_seems_dead(conn, m->data)) {
1175
    /* remove and disconnect. */
1176
0
    Curl_conn_terminate(m->data, conn, FALSE);
1177
0
    return FALSE;
1178
0
  }
1179
1180
  /* conn matches our needs. */
1181
0
  m->found = conn;
1182
0
  return TRUE;
1183
0
}
1184
1185
static bool url_match_result(void *userdata)
1186
0
{
1187
0
  struct url_conn_match *match = userdata;
1188
0
  if(match->found) {
1189
    /* Attach it now while still under lock, so the connection does
1190
     * no longer appear idle and can be reaped. */
1191
0
    Curl_attach_connection(match->data, match->found);
1192
0
    return TRUE;
1193
0
  }
1194
0
  else if(match->seen_single_use_conn && !match->seen_multiplex_conn) {
1195
    /* We have seen a single-use, existing connection to the destination and
1196
     * no multiplexed one. It seems safe to assume that the server does
1197
     * not support multiplexing. */
1198
0
    match->wait_pipe = FALSE;
1199
0
  }
1200
0
  else if(match->seen_pending_conn && match->data->set.pipewait) {
1201
0
    infof(match->data,
1202
0
          "Found pending candidate for reuse and CURLOPT_PIPEWAIT is set");
1203
0
    match->wait_pipe = TRUE;
1204
0
  }
1205
0
  match->force_reuse = FALSE;
1206
0
  return FALSE;
1207
0
}
1208
1209
/*
1210
 * Given a transfer and a prototype connection (needle),
1211
 * find and attach an existing connection that matches.
1212
 *
1213
 * Return TRUE if an existing connection was attached.
1214
 * `waitpipe` is TRUE if no existing connection matched, but there
1215
 * might be suitable one in the near future (common cause: multiplexing
1216
 * capability has not been determined yet, e.g. ALPN handshake).
1217
 */
1218
static bool url_attach_existing(struct Curl_easy *data,
1219
                                struct connectdata *needle,
1220
                                bool *waitpipe)
1221
0
{
1222
0
  struct url_conn_match match;
1223
0
  bool success;
1224
1225
0
  DEBUGASSERT(!data->conn);
1226
0
  memset(&match, 0, sizeof(match));
1227
0
  match.data = data;
1228
0
  match.needle = needle;
1229
0
  match.may_multiplex = xfer_may_multiplex(data, needle);
1230
1231
#ifdef USE_NTLM
1232
  match.want_ntlm_http =
1233
    (data->state.authhost.want & CURLAUTH_NTLM) &&
1234
    (needle->scheme->protocol & PROTO_FAMILY_HTTP);
1235
#ifndef CURL_DISABLE_PROXY
1236
  match.want_proxy_ntlm_http =
1237
    needle->http_proxy.creds &&
1238
    (data->state.authproxy.want & CURLAUTH_NTLM) &&
1239
    (needle->scheme->protocol & PROTO_FAMILY_HTTP);
1240
#endif
1241
#endif
1242
1243
#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO)
1244
  match.want_nego_http =
1245
    (data->state.authhost.want & CURLAUTH_NEGOTIATE) &&
1246
    (needle->scheme->protocol & PROTO_FAMILY_HTTP);
1247
#ifndef CURL_DISABLE_PROXY
1248
  match.want_proxy_nego_http =
1249
    needle->http_proxy.creds &&
1250
    (data->state.authproxy.want & CURLAUTH_NEGOTIATE) &&
1251
    (needle->scheme->protocol & PROTO_FAMILY_HTTP);
1252
#endif
1253
#endif
1254
0
  match.require_tls = data->set.use_ssl >= CURLUSESSL_CONTROL;
1255
0
  match.may_tls = data->set.use_ssl > CURLUSESSL_NONE;
1256
1257
  /* Find a connection in the pool that matches what "data + needle"
1258
   * requires. If a suitable candidate is found, it is attached to "data". */
1259
0
  success = Curl_cpool_find(data, needle->destination,
1260
0
                            url_match_conn, url_match_result, &match);
1261
1262
  /* wait_pipe is TRUE if we encounter a bundle that is undecided. There
1263
   * is no matching connection then, yet. */
1264
0
  *waitpipe = (bool)match.wait_pipe;
1265
0
  return success;
1266
0
}
1267
1268
/*
1269
 * Allocate and initialize a new connectdata object.
1270
 */
1271
static struct connectdata *allocate_conn(struct Curl_easy *data)
1272
0
{
1273
0
  struct connectdata *conn = curlx_calloc(1, sizeof(struct connectdata));
1274
0
  if(!conn)
1275
0
    return NULL;
1276
1277
  /* and we setup a few fields in case we end up actually using this struct */
1278
1279
0
  conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD;     /* no file descriptor */
1280
0
  conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
1281
0
  conn->recv_idx = 0; /* default for receiving transfer data */
1282
0
  conn->send_idx = 0; /* default for sending transfer data */
1283
0
  conn->connection_id = -1;    /* no ID */
1284
0
  conn->attached_xfers = 0;
1285
1286
  /* Store creation time to help future close decision making */
1287
0
  conn->created = *Curl_pgrs_now(data);
1288
1289
  /* Store current time to give a baseline to keepalive connection times. */
1290
0
  conn->keepalive = conn->created;
1291
1292
0
#ifndef CURL_DISABLE_PROXY
1293
0
  conn->http_proxy.proxytype = data->set.proxytype;
1294
0
  conn->socks_proxy.proxytype = CURLPROXY_SOCKS4;
1295
1296
  /* note that these two proxy bits are set on what looks to be
1297
     requested, they may be altered down the road */
1298
0
  conn->bits.proxy = (data->set.str[STRING_PROXY] &&
1299
0
                      *data->set.str[STRING_PROXY]);
1300
0
  conn->bits.httpproxy = (conn->bits.proxy &&
1301
0
                          (conn->http_proxy.proxytype == CURLPROXY_HTTP ||
1302
0
                           conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0 ||
1303
0
                           IS_HTTPS_PROXY(conn->http_proxy.proxytype)));
1304
0
  conn->bits.socksproxy = (conn->bits.proxy && !conn->bits.httpproxy);
1305
1306
0
  if(data->set.str[STRING_PRE_PROXY] && *data->set.str[STRING_PRE_PROXY]) {
1307
0
    conn->bits.proxy = TRUE;
1308
0
    conn->bits.socksproxy = TRUE;
1309
0
  }
1310
1311
0
  conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
1312
0
#endif /* CURL_DISABLE_PROXY */
1313
1314
0
#ifndef CURL_DISABLE_FTP
1315
0
  conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
1316
0
  conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
1317
0
#endif
1318
0
  conn->ip_version = data->set.ipver;
1319
0
  conn->bits.connect_only = (bool)data->set.connect_only;
1320
0
  conn->transport_wanted = TRNSPRT_TCP; /* most of them are TCP streams */
1321
1322
  /* Store the local bind parameters that will be used for this connection */
1323
0
  if(data->set.str[STRING_DEVICE]) {
1324
0
    conn->localdev = curlx_strdup(data->set.str[STRING_DEVICE]);
1325
0
    if(!conn->localdev)
1326
0
      goto error;
1327
0
  }
1328
0
#ifndef CURL_DISABLE_BINDLOCAL
1329
0
  conn->localportrange = data->set.localportrange;
1330
0
  conn->localport = data->set.localport;
1331
0
#endif
1332
1333
  /* the close socket stuff needs to be copied to the connection struct as
1334
     it may live on without (this specific) Curl_easy */
1335
0
  conn->fclosesocket = data->set.fclosesocket;
1336
0
  conn->closesocket_client = data->set.closesocket_client;
1337
0
  conn->lastused = conn->created;
1338
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
1339
  conn->gssapi_delegation = data->set.gssapi_delegation;
1340
#endif
1341
0
  DEBUGF(infof(data, "alloc connection, bits.close=%d", conn->bits.close));
1342
0
  return conn;
1343
0
error:
1344
1345
0
  curlx_free(conn->localdev);
1346
0
  curlx_free(conn);
1347
0
  return NULL;
1348
0
}
1349
1350
static CURLcode url_set_conn_scheme(struct Curl_easy *data,
1351
                                    struct connectdata *conn,
1352
                                    const struct Curl_scheme *scheme)
1353
0
{
1354
  /* URL scheme is usable for connection when it is
1355
   * - allowed
1356
   * - not from a redirect or an allowed redirect protocol */
1357
0
  if(scheme->run &&
1358
0
     (data->set.allowed_protocols & scheme->protocol) &&
1359
0
     (!data->state.this_is_a_follow ||
1360
0
       (data->set.redir_protocols & scheme->protocol))) {
1361
0
    conn->scheme = conn->given = scheme;
1362
0
    return CURLE_OK;
1363
0
  }
1364
0
  if(scheme->flags & PROTOPT_NO_TRANSFER)
1365
0
    failf(data, "Protocol \"%s\" is not for transfers", scheme->name);
1366
0
  else
1367
0
    failf(data, "Protocol \"%s\" is disabled%s", scheme->name,
1368
0
          data->state.this_is_a_follow ? " (in redirect)" : "");
1369
0
  return CURLE_UNSUPPORTED_PROTOCOL;
1370
0
}
1371
1372
CURLcode Curl_uc_to_curlcode(CURLUcode uc)
1373
0
{
1374
0
  switch(uc) {
1375
0
  default:
1376
0
    return CURLE_URL_MALFORMAT;
1377
0
  case CURLUE_UNSUPPORTED_SCHEME:
1378
0
    return CURLE_UNSUPPORTED_PROTOCOL;
1379
0
  case CURLUE_OUT_OF_MEMORY:
1380
0
    return CURLE_OUT_OF_MEMORY;
1381
0
  case CURLUE_USER_NOT_ALLOWED:
1382
0
    return CURLE_LOGIN_DENIED;
1383
0
  }
1384
0
}
1385
1386
#ifndef CURL_DISABLE_HSTS
1387
static CURLcode hsts_upgrade(struct Curl_easy *data,
1388
                             struct connectdata *conn,
1389
                             CURLU *uh,
1390
                             uint16_t port_override,
1391
                             uint32_t scope_id)
1392
0
{
1393
  /* HSTS upgrade */
1394
0
  if(data->hsts && (conn->origin->scheme == &Curl_scheme_http) &&
1395
0
     Curl_hsts_applies(data->hsts, conn->origin)) {
1396
0
    char *url;
1397
0
    CURLUcode uc;
1398
0
    CURLcode result;
1399
1400
0
    curlx_safefree(data->state.up.scheme);
1401
0
    uc = curl_url_set(uh, CURLUPART_SCHEME, "https", 0);
1402
0
    if(uc)
1403
0
      return Curl_uc_to_curlcode(uc);
1404
0
    Curl_bufref_free(&data->state.url);
1405
    /* after update, get the updated version */
1406
0
    uc = curl_url_get(uh, CURLUPART_URL, &url, 0);
1407
0
    if(uc)
1408
0
      return Curl_uc_to_curlcode(uc);
1409
0
    Curl_bufref_set(&data->state.url, url, 0, curl_free);
1410
1411
0
    result = Curl_peer_from_url(uh, data, port_override, scope_id,
1412
0
                                &data->state.up, &conn->origin);
1413
0
    if(result)
1414
0
      return result;
1415
0
    infof(data, "Switched from HTTP to HTTPS due to HSTS => %s", url);
1416
0
  }
1417
0
  return CURLE_OK;
1418
0
}
1419
#else
1420
#define hsts_upgrade(x, y, z, a, b) CURLE_OK
1421
#endif
1422
1423
static CURLcode url_set_data_creds(struct Curl_easy *data,
1424
                                   struct connectdata *conn,
1425
                                   CURLU *uh)
1426
0
{
1427
0
  CURLcode result = CURLE_OK;
1428
1429
  /* We reset any existing credentials on the transfer. Then
1430
   * set the CURLOPT_* credentials ONLY IF the origin is the initial one. */
1431
0
  Curl_creds_unlink(&data->state.creds);
1432
0
  if((data->set.str[STRING_USERNAME] ||
1433
0
      data->set.str[STRING_PASSWORD] ||
1434
0
      data->set.str[STRING_BEARER] ||
1435
0
      data->set.str[STRING_SASL_AUTHZID] ||
1436
0
      data->set.str[STRING_SERVICE_NAME]) &&
1437
0
     Curl_auth_allowed_to_origin(data, conn->origin)) {
1438
0
    result = Curl_creds_create(data->set.str[STRING_USERNAME],
1439
0
                               data->set.str[STRING_PASSWORD],
1440
0
                               data->set.str[STRING_BEARER],
1441
0
                               data->set.str[STRING_SASL_AUTHZID],
1442
0
                               data->set.str[STRING_SERVICE_NAME],
1443
0
                               CREDS_OPTION, &data->state.creds);
1444
0
    if(result)
1445
0
      return result;
1446
0
  }
1447
1448
  /* Extract credentials from the URL only if there are none OR
1449
   * if no CURLOPT_USER was set. */
1450
0
  if(!data->state.creds || !Curl_creds_has_user(data->state.creds)) {
1451
0
    char *udecoded = NULL;
1452
0
    char *pdecoded = NULL;
1453
0
    CURLUcode uc;
1454
1455
0
    uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user, 0);
1456
0
    if(uc && (uc != CURLUE_NO_USER)) {
1457
0
      result = Curl_uc_to_curlcode(uc);
1458
0
      goto out;
1459
0
    }
1460
0
    uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0);
1461
0
    if(uc && (uc != CURLUE_NO_PASSWORD)) {
1462
0
      result = Curl_uc_to_curlcode(uc);
1463
0
      goto out;
1464
0
    }
1465
0
    if(data->state.up.user) {
1466
0
      result = Curl_urldecode(data->state.up.user, 0, &udecoded, NULL,
1467
0
                              conn->scheme->flags&PROTOPT_USERPWDCTRL ?
1468
0
                              REJECT_ZERO : REJECT_CTRL);
1469
0
    }
1470
0
    if(!result && data->state.up.password) {
1471
0
      result = Curl_urldecode(data->state.up.password, 0, &pdecoded, NULL,
1472
0
                              conn->scheme->flags&PROTOPT_USERPWDCTRL ?
1473
0
                              REJECT_ZERO : REJECT_CTRL);
1474
0
    }
1475
0
    if(!result)
1476
0
      result = Curl_creds_merge(udecoded, pdecoded, data->state.creds,
1477
0
                                CREDS_URL, &data->state.creds);
1478
0
out:
1479
0
    curlx_free(udecoded);
1480
0
    curlx_free(pdecoded);
1481
0
    if(result)
1482
0
      failf(data, "error extracting credentials from URL");
1483
0
  }
1484
0
  return result;
1485
0
}
1486
1487
/*
1488
 * Parse URL and fill in the relevant members of the connection struct.
1489
 */
1490
static CURLcode parseurlandfillconn(struct Curl_easy *data,
1491
                                    struct connectdata *conn)
1492
0
{
1493
0
  CURLcode result = CURLE_OK;
1494
0
  CURLU *uh;
1495
0
  CURLUcode uc;
1496
0
  bool use_set_uh = (data->set.uh && !data->state.this_is_a_follow);
1497
0
  uint16_t port_override = data->state.allow_port ? data->set.use_port : 0;
1498
0
  uint32_t scope_id = 0;
1499
1500
0
  up_free(data); /* cleanup previous leftovers first */
1501
1502
  /* parse the URL */
1503
0
  if(use_set_uh)
1504
0
    uh = data->state.uh = curl_url_dup(data->set.uh);
1505
0
  else
1506
0
    uh = data->state.uh = curl_url();
1507
0
  if(!uh) {
1508
0
    result = CURLE_OUT_OF_MEMORY;
1509
0
    goto out;
1510
0
  }
1511
1512
  /* Calculate the *real* URL this transfer uses, applying defaults
1513
   * where information is missing. */
1514
0
  if(data->set.str[STRING_DEFAULT_PROTOCOL] &&
1515
0
     !Curl_is_absolute_url(Curl_bufref_ptr(&data->state.url), NULL, 0, TRUE)) {
1516
0
    char *url = curl_maprintf("%s://%s",
1517
0
                              data->set.str[STRING_DEFAULT_PROTOCOL],
1518
0
                              Curl_bufref_ptr(&data->state.url));
1519
0
    if(!url) {
1520
0
      result = CURLE_OUT_OF_MEMORY;
1521
0
      goto out;
1522
0
    }
1523
0
    Curl_bufref_set(&data->state.url, url, 0, curl_free);
1524
0
  }
1525
1526
0
  if(!use_set_uh) {
1527
0
    char *newurl;
1528
0
    uc = curl_url_set(uh, CURLUPART_URL, Curl_bufref_ptr(&data->state.url),
1529
0
                      (unsigned int)(CURLU_GUESS_SCHEME |
1530
0
                       CURLU_NON_SUPPORT_SCHEME |
1531
0
                       (data->set.disallow_username_in_url ?
1532
0
                        CURLU_DISALLOW_USER : 0) |
1533
0
                       (data->set.path_as_is ? CURLU_PATH_AS_IS : 0)));
1534
0
    if(uc) {
1535
0
      failf(data, "URL rejected: %s", curl_url_strerror(uc));
1536
0
      result = Curl_uc_to_curlcode(uc);
1537
0
      goto out;
1538
0
    }
1539
1540
    /* after it was parsed, get the generated normalized version */
1541
0
    uc = curl_url_get(uh, CURLUPART_URL, &newurl, CURLU_GET_EMPTY);
1542
0
    if(uc) {
1543
0
      result = Curl_uc_to_curlcode(uc);
1544
0
      goto out;
1545
0
    }
1546
0
    Curl_bufref_set(&data->state.url, newurl, 0, curl_free);
1547
0
  }
1548
1549
0
#ifdef USE_IPV6
1550
0
  scope_id = data->set.scope_id;
1551
0
#endif
1552
1553
  /* `uh` is now as the connection should use it, probably. */
1554
0
  result = Curl_peer_from_url(uh, data, port_override, scope_id,
1555
0
                              &data->state.up, &conn->origin);
1556
0
  if(result)
1557
0
    goto out;
1558
1559
0
  result = hsts_upgrade(data, conn, uh, port_override, scope_id);
1560
0
  if(result)
1561
0
    goto out;
1562
1563
  /* now that the origin is fixed, check and set the connection scheme */
1564
0
  result = url_set_conn_scheme(data, conn, conn->origin->scheme);
1565
0
  if(result)
1566
0
    goto out;
1567
1568
  /* When the transfers initial_origin is not set, this is the initial
1569
   * request. Remember this starting point. This is used to
1570
   * select credentials. */
1571
0
  if(!data->state.initial_origin)
1572
0
    Curl_peer_link(&data->state.initial_origin, conn->origin);
1573
1574
0
  result = url_set_data_creds(data, conn, uh);
1575
0
  if(result)
1576
0
    goto out;
1577
1578
0
  uc = curl_url_get(uh, CURLUPART_OPTIONS, &data->state.up.options,
1579
0
                    CURLU_URLDECODE);
1580
0
  if(!uc) {
1581
0
    conn->options = curlx_strdup(data->state.up.options);
1582
0
    if(!conn->options) {
1583
0
      result = CURLE_OUT_OF_MEMORY;
1584
0
      goto out;
1585
0
    }
1586
0
  }
1587
0
  else if(uc != CURLUE_NO_OPTIONS) {
1588
0
    result = Curl_uc_to_curlcode(uc);
1589
0
    goto out;
1590
0
  }
1591
1592
0
  uc = curl_url_get(uh, CURLUPART_PATH, &data->state.up.path, CURLU_URLENCODE);
1593
0
  if(uc) {
1594
0
    result = Curl_uc_to_curlcode(uc);
1595
0
    goto out;
1596
0
  }
1597
1598
0
  uc = curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query,
1599
0
                    CURLU_GET_EMPTY);
1600
0
  if(uc && (uc != CURLUE_NO_QUERY)) {
1601
0
    result = CURLE_OUT_OF_MEMORY;
1602
0
    goto out;
1603
0
  }
1604
1605
0
#ifdef USE_IPV6
1606
  /* Fill in the conn parts that do not use authority, yet. */
1607
0
  conn->scope_id = conn->origin->scopeid;
1608
0
#endif
1609
1610
0
#ifdef CURLVERBOSE
1611
0
  Curl_creds_trace(data, data->state.creds, "transfer credentials");
1612
0
#endif
1613
1614
0
out:
1615
0
  return result;
1616
0
}
1617
1618
/*
1619
 * If we are doing a resumed transfer, we need to setup our stuff
1620
 * properly.
1621
 */
1622
static CURLcode setup_range(struct Curl_easy *data)
1623
0
{
1624
0
  struct UrlState *s = &data->state;
1625
0
  s->resume_from = data->set.set_resume_from;
1626
0
  if(s->resume_from || data->set.str[STRING_SET_RANGE]) {
1627
0
    if(s->rangestringalloc)
1628
0
      curlx_free(s->range);
1629
1630
0
    if(s->resume_from)
1631
0
      s->range = curl_maprintf("%" FMT_OFF_T "-", s->resume_from);
1632
0
    else
1633
0
      s->range = curlx_strdup(data->set.str[STRING_SET_RANGE]);
1634
1635
0
    if(!s->range)
1636
0
      return CURLE_OUT_OF_MEMORY;
1637
1638
0
    s->rangestringalloc = TRUE;
1639
1640
    /* tell ourselves to fetch this range */
1641
0
    s->use_range = TRUE;        /* enable range download */
1642
0
  }
1643
0
  else
1644
0
    s->use_range = FALSE; /* disable range download */
1645
1646
0
  return CURLE_OK;
1647
0
}
1648
1649
/*
1650
 * setup_connection_internals() -
1651
 *
1652
 * Setup connection internals specific to the requested protocol in the
1653
 * Curl_easy. This is inited and setup before the connection is made but
1654
 * is about the particular protocol that is to be used.
1655
 *
1656
 * This MUST get called after proxy magic has been figured out.
1657
 */
1658
static CURLcode setup_connection_internals(struct Curl_easy *data,
1659
                                           struct connectdata *conn)
1660
0
{
1661
0
  struct Curl_peer *peer = NULL;
1662
0
  CURLcode result;
1663
1664
0
  DEBUGF(infof(data, "setup connection, bits.close=%d", conn->bits.close));
1665
0
  if(conn->scheme->run->setup_connection) {
1666
0
    result = conn->scheme->run->setup_connection(data, conn);
1667
0
    if(result)
1668
0
      return result;
1669
0
  }
1670
0
  DEBUGF(infof(data, "setup connection, bits.close=%d", conn->bits.close));
1671
1672
  /* Now create the destination name */
1673
0
  peer = Curl_conn_get_destination(conn, FIRSTSOCKET);
1674
0
  if(!peer)
1675
0
    return CURLE_FAILED_INIT;
1676
1677
  /* IPv6 addresses with a scope_id (0 is default == global) have a
1678
   * printable representation with a '%<scope_id>' suffix. */
1679
0
  if(peer->ipv6)
1680
0
    if(peer->scopeid)
1681
0
      conn->destination = curl_maprintf("[%s%%%u]:%u",
1682
0
        peer->hostname, peer->scopeid, peer->port);
1683
0
    else
1684
0
      conn->destination = curl_maprintf("[%s]:%u",
1685
0
        peer->hostname, peer->port);
1686
0
  else
1687
0
    conn->destination = curl_maprintf("%s:%u", peer->hostname, peer->port);
1688
0
  if(!conn->destination)
1689
0
    return CURLE_OUT_OF_MEMORY;
1690
1691
0
  Curl_strntolower(conn->destination, conn->destination,
1692
0
                   strlen(conn->destination));
1693
1694
0
  return CURLE_OK;
1695
0
}
1696
1697
#ifndef CURL_DISABLE_PROXY
1698
1699
#ifndef CURL_DISABLE_HTTP
1700
/****************************************************************
1701
 * Detect what (if any) proxy to use. Remember that this selects a host
1702
 * name and is not limited to HTTP proxies only.
1703
 * The returned pointer must be freed by the caller (unless NULL)
1704
 ****************************************************************/
1705
static char *url_detect_proxy(struct Curl_easy *data,
1706
                              struct connectdata *conn)
1707
0
{
1708
0
  char *proxy = NULL;
1709
1710
  /* If proxy was not specified, we check for default proxy environment
1711
   * variables, to enable i.e Lynx compliance:
1712
   *
1713
   * http_proxy=http://some.server.dom:port/
1714
   * https_proxy=http://some.server.dom:port/
1715
   * ftp_proxy=http://some.server.dom:port/
1716
   * no_proxy=domain1.dom,host.domain2.dom
1717
   *   (a comma-separated list of hosts which should
1718
   *   not be proxied, or an asterisk to override
1719
   *   all proxy variables)
1720
   * all_proxy=http://some.server.dom:port/
1721
   *   (seems to exist for the CERN www lib. Probably
1722
   *   the first to check for.)
1723
   *
1724
   * For compatibility, the all-uppercase versions of these variables are
1725
   * checked if the lowercase versions do not exist.
1726
   */
1727
0
  char proxy_env[20];
1728
0
  const char *envp;
1729
0
  VERBOSE(envp = proxy_env);
1730
1731
0
  curl_msnprintf(proxy_env, sizeof(proxy_env), "%s_proxy",
1732
0
                 conn->scheme->name);
1733
1734
  /* read the protocol proxy: */
1735
0
  proxy = curl_getenv(proxy_env);
1736
1737
  /*
1738
   * We do not try the uppercase version of HTTP_PROXY because of
1739
   * security reasons:
1740
   *
1741
   * When curl is used in a webserver application
1742
   * environment (cgi or php), this environment variable can
1743
   * be controlled by the web server user by setting the
1744
   * http header 'Proxy:' to some value.
1745
   *
1746
   * This can cause 'internal' http/ftp requests to be
1747
   * arbitrarily redirected by any external attacker.
1748
   */
1749
0
  if(!proxy && !curl_strequal("http_proxy", proxy_env)) {
1750
    /* There was no lowercase variable, try the uppercase version: */
1751
0
    Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env));
1752
0
    proxy = curl_getenv(proxy_env);
1753
0
  }
1754
1755
0
  if(!proxy) {
1756
0
#ifndef CURL_DISABLE_WEBSOCKETS
1757
    /* websocket proxy fallbacks */
1758
0
    if(curl_strequal("ws_proxy", proxy_env)) {
1759
0
      proxy = curl_getenv("http_proxy");
1760
0
    }
1761
0
    else if(curl_strequal("wss_proxy", proxy_env)) {
1762
0
      proxy = curl_getenv("https_proxy");
1763
0
      if(!proxy)
1764
0
        proxy = curl_getenv("HTTPS_PROXY");
1765
0
    }
1766
0
    if(!proxy) {
1767
0
#endif
1768
0
      envp = "all_proxy";
1769
0
      proxy = curl_getenv(envp); /* default proxy to use */
1770
0
      if(!proxy) {
1771
0
        envp = "ALL_PROXY";
1772
0
        proxy = curl_getenv(envp);
1773
0
      }
1774
0
#ifndef CURL_DISABLE_WEBSOCKETS
1775
0
    }
1776
0
#endif
1777
0
  }
1778
0
  if(proxy)
1779
0
    infof(data, "Uses proxy env variable %s == '%s'", envp, proxy);
1780
1781
0
  return proxy;
1782
0
}
1783
#endif /* CURL_DISABLE_HTTP */
1784
1785
/*
1786
 * If this is supposed to use a proxy, we need to figure out the proxy
1787
 * hostname, so that we can reuse an existing connection
1788
 * that may exist registered to the same proxy host.
1789
 */
1790
static CURLcode parse_proxy(struct Curl_easy *data,
1791
                            const char *proxy,
1792
                            bool for_pre_proxy,
1793
                            struct proxy_info *proxyinfo)
1794
0
{
1795
0
  char *proxyuser = NULL;
1796
0
  char *proxypasswd = NULL;
1797
0
  char *scheme = NULL;
1798
0
  CURLcode result = CURLE_OK;
1799
  /* Set the start proxy type for url scheme guessing */
1800
0
  uint8_t proxytype = for_pre_proxy ? CURLPROXY_SOCKS4 : data->set.proxytype;
1801
0
  CURLU *uhp = curl_url();
1802
0
  CURLUcode uc;
1803
1804
0
  if(!uhp) {
1805
0
    result = CURLE_OUT_OF_MEMORY;
1806
0
    goto error;
1807
0
  }
1808
  /* When parsing the proxy, allowing non-supported schemes since we have
1809
     these made up ones for proxies. Guess scheme for URLs without it. */
1810
0
  uc = curl_url_set(uhp, CURLUPART_URL, proxy,
1811
0
                    CURLU_NON_SUPPORT_SCHEME | CURLU_GUESS_SCHEME);
1812
0
  if(!uc) {
1813
    /* parsed okay as a URL - only update proxytype when scheme was explicit */
1814
0
    uc = curl_url_get(uhp, CURLUPART_SCHEME, &scheme, CURLU_NO_GUESS_SCHEME);
1815
0
    if(!uc) {
1816
0
      result = Curl_scheme_to_proxytype(data, scheme, &proxytype, proxy);
1817
0
      if(result)
1818
0
        goto error;
1819
0
    }
1820
0
    else if(uc != CURLUE_NO_SCHEME) {
1821
0
      result = CURLE_OUT_OF_MEMORY;
1822
0
      goto error;
1823
0
    }
1824
    /* else: no explicit scheme, keep the configured proxytype */
1825
0
  }
1826
0
  else {
1827
0
    failf(data, "Unsupported proxy syntax in \'%s\': %s", proxy,
1828
0
          curl_url_strerror(uc));
1829
0
    result = CURLE_COULDNT_RESOLVE_PROXY;
1830
0
    goto error;
1831
0
  }
1832
1833
0
  result = Curl_peer_from_proxy_url(uhp, data, proxy, proxytype,
1834
0
                                    &proxyinfo->peer, &proxytype);
1835
0
  if(result)
1836
0
    goto error;
1837
1838
0
  switch(proxytype) {
1839
0
    case CURLPROXY_HTTP:
1840
0
    case CURLPROXY_HTTP_1_0:
1841
0
    case CURLPROXY_HTTPS:
1842
0
    case CURLPROXY_HTTPS2:
1843
0
    case CURLPROXY_HTTPS3:
1844
0
      if(for_pre_proxy) {
1845
0
        failf(data, "Unsupported pre-proxy type for \'%s\'", proxy);
1846
0
        result = CURLE_COULDNT_RESOLVE_PROXY;
1847
0
        goto error;
1848
0
      }
1849
0
      break;
1850
0
    case CURLPROXY_SOCKS4:
1851
0
    case CURLPROXY_SOCKS4A:
1852
0
    case CURLPROXY_SOCKS5:
1853
0
    case CURLPROXY_SOCKS5_HOSTNAME:
1854
0
      break;
1855
0
    default:
1856
0
      failf(data, "Unsupported proxy type %u for \'%s\'", proxytype, proxy);
1857
0
      result = CURLE_COULDNT_RESOLVE_PROXY;
1858
0
      goto error;
1859
0
  }
1860
1861
  /* Is there a username and password given in this proxy URL? */
1862
0
  uc = curl_url_get(uhp, CURLUPART_USER, &proxyuser, CURLU_URLDECODE);
1863
0
  if(uc && (uc != CURLUE_NO_USER)) {
1864
0
    result = Curl_uc_to_curlcode(uc);
1865
0
    goto error;
1866
0
  }
1867
0
  uc = curl_url_get(uhp, CURLUPART_PASSWORD, &proxypasswd, CURLU_URLDECODE);
1868
0
  if(uc && (uc != CURLUE_NO_PASSWORD)) {
1869
0
    result = Curl_uc_to_curlcode(uc);
1870
0
    goto error;
1871
0
  }
1872
1873
0
  if(proxyuser || proxypasswd) {
1874
0
    result = Curl_creds_create(proxyuser, proxypasswd, NULL, NULL,
1875
0
                               data->set.str[STRING_PROXY_SERVICE_NAME],
1876
0
                               CREDS_URL, &proxyinfo->creds);
1877
0
    if(result)
1878
0
      goto error;
1879
0
  }
1880
0
  else if(!for_pre_proxy &&
1881
0
          (data->set.str[STRING_PROXYUSERNAME] ||
1882
0
           data->set.str[STRING_PROXYPASSWORD] ||
1883
0
           data->set.str[STRING_PROXY_SERVICE_NAME])) {
1884
    /* No user/passwd in URL, if this is not a pre-proxy, the
1885
     * CURLOPT_PROXY* settings apply. */
1886
0
    result = Curl_creds_create(data->set.str[STRING_PROXYUSERNAME],
1887
0
                               data->set.str[STRING_PROXYPASSWORD],
1888
0
                               NULL, NULL,
1889
0
                               data->set.str[STRING_PROXY_SERVICE_NAME],
1890
0
                               CREDS_OPTION, &proxyinfo->creds);
1891
0
  }
1892
0
  else
1893
0
    Curl_creds_unlink(&proxyinfo->creds);
1894
1895
0
  proxyinfo->proxytype = proxytype;
1896
1897
0
error:
1898
0
  curlx_free(scheme);
1899
0
  curlx_free(proxyuser);
1900
0
  curlx_free(proxypasswd);
1901
0
  curl_url_cleanup(uhp);
1902
0
#ifdef DEBUGBUILD
1903
0
  if(!result) {
1904
0
    DEBUGASSERT(proxyinfo);
1905
0
    DEBUGASSERT(proxyinfo->peer);
1906
0
  }
1907
0
#endif
1908
0
  return result;
1909
0
}
1910
1911
static CURLcode url_set_conn_proxies(struct Curl_easy *data,
1912
                                     struct connectdata *conn)
1913
0
{
1914
0
  char *proxy = NULL;
1915
0
  char *pre_proxy = NULL;
1916
0
  char *no_proxy = NULL;
1917
0
  CURLcode result = CURLE_OK;
1918
1919
  /*************************************************************
1920
   * Detect what (if any) proxy to use
1921
   *************************************************************/
1922
0
  if(data->set.str[STRING_PROXY]) {
1923
0
    proxy = curlx_strdup(data->set.str[STRING_PROXY]);
1924
    /* if global proxy is set, this is it */
1925
0
    if(!proxy) {
1926
0
      failf(data, "memory shortage");
1927
0
      result = CURLE_OUT_OF_MEMORY;
1928
0
      goto out;
1929
0
    }
1930
0
  }
1931
1932
0
  if(data->set.str[STRING_PRE_PROXY]) {
1933
0
    pre_proxy = curlx_strdup(data->set.str[STRING_PRE_PROXY]);
1934
    /* if global socks proxy is set, this is it */
1935
0
    if(!pre_proxy) {
1936
0
      failf(data, "memory shortage");
1937
0
      result = CURLE_OUT_OF_MEMORY;
1938
0
      goto out;
1939
0
    }
1940
0
  }
1941
1942
0
  if(!data->set.str[STRING_NOPROXY]) {
1943
0
    const char *p = "no_proxy";
1944
0
    no_proxy = curl_getenv(p);
1945
0
    if(!no_proxy) {
1946
0
      p = "NO_PROXY";
1947
0
      no_proxy = curl_getenv(p);
1948
0
    }
1949
0
    if(no_proxy) {
1950
0
      infof(data, "Uses proxy env variable %s == '%s'", p, no_proxy);
1951
0
    }
1952
0
  }
1953
1954
0
  if(Curl_check_noproxy(conn->origin->hostname, data->set.str[STRING_NOPROXY] ?
1955
0
                        data->set.str[STRING_NOPROXY] : no_proxy)) {
1956
0
    curlx_safefree(proxy);
1957
0
    curlx_safefree(pre_proxy);
1958
0
  }
1959
0
#ifndef CURL_DISABLE_HTTP
1960
0
  else if(!proxy && !pre_proxy)
1961
    /* if the host is not in the noproxy list, detect proxy. */
1962
0
    proxy = url_detect_proxy(data, conn);
1963
0
#endif /* CURL_DISABLE_HTTP */
1964
0
  curlx_safefree(no_proxy);
1965
1966
0
  if(proxy && (!*proxy || (conn->scheme->flags & PROTOPT_NONETWORK))) {
1967
0
    curlx_safefree(proxy);  /* Do not bother with an empty proxy string
1968
                               or if the protocol does not work with network */
1969
0
  }
1970
0
  if(pre_proxy && (!*pre_proxy ||
1971
0
                    (conn->scheme->flags & PROTOPT_NONETWORK))) {
1972
0
    curlx_safefree(pre_proxy);  /* Do not bother with an empty socks proxy
1973
                                   string or if the protocol does not work
1974
                                   with network */
1975
0
  }
1976
1977
  /***********************************************************************
1978
   * If this is supposed to use a proxy, we need to figure out the proxy host
1979
   * name, proxy type and port number, so that we can reuse an existing
1980
   * connection that may exist registered to the same proxy host.
1981
   ***********************************************************************/
1982
0
  if(proxy || pre_proxy) {
1983
0
    if(pre_proxy) {
1984
0
      result = parse_proxy(data, pre_proxy, TRUE, &conn->socks_proxy);
1985
0
      if(result)
1986
0
        goto out;
1987
0
    }
1988
1989
0
    if(proxy) {
1990
0
      result = parse_proxy(data, proxy, FALSE, &conn->http_proxy);
1991
0
      if(result)
1992
0
        goto out;
1993
0
      switch(conn->http_proxy.proxytype) {
1994
0
      case CURLPROXY_SOCKS4:
1995
0
      case CURLPROXY_SOCKS4A:
1996
0
      case CURLPROXY_SOCKS5:
1997
0
      case CURLPROXY_SOCKS5_HOSTNAME:
1998
        /* Whoops, it's not a HTTP proxy */
1999
0
        if(conn->socks_proxy.peer) {
2000
          /* and we already have a SOCKS pre-proxy. Cannot have both */
2001
0
          failf(data, "Having a SOCKS pre-proxy and proxy is not "
2002
0
                "supported with \'%s\'", proxy);
2003
0
          result = CURLE_COULDNT_RESOLVE_PROXY;
2004
0
          goto out;
2005
0
        }
2006
        /* switch */
2007
0
        conn->socks_proxy = conn->http_proxy;
2008
0
        memset(&conn->http_proxy, 0, sizeof(conn->http_proxy));
2009
0
        break;
2010
0
      default:
2011
0
        break;
2012
0
      }
2013
0
    }
2014
2015
0
    if(conn->http_proxy.peer) {
2016
#ifdef CURL_DISABLE_HTTP
2017
      /* asking for an HTTP proxy is a bit funny when HTTP is disabled... */
2018
      result = CURLE_UNSUPPORTED_PROTOCOL;
2019
      goto out;
2020
#else
2021
0
#ifndef CURL_DISABLE_DIGEST_AUTH
2022
0
      if(!Curl_safecmp(data->state.envproxy, proxy)) {
2023
        /* proxy changed */
2024
0
        Curl_auth_digest_cleanup(&data->state.proxydigest);
2025
0
        curlx_free(data->state.envproxy);
2026
0
        data->state.envproxy = curlx_strdup(proxy);
2027
0
      }
2028
0
#endif
2029
0
      if(conn->scheme->flags & PROTOPT_HTTP_PROXY_TUNNEL) {
2030
0
        conn->bits.tunnel_proxy = TRUE;
2031
0
      }
2032
0
      else if(!(conn->scheme->protocol & PROTO_FAMILY_HTTP)) {
2033
        /* force this connection's protocol to become HTTP if compatible */
2034
0
        if((conn->scheme->flags & PROTOPT_PROXY_AS_HTTP) &&
2035
0
           !conn->bits.tunnel_proxy)
2036
0
          conn->scheme = &Curl_scheme_http;
2037
0
        else
2038
          /* if not converting to HTTP over the proxy, enforce tunneling */
2039
0
          conn->bits.tunnel_proxy = TRUE;
2040
0
      }
2041
0
#endif
2042
0
    }
2043
0
    else
2044
0
      conn->bits.tunnel_proxy = FALSE; /* no tunneling if not HTTP */
2045
0
  }
2046
2047
0
  conn->bits.socksproxy = !!conn->socks_proxy.peer;
2048
0
  conn->bits.httpproxy = !!conn->http_proxy.peer;
2049
0
  conn->bits.proxy = conn->bits.httpproxy || conn->bits.socksproxy;
2050
2051
0
  if(!conn->bits.proxy) {
2052
    /* we are not using the proxy after all... */
2053
0
    conn->bits.proxy = FALSE;
2054
0
    conn->bits.httpproxy = FALSE;
2055
0
    conn->bits.socksproxy = FALSE;
2056
0
    conn->bits.tunnel_proxy = FALSE;
2057
    /* CURLPROXY_HTTPS does not have its own flag in conn->bits, yet we need
2058
       to signal that CURLPROXY_HTTPS is not used for this connection */
2059
0
    conn->http_proxy.proxytype = CURLPROXY_HTTP;
2060
0
  }
2061
2062
0
out:
2063
2064
0
  curlx_free(pre_proxy);
2065
0
  curlx_free(proxy);
2066
0
  return result;
2067
0
}
2068
#endif /* CURL_DISABLE_PROXY */
2069
2070
/*
2071
 * Curl_parse_login_details()
2072
 *
2073
 * This is used to parse a login string for username, password and options in
2074
 * the following formats:
2075
 *
2076
 *   user
2077
 *   user:password
2078
 *   user:password;options
2079
 *   user;options
2080
 *   user;options:password
2081
 *   :password
2082
 *   :password;options
2083
 *   ;options
2084
 *   ;options:password
2085
 *
2086
 * Parameters:
2087
 *
2088
 * login    [in]     - login string.
2089
 * len      [in]     - length of the login string.
2090
 * userp    [in/out] - address where a pointer to newly allocated memory
2091
 *                     holding the user will be stored upon completion.
2092
 * passwdp  [in/out] - address where a pointer to newly allocated memory
2093
 *                     holding the password will be stored upon completion.
2094
 * optionsp [in/out] - OPTIONAL address where a pointer to newly allocated
2095
 *                     memory holding the options will be stored upon
2096
 *                     completion.
2097
 *
2098
 * Returns CURLE_OK on success.
2099
 */
2100
CURLcode Curl_parse_login_details(const char *login, const size_t len,
2101
                                  char **userp, char **passwdp,
2102
                                  char **optionsp)
2103
0
{
2104
0
  char *ubuf = NULL;
2105
0
  char *pbuf = NULL;
2106
0
  const char *psep = NULL;
2107
0
  const char *osep = NULL;
2108
0
  size_t ulen;
2109
0
  size_t plen;
2110
0
  size_t olen;
2111
2112
0
  DEBUGASSERT(userp);
2113
0
  DEBUGASSERT(passwdp);
2114
2115
  /* Attempt to find the password separator */
2116
0
  psep = memchr(login, ':', len);
2117
2118
  /* Attempt to find the options separator */
2119
0
  if(optionsp)
2120
0
    osep = memchr(login, ';', len);
2121
2122
  /* Calculate the portion lengths */
2123
0
  ulen = (psep ?
2124
0
          (size_t)(osep && psep > osep ? osep - login : psep - login) :
2125
0
          (osep ? (size_t)(osep - login) : len));
2126
0
  plen = (psep ?
2127
0
          (osep && osep > psep ? (size_t)(osep - psep) :
2128
0
           (size_t)(login + len - psep)) - 1 : 0);
2129
0
  olen = (osep ?
2130
0
          (psep && psep > osep ? (size_t)(psep - osep) :
2131
0
           (size_t)(login + len - osep)) - 1 : 0);
2132
2133
  /* Clone the user portion buffer, which can be zero length */
2134
0
  ubuf = curlx_memdup0(login, ulen);
2135
0
  if(!ubuf)
2136
0
    goto error;
2137
2138
  /* Clone the password portion buffer */
2139
0
  if(psep) {
2140
0
    pbuf = curlx_memdup0(&psep[1], plen);
2141
0
    if(!pbuf)
2142
0
      goto error;
2143
0
  }
2144
2145
  /* Allocate the options portion buffer */
2146
0
  if(optionsp) {
2147
0
    char *obuf = NULL;
2148
0
    if(olen) {
2149
0
      obuf = curlx_memdup0(&osep[1], olen);
2150
0
      if(!obuf)
2151
0
        goto error;
2152
0
    }
2153
0
    *optionsp = obuf;
2154
0
  }
2155
0
  *userp = ubuf;
2156
0
  *passwdp = pbuf;
2157
0
  return CURLE_OK;
2158
0
error:
2159
0
  curlx_free(ubuf);
2160
0
  curlx_free(pbuf);
2161
0
  return CURLE_OUT_OF_MEMORY;
2162
0
}
2163
2164
#ifndef CURL_DISABLE_NETRC
2165
static bool str_has_ctrl(const char *input)
2166
0
{
2167
0
  if(input) {
2168
0
    const unsigned char *str = (const unsigned char *)input;
2169
0
    while(*str) {
2170
0
      if(*str < 0x20)
2171
0
        return TRUE;
2172
0
      str++;
2173
0
    }
2174
0
  }
2175
0
  return FALSE;
2176
0
}
2177
#endif
2178
2179
/*
2180
 * Override the login details from the URL with that in the CURLOPT_USERPWD
2181
 * option or a .netrc file, if applicable.
2182
 */
2183
static CURLcode override_login(struct Curl_easy *data,
2184
                               struct connectdata *conn)
2185
0
{
2186
0
  char **optionsp = &conn->options;
2187
0
#ifndef CURL_DISABLE_NETRC
2188
0
  struct Curl_creds *ncreds_out = NULL;
2189
0
#endif
2190
0
  CURLcode result = CURLE_OK;
2191
2192
0
  if(data->set.str[STRING_OPTIONS]) {
2193
0
    curlx_free(*optionsp);
2194
0
    *optionsp = curlx_strdup(data->set.str[STRING_OPTIONS]);
2195
0
    if(!*optionsp) {
2196
0
      result = CURLE_OUT_OF_MEMORY;
2197
0
      goto out;
2198
0
    }
2199
0
  }
2200
2201
0
#ifndef CURL_DISABLE_NETRC
2202
0
  if(data->set.use_netrc) { /* not CURL_NETRC_IGNORED */
2203
0
    struct Curl_creds *ncreds_in = NULL;
2204
0
    bool scan_netrc = TRUE;
2205
0
    NETRCcode ret;
2206
0
    CURLUcode uc;
2207
2208
0
    if(data->state.creds) {
2209
0
      switch(data->state.creds->source) {
2210
0
      case CREDS_OPTION:
2211
        /* we never override credentials set via CURLOPT_*, leave. */
2212
0
        scan_netrc = FALSE;
2213
0
        break;
2214
0
      case CREDS_URL: /* only apply when netrc is not required */
2215
0
        if(data->set.use_netrc == CURL_NETRC_REQUIRED) {
2216
          /* We ignore password from URL */
2217
0
          ncreds_in = data->state.creds;
2218
0
        }
2219
0
        else if(!Curl_creds_has_user(data->state.creds) ||
2220
0
                !Curl_creds_has_passwd(data->state.creds)) {
2221
          /* We use netrc to complete what is missing */
2222
0
          ncreds_in = data->state.creds;
2223
0
        }
2224
0
        else
2225
0
          scan_netrc = FALSE;
2226
0
        break;
2227
0
      default: /* ignore credentials from other sources */
2228
0
        break;
2229
0
      }
2230
0
    }
2231
2232
0
    if(!scan_netrc)
2233
0
      goto out;
2234
2235
0
    ret = Curl_netrc_scan(data, &data->state.netrc,
2236
0
                          conn->origin->hostname,
2237
0
                          Curl_creds_user(ncreds_in),
2238
0
                          data->set.str[STRING_NETRC_FILE],
2239
0
                          &ncreds_out);
2240
0
    DEBUGASSERT(!ret || !ncreds_out);
2241
0
    if(ret == NETRC_OUT_OF_MEMORY) {
2242
0
      result = CURLE_OUT_OF_MEMORY;
2243
0
      goto out;
2244
0
    }
2245
0
    else if(ret && ((ret == NETRC_NO_MATCH) ||
2246
0
                    (data->set.use_netrc == CURL_NETRC_OPTIONAL))) {
2247
0
      infof(data, "Could not find host %s in the %s file; using defaults",
2248
0
            conn->origin->hostname,
2249
0
            (data->set.str[STRING_NETRC_FILE] ?
2250
0
             data->set.str[STRING_NETRC_FILE] : ".netrc"));
2251
0
    }
2252
0
    else if(ret) {
2253
0
      const char *m = Curl_netrc_strerror(ret);
2254
0
      failf(data, ".netrc error: %s", m);
2255
0
      result = CURLE_READ_ERROR;
2256
0
      goto out;
2257
0
    }
2258
0
    else if(ncreds_out) {
2259
0
      if(!(conn->scheme->flags & PROTOPT_USERPWDCTRL)) {
2260
        /* if the protocol cannot handle control codes in credentials, make
2261
           sure there are none */
2262
0
        if(str_has_ctrl(ncreds_out->user) ||
2263
0
           str_has_ctrl(ncreds_out->passwd)) {
2264
0
          failf(data, "control code detected in .netrc credentials");
2265
0
          result = CURLE_READ_ERROR;
2266
0
          goto out;
2267
0
        }
2268
0
      }
2269
0
      CURL_TRC_M(data, "netrc: using credentials for %s as %s",
2270
0
                 conn->origin->hostname, ncreds_out->user);
2271
0
      result = Curl_creds_merge(ncreds_out->user, ncreds_out->passwd,
2272
0
                                data->state.creds, CREDS_NETRC,
2273
0
                                &data->state.creds);
2274
0
      if(result)
2275
0
        goto out;
2276
      /* for updated strings, we update them in the URL */
2277
0
      uc = curl_url_set(data->state.uh, CURLUPART_USER,
2278
0
                        Curl_creds_user(data->state.creds), CURLU_URLENCODE);
2279
0
      if(!uc)
2280
0
        uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD,
2281
0
                          Curl_creds_passwd(data->state.creds),
2282
0
                          CURLU_URLENCODE);
2283
0
      if(uc)
2284
0
        result = Curl_uc_to_curlcode(uc);
2285
0
    }
2286
0
    else
2287
0
      DEBUGASSERT(0);
2288
0
  }
2289
0
#endif
2290
2291
0
out:
2292
0
#ifndef CURL_DISABLE_NETRC
2293
0
  Curl_creds_unlink(&ncreds_out);
2294
0
#endif
2295
0
  return result;
2296
0
}
2297
2298
/*
2299
 * Set the login details so they are available in the connection
2300
 */
2301
static CURLcode url_set_conn_login(struct Curl_easy *data,
2302
                                   struct connectdata *conn)
2303
0
{
2304
  /* If our protocol needs a password and we have none, use the defaults */
2305
0
  if((conn->scheme->flags & PROTOPT_NEEDSPWD) && !conn->creds) {
2306
0
    if(data->state.creds)
2307
0
      Curl_creds_link(&conn->creds, data->state.creds);
2308
0
    else
2309
0
      return Curl_creds_create(CURL_DEFAULT_USER, CURL_DEFAULT_PASSWORD,
2310
0
                               NULL, NULL, NULL, CREDS_NONE, &conn->creds);
2311
0
  }
2312
0
  else if(!(conn->scheme->flags & PROTOPT_CREDSPERREQUEST)) {
2313
    /* for protocols that do not handle credentials per request,
2314
     * the connection credentials are set by the initial transfer. */
2315
0
    Curl_creds_link(&conn->creds, data->state.creds);
2316
0
  }
2317
2318
0
  return CURLE_OK;
2319
0
}
2320
2321
/*
2322
 * Parses one "connect to" string in the form:
2323
 * "HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT".
2324
 */
2325
static CURLcode parse_connect_to_string(struct Curl_easy *data,
2326
                                        const struct Curl_peer *dest,
2327
                                        const char *conn_to_line,
2328
                                        struct Curl_peer **pvia_dest)
2329
0
{
2330
0
  CURLcode result = CURLE_OK;
2331
0
  const char *ptr = conn_to_line;
2332
0
  bool host_match = FALSE;
2333
0
  bool port_match = FALSE;
2334
2335
0
  *pvia_dest = NULL;
2336
2337
0
  if(*ptr == ':') {
2338
    /* an empty hostname always matches */
2339
0
    host_match = TRUE;
2340
0
    ptr++;
2341
0
  }
2342
0
  else {
2343
    /* check whether the URL's hostname matches. Use the URL hostname
2344
     * when it was an IPv6 address. Otherwise use the connection's hostname
2345
     * that has IDN conversion. */
2346
0
    const char *hostname_to_match = (dest->user_hostname[0] == '[') ?
2347
0
      dest->user_hostname : dest->hostname;
2348
0
    size_t hlen = strlen(hostname_to_match);
2349
0
    host_match = curl_strnequal(ptr, hostname_to_match, hlen);
2350
0
    ptr += hlen;
2351
2352
0
    host_match = host_match && *ptr == ':';
2353
0
    ptr++;
2354
0
  }
2355
2356
0
  if(host_match) {
2357
0
    if(*ptr == ':') {
2358
      /* an empty port always matches */
2359
0
      port_match = TRUE;
2360
0
      ptr++;
2361
0
    }
2362
0
    else {
2363
      /* check whether the URL's port matches */
2364
0
      const char *ptr_next = strchr(ptr, ':');
2365
0
      if(ptr_next) {
2366
0
        curl_off_t port_to_match;
2367
0
        if(!curlx_str_number(&ptr, &port_to_match, 0xffff) &&
2368
0
           ((uint16_t)port_to_match == dest->port)) {
2369
0
          port_match = TRUE;
2370
0
        }
2371
0
        ptr = ptr_next + 1;
2372
0
      }
2373
0
    }
2374
0
  }
2375
2376
0
  if(host_match && port_match && ptr && *ptr)
2377
0
    result = Curl_peer_from_connect_to(data, dest, ptr, pvia_dest);
2378
2379
0
  return result;
2380
0
}
2381
2382
/* With `conn->origin` known, determine if we should talk to that
2383
 * directly or via another peer. This is the result of inspecting
2384
 * the "connect to" slist and "alt-svc" settings. */
2385
static CURLcode url_set_conn_peer(struct Curl_easy *data,
2386
                                  struct connectdata *conn)
2387
0
{
2388
0
  CURLcode result = CURLE_OK;
2389
0
  const struct Curl_peer *origin = conn->origin;
2390
0
  struct Curl_peer *via_peer = NULL;
2391
0
  struct curl_slist *conn_to_entry = data->set.connect_to;
2392
2393
0
  DEBUGASSERT(!conn->via_peer);
2394
0
  Curl_peer_unlink(&conn->via_peer);
2395
2396
0
  while(conn_to_entry && !via_peer) {
2397
0
    result = parse_connect_to_string(data, origin, conn_to_entry->data,
2398
0
                                     &via_peer);
2399
0
    if(result)
2400
0
      return result;
2401
0
    conn_to_entry = conn_to_entry->next;
2402
0
  }
2403
2404
0
#ifndef CURL_DISABLE_ALTSVC
2405
0
  if(data->asi && !via_peer &&
2406
0
     ((conn->scheme->protocol == CURLPROTO_HTTPS) ||
2407
0
#ifdef DEBUGBUILD
2408
      /* allow debug builds to circumvent the HTTPS restriction */
2409
0
      getenv("CURL_ALTSVC_HTTP")
2410
#else
2411
      0
2412
#endif
2413
0
       )) {
2414
    /* no connect_to match, try alt-svc! */
2415
0
    enum alpnid srcalpnid = ALPN_none;
2416
0
    bool hit = FALSE;
2417
0
    struct altsvc *as = NULL;
2418
0
    int allowed_alpns = ALPN_none;
2419
0
    struct http_negotiation *neg = &data->state.http_neg;
2420
0
    bool same_dest = FALSE;
2421
2422
0
    DEBUGF(infof(data, "Alt-svc check wanted=%x, allowed=%x",
2423
0
                 neg->wanted, neg->allowed));
2424
#ifdef USE_HTTP3
2425
    if(neg->allowed & CURL_HTTP_V3x)
2426
      allowed_alpns |= ALPN_h3;
2427
#endif
2428
0
#ifdef USE_HTTP2
2429
0
    if(neg->allowed & CURL_HTTP_V2x)
2430
0
      allowed_alpns |= ALPN_h2;
2431
0
#endif
2432
0
    if(neg->allowed & CURL_HTTP_V1x)
2433
0
      allowed_alpns |= ALPN_h1;
2434
0
    allowed_alpns &= (int)data->asi->flags;
2435
2436
0
    DEBUGF(infof(data, "check Alt-Svc for host '%s'", origin->hostname));
2437
#ifdef USE_HTTP3
2438
    if(!hit && (neg->wanted & CURL_HTTP_V3x)) {
2439
      srcalpnid = ALPN_h3;
2440
      hit = Curl_altsvc_lookup(data->asi,
2441
                               ALPN_h3, origin->hostname,
2442
                               origin->port, /* from */
2443
                               &as /* to */,
2444
                               allowed_alpns, &same_dest);
2445
    }
2446
#endif
2447
0
#ifdef USE_HTTP2
2448
0
    if(!hit && (neg->wanted & CURL_HTTP_V2x) &&
2449
0
       !neg->h2_prior_knowledge) {
2450
0
      srcalpnid = ALPN_h2;
2451
0
      hit = Curl_altsvc_lookup(data->asi,
2452
0
                               ALPN_h2, origin->hostname,
2453
0
                               origin->port, /* from */
2454
0
                               &as /* to */,
2455
0
                               allowed_alpns, &same_dest);
2456
0
    }
2457
0
#endif
2458
0
    if(!hit && (neg->wanted & CURL_HTTP_V1x) &&
2459
0
       !neg->only_10) {
2460
0
      srcalpnid = ALPN_h1;
2461
0
      hit = Curl_altsvc_lookup(data->asi,
2462
0
                               ALPN_h1, origin->hostname,
2463
0
                               origin->port, /* from */
2464
0
                               &as /* to */,
2465
0
                               allowed_alpns, &same_dest);
2466
0
    }
2467
2468
0
    if(hit && same_dest) {
2469
      /* same destination, but more HTTPS version options */
2470
0
      switch(as->dst.alpnid) {
2471
0
      case ALPN_h1:
2472
0
        neg->wanted |= CURL_HTTP_V1x;
2473
0
        neg->preferred = CURL_HTTP_V1x;
2474
0
        break;
2475
0
      case ALPN_h2:
2476
0
        neg->wanted |= CURL_HTTP_V2x;
2477
0
        neg->preferred = CURL_HTTP_V2x;
2478
0
        break;
2479
0
      case ALPN_h3:
2480
0
        neg->wanted |= CURL_HTTP_V3x;
2481
0
        neg->preferred = CURL_HTTP_V3x;
2482
0
        break;
2483
0
      default: /* should not be possible */
2484
0
        break;
2485
0
      }
2486
0
    }
2487
0
    else if(hit) {
2488
0
      result = Curl_peer_create(data, conn->origin->scheme,
2489
0
                                as->dst.host, as->dst.port,
2490
0
                                &via_peer);
2491
0
      if(result)
2492
0
        return result;
2493
0
      infof(data, "Alt-svc connecting from [%s]%s:%u to [%s]%s:%u",
2494
0
            Curl_alpnid2str(srcalpnid), origin->hostname, origin->port,
2495
0
            Curl_alpnid2str(as->dst.alpnid),
2496
0
            via_peer->hostname, via_peer->port);
2497
0
      conn->bits.altused = TRUE;
2498
0
      if(srcalpnid != as->dst.alpnid) {
2499
        /* protocol version switch */
2500
0
        switch(as->dst.alpnid) {
2501
0
        case ALPN_h1:
2502
0
          neg->wanted = neg->allowed = CURL_HTTP_V1x;
2503
0
          neg->only_10 = FALSE;
2504
0
          break;
2505
0
        case ALPN_h2:
2506
0
          neg->wanted = neg->allowed = CURL_HTTP_V2x;
2507
0
          break;
2508
0
        case ALPN_h3:
2509
0
          conn->transport_wanted = TRNSPRT_QUIC;
2510
0
          neg->wanted = neg->allowed = CURL_HTTP_V3x;
2511
0
          break;
2512
0
        default: /* should not be possible */
2513
0
          break;
2514
0
        }
2515
0
      }
2516
0
    }
2517
0
  }
2518
0
#endif
2519
2520
0
  if(via_peer)
2521
0
    conn->via_peer = via_peer;
2522
2523
0
  return result;
2524
0
}
2525
2526
/*
2527
 * Adjust reused connection settings to the transfer/needle.
2528
 */
2529
static void url_conn_reuse_adjust(struct Curl_easy *data,
2530
                                  struct connectdata *needle)
2531
0
{
2532
0
  struct connectdata *conn = data->conn;
2533
2534
  /* get the user+password information from the needle since it may
2535
   * be new for this request even when we reuse conn */
2536
0
  if(needle->creds) {
2537
    /* use the new username and password though */
2538
0
    Curl_creds_link(&conn->creds, needle->creds);
2539
0
  }
2540
2541
0
#ifndef CURL_DISABLE_PROXY
2542
  /* use the new proxy username and proxy password though */
2543
0
  Curl_creds_link(&conn->http_proxy.creds, needle->http_proxy.creds);
2544
0
  Curl_creds_link(&conn->socks_proxy.creds, needle->socks_proxy.creds);
2545
0
#endif
2546
2547
  /* Finding a connection for reuse in the cpool matches, among other
2548
   * things on the "remote-relevant" hostname. This is not necessarily
2549
   * the authority of the URL, e.g. conn->origin. For example:
2550
   * - we use a proxy (not tunneling). we want to send all requests
2551
   *   that use the same proxy on this connection.
2552
   * - we have a "connect-to" setting that may redirect the hostname of
2553
   *   a new request to the same remote endpoint of an existing conn.
2554
   *   We want to reuse an existing conn to the remote endpoint.
2555
   * Since connection reuse does not match on conn->origin necessarily, we
2556
   * switch conn to needle's host settings.
2557
   */
2558
0
  Curl_peer_link(&conn->origin, needle->origin);
2559
0
  Curl_peer_link(&conn->via_peer, needle->via_peer);
2560
0
  Curl_peer_link(&conn->origin2, needle->origin2);
2561
0
  Curl_peer_link(&conn->via_peer2, needle->via_peer2);
2562
0
}
2563
2564
static void conn_meta_freeentry(void *p)
2565
0
{
2566
0
  (void)p;
2567
  /* Always FALSE. Cannot use a 0 assert here since compilers
2568
   * are not in agreement if they then want a NORETURN attribute or
2569
   * not. *sigh* */
2570
0
  DEBUGASSERT(p == NULL);
2571
0
}
2572
2573
static CURLcode url_create_needle(struct Curl_easy *data,
2574
                                  struct connectdata **pneedle)
2575
0
{
2576
0
  struct connectdata *needle = NULL;
2577
0
  CURLcode result = CURLE_OK;
2578
0
  bool network_scheme = TRUE; /* almost all are */
2579
2580
  /*************************************************************
2581
   * Check input data
2582
   *************************************************************/
2583
0
  if(!Curl_bufref_ptr(&data->state.url)) {
2584
0
    result = CURLE_URL_MALFORMAT;
2585
0
    goto out;
2586
0
  }
2587
2588
  /* First, split up the current URL in parts so that we can use the
2589
     parts for checking against the already present connections. In order
2590
     to not have to modify everything at once, we allocate a temporary
2591
     connection data struct and fill in for comparison purposes. */
2592
0
  needle = allocate_conn(data);
2593
0
  if(!needle) {
2594
0
    result = CURLE_OUT_OF_MEMORY;
2595
0
    goto out;
2596
0
  }
2597
2598
  /* Do the unfailable inits first, before checks that may early return */
2599
0
  Curl_hash_init(&needle->meta_hash, 23,
2600
0
                 Curl_hash_str, curlx_str_key_compare, conn_meta_freeentry);
2601
2602
  /*************************************************************
2603
   * Determine `conn->origin` and propulate `data->state.up` and
2604
   * other URL related properties.
2605
   *************************************************************/
2606
0
  result = parseurlandfillconn(data, needle);
2607
0
  if(result)
2608
0
    goto out;
2609
0
  DEBUGASSERT(needle->origin);
2610
0
  network_scheme = !(needle->origin->scheme->flags & PROTOPT_NONETWORK);
2611
2612
0
#ifdef USE_UNIX_SOCKETS
2613
  /*************************************************************
2614
   * Set UDS first. It overrides "via_peer" and proxy settings.
2615
   *************************************************************/
2616
0
  if(network_scheme && data->set.str[STRING_UNIX_SOCKET_PATH]) {
2617
0
    result = Curl_peer_uds_create(needle->origin->scheme,
2618
0
                                  data->set.str[STRING_UNIX_SOCKET_PATH],
2619
0
                                  (bool)data->set.abstract_unix_socket,
2620
0
                                  &needle->via_peer);
2621
0
    if(result)
2622
0
      goto out;
2623
0
  }
2624
0
#endif /* USE_UNIX_SOCKETS */
2625
2626
0
  if(network_scheme && !needle->via_peer) {
2627
    /*************************************************************
2628
     * If the `via_peer` is not already set (via UDS above),
2629
     * determine if we talk to `conn->origin` directly or use
2630
     * `conn->via_peer` using "connect to" and "alt-svc" properties.
2631
     *************************************************************/
2632
0
    result = url_set_conn_peer(data, needle);
2633
0
    if(result)
2634
0
      goto out;
2635
0
  }
2636
2637
0
#ifndef CURL_DISABLE_PROXY
2638
  /* Going via a unix socket ignores any proxy settings */
2639
0
  if(needle->via_peer && needle->via_peer->unix_socket) {
2640
0
    needle->bits.socksproxy = FALSE;
2641
0
    needle->bits.httpproxy = FALSE;
2642
0
    needle->bits.proxy = FALSE;
2643
0
  }
2644
0
  else if(network_scheme) {
2645
0
    result = url_set_conn_proxies(data, needle);
2646
0
    if(result)
2647
0
      goto out;
2648
2649
    /*************************************************************
2650
     * If the protocol is using SSL and HTTP proxy is used, we set
2651
     * the tunnel_proxy bit.
2652
     *************************************************************/
2653
0
    if((needle->given->flags & PROTOPT_SSL) && needle->bits.httpproxy)
2654
0
      needle->bits.tunnel_proxy = TRUE;
2655
0
  }
2656
0
#endif /* CURL_DISABLE_PROXY */
2657
2658
  /* Check for overridden login details and set them accordingly so that
2659
     they are known when protocol->setup_connection is called! */
2660
0
  result = override_login(data, needle);
2661
0
  if(result)
2662
0
    goto out;
2663
2664
0
  result = url_set_conn_login(data, needle); /* default credentials */
2665
0
  if(result)
2666
0
    goto out;
2667
2668
  /*************************************************************
2669
   * Check whether the host and the "connect to host" are equal.
2670
   * Do this after the hostnames have been IDN-converted.
2671
   *************************************************************/
2672
0
  if(Curl_peer_equal(needle->origin, needle->via_peer)) {
2673
0
    Curl_peer_unlink(&needle->via_peer);
2674
0
  }
2675
2676
0
#ifndef CURL_DISABLE_PROXY
2677
  /*************************************************************
2678
   * If the "connect to" feature is used with an HTTP proxy,
2679
   * we set the tunnel_proxy bit.
2680
   *************************************************************/
2681
0
  if(needle->via_peer && needle->bits.httpproxy)
2682
0
    needle->bits.tunnel_proxy = TRUE;
2683
0
#endif
2684
2685
  /*************************************************************
2686
   * Setup internals depending on protocol. Needs to be done after
2687
   * we figured out what/if proxy to use.
2688
   *************************************************************/
2689
0
  result = setup_connection_internals(data, needle);
2690
0
  if(result)
2691
0
    goto out;
2692
2693
0
  if(needle->scheme->flags & PROTOPT_ALPN) {
2694
    /* The protocol wants it, so set the bits if enabled in the easy handle
2695
       (default) */
2696
0
    if(data->set.ssl_enable_alpn)
2697
0
      needle->bits.tls_enable_alpn = TRUE;
2698
0
  }
2699
2700
0
  if(network_scheme) {
2701
    /* Setup callbacks for network connections */
2702
0
    needle->recv[FIRSTSOCKET] = Curl_cf_recv;
2703
0
    needle->send[FIRSTSOCKET] = Curl_cf_send;
2704
0
    needle->recv[SECONDARYSOCKET] = Curl_cf_recv;
2705
0
    needle->send[SECONDARYSOCKET] = Curl_cf_send;
2706
0
    needle->bits.tcp_fastopen = data->set.tcp_fastopen;
2707
0
#ifdef USE_UNIX_SOCKETS
2708
0
    if(Curl_conn_get_first_peer(needle, FIRSTSOCKET)->unix_socket)
2709
0
      needle->transport_wanted = TRNSPRT_UNIX;
2710
0
#endif
2711
0
  }
2712
2713
0
out:
2714
0
  if(!result) {
2715
0
    DEBUGASSERT(needle);
2716
0
    DEBUGASSERT(needle->origin);
2717
0
    *pneedle = needle;
2718
0
  }
2719
0
  else {
2720
0
    *pneedle = NULL;
2721
0
    if(needle)
2722
0
      Curl_conn_free(data, needle);
2723
0
  }
2724
0
  return result;
2725
0
}
2726
2727
/**
2728
 * Find an existing connection for the transfer or create a new one.
2729
 * Returns
2730
 * - CURLE_OK on success with a connection attached to data
2731
 * - CURLE_NO_CONNECTION_AVAILABLE when connection limits apply or when
2732
 *   a suitable connection has not determined its multiplex capability.
2733
 * - a fatal error
2734
 */
2735
static CURLcode url_find_or_create_conn(struct Curl_easy *data)
2736
0
{
2737
0
  struct connectdata *needle = NULL;
2738
0
  bool waitpipe = FALSE;
2739
0
  CURLcode result;
2740
2741
  /* create the template connection for transfer data. Use this needle to
2742
   * find an existing connection or, if none exists, convert needle
2743
   * to a full connection and attach it to data. */
2744
0
  result = url_create_needle(data, &needle);
2745
0
  if(result)
2746
0
    goto out;
2747
0
  DEBUGASSERT(needle);
2748
2749
  /***********************************************************************
2750
   * file: is a special case in that it does not need a network connection
2751
   ***********************************************************************/
2752
0
#ifndef CURL_DISABLE_FILE
2753
0
  if(needle->scheme->flags & PROTOPT_NONETWORK) {
2754
0
    bool done;
2755
    /* this is supposed to be the connect function so we better at least check
2756
       that the file is present here! */
2757
0
    DEBUGASSERT(needle->scheme->run->connect_it);
2758
0
    data->info.conn_scheme = needle->scheme->name;
2759
    /* conn_protocol can only provide "old" protocols */
2760
0
    data->info.conn_protocol = (needle->scheme->protocol) & CURLPROTO_MASK;
2761
0
    result = needle->scheme->run->connect_it(data, &done);
2762
0
    if(result)
2763
0
      goto out;
2764
2765
    /* Setup a "faked" transfer that will do nothing */
2766
0
    Curl_attach_connection(data, needle);
2767
0
    needle = NULL;
2768
0
    result = Curl_cpool_add(data, data->conn);
2769
0
    if(!result) {
2770
      /* Setup whatever necessary for a resumed transfer */
2771
0
      result = setup_range(data);
2772
0
      if(!result) {
2773
0
        Curl_xfer_setup_nop(data);
2774
0
        result = Curl_init_do(data, data->conn);
2775
0
      }
2776
0
    }
2777
2778
0
    if(result) {
2779
0
      DEBUGASSERT(data->conn->scheme->run->done);
2780
      /* we ignore the return code for the protocol-specific DONE */
2781
0
      (void)data->conn->scheme->run->done(data, result, FALSE);
2782
0
    }
2783
0
    goto out;
2784
0
  }
2785
0
#endif
2786
2787
  /* Complete the easy's SSL configuration for connection cache matching */
2788
0
  result = Curl_ssl_easy_config_complete(data);
2789
0
  if(result)
2790
0
    goto out;
2791
2792
  /* Get rid of any dead connections so limit are easier kept. */
2793
0
  Curl_cpool_prune_dead(data);
2794
2795
  /*************************************************************
2796
   * Reuse of existing connection is not allowed when
2797
   * - connect_only is set or
2798
   * - reuse_fresh is set and this is not a follow-up request
2799
   *   (like with HTTP followlocation)
2800
   *************************************************************/
2801
0
  if((!data->set.reuse_fresh || data->state.followlocation) &&
2802
0
     !data->set.connect_only) {
2803
    /* Ok, try to find and attach an existing one */
2804
0
    url_attach_existing(data, needle, &waitpipe);
2805
0
  }
2806
2807
0
  if(data->conn) {
2808
    /* We attached an existing connection for this transfer. Copy
2809
     * over transfer specific properties over from needle. */
2810
0
    struct connectdata *conn = data->conn;
2811
0
    VERBOSE(bool tls_upgraded = (!(needle->given->flags & PROTOPT_SSL) &&
2812
0
                                 Curl_conn_is_ssl(conn, FIRSTSOCKET)));
2813
2814
0
    conn->bits.reuse = TRUE;
2815
0
    url_conn_reuse_adjust(data, needle);
2816
2817
0
#ifndef CURL_DISABLE_PROXY
2818
0
    infof(data, "Reusing existing %s: connection%s with %s %s",
2819
0
          conn->given->name,
2820
0
          tls_upgraded ? " (upgraded to SSL)" : "",
2821
0
          conn->bits.proxy ? "proxy" : "host",
2822
0
          conn->socks_proxy.peer ? conn->socks_proxy.peer->user_hostname :
2823
0
          conn->http_proxy.peer ? conn->http_proxy.peer->user_hostname :
2824
0
          conn->origin->hostname);
2825
#else
2826
    infof(data, "Reusing existing %s: connection%s with host %s",
2827
          conn->given->name,
2828
          tls_upgraded ? " (upgraded to SSL)" : "",
2829
          conn->origin->hostname);
2830
#endif
2831
0
  }
2832
0
  else {
2833
    /* We have decided that we want a new connection. We may not be able to do
2834
       that if we have reached the limit of how many connections we are
2835
       allowed to open. */
2836
0
    DEBUGF(infof(data, "new connection, bits.close=%d", needle->bits.close));
2837
2838
0
    if(waitpipe) {
2839
      /* There is a connection that *might* become usable for multiplexing
2840
         "soon", and we wait for that */
2841
0
      infof(data, "Waiting on connection to negotiate possible multiplexing.");
2842
0
      result = CURLE_NO_CONNECTION_AVAILABLE;
2843
0
      goto out;
2844
0
    }
2845
0
    else {
2846
0
      switch(Curl_cpool_check_limits(data, needle)) {
2847
0
      case CPOOL_LIMIT_DEST:
2848
0
        infof(data, "No more connections allowed to host");
2849
0
        result = CURLE_NO_CONNECTION_AVAILABLE;
2850
0
        goto out;
2851
0
      case CPOOL_LIMIT_TOTAL:
2852
0
        if(data->master_mid != UINT32_MAX)
2853
0
          CURL_TRC_M(data, "Allowing sub-requests (like DoH) to override "
2854
0
                     "max connection limit");
2855
0
        else {
2856
0
          infof(data, "No connections available, total of %zu reached.",
2857
0
                data->multi->max_total_connections);
2858
0
          result = CURLE_NO_CONNECTION_AVAILABLE;
2859
0
          goto out;
2860
0
        }
2861
0
        break;
2862
0
      default:
2863
0
        break;
2864
0
      }
2865
0
    }
2866
2867
    /* Convert needle into a full connection by filling in all the
2868
     * remaining parts like the cloned SSL configuration. */
2869
0
    result = Curl_ssl_conn_config_init(data, needle);
2870
0
    if(result) {
2871
0
      DEBUGF(curl_mfprintf(stderr, "Error: init connection SSL config\n"));
2872
0
      goto out;
2873
0
    }
2874
    /* attach it and no longer own it */
2875
0
    Curl_attach_connection(data, needle);
2876
0
    needle = NULL;
2877
2878
0
    result = Curl_cpool_add(data, data->conn);
2879
0
    if(result)
2880
0
      goto out;
2881
2882
#ifdef USE_NTLM
2883
    /* If NTLM is requested in a part of this connection, make sure we do not
2884
       assume the state is fine as this is a fresh connection and NTLM is
2885
       connection based. */
2886
    if((data->state.authhost.picked & CURLAUTH_NTLM) &&
2887
       data->state.authhost.done) {
2888
      infof(data, "NTLM picked AND auth done set, clear picked");
2889
      data->state.authhost.picked = CURLAUTH_NONE;
2890
      data->state.authhost.done = FALSE;
2891
    }
2892
2893
    if((data->state.authproxy.picked & CURLAUTH_NTLM) &&
2894
       data->state.authproxy.done) {
2895
      infof(data, "NTLM-proxy picked AND auth done set, clear picked");
2896
      data->state.authproxy.picked = CURLAUTH_NONE;
2897
      data->state.authproxy.done = FALSE;
2898
    }
2899
#endif
2900
0
  }
2901
2902
  /* Setup and init stuff before DO starts, in preparing for the transfer. */
2903
0
  result = Curl_init_do(data, data->conn);
2904
0
  if(result)
2905
0
    goto out;
2906
2907
  /* Setup whatever necessary for a resumed transfer */
2908
0
  result = setup_range(data);
2909
0
  if(result)
2910
0
    goto out;
2911
2912
  /* persist the scheme and handler the transfer is using */
2913
0
  data->info.conn_scheme = data->conn->scheme->name;
2914
  /* conn_protocol can only provide "old" protocols */
2915
0
  data->info.conn_protocol = (data->conn->scheme->protocol) & CURLPROTO_MASK;
2916
0
  data->info.used_proxy =
2917
#ifdef CURL_DISABLE_PROXY
2918
    0
2919
#else
2920
0
    data->conn->bits.proxy
2921
0
#endif
2922
0
    ;
2923
2924
  /* Lastly, inform connection filters that a new transfer is attached */
2925
0
  result = Curl_conn_ev_data_setup(data);
2926
2927
0
out:
2928
0
  if(needle)
2929
0
    Curl_conn_free(data, needle);
2930
0
  DEBUGASSERT(result || data->conn);
2931
0
  return result;
2932
0
}
2933
2934
CURLcode Curl_connect(struct Curl_easy *data, bool *pconnected)
2935
0
{
2936
0
  CURLcode result;
2937
0
  struct connectdata *conn;
2938
2939
0
  *pconnected = FALSE;
2940
2941
  /* Set the request to virgin state based on transfer settings */
2942
0
  Curl_req_hard_reset(&data->req, data);
2943
2944
  /* Get or create a connection for the transfer. */
2945
0
  result = url_find_or_create_conn(data);
2946
0
  conn = data->conn;
2947
2948
0
  if(result)
2949
0
    goto out;
2950
2951
0
  DEBUGASSERT(conn);
2952
0
  Curl_pgrsTime(data, TIMER_POSTQUEUE);
2953
0
  if(conn->bits.reuse) {
2954
0
    if(conn->attached_xfers > 1)
2955
      /* multiplexed */
2956
0
      *pconnected = TRUE;
2957
0
  }
2958
0
  else if(conn->scheme->flags & PROTOPT_NONETWORK) {
2959
0
    Curl_pgrsTime(data, TIMER_NAMELOOKUP);
2960
0
    *pconnected = TRUE;
2961
0
  }
2962
0
  else {
2963
0
    result = Curl_conn_setup(data, conn, FIRSTSOCKET, CURL_CF_SSL_DEFAULT);
2964
0
    if(!result)
2965
0
      result = Curl_headers_init(data);
2966
0
    CURL_TRC_M(data, "Curl_conn_setup() -> %d", result);
2967
0
  }
2968
2969
0
out:
2970
0
  if(result == CURLE_NO_CONNECTION_AVAILABLE)
2971
0
    DEBUGASSERT(!conn);
2972
2973
0
  if(result && conn) {
2974
    /* We are not allowed to return failure with memory left allocated in the
2975
       connectdata struct, free those here */
2976
0
    Curl_detach_connection(data);
2977
0
    Curl_conn_terminate(data, conn, TRUE);
2978
0
  }
2979
2980
0
  return result;
2981
0
}
2982
2983
/*
2984
 * Curl_init_do() inits the readwrite session. This is inited each time (in
2985
 * the DO function before the protocol-specific DO functions are invoked) for
2986
 * a transfer, sometimes multiple times on the same Curl_easy. Make sure
2987
 * nothing in here depends on stuff that are setup dynamically for the
2988
 * transfer.
2989
 *
2990
 * Allow this function to get called with 'conn' set to NULL.
2991
 */
2992
2993
CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
2994
0
{
2995
0
  CURLcode result;
2996
2997
0
  if(conn) {
2998
0
    conn->bits.do_more = FALSE; /* by default there is no curl_do_more() to
2999
                                   use */
3000
    /* if the protocol used does not support wildcards, switch it off */
3001
0
    if(data->state.wildcardmatch &&
3002
0
       !(conn->scheme->flags & PROTOPT_WILDCARD))
3003
0
      data->state.wildcardmatch = FALSE;
3004
0
  }
3005
3006
0
  data->state.done = FALSE; /* *_done() is not called yet */
3007
3008
0
  data->req.no_body = data->set.opt_no_body;
3009
0
  if(data->req.no_body)
3010
    /* in HTTP lingo, no body means using the HEAD request... */
3011
0
    data->state.httpreq = HTTPREQ_HEAD;
3012
3013
0
  result = Curl_req_start(&data->req, data);
3014
0
  if(!result) {
3015
0
    Curl_pgrsReset(data);
3016
0
  }
3017
0
  return result;
3018
0
}
3019
3020
#if defined(USE_HTTP2) || defined(USE_HTTP3)
3021
3022
void Curl_data_priority_clear_state(struct Curl_easy *data)
3023
0
{
3024
0
  memset(&data->state.priority, 0, sizeof(data->state.priority));
3025
0
}
3026
3027
#endif /* USE_HTTP2 || USE_HTTP3 */
3028
3029
CURLcode Curl_conn_meta_set(struct connectdata *conn, const char *key,
3030
                            void *meta_data, Curl_meta_dtor *meta_dtor)
3031
0
{
3032
0
  if(!Curl_hash_add2(&conn->meta_hash, CURL_UNCONST(key), strlen(key) + 1,
3033
0
                     meta_data, meta_dtor)) {
3034
0
    meta_dtor(CURL_UNCONST(key), strlen(key) + 1, meta_data);
3035
0
    return CURLE_OUT_OF_MEMORY;
3036
0
  }
3037
0
  return CURLE_OK;
3038
0
}
3039
3040
void Curl_conn_meta_remove(struct connectdata *conn, const char *key)
3041
0
{
3042
0
  Curl_hash_delete(&conn->meta_hash, CURL_UNCONST(key), strlen(key) + 1);
3043
0
}
3044
3045
void *Curl_conn_meta_get(struct connectdata *conn, const char *key)
3046
0
{
3047
0
  return Curl_hash_pick(&conn->meta_hash, CURL_UNCONST(key), strlen(key) + 1);
3048
0
}
3049
3050
CURLcode Curl_1st_fatal(CURLcode r1, CURLcode r2)
3051
0
{
3052
0
  if(r1 && (r1 != CURLE_AGAIN))
3053
0
    return r1;
3054
0
  if(r2 && (r2 != CURLE_AGAIN))
3055
0
    return r2;
3056
0
  return r1;
3057
0
}