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
Fix a bug where a request has failed to be routed when both a '/path' and a '/{var}' path mappings exist with different HTTP methods #3340
Conversation
764134c
to
3592fd0
Compare
dc244fb
to
b089f3b
Compare
Codecov Report
@@ Coverage Diff @@
## master #3340 +/- ##
============================================
- Coverage 74.31% 74.31% -0.01%
- Complexity 13527 13571 +44
============================================
Files 1174 1178 +4
Lines 51703 51916 +213
Branches 6631 6666 +35
============================================
+ Hits 38422 38580 +158
- Misses 9915 9958 +43
- Partials 3366 3378 +12
Continue to review full report at Codecov.
|
e68eca1
to
1f3bd54
Compare
@@ -61,9 +61,6 @@ protected void configure(ServerBuilder sb) throws Exception { | |||
// returning `202 Accepted`. | |||
sb.service("/f/", service); | |||
sb.routeDecorator().pathPrefix("/f/").build((delegate, ctx, req) -> HttpResponse.of(202)); | |||
|
|||
// This should never be invoked in this test. | |||
sb.serviceUnder("/", service); |
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.
@trustin I removed this line because of the following test:
// `GET /e` should be redirected to `/e/`.
// `DELETE /e` should NOT be redirected to `/e/`.
sb.route().get("/e/").build(service);
Because my fix made /e/
's fallback route support HTTP GET only. So the request would be routed the '/' service if this line exists. Please let me know if I'm wrong. 😄
Sorry. 😭 I will review this today! 🔥 |
core/src/main/java/com/linecorp/armeria/server/DefaultRoute.java
Outdated
Show resolved
Hide resolved
/** | ||
* Returns the {@link PathMapping} of this {@link Route}. | ||
*/ | ||
PathMapping pathMapping(); |
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.
PathMapping
is package-private so we need to make it public.
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.
Removed this method and fixed the following lines:
https://github.com/line/armeria/pull/3340/files#diff-d94019f9ef8458d0b4a04a1be6e2a6ebaf9f85cbab92e2ac6bc6bc42f89f0d2bR81-R96
Is it okay if I use CatchAllPathMapping.INSTANCE
directly from there? I'm not sure, but I think the fallback route's PathMapping
must be CatchAllPathMapping
because /a/
's fallback path is always /a
. So I think it would be better to use CatchAllPathMapping.INSTANCE
rather than making PathMapping
public. Please let me know what you think. 🙇♂️
core/src/main/java/com/linecorp/armeria/server/RouteBuilder.java
Outdated
Show resolved
Hide resolved
Sorry for the late review. 😄 |
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.
Mostly looking good.
core/src/main/java/com/linecorp/armeria/server/RouteBuilder.java
Outdated
Show resolved
Hide resolved
b79201b
to
5ab524e
Compare
@hyangtack Sorry, but would you mind merging master to resolve the conflicts? 😅 |
… and a '/{var}' path mappings exist with different HTTP methods Motivation: Currently `RoutingTrie` can find a route only based on the request path. But there's lots of conditions used to resolve a correct path such as HTTP methods, content-type header, accept header, and even a certain HTTP header and/or parameter. So we need to check whether a route is acceptable for the request or not earlier than now, in order to avoid picking up wrong routes. Modifications: - Introduce `NodeProcessor<?>` and pass a node into it when the node is selected as a candidate. - Create a `ResultCachingNodeProcessor` and pass it to `RoutingTrie#find` method when finding `ServiceConfig` instances from `RoutingTrie`. - It holds `Routed` instances resolved while visiting the trie. - If a node is not acceptable for the request, it would be dropped. - Add `setDeferredExceptionToRoutingContext(boolean)` method to `Route` in order to avoid propagating an exception raised while resolving a route to fallback services. - By default, it sets `true`. It would be set as `false` if the original route does not support all HTTP methods and the fallback route needs to be added. - For example, assume that a route `/a/b/c/` supports HTTP GET method only. Its fallback route would be added like `/a/b/c` with supporting HTTP GET method as well. In this case, `404 not found` would be better other than `405 method not allowed` if a request is coming like `DELETE /a/b/c`, because the fallback route radically does not exist. Result: - Closes line#3330
Co-authored-by: Ikhun Um <ih.pert@gmail.com>
5ab524e
to
58de162
Compare
core/src/main/java/com/linecorp/armeria/server/DefaultRoute.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/RoutingTrie.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/RoutingTrie.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/DefaultRoute.java
Outdated
Show resolved
Hide resolved
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.
Awesome job as usual, @hyangtack. 💯
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.
Many thanks for all your hard work! 🙇♂️ @hyangtack
@minwoox Ping |
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.
Thanks! just one nit. 😄
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.
You are the superhero.
🎉🎉🎉 |
Motivation:
Currently
RoutingTrie
can find a route only based on the request path. But there's lots of conditionsused to resolve a correct path such as HTTP methods, content-type header, accept header, and even
a certain HTTP header and/or parameter.
So we need to check whether a route is acceptable for the request or not earlier than now,
in order to avoid picking up wrong routes.
Modifications:
NodeProcessor<?>
and pass a node into it when the node is selected as a candidate.RouteCandidateCollectingNodeProcessor
and pass it toRoutingTrie#find
method when findingServiceConfig
instances fromRoutingTrie
.Routed
instances resolved while visiting the trie.The fallback
ServiceConfig
would be served on the fallback route.isFallback
value defined in aDefaultRoute
in order to avoid propagatingan exception raised while resolving a route to fallback services.
/a/b/c/
supports HTTP GET method only. Its fallback route wouldbe added like
/a/b/c
with supporting HTTP GET method as well.In this case,
404 not found
would be better other than405 method not allowed
if a request iscoming like
DELETE /a/b/c
, because the fallback route wasn't specified by a user.Result:
405 Method Not Allowed
if defines both exact path and param path #3330