Coverage Report

Created: 2023-12-08 06:48

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