Skip to content

request headers to override path/query - #1361

Merged
eschultink merged 2 commits into
rc-v0.6.9from
s230-fallback-request-headers
Jul 30, 2026
Merged

request headers to override path/query #1361
eschultink merged 2 commits into
rc-v0.6.9from
s230-fallback-request-headers

Conversation

@eschultink

Copy link
Copy Markdown
Member

Adds support for request headers that override the proxied path and query string, enabling fallback routing or request shaping without changing the underlying connector configuration.

Use case: GCP does some decoding of path / query string values we don't want; as well as weird routing with //. have had similar issues with AWS lambda/api gateway, although could more reliably work around those; still worth having feature everywhere in case needed.

Features

  • x-Psoxy-TargetPath header - overrides path that request will be sent to in source
  • x-Psoxy-TargetQuery header - overrides querystring that will be sent with request to source

Change implications

  • dependencies added/changed? no
  • something important to note in future release notes?
    • NOTE in CHANGELOG.md anything that will show up in terraform plan/apply that isn't obviously a no-op?
      • Unlikely unless new env vars or Terraform inputs were added for the override headers (not evident from the commit message alone).
    • breaking changes? if in module/example that is NOT marked alpha, requires major version change
      • No — this appears to be additive behavior (new override headers), not a change to existing defaults.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for API-mode “control headers” that let callers override the effective upstream request path and query string, enabling routing/workarounds for fronting layers that rewrite or decode URLs.

Changes:

  • Introduces TargetOverrideRequestResolver to apply and validate X-Psoxy-TargetPath / X-Psoxy-TargetQuery overrides.
  • Wires override handling into ApiDataRequestHandler (invalid overrides return HTTP 400 with INVALID_REQUEST).
  • Adds unit tests and documentation for the new control headers.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
java/core/src/main/java/co/worklytics/psoxy/gateway/TargetOverrideRequestResolver.java New resolver that validates and applies path/query overrides via a request wrapper.
java/core/src/main/java/co/worklytics/psoxy/gateway/impl/ApiDataRequestHandler.java Applies overrides early in request handling and maps invalid overrides to HTTP 400.
java/core/src/main/java/co/worklytics/psoxy/ControlHeader.java Adds TARGET_PATH / TARGET_QUERY control headers with Javadoc.
java/core/src/test/java/co/worklytics/psoxy/gateway/TargetOverrideRequestResolverTest.java New unit tests for override behavior and validation.
java/core/src/test/java/co/worklytics/psoxy/gateway/impl/ApiDataRequestHandlerTest.java Adds coverage that override headers influence requested target URL and invalid overrides are rejected.
docs/SUMMARY.md Adds the new “Control Headers” doc page to the docs navigation.
docs/configuration/README.md Links to control headers documentation from configuration index.
docs/configuration/control-headers.md New documentation describing supported X-Psoxy-* control headers and validation behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +81 to +86
validateUntrustedHeaderValue(ControlHeader.TARGET_PATH.getHttpHeader(), path);
if (!path.startsWith("/")) {
throw new IllegalArgumentException(
ControlHeader.TARGET_PATH.getHttpHeader() + " must start with '/'");
}
return path;
Comment on lines +93 to +98
String normalized = StringUtils.removeStart(query, "?");
// empty string is a valid override meaning "no query"
if (StringUtils.isNotEmpty(normalized)) {
validateUntrustedHeaderValue(ControlHeader.TARGET_QUERY.getHttpHeader(), normalized);
}
return normalized;
Comment on lines +100 to +108
@ParameterizedTest
@ValueSource(strings = {"missing-slash", "relative/path", ""})
void targetPath_rejectsMissingLeadingSlashOrEmpty(String path) {
when(request.getHeader(ControlHeader.TARGET_PATH.getHttpHeader()))
.thenReturn(Optional.of(path));

assertThrows(IllegalArgumentException.class, () -> resolver.applyOverrides(request));
}

Comment on lines +140 to +146
@Test
void targetQuery_rejectsCrLf() {
when(request.getHeader(ControlHeader.TARGET_QUERY.getHttpHeader()))
.thenReturn(Optional.of("a=1\nb=2"));

assertThrows(IllegalArgumentException.class, () -> resolver.applyOverrides(request));
}
- Reject whitespace, ?/# in TargetPath and whitespace/# in TargetQuery
- Use isBlank for empty TargetPath check
- Fix Mockito mocking for Java 25/26 CI via MockModules.provideMock
- Add unit coverage for delimiter/whitespace rejection

Co-authored-by: Cursor <cursoragent@cursor.com>
@eschultink
eschultink enabled auto-merge (squash) July 30, 2026 16:32
@eschultink
eschultink merged commit c612dbb into rc-v0.6.9 Jul 30, 2026
120 checks passed
@eschultink
eschultink deleted the s230-fallback-request-headers branch July 30, 2026 16:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants