Minor Proxy Improvements (#1289)

* fix(serve): provide a clear error with pathless proxy URLs

Without this, `dx serve` panics with this message:

```
Paths must start with a `/`. Use "/" for
 root routes
 ```

 That's not very clear. Instead, we can detect this situation and provide a better error message:

```
Error: 🚫 Serving project failed: Failed to establish proxy: Proxy backend URL must have a non-empty path, e.g. http://localhost:8080/api instead of http://localhost:8080
```

* docs(config): correct format for `web.proxy`
This commit is contained in:
Brian Donovan 2023-08-04 11:44:56 -07:00 committed by GitHub
parent 50230b6f71
commit 6d154b5072
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 33 additions and 3 deletions

View file

@ -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
```

View file

@ -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),

View file

@ -48,6 +48,16 @@ impl ProxyClient {
pub fn add_proxy(mut router: Router, proxy: &WebProxyConfig) -> Result<Router> {
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 = 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<Router> {
// 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),
}
}
}