google / google/adk-java

AdkWebServer's root->dev-ui redirect breaks behind a path-stripping reverse proxy

Open
#1,457 2 comments 0 reactions 1 assignee Claimed by @hemasekhar-p View on GitHub
needs review
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.