Coverage Report

Created: 2024-05-04 12:45

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