diff --git a/websocket/src/browser.rs b/websocket/src/browser.rs index 14939c2e..f889c3fe 100644 --- a/websocket/src/browser.rs +++ b/websocket/src/browser.rs @@ -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 { (&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(()), } } diff --git a/websocket/src/desktop.rs b/websocket/src/desktop.rs index 99b6c217..4a6b92a2 100644 --- a/websocket/src/desktop.rs +++ b/websocket/src/desktop.rs @@ -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 { @@ -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;