Merge branch 'main' into hyper-docs
This commit is contained in:
commit
5610cec095
|
@ -41,6 +41,15 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
|
@ -166,6 +175,8 @@ dependencies = [
|
|||
"hyper",
|
||||
"pin-project",
|
||||
"thiserror",
|
||||
"tls-api",
|
||||
"tls-api-native-tls",
|
||||
"tokio",
|
||||
"tor-error",
|
||||
"tor-rtcompat",
|
||||
|
@ -323,7 +334,7 @@ checksum = "9c86f33abd5a4f3e2d6d9251a9e0c6a7e52eb1113caf893dae8429bf4a53f378"
|
|||
dependencies = [
|
||||
"futures-lite",
|
||||
"rustls",
|
||||
"webpki",
|
||||
"webpki 0.21.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -971,6 +982,19 @@ version = "1.6.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.5.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"humantime 1.3.0",
|
||||
"log",
|
||||
"regex",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "2.5.2"
|
||||
|
@ -1103,6 +1127,12 @@ dependencies = [
|
|||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-cprng"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
|
@ -1387,6 +1417,15 @@ version = "1.0.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
|
||||
dependencies = [
|
||||
"quick-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.1.0"
|
||||
|
@ -1399,7 +1438,7 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac34a56cfd4acddb469cc7fff187ed5ac36f498ba085caf8bbc725e3ff474058"
|
||||
dependencies = [
|
||||
"humantime",
|
||||
"humantime 2.1.0",
|
||||
"serde",
|
||||
]
|
||||
|
||||
|
@ -1997,6 +2036,17 @@ version = "0.2.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
|
||||
|
||||
[[package]]
|
||||
name = "pem"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd56cbd21fea48d0c440b41cd69c589faacade08c992d9a54e471b79d0fd13eb"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"once_cell",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pem-rfc7468"
|
||||
version = "0.2.4"
|
||||
|
@ -2166,6 +2216,12 @@ dependencies = [
|
|||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "1.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||
|
||||
[[package]]
|
||||
name = "quickcheck"
|
||||
version = "1.0.3"
|
||||
|
@ -2184,6 +2240,19 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
|
||||
dependencies = [
|
||||
"fuchsia-cprng",
|
||||
"libc",
|
||||
"rand_core 0.3.1",
|
||||
"rdrand",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.7.3"
|
||||
|
@ -2228,6 +2297,21 @@ dependencies = [
|
|||
"rand_core 0.6.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
|
||||
dependencies = [
|
||||
"rand_core 0.4.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.5.1"
|
||||
|
@ -2255,6 +2339,15 @@ dependencies = [
|
|||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rdrand"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
|
||||
dependencies = [
|
||||
"rand_core 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.10"
|
||||
|
@ -2280,6 +2373,8 @@ version = "1.5.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
|
@ -2330,7 +2425,7 @@ dependencies = [
|
|||
"libc",
|
||||
"once_cell",
|
||||
"spin",
|
||||
"untrusted",
|
||||
"untrusted 0.7.1",
|
||||
"web-sys",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
@ -2405,7 +2500,7 @@ dependencies = [
|
|||
"log",
|
||||
"ring",
|
||||
"sct",
|
||||
"webpki",
|
||||
"webpki 0.21.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2456,7 +2551,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
"untrusted 0.7.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2718,6 +2813,16 @@ dependencies = [
|
|||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempdir"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
|
||||
dependencies = [
|
||||
"rand 0.4.6",
|
||||
"remove_dir_all",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.3.0"
|
||||
|
@ -2732,6 +2837,25 @@ dependencies = [
|
|||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "test-cert-gen"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3208d0ae2e3736d4ac2f6ba2229c4d9bbd54080e228e662a7684eabcf13ff419"
|
||||
dependencies = [
|
||||
"pem",
|
||||
"tempdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
|
@ -2804,6 +2928,53 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
||||
|
||||
[[package]]
|
||||
name = "tls-api"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7dded74ddc6d4a98f9f94f17f1c4d796e4af3cb5fba9e7655f157a036ee7de0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"log",
|
||||
"pem",
|
||||
"tempdir",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"void",
|
||||
"webpki 0.22.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tls-api-native-tls"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c547db405b51a4e549f803c980572f3cb3957dff153b04e3e7aebb1fc5f249b4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"native-tls",
|
||||
"thiserror",
|
||||
"tls-api",
|
||||
"tls-api-test",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tls-api-test"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "344ab291be7ed9ab296fc28153fe3ac1e430f44c4dfb3f1324a3c09bbbb5f104"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"env_logger",
|
||||
"log",
|
||||
"pem",
|
||||
"test-cert-gen",
|
||||
"tls-api",
|
||||
"tokio",
|
||||
"untrusted 0.6.2",
|
||||
"webpki 0.22.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.17.0"
|
||||
|
@ -3480,6 +3651,12 @@ version = "0.2.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.7.1"
|
||||
|
@ -3532,6 +3709,12 @@ version = "0.9.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
|
||||
[[package]]
|
||||
name = "waker-fn"
|
||||
version = "1.1.0"
|
||||
|
@ -3666,7 +3849,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
"untrusted 0.7.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted 0.7.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3792,7 +3985,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "9fb2bc2a902d992cd5f471ee3ab0ffd6603047a4207384562755b9d6de977518"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
"untrusted 0.7.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -23,14 +23,16 @@ static = [ "arti-client/static" ]
|
|||
experimental-api = []
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.23"
|
||||
arti-client = { path="../arti-client", version = "0.0.4"}
|
||||
hyper = { version = "0.14", features = ["http1", "client", "runtime"] }
|
||||
pin-project = "1"
|
||||
tokio = { package = "tokio", version = "1.7", features = ["rt", "rt-multi-thread", "io-util", "net", "time", "macros" ] }
|
||||
thiserror = "1"
|
||||
tls-api = { version = "0.7" }
|
||||
tls-api-native-tls = { version = "0.7.0" }
|
||||
tor-error = { path="../tor-error", version = "0.0.1" }
|
||||
tor-rtcompat = { path="../tor-rtcompat", version = "0.0.4", features=["tokio"] }
|
||||
|
||||
[dev-dependencies]
|
||||
anyhow = "1.0.23"
|
||||
tracing-subscriber = "0.3.0"
|
||||
|
|
|
@ -8,9 +8,7 @@ High-level layer for making http(s) requests the Tor network as a client.
|
|||
Note that these APIs are NOT covered by semantic versioning guarantees:
|
||||
we might break them or remove them between patch versions.
|
||||
|
||||
`error_detail` -- Make the `TorError` type transparent, and expose the `Error` within.
|
||||
Note that the resulting APIs are not stable.
|
||||
|
||||
`native-tls` (default), `rustls` -- Select TLS libraries to support.
|
||||
`native-tls` (default), `rustls` -- Select TLS libraries to use for Tor's purposes.
|
||||
(The end-to-end TLS to the origin server is separate, and handled via `tls-api`.)
|
||||
|
||||
License: MIT OR Apache-2.0
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/// TODO this ought to support https!
|
||||
use arti_hyper::*;
|
||||
|
||||
use anyhow::Result;
|
||||
use arti_client::{TorClient, TorClientConfig};
|
||||
use hyper::Body;
|
||||
use std::convert::TryInto;
|
||||
use tls_api::{TlsConnector, TlsConnectorBuilder};
|
||||
use tor_rtcompat::tokio::TokioNativeTlsRuntime;
|
||||
|
||||
#[tokio::main]
|
||||
|
@ -34,8 +34,10 @@ async fn main() -> Result<()> {
|
|||
// (This takes a while to gather the necessary consensus state, etc.)
|
||||
let tor_client = TorClient::create_bootstrapped(rt, config).await?;
|
||||
|
||||
let tls_connector = tls_api_native_tls::TlsConnector::builder()?.build()?;
|
||||
|
||||
// The `ArtiHttpConnector` lets us make HTTP requests via the Tor network.
|
||||
let tor_connector = ArtiHttpConnector::new(tor_client);
|
||||
let tor_connector = ArtiHttpConnector::new(tor_client, tls_connector);
|
||||
let http = hyper::Client::builder().build::<_, Body>(tor_connector);
|
||||
|
||||
// The rest is just standard usage of Hyper.
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
//! High-level layer for making http(s) requests the Tor network as a client.
|
||||
//!
|
||||
//! Work-in-progress.
|
||||
//! This is **not suitable for use** right now because it does not support HTTPs.
|
||||
|
||||
#![deny(missing_docs)]
|
||||
#![warn(noop_method_call)]
|
||||
|
@ -11,7 +8,6 @@
|
|||
#![deny(clippy::cargo_common_metadata)]
|
||||
#![deny(clippy::cast_lossless)]
|
||||
#![deny(clippy::checked_conversions)]
|
||||
#![warn(clippy::clone_on_ref_ptr)]
|
||||
#![warn(clippy::cognitive_complexity)]
|
||||
#![deny(clippy::debug_assert_with_mut_call)]
|
||||
#![deny(clippy::exhaustive_enums)]
|
||||
|
@ -37,6 +33,7 @@
|
|||
use std::future::Future;
|
||||
use std::io::Error;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use arti_client::{DataStream, IntoTorAddr, TorClient};
|
||||
|
@ -46,6 +43,7 @@ use hyper::http::Uri;
|
|||
use hyper::service::Service;
|
||||
use pin_project::pin_project;
|
||||
use thiserror::Error;
|
||||
use tls_api::TlsConnector as TlsConn; // This is different from tor_rtompat::TlsConnector
|
||||
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
|
||||
use tor_rtcompat::Runtime;
|
||||
|
||||
|
@ -62,7 +60,7 @@ pub enum ConnectionError {
|
|||
uri: Uri,
|
||||
},
|
||||
|
||||
/// Unsupported URI scheme
|
||||
/// Missing hostname
|
||||
#[error("Missing hostname in {uri:?}")]
|
||||
MissingHostname {
|
||||
/// URI
|
||||
|
@ -72,6 +70,10 @@ pub enum ConnectionError {
|
|||
/// Tor connection failed
|
||||
#[error("Tor connection failed")]
|
||||
Arti(#[from] arti_client::Error),
|
||||
|
||||
/// TLS connection failed
|
||||
#[error("TLS connection failed")]
|
||||
TLS(#[source] Arc<anyhow::Error>),
|
||||
}
|
||||
|
||||
/// We implement this for form's sake
|
||||
|
@ -83,7 +85,8 @@ impl tor_error::HasKind for ConnectionError {
|
|||
match self {
|
||||
CE::UnsupportedUriScheme{..} => EK::NotImplemented,
|
||||
CE::MissingHostname{..} => EK::BadApiUsage,
|
||||
CE::Arti(e) => e.kind(),
|
||||
CE::Arti(e) => e.kind(),
|
||||
CE::TLS(_) => EK::RemoteProtocolFailed,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -91,29 +94,56 @@ impl tor_error::HasKind for ConnectionError {
|
|||
/// A `hyper` connector to proxy HTTP connections via the Tor network, using Arti.
|
||||
///
|
||||
/// Only supports plaintext HTTP for now.
|
||||
#[derive(Clone)]
|
||||
pub struct ArtiHttpConnector<R: Runtime> {
|
||||
///
|
||||
/// TC is the TLS to used *across* Tor to connect to the origin server.
|
||||
/// This is a different Rust type to the TLS used *by* Tor to connect to relays etc.
|
||||
/// It might even be a different underlying TLS implementation
|
||||
/// (although that is usually not a particularly good idea).
|
||||
pub struct ArtiHttpConnector<R: Runtime, TC: TlsConn> {
|
||||
/// The client
|
||||
client: TorClient<R>,
|
||||
|
||||
/// TLS for using across Tor.
|
||||
tls_conn: Arc<TC>,
|
||||
}
|
||||
|
||||
impl<R: Runtime> ArtiHttpConnector<R> {
|
||||
// #[derive(Clone)] infers a TC: Clone bound
|
||||
impl<R: Runtime, TC: TlsConn> Clone for ArtiHttpConnector<R, TC> {
|
||||
fn clone(&self) -> Self {
|
||||
let client = self.client.clone();
|
||||
let tls_conn = self.tls_conn.clone();
|
||||
Self { client, tls_conn }
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Runtime, TC: TlsConn> ArtiHttpConnector<R, TC> {
|
||||
/// Make a new `ArtiHttpConnector` using an Arti `TorClient` object.
|
||||
pub fn new(client: TorClient<R>) -> Self {
|
||||
Self { client }
|
||||
pub fn new(client: TorClient<R>, tls_conn: TC) -> Self {
|
||||
let tls_conn = tls_conn.into();
|
||||
Self { client, tls_conn }
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper type that makes an Arti `DataStream` implement necessary traits to be used as
|
||||
/// a `hyper` connection object (mainly `Connection`).
|
||||
#[pin_project]
|
||||
pub struct ArtiHttpConnection {
|
||||
pub struct ArtiHttpConnection<TC: TlsConn> {
|
||||
/// The stream
|
||||
#[pin]
|
||||
inner: DataStream,
|
||||
inner: MaybeHttpsStream<TC>,
|
||||
}
|
||||
|
||||
impl Connection for ArtiHttpConnection {
|
||||
/// The actual actual stream; might be TLS, might not
|
||||
#[pin_project(project = MaybeHttpsStreamProj)]
|
||||
enum MaybeHttpsStream<TC: TlsConn> {
|
||||
/// http
|
||||
Http(Pin<Box<DataStream>>), // Tc:TlsStream is generally boxed; box this one too
|
||||
|
||||
/// https
|
||||
Https(#[pin] TC::TlsStream),
|
||||
}
|
||||
|
||||
impl<TC: TlsConn> Connection for ArtiHttpConnection<TC> {
|
||||
fn connected(&self) -> Connected {
|
||||
Connected::new()
|
||||
}
|
||||
|
@ -121,50 +151,83 @@ impl Connection for ArtiHttpConnection {
|
|||
|
||||
// These trait implementations just defer to the inner `DataStream`; the wrapper type is just
|
||||
// there to implement the `Connection` trait.
|
||||
impl AsyncRead for ArtiHttpConnection {
|
||||
impl<TC: TlsConn> AsyncRead for ArtiHttpConnection<TC> {
|
||||
fn poll_read(
|
||||
self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &mut ReadBuf<'_>,
|
||||
) -> Poll<Result<(), std::io::Error>> {
|
||||
self.project().inner.poll_read(cx, buf)
|
||||
match self.project().inner.project() {
|
||||
MaybeHttpsStreamProj::Http(ds) => ds.as_mut().poll_read(cx, buf),
|
||||
MaybeHttpsStreamProj::Https(t) => t.poll_read(cx, buf),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncWrite for ArtiHttpConnection {
|
||||
impl<TC: TlsConn> AsyncWrite for ArtiHttpConnection<TC> {
|
||||
fn poll_write(
|
||||
self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &[u8],
|
||||
) -> Poll<Result<usize, Error>> {
|
||||
self.project().inner.poll_write(cx, buf)
|
||||
match self.project().inner.project() {
|
||||
MaybeHttpsStreamProj::Http(ds) => ds.as_mut().poll_write(cx, buf),
|
||||
MaybeHttpsStreamProj::Https(t) => t.poll_write(cx, buf),
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
|
||||
self.project().inner.poll_flush(cx)
|
||||
match self.project().inner.project() {
|
||||
MaybeHttpsStreamProj::Http(ds) => ds.as_mut().poll_flush(cx),
|
||||
MaybeHttpsStreamProj::Https(t) => t.poll_flush(cx),
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
|
||||
self.project().inner.poll_shutdown(cx)
|
||||
match self.project().inner.project() {
|
||||
MaybeHttpsStreamProj::Http(ds) => ds.as_mut().poll_shutdown(cx),
|
||||
MaybeHttpsStreamProj::Https(t) => t.poll_shutdown(cx),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert uri to host and port
|
||||
fn uri_to_host_port(uri: Uri) -> Result<(String, u16), ConnectionError> {
|
||||
if uri.scheme() != Some(&Scheme::HTTP) {
|
||||
return Err(ConnectionError::UnsupportedUriScheme { uri });
|
||||
}
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
/// Are we doing TLS?
|
||||
enum UseTls {
|
||||
/// No
|
||||
Bare,
|
||||
|
||||
/// Yes
|
||||
Tls,
|
||||
}
|
||||
|
||||
/// Convert uri to http[s] host and port, and whether to do tls
|
||||
fn uri_to_host_port_tls(uri: Uri) -> Result<(String, u16, UseTls), ConnectionError> {
|
||||
let use_tls = {
|
||||
// Scheme doesn't derive PartialEq so can't be matched on
|
||||
let scheme = uri.scheme();
|
||||
if scheme == Some(&Scheme::HTTP) {
|
||||
UseTls::Bare
|
||||
} else if scheme == Some(&Scheme::HTTPS) {
|
||||
UseTls::Tls
|
||||
} else {
|
||||
return Err(ConnectionError::UnsupportedUriScheme { uri });
|
||||
}
|
||||
};
|
||||
let host = match uri.host() {
|
||||
Some(h) => h,
|
||||
_ => return Err(ConnectionError::MissingHostname { uri }),
|
||||
};
|
||||
let port = uri.port().map(|x| x.as_u16()).unwrap_or(80);
|
||||
let port = uri.port().map(|x| x.as_u16()).unwrap_or(match use_tls {
|
||||
UseTls::Tls => 443,
|
||||
UseTls::Bare => 80,
|
||||
});
|
||||
|
||||
Ok((host.to_owned(), port))
|
||||
Ok((host.to_owned(), port, use_tls))
|
||||
}
|
||||
|
||||
impl<R: Runtime> Service<Uri> for ArtiHttpConnector<R> {
|
||||
type Response = ArtiHttpConnection;
|
||||
impl<R: Runtime, TC: TlsConn> Service<Uri> for ArtiHttpConnector<R, TC> {
|
||||
type Response = ArtiHttpConnection<TC>;
|
||||
type Error = ConnectionError;
|
||||
#[allow(clippy::type_complexity)]
|
||||
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
|
||||
|
@ -178,15 +241,28 @@ impl<R: Runtime> Service<Uri> for ArtiHttpConnector<R> {
|
|||
// underlying handles required to make Tor connections internally).
|
||||
// We use this to avoid the returned future having to borrow `self`.
|
||||
let client = self.client.clone();
|
||||
let tls_conn = self.tls_conn.clone();
|
||||
Box::pin(async move {
|
||||
// Extract the host and port to connect to from the URI.
|
||||
let (host, port) = uri_to_host_port(req)?;
|
||||
let (host, port, use_tls) = uri_to_host_port_tls(req)?;
|
||||
// Initiate a new Tor connection, producing a `DataStream` if successful.
|
||||
let addr = (&host as &str, port)
|
||||
.into_tor_addr()
|
||||
.map_err(arti_client::Error::from)?;
|
||||
let ds = client.connect(addr).await?;
|
||||
Ok(ArtiHttpConnection { inner: ds })
|
||||
|
||||
let inner = match use_tls {
|
||||
UseTls::Tls => {
|
||||
let conn = tls_conn
|
||||
.connect_impl_tls_stream(&host, ds)
|
||||
.await
|
||||
.map_err(|e| ConnectionError::TLS(e.into()))?;
|
||||
MaybeHttpsStream::Https(conn)
|
||||
}
|
||||
UseTls::Bare => MaybeHttpsStream::Http(Box::new(ds).into()),
|
||||
};
|
||||
|
||||
Ok(ArtiHttpConnection { inner })
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -936,7 +936,56 @@ impl<B: AbstractCircBuilder + 'static, R: Runtime> AbstractCircMgr<B, R> {
|
|||
let mut retry_error = RetryError::in_attempt_to("wait for circuits");
|
||||
|
||||
while let Some((src, id)) = incoming.next().await {
|
||||
let id = match id {
|
||||
match id {
|
||||
Ok(Ok(ref id)) => {
|
||||
// Great, we have a circuit. See if we can use it!
|
||||
let mut list = self.circs.lock().expect("poisoned lock");
|
||||
if let Some(ent) = list.get_open_mut(id) {
|
||||
let now = self.runtime.now();
|
||||
match ent.restrict_mut(usage, now) {
|
||||
Ok(()) => {
|
||||
// Great, this will work. We drop the
|
||||
// pending request now explicitly to remove
|
||||
// it from the list.
|
||||
drop(pending_request);
|
||||
if matches!(ent.expiration, ExpirationInfo::Unused { .. }) {
|
||||
// Since this circuit hasn't been used yet, schedule expiration task after `max_dirtiness` from now.
|
||||
spawn_expiration_task(
|
||||
&self.runtime,
|
||||
Arc::downgrade(&self),
|
||||
ent.circ.id(),
|
||||
now + self.circuit_timing().max_dirtiness,
|
||||
);
|
||||
}
|
||||
return Ok(ent.circ.clone());
|
||||
}
|
||||
Err(e) => {
|
||||
// TODO: as below, improve this log message.
|
||||
if src == streams::Source::Left {
|
||||
info!(
|
||||
"{:?} suggested we use {:?}, but restrictions failed: {:?}",
|
||||
src, id, &e
|
||||
);
|
||||
} else {
|
||||
debug!(
|
||||
"{:?} suggested we use {:?}, but restrictions failed: {:?}",
|
||||
src, id, &e
|
||||
);
|
||||
}
|
||||
if src == streams::Source::Left {
|
||||
retry_error.push(e);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Err(ref e)) => {
|
||||
debug!("{:?} sent error {:?}", src, e);
|
||||
if src == streams::Source::Left {
|
||||
retry_error.push(e.clone());
|
||||
}
|
||||
}
|
||||
Err(oneshot::Canceled) => {
|
||||
debug!(
|
||||
"{:?} went away (Canceled), quitting take_action right away",
|
||||
|
@ -945,50 +994,6 @@ impl<B: AbstractCircBuilder + 'static, R: Runtime> AbstractCircMgr<B, R> {
|
|||
retry_error.push(Error::PendingCanceled);
|
||||
return Err(retry_error);
|
||||
}
|
||||
Ok(id) => id,
|
||||
};
|
||||
if let Ok(ref id) = id {
|
||||
// Great, we have a circuit. See if we can use it!
|
||||
let mut list = self.circs.lock().expect("poisoned lock");
|
||||
if let Some(ent) = list.get_open_mut(id) {
|
||||
let now = self.runtime.now();
|
||||
match ent.restrict_mut(usage, now) {
|
||||
Ok(()) => {
|
||||
// Great, this will work. We drop the
|
||||
// pending request now explicitly to remove
|
||||
// it from the list.
|
||||
drop(pending_request);
|
||||
if matches!(ent.expiration, ExpirationInfo::Unused { .. }) {
|
||||
// Since this circuit hasn't been used yet, schedule expiration task after `max_dirtiness` from now.
|
||||
spawn_expiration_task(
|
||||
&self.runtime,
|
||||
Arc::downgrade(&self),
|
||||
ent.circ.id(),
|
||||
now + self.circuit_timing().max_dirtiness,
|
||||
);
|
||||
}
|
||||
return Ok(ent.circ.clone());
|
||||
}
|
||||
Err(e) => {
|
||||
// TODO: as below, improve this log message.
|
||||
if src == streams::Source::Left {
|
||||
info!(
|
||||
"{:?} suggested we use {:?}, but restrictions failed: {:?}",
|
||||
src, id, &e
|
||||
);
|
||||
} else {
|
||||
debug!(
|
||||
"{:?} suggested we use {:?}, but restrictions failed: {:?}",
|
||||
src, id, &e
|
||||
);
|
||||
}
|
||||
if src == streams::Source::Left {
|
||||
retry_error.push(e);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Improve this log message; using :? here will make it
|
||||
|
|
|
@ -424,6 +424,23 @@ pub enum ErrorKind {
|
|||
#[display(fmt = "remote hostname lookup failure")]
|
||||
RemoteHostNotFound,
|
||||
|
||||
/// Trouble involving a protocol we're using with a peer on the far side of the Tor network
|
||||
///
|
||||
/// We were using a higher-layer protocol over a Tor connection,
|
||||
/// and something went wrong.
|
||||
/// This might be an error reported by the remote host within that higher protocol,
|
||||
/// or a problem detected locally but relating to that higher protocol.
|
||||
///
|
||||
/// The nature of the problem can vary:
|
||||
/// examples could include:
|
||||
/// failure to agree suitable parameters (incompatibility);
|
||||
/// authentication problems (eg, TLS certificate trouble);
|
||||
/// protocol violation by the peer;
|
||||
/// peer refusing to provide service;
|
||||
/// etc.
|
||||
#[display(fmt = "remote protocol failed")]
|
||||
RemoteProtocolFailed,
|
||||
|
||||
/// An operation failed, and the relay in question reported that it's too
|
||||
/// busy to answer our request.
|
||||
#[display(fmt = "relay too busy")]
|
||||
|
|
|
@ -9,4 +9,7 @@ cargo +nightly update -Z minimal-versions
|
|||
cargo update \
|
||||
-p crc32fast \
|
||||
-p quote:0.6.3 \
|
||||
-p synstructure:0.12.0
|
||||
-p zeroize_derive:1.1.1 \
|
||||
-p env_logger:0.5.0 \
|
||||
-p synstructure:0.12.0 \
|
||||
-p nix:0.4.2
|
||||
|
|
Loading…
Reference in New Issue