1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![doc = include_str!("../README.md")]
3#![allow(renamed_and_removed_lints)] #![allow(unknown_lints)] #![warn(missing_docs)]
7#![warn(noop_method_call)]
8#![warn(unreachable_pub)]
9#![warn(clippy::all)]
10#![deny(clippy::await_holding_lock)]
11#![deny(clippy::cargo_common_metadata)]
12#![deny(clippy::cast_lossless)]
13#![deny(clippy::checked_conversions)]
14#![warn(clippy::cognitive_complexity)]
15#![deny(clippy::debug_assert_with_mut_call)]
16#![deny(clippy::exhaustive_enums)]
17#![deny(clippy::exhaustive_structs)]
18#![deny(clippy::expl_impl_clone_on_copy)]
19#![deny(clippy::fallible_impl_from)]
20#![deny(clippy::implicit_clone)]
21#![deny(clippy::large_stack_arrays)]
22#![warn(clippy::manual_ok_or)]
23#![deny(clippy::missing_docs_in_private_items)]
24#![warn(clippy::needless_borrow)]
25#![warn(clippy::needless_pass_by_value)]
26#![warn(clippy::option_option)]
27#![deny(clippy::print_stderr)]
28#![deny(clippy::print_stdout)]
29#![warn(clippy::rc_buffer)]
30#![deny(clippy::ref_option_ref)]
31#![warn(clippy::semicolon_if_nothing_returned)]
32#![warn(clippy::trait_duplication_in_bounds)]
33#![deny(clippy::unchecked_time_subtraction)]
34#![deny(clippy::unnecessary_wraps)]
35#![warn(clippy::unseparated_literal_suffix)]
36#![deny(clippy::unwrap_used)]
37#![deny(clippy::mod_module_files)]
38#![allow(clippy::let_unit_value)] #![allow(clippy::uninlined_format_args)]
40#![allow(clippy::significant_drop_in_scrutinee)] #![allow(clippy::result_large_err)] #![allow(clippy::needless_raw_string_hashes)] #![allow(clippy::needless_lifetimes)] #![allow(mismatched_lifetime_syntaxes)] #![allow(clippy::collapsible_if)] #![deny(clippy::unused_async)]
47use std::sync::{Arc, Mutex};
50
51use arti_client::{IntoTorAddr, TorClient};
52use ureq::{
53 http::{Uri, uri::Scheme},
54 tls::TlsProvider as UreqTlsProvider,
55 unversioned::{
56 resolver::{ArrayVec, ResolvedSocketAddrs, Resolver as UreqResolver},
57 transport::{Buffers, Connector as UreqConnector, LazyBuffers, NextTimeout, Transport},
58 },
59};
60
61use educe::Educe;
62use thiserror::Error;
63use tor_proto::client::stream::{DataReader, DataWriter};
64use tor_rtcompat::{Runtime, ToplevelBlockOn};
65
66#[cfg(feature = "rustls")]
67use ureq::unversioned::transport::RustlsConnector;
68
69#[cfg(feature = "native-tls")]
70use ureq::unversioned::transport::NativeTlsConnector;
71
72use futures::io::{AsyncReadExt, AsyncWriteExt};
73
74pub use arti_client;
76
77pub use tor_rtcompat;
79
80pub use ureq;
82
83pub fn default_agent() -> Result<ureq::Agent, Error> {
100 Ok(Connector::new()?.agent())
101}
102
103#[derive(Educe)]
164#[educe(Debug)]
165pub struct Connector<R: Runtime> {
166 #[educe(Debug(ignore))]
168 client: Arc<TorClient<R>>,
169
170 tls_provider: UreqTlsProvider,
172}
173
174pub struct ConnectorBuilder<R: Runtime> {
192 client: Option<Arc<TorClient<R>>>,
194
195 runtime: R,
203
204 tls_provider: Option<UreqTlsProvider>,
206}
207
208#[derive(Educe)]
211#[educe(Debug)]
212struct HttpTransport<R: Runtime> {
213 r: Arc<Mutex<DataReader>>,
216
217 w: Arc<Mutex<DataWriter>>, #[educe(Debug(ignore))]
222 buffer: LazyBuffers,
223
224 rt: R,
226}
227
228#[derive(Educe)]
252#[educe(Debug)]
253pub struct Resolver<R: Runtime> {
254 #[educe(Debug(ignore))]
258 client: Arc<TorClient<R>>,
259}
260
261#[derive(Error, Debug)]
263#[non_exhaustive]
264pub enum Error {
265 #[error("unsupported URI scheme in {uri:?}")]
267 UnsupportedUriScheme {
268 uri: Uri,
270 },
271
272 #[error("Missing hostname in {uri:?}")]
274 MissingHostname {
275 uri: Uri,
277 },
278
279 #[error("Tor connection failed")]
281 Arti(#[from] arti_client::Error),
282
283 #[error("General I/O error")]
285 Io(#[from] std::io::Error),
286
287 #[error("TLS provider in config does not match the one in Connector.")]
289 TlsConfigMismatch,
290}
291
292impl tor_error::HasKind for Error {
294 #[rustfmt::skip]
295 fn kind(&self) -> tor_error::ErrorKind {
296 use tor_error::ErrorKind as EK;
297 match self {
298 Error::UnsupportedUriScheme{..} => EK::NotImplemented,
299 Error::MissingHostname{..} => EK::BadApiUsage,
300 Error::Arti(e) => e.kind(),
301 Error::Io(..) => EK::Other,
302 Error::TlsConfigMismatch => EK::BadApiUsage,
303 }
304 }
305}
306
307impl std::convert::From<Error> for ureq::Error {
309 fn from(err: Error) -> Self {
310 match err {
311 Error::MissingHostname { uri } => {
312 ureq::Error::BadUri(format!("Missing hostname in {uri:?}"))
313 }
314 Error::UnsupportedUriScheme { uri } => {
315 ureq::Error::BadUri(format!("Unsupported URI scheme in {uri:?}"))
316 }
317 Error::Arti(e) => ureq::Error::Io(std::io::Error::other(e)), Error::Io(e) => ureq::Error::Io(e),
319 Error::TlsConfigMismatch => {
320 ureq::Error::Tls("TLS provider in config does not match the one in Connector.")
321 }
322 }
323 }
324}
325
326impl<R: Runtime + ToplevelBlockOn> Transport for HttpTransport<R> {
336 fn buffers(&mut self) -> &mut dyn Buffers {
338 &mut self.buffer
339 }
340
341 fn transmit_output(&mut self, amount: usize, _timeout: NextTimeout) -> Result<(), ureq::Error> {
343 let mut writer = self.w.lock().expect("lock poisoned");
344
345 let buffer = self.buffer.output();
346 let data_to_write = &buffer[..amount];
347
348 self.rt.block_on(async {
349 writer.write_all(data_to_write).await?;
350 writer.flush().await?;
351 Ok(())
352 })
353 }
354
355 fn await_input(&mut self, _timeout: NextTimeout) -> Result<bool, ureq::Error> {
357 let mut reader = self.r.lock().expect("lock poisoned");
358
359 let buffers = self.buffer.input_append_buf();
360 let size = self.rt.block_on(reader.read(buffers))?;
361 self.buffer.input_appended(size);
362
363 Ok(size > 0)
364 }
365
366 fn is_open(&mut self) -> bool {
368 self.r.lock().is_ok_and(|guard| {
372 guard
373 .client_stream_ctrl()
374 .is_some_and(|ctrl| ctrl.is_connected())
375 })
376 }
377}
378
379impl ConnectorBuilder<tor_rtcompat::PreferredRuntime> {
380 pub fn new() -> Result<Self, Error> {
382 Ok(ConnectorBuilder {
383 client: None,
384 runtime: tor_rtcompat::PreferredRuntime::create()?,
385 tls_provider: None,
386 })
387 }
388}
389
390impl<R: Runtime> ConnectorBuilder<R> {
391 pub fn build(self) -> Result<Connector<R>, Error> {
393 let client = match self.client {
394 Some(client) => client,
395 None => TorClient::with_runtime(self.runtime).create_unbootstrapped()?,
396 };
397
398 let tls_provider = self.tls_provider.unwrap_or(get_default_tls_provider());
399
400 Ok(Connector {
401 client,
402 tls_provider,
403 })
404 }
405
406 pub fn with_runtime(runtime: R) -> Result<ConnectorBuilder<R>, Error> {
410 Ok(ConnectorBuilder {
411 client: None,
412 runtime,
413 tls_provider: None,
414 })
415 }
416
417 pub fn tor_client(mut self, client: Arc<TorClient<R>>) -> ConnectorBuilder<R> {
424 self.runtime = client.runtime().clone();
425 self.client = Some(client);
426 self
427 }
428
429 pub fn tls_provider(mut self, tls_provider: UreqTlsProvider) -> Self {
431 self.tls_provider = Some(tls_provider);
432 self
433 }
434}
435
436impl<R: Runtime + ToplevelBlockOn> UreqResolver for Resolver<R> {
444 fn resolve(
446 &self,
447 uri: &Uri,
448 _config: &ureq::config::Config,
449 _timeout: NextTimeout,
450 ) -> Result<ResolvedSocketAddrs, ureq::Error> {
451 let (host, port) = uri_to_host_port(uri)?;
454 let ips = self
455 .client
456 .runtime()
457 .block_on(async { self.client.resolve(&host).await })
458 .map_err(Error::from)?;
459
460 let mut array_vec: ArrayVec<core::net::SocketAddr, 16> = ArrayVec::from_fn(|_| {
461 core::net::SocketAddr::new(core::net::IpAddr::V4(core::net::Ipv4Addr::UNSPECIFIED), 0)
462 });
463
464 for ip in ips {
465 let socket_addr = core::net::SocketAddr::new(ip, port);
466 array_vec.push(socket_addr);
467 }
468
469 Ok(array_vec)
470 }
471}
472
473impl<R: Runtime + ToplevelBlockOn> Connector<R> {
474 pub fn with_tor_client(client: Arc<TorClient<R>>) -> Connector<R> {
476 Connector {
477 client,
478 tls_provider: get_default_tls_provider(),
479 }
480 }
481}
482
483impl<R: Runtime + ToplevelBlockOn> UreqConnector<()> for Connector<R> {
484 type Out = Box<dyn Transport>;
485
486 fn connect(
490 &self,
491 details: &ureq::unversioned::transport::ConnectionDetails,
492 _chained: Option<()>,
493 ) -> Result<Option<Self::Out>, ureq::Error> {
494 let (host, port) = uri_to_host_port(details.uri)?;
496
497 let addr = (host.as_str(), port)
499 .into_tor_addr()
500 .map_err(|e| Error::Arti(e.into()))?;
501
502 let stream = self
504 .client
505 .runtime()
506 .block_on(async { self.client.connect(addr).await })
507 .map_err(Error::from)?;
508
509 let (r, w) = stream.split();
511 Ok(Some(Box::new(HttpTransport {
512 r: Arc::new(Mutex::new(r)),
513 w: Arc::new(Mutex::new(w)),
514 buffer: LazyBuffers::new(2048, 2048),
515 rt: self.client.runtime().clone(),
516 })))
517 }
518}
519
520impl Connector<tor_rtcompat::PreferredRuntime> {
521 pub fn new() -> Result<Self, Error> {
529 Self::builder()?.build()
530 }
531}
532
533impl<R: Runtime + ToplevelBlockOn> Connector<R> {
534 pub fn resolver(&self) -> Resolver<R> {
536 Resolver {
537 client: self.client.clone(),
538 }
539 }
540
541 pub fn agent(self) -> ureq::Agent {
560 let resolver = self.resolver();
561
562 let ureq_config = ureq::config::Config::builder()
563 .tls_config(
564 ureq::tls::TlsConfig::builder()
565 .provider(self.tls_provider)
566 .build(),
567 )
568 .build();
569
570 ureq::Agent::with_parts(ureq_config, self.connector_chain(), resolver)
571 }
572
573 pub fn agent_with_ureq_config(
577 self,
578 config: ureq::config::Config,
579 ) -> Result<ureq::Agent, Error> {
580 let resolver = self.resolver();
581
582 if self.tls_provider != config.tls_config().provider() {
583 return Err(Error::TlsConfigMismatch);
584 }
585
586 Ok(ureq::Agent::with_parts(
587 config,
588 self.connector_chain(),
589 resolver,
590 ))
591 }
592
593 fn connector_chain(self) -> impl UreqConnector {
595 let chain = self;
596
597 #[cfg(feature = "rustls")]
598 let chain = chain.chain(RustlsConnector::default());
599
600 #[cfg(feature = "native-tls")]
601 let chain = chain.chain(NativeTlsConnector::default());
602
603 chain
604 }
605}
606
607pub fn get_default_tls_provider() -> UreqTlsProvider {
609 if cfg!(feature = "native-tls") {
610 UreqTlsProvider::NativeTls
611 } else {
612 UreqTlsProvider::Rustls
613 }
614}
615
616impl Connector<tor_rtcompat::PreferredRuntime> {
636 pub fn builder() -> Result<ConnectorBuilder<tor_rtcompat::PreferredRuntime>, Error> {
638 ConnectorBuilder::new()
639 }
640}
641
642fn uri_to_host_port(uri: &Uri) -> Result<(String, u16), Error> {
646 let host = uri
647 .host()
648 .ok_or_else(|| Error::MissingHostname { uri: uri.clone() })?;
649
650 let port = match uri.scheme() {
651 Some(scheme) if scheme == &Scheme::HTTPS => Ok(443),
652 Some(scheme) if scheme == &Scheme::HTTP => Ok(80),
653 Some(_) => Err(Error::UnsupportedUriScheme { uri: uri.clone() }),
654 None => Err(Error::UnsupportedUriScheme { uri: uri.clone() }),
655 }?;
656
657 Ok((host.to_owned(), port))
658}
659
660#[cfg(test)]
661mod arti_ureq_test {
662 #![allow(clippy::bool_assert_comparison)]
664 #![allow(clippy::clone_on_copy)]
665 #![allow(clippy::dbg_macro)]
666 #![allow(clippy::mixed_attributes_style)]
667 #![allow(clippy::print_stderr)]
668 #![allow(clippy::print_stdout)]
669 #![allow(clippy::single_char_pattern)]
670 #![allow(clippy::unwrap_used)]
671 #![allow(clippy::unchecked_time_subtraction)]
672 #![allow(clippy::useless_vec)]
673 #![allow(clippy::needless_pass_by_value)]
674 use super::*;
677 use arti_client::config::TorClientConfigBuilder;
678 use std::str::FromStr;
679 use test_temp_dir::test_temp_dir;
680
681 const ARTI_TEST_LIVE_NETWORK: &str = "ARTI_TEST_LIVE_NETWORK";
682 const ARTI_TESTING_ON_LOCAL: &str = "ARTI_TESTING_ON_LOCAL";
683
684 fn assert_equal_types<T>(_: &T, _: &T) {}
687
688 fn test_live_network() -> bool {
691 let run_test = std::env::var(ARTI_TEST_LIVE_NETWORK).is_ok_and(|v| v == "1");
692 if !run_test {
693 println!("Skipping test, set {}=1 to run.", ARTI_TEST_LIVE_NETWORK);
694 }
695
696 run_test
697 }
698
699 fn testing_on_local() -> bool {
703 let run_test = std::env::var(ARTI_TESTING_ON_LOCAL).is_ok_and(|v| v == "1");
704 if !run_test {
705 println!("Skipping test, set {}=1 to run.", ARTI_TESTING_ON_LOCAL);
706 }
707
708 run_test
709 }
710
711 fn test_with_tor_client<R: Runtime>(rt: R, f: impl FnOnce(Arc<TorClient<R>>)) {
713 let temp_dir = test_temp_dir!();
714 temp_dir.used_by(move |temp_dir| {
715 let arti_config = TorClientConfigBuilder::from_directories(
716 temp_dir.join("state"),
717 temp_dir.join("cache"),
718 )
719 .build()
720 .expect("Failed to build TorClientConfig");
721
722 let tor_client = arti_client::TorClient::with_runtime(rt)
723 .config(arti_config)
724 .create_unbootstrapped()
725 .expect("Error creating Tor Client.");
726
727 f(tor_client);
728 });
729 }
730
731 fn request_is_tor(agent: ureq::Agent, https: bool) -> bool {
734 let mut request = agent
735 .get(format!(
736 "http{}://check.torproject.org/api/ip",
737 if https { "s" } else { "" }
738 ))
739 .call()
740 .expect("Failed to make request.");
741 let response = request
742 .body_mut()
743 .read_to_string()
744 .expect("Failed to read body.");
745 let json_response: serde_json::Value =
746 serde_json::from_str(&response).expect("Failed to parse JSON.");
747 json_response
748 .get("IsTor")
749 .expect("Failed to retrieve IsTor property from response")
750 .as_bool()
751 .expect("Failed to convert IsTor to bool")
752 }
753
754 #[test]
757 fn test_equal_types() {
758 assert_equal_types(&1, &i32::MIN);
759 assert_equal_types(&1, &i64::MIN);
760 assert_equal_types(&String::from("foo"), &String::with_capacity(1));
761 }
762
763 #[test]
766 #[cfg(all(feature = "rustls", not(feature = "native-tls")))]
767 fn articonnector_new_returns_default() {
768 if !testing_on_local() {
769 return;
770 }
771
772 let actual_connector = Connector::new().expect("Failed to create Connector.");
773 let expected_connector = Connector {
774 client: TorClient::with_runtime(
775 tor_rtcompat::PreferredRuntime::create().expect("Failed to create runtime."),
776 )
777 .create_unbootstrapped()
778 .expect("Error creating Tor Client."),
779 tls_provider: UreqTlsProvider::Rustls,
780 };
781
782 assert_equal_types(&expected_connector, &actual_connector);
783 assert_equal_types(
784 &actual_connector.client.runtime().clone(),
785 &tor_rtcompat::PreferredRuntime::create().expect("Failed to create runtime."),
786 );
787 assert_eq!(
788 &actual_connector.tls_provider,
789 &ureq::tls::TlsProvider::Rustls,
790 );
791 }
792
793 #[test]
796 #[cfg(all(feature = "rustls", not(feature = "native-tls")))]
797 fn articonnector_with_tor_client() {
798 if !testing_on_local() {
799 return;
800 }
801
802 let tor_client = TorClient::with_runtime(
803 tor_rtcompat::PreferredRuntime::create().expect("Failed to create runtime."),
804 )
805 .create_unbootstrapped()
806 .expect("Error creating Tor Client.");
807
808 let actual_connector = Connector::with_tor_client(tor_client);
809 let expected_connector = Connector {
810 client: TorClient::with_runtime(
811 tor_rtcompat::PreferredRuntime::create().expect("Failed to create runtime."),
812 )
813 .create_unbootstrapped()
814 .expect("Error creating Tor Client."),
815 tls_provider: UreqTlsProvider::Rustls,
816 };
817
818 assert_equal_types(&expected_connector, &actual_connector);
819 assert_equal_types(
820 &actual_connector.client.runtime().clone(),
821 &tor_rtcompat::PreferredRuntime::create().expect("Failed to create runtime."),
822 );
823 assert_eq!(
824 &actual_connector.tls_provider,
825 &ureq::tls::TlsProvider::Rustls,
826 );
827 }
828
829 #[test]
832 fn articonnectorbuilder_new_returns_default() {
833 if !testing_on_local() {
834 return;
835 }
836
837 let expected = Connector::new().expect("Failed to create Connector.");
838 let actual = Connector::<tor_rtcompat::PreferredRuntime>::builder()
839 .expect("Failed to create ConnectorBuilder.")
840 .build()
841 .expect("Failed to create Connector.");
842
843 assert_equal_types(&expected, &actual);
844 assert_equal_types(&expected.client.runtime(), &actual.client.runtime());
845 assert_eq!(&expected.tls_provider, &actual.tls_provider);
846 }
847
848 #[cfg(all(feature = "tokio", feature = "rustls"))]
851 #[test]
852 fn articonnectorbuilder_with_runtime() {
853 if !testing_on_local() {
854 return;
855 }
856
857 let arti_connector = ConnectorBuilder::with_runtime(
858 tor_rtcompat::tokio::TokioRustlsRuntime::create().expect("Failed to create runtime."),
859 )
860 .expect("Failed to create ConnectorBuilder.")
861 .build()
862 .expect("Failed to create Connector.");
863
864 assert_equal_types(
865 &arti_connector.client.runtime().clone(),
866 &tor_rtcompat::tokio::TokioRustlsRuntime::create().expect("Failed to create runtime."),
867 );
868
869 let arti_connector = ConnectorBuilder::with_runtime(
870 tor_rtcompat::PreferredRuntime::create().expect("Failed to create runtime."),
871 )
872 .expect("Failed to create ConnectorBuilder.")
873 .build()
874 .expect("Failed to create Connector.");
875
876 assert_equal_types(
877 &arti_connector.client.runtime().clone(),
878 &tor_rtcompat::PreferredRuntime::create().expect("Failed to create runtime."),
879 );
880 }
881
882 #[cfg(all(feature = "tokio", feature = "rustls"))]
884 #[test]
885 fn articonnectorbuilder_set_tor_client() {
886 let rt =
887 tor_rtcompat::tokio::TokioRustlsRuntime::create().expect("Failed to create runtime.");
888
889 test_with_tor_client(rt.clone(), move |tor_client| {
890 let arti_connector = ConnectorBuilder::with_runtime(rt)
891 .expect("Failed to create ConnectorBuilder.")
892 .tor_client(tor_client.clone().isolated_client())
893 .build()
894 .expect("Failed to create Connector.");
895
896 assert_equal_types(
897 &arti_connector.client.runtime().clone(),
898 &tor_rtcompat::tokio::TokioRustlsRuntime::create()
899 .expect("Failed to create runtime."),
900 );
901 });
902 }
903
904 #[test]
906 fn test_uri_to_host_port() {
907 let uri = Uri::from_str("http://torproject.org").expect("Error parsing uri.");
908 let (host, port) = uri_to_host_port(&uri).expect("Error parsing uri.");
909
910 assert_eq!(host, "torproject.org");
911 assert_eq!(port, 80);
912
913 let uri = Uri::from_str("https://torproject.org").expect("Error parsing uri.");
914 let (host, port) = uri_to_host_port(&uri).expect("Error parsing uri.");
915
916 assert_eq!(host, "torproject.org");
917 assert_eq!(port, 443);
918
919 let uri = Uri::from_str("https://www.torproject.org/test").expect("Error parsing uri.");
920 let (host, port) = uri_to_host_port(&uri).expect("Error parsing uri.");
921
922 assert_eq!(host, "www.torproject.org");
923 assert_eq!(port, 443);
924 }
925
926 #[test]
929 fn request_goes_over_tor() {
930 if !test_live_network() {
931 return;
932 }
933
934 let is_tor = request_is_tor(
935 default_agent().expect("Failed to retrieve default agent."),
936 true,
937 );
938
939 assert_eq!(is_tor, true);
940 }
941
942 #[test]
947 #[cfg(all(feature = "rustls", not(feature = "native-tls")))]
948 fn request_goes_over_tor_with_unsafe_check() {
949 if !test_live_network() {
950 return;
951 }
952
953 let is_tor = request_is_tor(ureq::Agent::new_with_defaults(), true);
954 assert_eq!(is_tor, false);
955
956 let is_tor = request_is_tor(
957 default_agent().expect("Failed to retrieve default agent."),
958 true,
959 );
960 assert_eq!(is_tor, true);
961 }
962
963 #[test]
966 fn request_with_bare_http() {
967 if !test_live_network() {
968 return;
969 }
970
971 let rt = tor_rtcompat::PreferredRuntime::create().expect("Failed to create runtime.");
972
973 test_with_tor_client(rt, |tor_client| {
974 let arti_connector = Connector::with_tor_client(tor_client);
975 let is_tor = request_is_tor(arti_connector.agent(), false);
976
977 assert_eq!(is_tor, true);
978 });
979 }
980
981 #[test]
983 fn test_get_default_tls_provider() {
984 #[cfg(feature = "native-tls")]
985 assert_eq!(get_default_tls_provider(), UreqTlsProvider::NativeTls);
986
987 #[cfg(not(feature = "native-tls"))]
988 assert_eq!(get_default_tls_provider(), UreqTlsProvider::Rustls);
989 }
990
991 #[test]
995 fn test_tor_client_with_get_default_tls_provider() {
996 if !testing_on_local() {
997 return;
998 }
999
1000 let tor_client = TorClient::with_runtime(
1001 tor_rtcompat::PreferredRuntime::create().expect("Failed to create runtime."),
1002 )
1003 .create_unbootstrapped()
1004 .expect("Error creating Tor Client.");
1005
1006 let arti_connector = Connector::<tor_rtcompat::PreferredRuntime>::builder()
1007 .expect("Failed to create ConnectorBuilder.")
1008 .tor_client(tor_client.clone().isolated_client())
1009 .tls_provider(get_default_tls_provider())
1010 .build()
1011 .expect("Failed to create Connector.");
1012
1013 #[cfg(feature = "native-tls")]
1014 assert_eq!(
1015 &arti_connector.tls_provider,
1016 &ureq::tls::TlsProvider::NativeTls,
1017 );
1018
1019 #[cfg(not(feature = "native-tls"))]
1020 assert_eq!(
1021 &arti_connector.tls_provider,
1022 &ureq::tls::TlsProvider::Rustls,
1023 );
1024 }
1025}