-
Notifications
You must be signed in to change notification settings - Fork 892
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support colons in path for server-side #5676
base: main
Are you sure you want to change the base?
Conversation
@@ -74,13 +74,13 @@ service HttpJsonTranscodingTestService { | |||
|
|||
rpc EchoTimestampAndDuration(EchoTimestampAndDurationRequest) returns (EchoTimestampAndDurationResponse) { | |||
option (google.api.http) = { | |||
get: "/v1/echo/{timestamp}/{duration}" | |||
get: "/v1/echo/timestamp/{timestamp}/{duration}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These paths can be a source of flakiness since it clashes with the following path:
get: "/v1/echo/response_body/value" |
get: "/v1/echo/response_body/repeated" |
}; | ||
} | ||
|
||
rpc EchoTimestamp(EchoTimestampRequest) returns (EchoTimestampResponse) { | ||
option (google.api.http) = { | ||
post: "/v1/echo/{timestamp}:get", | ||
post: "/v1/echo/timestamp/{timestamp}:get", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto
post: "/v1/echo/{timestamp}:get", |
sortedEndpoints.stream().map(httpEndpoint -> httpEndpoint.spec().route().patternString()) | ||
sortedEndpoints.stream() | ||
.map(httpEndpoint -> httpEndpoint.spec().route()) | ||
.filter(route -> route.pathType() != RoutePathType.REGEX) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is necessary because GrpcDocServicePluginTest.servicesTest
fails.
When the path type is regex, a question mark is included in the path. e.g. /(?<p0>[^/])/hello
However, the regex path is incorrectly cleansed in MethodInfo
.
final RequestTarget reqTarget = RequestTarget.forServer(path); |
Since this automatic behavior is done for gRPC only, I've added a logic to filter out this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we create the method info with the examplepath as is?
I'm a bit worried about the situation that all paths that have verb suffixes wouldn't have the example paths. 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, I guess I didn't think example paths were too important.
Having said this, I do think it's possible to replace regex patterns with the capturing group name at the cost of extra complexity. Pushed a commit to address this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks straightforward! Left small suggestions. 👍
core/src/main/java/com/linecorp/armeria/server/RouteBuilder.java
Outdated
Show resolved
Hide resolved
sortedEndpoints.stream().map(httpEndpoint -> httpEndpoint.spec().route().patternString()) | ||
sortedEndpoints.stream() | ||
.map(httpEndpoint -> httpEndpoint.spec().route()) | ||
.filter(route -> route.pathType() != RoutePathType.REGEX) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we create the method info with the examplepath as is?
I'm a bit worried about the situation that all paths that have verb suffixes wouldn't have the example paths. 🤔
766d8c2
to
50d8dcc
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 👍 👍 👍 👍
Motivation:
Currently, gRPC verb suffix is supported by introducing a
VerbSuffixPathMapping
.There were several issues with this approach:
VerbSuffixPathMapping
was applied inconsistently.RouteBuilder path(String pathPattern)
appliesVerbSuffixPathMapping
, butRouteBuilder path(String prefix, String pathPattern)
doesn't.ExactPathMapping
,VerbSuffixPathMapping
was acting as a workaround to support colons in the path. Additionally the support for colons is incomplete since only the last colon is correctly handled.VerbSuffixPathMapping
makes supporting colons natively difficult./path\\
The original motivation for #5613 was that the following patterns weren't supported.
I propose that the first case be handled via using
REGEX
PathMapping
types, and the second case be handled by natively supporting colons in our path parameters.Note that colons are supported per the rfc3986, and we already have an issue #4577.
/path/{param}:verb
I propose that we support this simply by introducing a new
PathMappingType.REGEX
. We can simply check if the lastPathSegment
is aVerbPathSegment
. If it is aVerbPathSegment
, then we can just usePathMappingType.REGEX
./path/literal:verb
Internally, we represent colons as parameterized variables both in
ParameterizedPathMapping
andRoutingTrieBuilder
. This makes it difficult to support colons, so I propose that we modify the internal representation to a different character (\0
). This character isn't a valid path character per rfc3986, so I believe the impact is minimal.One side effect of this approach is that
ParameterizedPathMapping#paths
will return null character delimited paths.e.g.
/v0/:/path
->/v0/\0/path
Having said this, I believe the normal user path doesn't really use this value so it shouldn't matter.
When one calls
RouteBuilder#path(String)
, we determine whether to useParameterizedPathMapping
orExactPathMapping
depending on whether a colon is used.armeria/core/src/main/java/com/linecorp/armeria/server/RouteBuilder.java
Line 546 in 8ab4284
/a:b
), it is trivial to assume that the colon should be matched exactly./:param
), it is ambiguous whether the user intended this to be a literal or parameter.For this case, I propose the following:
/:param
, then the segment will be used to represent a parameter/\\:param
, then the segment will be treated as a literalOptimization)
ExactPathMapping
is more performant thanParameterizedPathMapping
because a simple equality check is done. I propose as an optimization we modify the condition to check if/:
is contained instead of:
. As a downside of this approach, the colon escape logic needs to also be added toExactPathMapping
. This can be undone if this logic seems too complicated though.Modifications:
VerbPathSegment
is used, useRegexPathMapping
for gRPC transcoding.VerbSuffixPathMapping
and related changes inRoutingTrieBuilder
,RouteBuilder
, andParameterizedPathMapping
RoutingTrieBuilder
andParameterizedPathMapping
to use\0
instead of ':' to represent parameterized path segments. This allows us to use ':' in mostPathMapping
types.ParameterizedPathMapping
to act likeExactPathMapping
when a path segment isn't capturing a path parameter./\\:
to/:
inParameterizedPathMapping
andExactPathMapping
to give users an option to use the first colon as a literal.Result: