diff --git a/packages/cli/docs/src/configure.md b/packages/cli/docs/src/configure.md index 8da66d9ec..9d0cb0a9b 100644 --- a/packages/cli/docs/src/configure.md +++ b/packages/cli/docs/src/configure.md @@ -144,7 +144,7 @@ Configeration related to static resources your application uses in development: Configeration related to any proxies your application requires durring development. Proxies will forward requests to a new service ``` -[web.proxy] +[[web.proxy]] # configuration ``` diff --git a/packages/cli/src/error.rs b/packages/cli/src/error.rs index 7832ab326..84b9d4b71 100644 --- a/packages/cli/src/error.rs +++ b/packages/cli/src/error.rs @@ -35,6 +35,9 @@ pub enum Error { #[error("Invalid proxy URL: {0}")] InvalidProxy(#[from] hyper::http::uri::InvalidUri), + #[error("Failed to establish proxy: {0}")] + ProxySetupError(String), + #[error("Error proxying request: {0}")] ProxyRequestError(hyper::Error), diff --git a/packages/cli/src/server/web/proxy.rs b/packages/cli/src/server/web/proxy.rs index 8de65f4db..e35635b6b 100644 --- a/packages/cli/src/server/web/proxy.rs +++ b/packages/cli/src/server/web/proxy.rs @@ -48,6 +48,16 @@ impl ProxyClient { pub fn add_proxy(mut router: Router, proxy: &WebProxyConfig) -> Result { let url: Uri = proxy.backend.parse()?; let path = url.path().to_string(); + let trimmed_path = path.trim_end_matches('/'); + + if trimmed_path.is_empty() { + return Err(crate::Error::ProxySetupError(format!( + "Proxy backend URL must have a non-empty path, e.g. {}/api instead of {}", + proxy.backend.trim_end_matches('/'), + proxy.backend + ))); + } + let client = ProxyClient::new(url); // We also match everything after the path using a wildcard matcher. @@ -56,7 +66,7 @@ pub fn add_proxy(mut router: Router, proxy: &WebProxyConfig) -> Result { router = router.route( // Always remove trailing /'s so that the exact route // matches. - path.trim_end_matches('/'), + trimmed_path, any(move |req| async move { client .send(req) @@ -68,7 +78,7 @@ pub fn add_proxy(mut router: Router, proxy: &WebProxyConfig) -> Result { // Wildcard match anything else _after_ the backend URL's path. // Note that we know `path` ends with a trailing `/` in this branch, // so `wildcard` will look like `http://localhost/api/*proxywildcard`. - let wildcard = format!("{}/*proxywildcard", path.trim_end_matches('/')); + let wildcard = format!("{}/*proxywildcard", trimmed_path); router = router.route( &wildcard, any(move |req| async move { @@ -168,4 +178,21 @@ mod test { async fn add_proxy_trailing_slash() { test_proxy_requests("/api/".to_string()).await; } + + #[test] + fn add_proxy_empty_path() { + let config = WebProxyConfig { + backend: "http://localhost:8000".to_string(), + }; + let router = super::add_proxy(Router::new(), &config); + match router.unwrap_err() { + crate::Error::ProxySetupError(e) => { + assert_eq!( + e, + "Proxy backend URL must have a non-empty path, e.g. http://localhost:8000/api instead of http://localhost:8000" + ); + } + e => panic!("Unexpected error type: {}", e), + } + } }