Coverage Report

Created: 2026-04-12 06:56

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