Coverage Report

Created: 2026-03-11 07:11

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