- Ya
- 7 Agosti 2026, 05:02 UTC
- Mwandishi
- Kamo
- Ahadi ya
- 21670e5
The gateway stopped double-encoding forwarded query strings in 3c24d32, but four other proxies in this service still concatenated already-percent-encoded bytes into a String and handed it to RestTemplate's String overload, which treats it as a URI template and encodes it a second time: %2C left as %252C, the upstream decoded once and got the literal token A%2CB. These are all public surfaces, so the failures are silent and land outside the company: - /api/public/esign/** — a Business-plan customer's status=SENT%2CCOMPLETED filter arrived at ESigService as one run-together token. - /api/public/webinar/** — same shape, MediaService side. - /api/social/webhook/{token} — the GET verification handshake IS the query string. A Meta verify token containing a space compared unequal downstream and MediaService answered 200-empty, so Meta dropped the subscription; X's crc_token is HMAC'd verbatim, so a mangled one deregisters the webhook. Safe to change: Meta's x-hub-signature-256 and X's signature are both HMAC over the raw BODY (MessengerAdapter:110, InstagramAdapter:114, XAdapter:151), which is forwarded as an untouched byte[]. No signature covers the URL. - /api/public-chat/** — the three handlers that append getQueryString(). The helper moves out of APIGatewayController into UpstreamUri so four classes share one parse-and-fall-back branch instead of four copies. A URL that URI.create rejects (raw space, |, {}, truncated escape — shapes that work today only BECAUSE of the second encode) still goes down the old String path with a WARN, so malformed traffic behaves exactly as it did. Public chat needed a second entry point rather than the gateway's. Its path is built from @PathVariables that Spring has already DECODED while its query is raw, so wrapping the concatenated URL in URI.create would have been a regression: a session token arriving as abc%23xyz decodes to abc#xyz, which URI.create accepts while silently truncating the path at the fragment. The halves are kept apart to the call site — the path encoded through the same UriComponentsBuilder call DefaultUriBuilderFactory makes, so those bytes are unchanged; the query left alone. The seven query-less handlers keep the String path untouched: no query, no double-encode to fix. Deliberately NOT changed, and they must stay that way — all encode exactly once today, so "fixing" them would 502 live traffic: subscription-catalog (splices a DECODED @RequestParam locale), subscription-promotions (fixed literal), validate-key in **************** (SHA-256 hex, a fixed point under URI_COMPONENT), LeadIntakePublicController (decoded UUID path variable, never calls getQueryString), the VOIP recording ingest POST (config literal, all input in the multipart body), and CapchaVerificationService (payload is in the JSON body).