Pedro Galan
Pedro Galan

Reputation: 704

Spring Cloud Gateway. using + (plus) in the value of a query parameter

We are using Spring Cloud Gateway (MVC version) in front o a Rails service (let's call it mailbox) and are struggling when the value of a query parameter includes the + (plus) character. Here is an example:

  1. Client sends a request to the gateway with [email protected]
  2. Gateway decodes the parameter value, turning + into a space.
  3. Before sending the request to mailbox, it encodes back the value, resulting in email=bob%[email protected]
  4. When receiving this param, mailbox decodes it as email=bob [email protected] which makes it fail

An alternative was to encode + in the client, but then we have:

  1. Client sends a request to the gateway with ?email=bob%[email protected]
  2. Gateway decodes the parameter value, turning %2B into +.
  3. Before sending the request to mailbox, it encodes back the value but, given that + is not considered special character, it stays as [email protected]
  4. When receiving this param, mailbox decodes it as email=bob [email protected] which makes it fail

I can't find a way to either tell gateway not to decode the original request or force it to encode + before sending the request to mailbox. Is there any way to do that? Is there any other solution? I can't think of anything. It's like all the steps taken are okay (first decode, then encode), but the final result is wrong. I need mailbox to receive an email with a + in it, but I can't.

Thanks for your help!

Upvotes: 1

Views: 298

Answers (1)

Dan Chivers
Dan Chivers

Reputation: 56

We encountered the same issue and were able to work around the problem by manually encoding + in the forwarded requests after the existing encoder has run.

This was achieved by using a customised ClientHttpRequestFactory as follows:

@Configuration
class WebMvcConfiguration {

    @Bean
    fun clientHttpRequestFactory(): ClientHttpRequestFactory =
        CustomClientHttpRequestFactory()

}
class CustomClientHttpRequestFactory : JdkClientHttpRequestFactory() {

    override fun createRequest(uri: URI, httpMethod: HttpMethod): ClientHttpRequest {
        val encodedURI = URI(customUriEncode(uri.toString()))
        return super.createRequest(encodedURI, httpMethod)
    }

    private fun customUriEncode(str: String): String = 
        str.replace(oldValue = "+", newValue = "%2B")

}

We believe this to be safe, because both + and %20 in the original request are decoded into (a space) before it reaches the request factory, so will not be re-encoded back into %2B.

Upvotes: 2

Related Questions