Encode the decoded token exactly once on the way upstream

FixAPIService
Shipped
August 7, 2026 at 5:11 AM UTC
Author
Kamo
Commit
b10c950

21670e5 routed SocialWebhookController through UpstreamUri's FULLY-PRE-ENCODED entry point, but its URL is a hybrid: `token` is an @PathVariable, so Spring hands the handler the DECODED value, while getQueryString() is raw. That entry point encodes nothing, which is right for the raw half and wrong for the decoded one — the mirror image of the double-encode this whole change set is about. POST /api/social/webhook/ab%252Ccd arrives as the string ab%2Ccd, was forwarded verbatim, and MediaService decoded it a second time down to ab,cd. Before 21670e5 it round-tripped correctly, so this was a regression, not a pre-existing hole. Zero live impact: tokens are 32 hex chars **************** and so encoding-inert, which is exactly why nothing caught it. The contract was inverted though, and the first non-hex segment added to this route would have corrupted silently. Switched to the hybrid entry point, which encodes the path once through the same UriComponentsBuilder call DefaultUriBuilderFactory makes and leaves the query untouched. The Meta/X handshake behaviour is unchanged — verified by the four existing tests, which still assert byte-identical query strings. Two new tests pin the contract with a non-hex ab%252Ccd token, with and without a query. Both fail against the previous entry point with exactly ab%2Ccd. Also corrects two overstatements in UpstreamUri's javadoc: - It claimed the hybrid form PREVENTS a `#` in a decoded path variable truncating the request at the fragment. It does not: **************** splits on `#` exactly like the DefaultUriBuilderFactory behind the String overload, so the behaviour is unchanged either way. Unchanged is the right call on a public surface, but it is not an improvement and should not read as one. The real reason the entry points are split is the encode-once-vs-not-at-all distinction above, which is now what the javadoc says. - An empty (not null) query string used to yield a trailing `?` and now yields none. Same request under RFC 3986; noted in a comment so it is not mistaken for an oversight later. Prose and comments only for those two — no behaviour change. Suite: 45 tests, 0 failures, 0 errors.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing