AdkWebServer's root->dev-ui redirect breaks behind a path-stripping reverse proxy
- Dominant language
- Java
- Stars
- 1.7k
- Forks
- 420
- Avg merge
- 4d 12h
- Merged PRs (30d)
- 31
Description
## Description
`AdkWebServer.addViewControllers()` redirects `"/"` to the **root-relative** path `"/dev-ui"`:
https://github.com/google/adk-java/blob/e8b1c20d10680e7ed8e936ae1ac0ab768a0b8345/dev/src/main/java/com/google/adk/web/AdkWebServer.java#L151
```java
registry.addRedirectViewController("/", "/dev-ui");
```
When this app is deployed behind a reverse proxy that strips a path prefix before forwarding the request (a common pattern for platform-managed multi-tenant gateways, e.g. Kubernetes Gateway API `HTTPRoute` with a `URLRewrite`/`ReplacePrefixMatch` filter), the browser follows this redirect to an unprefixed path the proxy has no route for, and the dev UI 404s.
## Why this can't be fixed by the app alone with standard Spring mechanisms
Spring's own reverse-proxy support (`server.forward-headers-strategy=framework`, which installs `ForwardedHeaderFilter`) is specifically designed to solve exactly this class of problem via the `X-Forwarded-Prefix` header — but it only works for **context-relative** redirect targets (ones that do *not* start with `/`). I traced this through `ForwardedHeaderExtractingResponse#sendRedirect`:
```java
path = (path.startsWith(FOLDER_SEPARATOR) ? path :
StringUtils.applyRelativePath(this.request.getRequestURI(), path));
```
Root-relative targets (starting with `/`, as `"/dev-ui"` does) skip the `applyRelativePath` branch entirely — the one place `X-Forwarded-Prefix` awareness would apply — so the prefix is never spliced back in, no matter how the proxy is configured.
## Proposed fix
Change the redirect target to be context-relative instead of root-relative:
```java
registry.addRedirectViewController("/", "dev-ui");
```
I verified this doesn't change behavior for the common local/non-proxied case: `RedirectView`'s `contextRelative` handling only prepends the context path when the target starts with `/` (so a context-relative target like `"dev-ui"` is passed through as-is), and the servlet container's own relative-URL resolution for `sendRedirect` still resolves `"dev-ui"` against the current request path `"/"` to `"/dev-ui"`. It *does* additionally allow `server.forward-headers-strategy=framework` + an `X-Forwarded-Prefix` header to correctly restore a proxy's path prefix, fixing the reverse-proxy case with zero app-specific workaround code.
I've opened a PR with this one-line fix plus the corresponding test update: (link to follow)
## Environment
- adk-java: current `main` (verified against commit `e8b1c20`)
- Encountered while deploying a Java ADK agent behind a Kubernetes Gateway API `HTTPRoute` that strips a per-app path prefix
Contributor guide
Assessment
This issue has not been assessed yet.