diff --git a/iroh-net/src/relay/http.rs b/iroh-net/src/relay/http.rs index a61d17b798..dd5b180871 100644 --- a/iroh-net/src/relay/http.rs +++ b/iroh-net/src/relay/http.rs @@ -12,6 +12,18 @@ pub(crate) const HTTP_UPGRADE_PROTOCOL: &str = "iroh derp http"; pub(crate) const WEBSOCKET_UPGRADE_PROTOCOL: &str = "websocket"; pub(crate) const SUPPORTED_WEBSOCKET_VERSION: &str = "13"; +/// The HTTP path under which the relay accepts relaying connections +/// (over websockets and a custom upgrade protocol). +pub const RELAY_PATH: &str = "/relay"; +/// The HTTP path under which the relay allows doing latency queries for testing. +pub const RELAY_PROBE_PATH: &str = "/relay/probe"; +/// The legacy HTTP path under which the relay used to accept relaying connections. +/// We keep this for backwards compatibility. +pub(crate) const LEGACY_RELAY_PATH: &str = "/derp"; +/// The legacy HTTP path under which the relay used to allow latency queries. +/// We keep this for backwards compatibility. +pub(crate) const LEGACY_RELAY_PROBE_PATH: &str = "/derp/probe"; + #[cfg(test)] mod tests { use super::*; diff --git a/iroh-net/src/relay/http/server.rs b/iroh-net/src/relay/http/server.rs index f21cb75460..7057117283 100644 --- a/iroh-net/src/relay/http/server.rs +++ b/iroh-net/src/relay/http/server.rs @@ -30,6 +30,8 @@ use crate::relay::http::{ use crate::relay::server::{ClientConnHandler, MaybeTlsStream}; use crate::relay::MaybeTlsStreamServer; +use super::{LEGACY_RELAY_PATH, RELAY_PATH}; + type BytesBody = http_body_util::Full; type HyperError = Box; type HyperResult = std::result::Result; @@ -226,8 +228,6 @@ pub struct ServerBuilder { /// Used when certain routes in your server should be made available at the same port as /// the relay server, and so must be handled along side requests to the relay endpoint. handlers: Handlers, - /// Defaults to `GET` request at "/derp". - relay_endpoint: &'static str, /// Use a custom relay response handler. /// /// Typically used when you want to disable any relay connections. @@ -250,7 +250,6 @@ impl ServerBuilder { addr, tls_config: None, handlers: Default::default(), - relay_endpoint: "/derp", relay_override: None, headers: HeaderMap::new(), not_found_fn: None, @@ -296,14 +295,6 @@ impl ServerBuilder { self } - /// Sets a custom endpoint for the relay handler. - /// - /// The default is `/derp`. - pub fn relay_endpoint(mut self, endpoint: &'static str) -> Self { - self.relay_endpoint = endpoint; - self - } - /// Adds HTTP headers to responses. pub fn headers(mut self, headers: HeaderMap) -> Self { for (k, v) in headers.iter() { @@ -347,13 +338,7 @@ impl ServerBuilder { }), }; - let service = RelayService::new( - self.handlers, - relay_handler, - self.relay_endpoint, - not_found_fn, - self.headers, - ); + let service = RelayService::new(self.handlers, relay_handler, not_found_fn, self.headers); let server_state = ServerState { addr: self.addr, @@ -564,7 +549,11 @@ impl Service> for RelayService { fn call(&self, req: Request) -> Self::Future { // if the request hits the relay endpoint - if req.method() == hyper::Method::GET && req.uri().path() == self.0.relay_endpoint { + // or /derp for backwards compat + if matches!( + (req.method(), req.uri().path()), + (&hyper::Method::GET, LEGACY_RELAY_PATH | RELAY_PATH) + ) { match &self.0.relay_handler { RelayHandler::Override(f) => { // see if we have some override response @@ -597,7 +586,6 @@ struct RelayService(Arc); #[derive(derive_more::Debug)] struct Inner { pub relay_handler: RelayHandler, - pub relay_endpoint: &'static str, #[debug("Box Result> + Send + Sync + 'static>")] pub not_found_fn: HyperHandler, pub handlers: Handlers, @@ -645,14 +633,12 @@ impl RelayService { fn new( handlers: Handlers, relay_handler: RelayHandler, - relay_endpoint: &'static str, not_found_fn: HyperHandler, headers: HeaderMap, ) -> Self { Self(Arc::new(Inner { relay_handler, handlers, - relay_endpoint, not_found_fn, headers, })) diff --git a/iroh-net/src/relay/iroh_relay.rs b/iroh-net/src/relay/iroh_relay.rs index 253b7077f0..d71c91fc39 100644 --- a/iroh-net/src/relay/iroh_relay.rs +++ b/iroh-net/src/relay/iroh_relay.rs @@ -27,7 +27,9 @@ use tracing::{debug, error, info, info_span, instrument, trace, warn, Instrument use crate::key::SecretKey; use crate::relay; -use crate::relay::http::{ServerBuilder as RelayServerBuilder, TlsAcceptor}; +use crate::relay::http::{ + ServerBuilder as RelayServerBuilder, TlsAcceptor, LEGACY_RELAY_PROBE_PATH, RELAY_PROBE_PATH, +}; use crate::stun; use crate::util::AbortingJoinHandle; @@ -76,7 +78,7 @@ pub struct ServerConfig { /// Configuration for the Relay HTTP and HTTPS server. /// -/// This includes the HTTP services hosted by the Relay server, the Relay `/derp` HTTP +/// This includes the HTTP services hosted by the Relay server, the Relay `/relay` HTTP /// endpoint is only one of the services served. #[derive(Debug)] pub struct RelayConfig { @@ -235,7 +237,12 @@ impl Server { .relay_override(Box::new(relay_disabled_handler)) .request_handler(Method::GET, "/", Box::new(root_handler)) .request_handler(Method::GET, "/index.html", Box::new(root_handler)) - .request_handler(Method::GET, "/derp/probe", Box::new(probe_handler)) + .request_handler( + Method::GET, + LEGACY_RELAY_PROBE_PATH, + Box::new(probe_handler), + ) // backwards compat + .request_handler(Method::GET, RELAY_PROBE_PATH, Box::new(probe_handler)) .request_handler(Method::GET, "/robots.txt", Box::new(robots_handler)); let http_addr = match relay_config.tls { Some(tls_config) => { @@ -702,14 +709,29 @@ mod tests { use std::time::Duration; use bytes::Bytes; + use http::header::UPGRADE; use iroh_base::node_addr::RelayUrl; - use crate::relay::http::ClientBuilder; + use crate::relay::http::{ClientBuilder, HTTP_UPGRADE_PROTOCOL}; use self::relay::ReceivedMessage; use super::*; + async fn spawn_local_relay() -> Result { + Server::spawn(ServerConfig::<(), ()> { + relay: Some(RelayConfig { + secret_key: SecretKey::generate(), + http_bind_addr: (Ipv4Addr::LOCALHOST, 0).into(), + tls: None, + limits: Default::default(), + }), + stun: None, + metrics_addr: None, + }) + .await + } + #[tokio::test] async fn test_no_services() { let _guard = iroh_test::logging::setup(); @@ -748,18 +770,7 @@ mod tests { #[tokio::test] async fn test_root_handler() { let _guard = iroh_test::logging::setup(); - let server = Server::spawn(ServerConfig::<(), ()> { - relay: Some(RelayConfig { - secret_key: SecretKey::generate(), - http_bind_addr: (Ipv4Addr::LOCALHOST, 0).into(), - tls: None, - limits: Default::default(), - }), - stun: None, - metrics_addr: None, - }) - .await - .unwrap(); + let server = spawn_local_relay().await.unwrap(); let url = format!("http://{}", server.http_addr().unwrap()); let response = reqwest::get(&url).await.unwrap(); @@ -771,18 +782,7 @@ mod tests { #[tokio::test] async fn test_captive_portal_service() { let _guard = iroh_test::logging::setup(); - let server = Server::spawn(ServerConfig::<(), ()> { - relay: Some(RelayConfig { - secret_key: SecretKey::generate(), - http_bind_addr: (Ipv4Addr::LOCALHOST, 0).into(), - tls: None, - limits: Default::default(), - }), - stun: None, - metrics_addr: None, - }) - .await - .unwrap(); + let server = spawn_local_relay().await.unwrap(); let url = format!("http://{}/generate_204", server.http_addr().unwrap()); let challenge = "123az__."; @@ -800,21 +800,28 @@ mod tests { assert!(body.is_empty()); } + #[tokio::test] + async fn test_relay_client_legacy_route() { + let _guard = iroh_test::logging::setup(); + let server = spawn_local_relay().await.unwrap(); + // We're testing the legacy endpoint at `/derp` + let endpoint_url = format!("http://{}/derp", server.http_addr().unwrap()); + + let client = reqwest::Client::new(); + let result = client + .get(endpoint_url) + .header(UPGRADE, HTTP_UPGRADE_PROTOCOL) + .send() + .await + .unwrap(); + + assert_eq!(result.status(), StatusCode::SWITCHING_PROTOCOLS); + } + #[tokio::test] async fn test_relay_clients_both_derp() { let _guard = iroh_test::logging::setup(); - let server = Server::spawn(ServerConfig::<(), ()> { - relay: Some(RelayConfig { - secret_key: SecretKey::generate(), - http_bind_addr: (Ipv4Addr::LOCALHOST, 0).into(), - tls: None, - limits: Default::default(), - }), - stun: None, - metrics_addr: None, - }) - .await - .unwrap(); + let server = spawn_local_relay().await.unwrap(); let relay_url = format!("http://{}", server.http_addr().unwrap()); let relay_url: RelayUrl = relay_url.parse().unwrap(); @@ -879,18 +886,7 @@ mod tests { #[tokio::test] async fn test_relay_clients_both_websockets() { let _guard = iroh_test::logging::setup(); - let server = Server::spawn(ServerConfig::<(), ()> { - relay: Some(RelayConfig { - secret_key: SecretKey::generate(), - http_bind_addr: (Ipv4Addr::LOCALHOST, 0).into(), - tls: None, - limits: Default::default(), - }), - stun: None, - metrics_addr: None, - }) - .await - .unwrap(); + let server = spawn_local_relay().await.unwrap(); // NOTE: Using `ws://` URL scheme to trigger websockets. let relay_url = format!("ws://{}", server.http_addr().unwrap()); let relay_url: RelayUrl = relay_url.parse().unwrap(); @@ -956,18 +952,7 @@ mod tests { #[tokio::test] async fn test_relay_clients_websocket_and_derp() { let _guard = iroh_test::logging::setup(); - let server = Server::spawn(ServerConfig::<(), ()> { - relay: Some(RelayConfig { - secret_key: SecretKey::generate(), - http_bind_addr: (Ipv4Addr::LOCALHOST, 0).into(), - tls: None, - limits: Default::default(), - }), - stun: None, - metrics_addr: None, - }) - .await - .unwrap(); + let server = spawn_local_relay().await.unwrap(); let derp_relay_url = format!("http://{}", server.http_addr().unwrap()); let derp_relay_url: RelayUrl = derp_relay_url.parse().unwrap();