request headers to override path/query - #1361
Merged
Merged
Conversation
Contributor
There was a problem hiding this comment.
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
TargetOverrideRequestResolverto apply and validateX-Psoxy-TargetPath/X-Psoxy-TargetQueryoverrides. - Wires override handling into
ApiDataRequestHandler(invalid overrides return HTTP 400 withINVALID_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)); | ||
| } |
aperez-worklytics
approved these changes
Jul 30, 2026
- 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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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-TargetPathheader - overrides path that request will be sent to in sourcex-Psoxy-TargetQueryheader - overrides querystring that will be sent with request to sourceChange implications
CHANGELOG.mdanything that will show up interraform plan/applythat isn't obviously a no-op?alpha, requires major version change