Skip to content

Commit edeb7be

Browse files
committed
Add normPath to route option
1 parent deaa262 commit edeb7be

File tree

7 files changed

+184
-36
lines changed

7 files changed

+184
-36
lines changed

jooby/src/main/java/io/jooby/RouterOptions.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ public class RouterOptions {
3232

3333
private boolean ignoreTrailingSlash;
3434

35+
private boolean normalizePath;
36+
3537
private boolean resetHeadersOnError = true;
3638

3739
/**
@@ -96,4 +98,13 @@ public boolean getResetHeadersOnError() {
9698
this.resetHeadersOnError = resetHeadersOnError;
9799
return this;
98100
}
101+
102+
public boolean getNormalizePath() {
103+
return normalizePath;
104+
}
105+
106+
public RouterOptions setNormalizePath(boolean normalizePath) {
107+
this.normalizePath = normalizePath;
108+
return this;
109+
}
99110
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package io.jooby.internal;
2+
3+
import io.jooby.MessageEncoder;
4+
import io.jooby.Router;
5+
6+
public class RouteTreeIgnoreTrailingSlash extends RouteTreeForwarding {
7+
public RouteTreeIgnoreTrailingSlash(RouteTree tree) {
8+
super(tree);
9+
}
10+
11+
@Override public boolean find(String method, String path) {
12+
return super.find(method, Router.noTrailingSlash(path));
13+
}
14+
15+
@Override public RouterMatch find(String method, String path, MessageEncoder encoder) {
16+
return super.find(method, Router.noTrailingSlash(path), encoder);
17+
}
18+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package io.jooby.internal;
2+
3+
import io.jooby.MessageEncoder;
4+
5+
public class RouteTreeLowerCasePath extends RouteTreeForwarding {
6+
public RouteTreeLowerCasePath(RouteTree tree) {
7+
super(tree);
8+
}
9+
10+
@Override public boolean find(String method, String path) {
11+
return super.find(method, path.toLowerCase());
12+
}
13+
14+
@Override public RouterMatch find(String method, String path, MessageEncoder encoder) {
15+
return super.find(method, path.toLowerCase(), encoder);
16+
}
17+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package io.jooby.internal;
2+
3+
import io.jooby.MessageEncoder;
4+
import io.jooby.Router;
5+
6+
public class RouteTreeNormPath extends RouteTreeForwarding {
7+
public RouteTreeNormPath(RouteTree tree) {
8+
super(tree);
9+
}
10+
11+
@Override public boolean find(String method, String path) {
12+
return super.find(method, Router.normalizePath(path));
13+
}
14+
15+
@Override public RouterMatch find(String method, String path, MessageEncoder encoder) {
16+
return super.find(method, Router.normalizePath(path), encoder);
17+
}
18+
}

jooby/src/main/java/io/jooby/internal/RouteTreeWithOptions.java

Lines changed: 0 additions & 33 deletions
This file was deleted.

jooby/src/main/java/io/jooby/internal/RouterImpl.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -505,9 +505,14 @@ private Route newRoute(@Nonnull String method, @Nonnull String pattern,
505505
}
506506
}
507507
/** router options: */
508-
if (options.getIgnoreCase() || options.getIgnoreTrailingSlash()) {
509-
chi = new RouteTreeWithOptions(chi, options.getIgnoreCase(),
510-
options.getIgnoreTrailingSlash());
508+
if (options.getIgnoreCase()) {
509+
chi = new RouteTreeLowerCasePath(chi);
510+
}
511+
if (options.getIgnoreTrailingSlash()) {
512+
chi = new RouteTreeIgnoreTrailingSlash(chi);
513+
}
514+
if (options.getNormalizePath()) {
515+
chi = new RouteTreeNormPath(chi);
511516
}
512517

513518
// unwrap executor
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package io.jooby;
2+
3+
import io.jooby.junit.ServerTest;
4+
import io.jooby.junit.ServerTestRunner;
5+
6+
import static org.junit.jupiter.api.Assertions.assertEquals;
7+
8+
public class Issue1409 {
9+
10+
@ServerTest
11+
public void shouldKeepDeveloperProvidedPath(ServerTestRunner runner) {
12+
runner.define(app -> {
13+
app.get("//doubleslash", Context::getRequestPath);
14+
15+
app.path("//path", () -> {
16+
app.get("//", Context::getRequestPath);
17+
});
18+
19+
app.path("/context", () -> {
20+
app.get("/", Context::getRequestPath);
21+
22+
app.get("//", Context::getRequestPath);
23+
});
24+
25+
app.get("/trailing/", Context::getRequestPath);
26+
27+
app.get("/trailing", ctx -> "/trailing!");
28+
}).ready(client -> {
29+
client.get("//doubleslash", rsp -> {
30+
assertEquals("//doubleslash", rsp.body().string());
31+
assertEquals(200, rsp.code());
32+
});
33+
34+
client.get("//path//", rsp -> {
35+
assertEquals("//path//", rsp.body().string());
36+
assertEquals(200, rsp.code());
37+
});
38+
39+
client.get("/trailing/", rsp -> {
40+
assertEquals("/trailing/", rsp.body().string());
41+
assertEquals(200, rsp.code());
42+
});
43+
44+
client.get("/trailing", rsp -> {
45+
assertEquals("/trailing!", rsp.body().string());
46+
assertEquals(200, rsp.code());
47+
});
48+
49+
client.get("/context", rsp -> {
50+
assertEquals("/context", rsp.body().string());
51+
assertEquals(200, rsp.code());
52+
});
53+
54+
client.get("/context//", rsp -> {
55+
assertEquals("/context//", rsp.body().string());
56+
assertEquals(200, rsp.code());
57+
});
58+
});
59+
}
60+
61+
@ServerTest
62+
public void shouldNormRequestPath(ServerTestRunner runner) {
63+
runner.define(app -> {
64+
app.setRouterOptions(new RouterOptions()
65+
.setNormalizePath(true)
66+
.setIgnoreTrailingSlash(true)
67+
);
68+
app.get("/doubleslash", Context::getRequestPath);
69+
70+
app.path("/path", () -> {
71+
app.get("/", Context::getRequestPath);
72+
});
73+
74+
app.path("/context", () -> {
75+
app.get("/", Context::getRequestPath);
76+
});
77+
78+
app.get("/trailing", Context::getRequestPath);
79+
80+
}).ready(client -> {
81+
client.get("//doubleslash", rsp -> {
82+
assertEquals("//doubleslash", rsp.body().string());
83+
assertEquals(200, rsp.code());
84+
});
85+
86+
client.get("//path//", rsp -> {
87+
assertEquals("//path//", rsp.body().string());
88+
assertEquals(200, rsp.code());
89+
});
90+
91+
client.get("/trailing/", rsp -> {
92+
assertEquals("/trailing/", rsp.body().string());
93+
assertEquals(200, rsp.code());
94+
});
95+
96+
client.get("/trailing", rsp -> {
97+
assertEquals("/trailing", rsp.body().string());
98+
assertEquals(200, rsp.code());
99+
});
100+
101+
client.get("/context", rsp -> {
102+
assertEquals("/context", rsp.body().string());
103+
assertEquals(200, rsp.code());
104+
});
105+
106+
client.get("/context//", rsp -> {
107+
assertEquals("/context//", rsp.body().string());
108+
assertEquals(200, rsp.code());
109+
});
110+
});
111+
}
112+
}

0 commit comments

Comments
 (0)