Coverage Report

Created: 2024-09-08 06:32

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