Coverage Report

Created: 2023-11-19 06:21

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