Pass the host name with websockets (#177)

This commit is contained in:
Pierre Krieger
2018-05-08 22:07:07 +02:00
committed by GitHub
parent 64278244de
commit 37881d511e
2 changed files with 57 additions and 8 deletions

View File

@ -35,7 +35,11 @@ use tokio_io::{AsyncRead, AsyncWrite};
/// Represents the configuration for a websocket transport capability for libp2p.
///
/// This implementation of `Transport` accepts any address that looks like
/// `/ip4/.../tcp/.../ws` or `/ip6/.../tcp/.../ws`, and connect to the corresponding IP and port.
/// `/ip4/.../tcp/.../ws`, `/ip6/.../tcp/.../ws`, `/dns4/.../ws` or `/dns6/.../ws`, and connect to
/// the corresponding IP and port.
///
/// If the underlying multiaddress uses `/dns4` or `/dns6`, then the domain name will be passed in
/// the headers of the request. This is important is the listener is behind an HTTP proxy.
#[derive(Debug, Clone)]
pub struct BrowserWsConfig;
@ -339,6 +343,18 @@ fn multiaddr_to_target(addr: &Multiaddr) -> Result<String, ()> {
(&AddrComponent::IP6(ref ip), &AddrComponent::TCP(port), &AddrComponent::WSS) => {
Ok(format!("wss://[{}]:{}/", ip, port))
}
(&AddrComponent::DNS4(ref ns), &AddrComponent::TCP(port), &AddrComponent::WS) => {
Ok(format!("ws://{}:{}/", ns, port))
}
(&AddrComponent::DNS6(ref ns), &AddrComponent::TCP(port), &AddrComponent::WS) => {
Ok(format!("ws://{}:{}/", ns, port))
}
(&AddrComponent::DNS4(ref ns), &AddrComponent::TCP(port), &AddrComponent::WSS) => {
Ok(format!("wss://{}:{}/", ns, port))
}
(&AddrComponent::DNS6(ref ns), &AddrComponent::TCP(port), &AddrComponent::WSS) => {
Ok(format!("wss://{}:{}/", ns, port))
}
_ => Err(()),
}
}

View File

@ -34,6 +34,10 @@ use websocket::stream::async::Stream as AsyncStream;
/// This implementation of `Transport` accepts any address that ends with `/ws` or `/wss`, and will
/// try to pass the underlying multiaddress to the underlying `Transport`.
///
/// Note that the underlying multiaddr is `/dns4/...` or `/dns6/...`, then this library will
/// pass the domain name in the headers of the request. This is important is the listener is behind
/// an HTTP proxy.
///
/// > **Note**: `/wss` is only supported for dialing and not listening.
#[derive(Debug, Clone)]
pub struct WsConfig<T> {
@ -159,6 +163,8 @@ where
debug!(target: "libp2p-websocket", "Dialing {} through inner transport", inner_addr);
let ws_addr = client_addr_to_ws(&inner_addr, is_wss);
let inner_dial = match self.transport.dial(inner_addr) {
Ok(d) => d,
Err((transport, old_addr)) => {
@ -177,13 +183,8 @@ where
let dial = inner_dial
.into_future()
.and_then(move |(connec, client_addr)| {
// We pass a dummy address to `ClientBuilder` because it is never used anywhere
// in the negotiation anyway, and we use `async_connect_on` to pass a stream.
ClientBuilder::new(if is_wss {
"wss://127.0.0.1"
} else {
"ws://127.0.0.1"
}).expect("hard-coded ws address is always valid")
ClientBuilder::new(&ws_addr)
.expect("generated ws address is always valid")
.async_connect_on(connec)
.map_err(|err| IoError::new(IoErrorKind::Other, err))
.map(|(client, _)| {
@ -245,6 +246,38 @@ where
}
}
fn client_addr_to_ws(client_addr: &Multiaddr, is_wss: bool) -> String {
let inner = {
let protocols: Vec<_> = client_addr.iter().collect();
if protocols.len() != 2 {
"127.0.0.1".to_owned()
} else {
match (&protocols[0], &protocols[1]) {
(&AddrComponent::IP4(ref ip), &AddrComponent::TCP(port)) => {
format!("{}:{}", ip, port)
}
(&AddrComponent::IP6(ref ip), &AddrComponent::TCP(port)) => {
format!("[{}]:{}", ip, port)
}
(&AddrComponent::DNS4(ref ns), &AddrComponent::TCP(port)) => {
format!("{}:{}", ns, port)
}
(&AddrComponent::DNS6(ref ns), &AddrComponent::TCP(port)) => {
format!("{}:{}", ns, port)
}
_ => "127.0.0.1".to_owned(),
}
}
};
if is_wss {
format!("wss://{}", inner)
} else {
format!("ws://{}", inner)
}
}
#[cfg(test)]
mod tests {
extern crate libp2p_tcp_transport as tcp;