line / armeria

Your go-to microservice framework for any situation, from the creator of Netty et al. You can build any type of microservice leveraging your favorite technologies, including gRPC, Thrift, Kotlin, Retrofit, Reactive Streams, Spring Boot and Dropwizard.
https://armeria.dev
Apache License 2.0
4.83k stars 923 forks source link

Provide a option to preserve percent-encoding in the request path. #5219

Open ikhoon opened 1 year ago

ikhoon commented 1 year ago

Armeria automatically decodes percent-encoded characters if they are not in the preserved chars. https://github.com/line/armeria/blob/eb36d93f0a197019a5c790650c3f556b86b22973/core/src/main/java/com/linecorp/armeria/internal/common/DefaultRequestTarget.java#L60-L68

If a service proxies incoming requests, users may want to see the original percent-encoding as is.

An option to preserve percent-encoding would be useful for that case.

WebClient
  .builder("https://my-proxy.com")
  .preservePercentEncoding(true)
  ...
  build();

Server
  .builder()
  .preservePercentEncoding(true)
  ...
  build();

Discord thread: https://discord.com/channels/1087271586832318494/1087272728177942629/1157388108032118886

vkostyukov commented 1 year ago

Would be awesome if we could opt-in for original percent encoding on per route basis on a server. Most routes/endpoints don't care for path but, as mentioned in the ticket, a proxy-type of endpoints do.

HongGeonUi commented 11 months ago

Hi, I'm student interested in Armenia. I think I can make this feature. Can you assign me?

ikhoon commented 11 months ago

Sorry for the late reply. @HongGeonUi are you still interested in implementing this feature?

HongGeonUi commented 10 months ago

@ikhoon Sorry, I'm still interested in this feature. but I didn't care about this. I make PR #5374. Happy belated New Year!

jrhee17 commented 10 months ago

Would be awesome if we could opt-in for original percent encoding on per route basis on a server

While looking at this comment, it seems at the moment there seems to be a circular dependency:

We may need to consider either

  1. Updating the HttpRequest.header after routing completed and we know whether to preserve percent encoding

  2. Just exposing the original path (this may be a breaking change though for those using headers.get(HttpHeaderNames.PATH))

HttpHeaders.path() // the normalized path that is used for routing, pattern matching, etc.
HttpHeaders.rawPath() // the raw path that was received with no normalization
jrhee17 commented 10 months ago

Talked with the others, I propose the following:

Server side

A new method is added such that the original (raw) path of the request can be retrieved to ServiceRequestContext.

DecodedHttpRequest.rawPath() <- internally carries the raw path across the netty pipeline
ServiceRequestContext.rawPath() <- public api exposed to users

Client-side

A new option is added per-client which preserves percent-encoding like mentioned in the original proposal.

WebClient
  .builder("https://my-proxy.com")
  .preservePercentEncoding(true)
  ...
  build();

In conjunction, the two methods can be used like the following:

val client = WebClient
  .builder("https://my-proxy.com")
  .preservePercentEncoding(true)
  ...
Server.builder().service("/proxy", (ctx, req) -> {
  return client.execute(req.withHeaders(req.headers().toBuilder().path(ctx.rawPath()).build()));
})

Note that it might be difficult to determine the prefix path with this approach. For instance, the normalized path strips consecutive slashes, so the following scenario is possible:

originalPath: //%70roxy//a
path (normalized): /proxy/a

The user may choose to reject unnormalized paths and strip the prefix path depending on his/her requirements

dipeshsingh253 commented 1 month ago

Hi @ikhoon , Can you please assign this issue to me??

ikhoon commented 1 month ago

Sure, did it.