Coverage Report

Created: 2024-02-25 06:14

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