Skip to content

Commit d593493

Browse files
committed
Redo router options
1 parent 2e01d3a commit d593493

File tree

10 files changed

+89
-92
lines changed

10 files changed

+89
-92
lines changed

examples/src/main/java/examples/HelloApp.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,18 @@ public class HelloApp extends Jooby {
1717
.forEach(clazz -> {
1818
System.out.println(clazz.getName() + " loaded by: " + clazz.getClassLoader());
1919
});
20-
setRouterOptions(new RouterOptions().setCaseSensitive(false).setIgnoreTrailingSlash(false));
20+
setRouterOptions(new RouterOptions().setIgnoreCase(false).setIgnoreTrailingSlash(true));
21+
22+
get("/", ctx -> {
23+
return ctx.pathString() + "oo";
24+
});
2125

2226
get("/foo/bar", ctx -> {
2327
return ctx.pathString() + "oo";
2428
});
29+
get("/foo/bar/", ctx -> {
30+
return ctx.pathString() + "oo/";
31+
});
2532

2633
get("/foo/{bar}", ctx -> {
2734
return ctx.path("bar").value();

jooby/src/main/java/io/jooby/AssetSource.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public interface AssetSource {
4242
* @return An asset source.
4343
*/
4444
static @Nonnull AssetSource create(@Nonnull ClassLoader loader, @Nonnull String location) {
45-
String safeloc = Router.normalizePath(location, true, true)
45+
String safeloc = Router.normalizePath(location, false, true)
4646
.substring(1);
4747
MediaType type = MediaType.byFile(location);
4848
if (type != MediaType.octetStream) {

jooby/src/main/java/io/jooby/Router.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -683,11 +683,11 @@ default Router error(@Nonnull Predicate<StatusCode> predicate,
683683
* removing trailing slash.
684684
*
685685
* @param path Path to process.
686-
* @param caseSensitive True to make it lower case.
686+
* @param ignoreCase True to make it lower case.
687687
* @param ignoreTrailingSlash True to remove trailing slash.
688688
* @return Safe path pattern.
689689
*/
690-
static @Nonnull String normalizePath(@Nonnull String path, boolean caseSensitive,
690+
static @Nonnull String normalizePath(@Nonnull String path, boolean ignoreCase,
691691
boolean ignoreTrailingSlash) {
692692
if (path == null) {
693693
return "/";
@@ -708,14 +708,14 @@ default Router error(@Nonnull Predicate<StatusCode> predicate,
708708
for (int i = 0; i < path.length(); i++) {
709709
char ch = path.charAt(i);
710710
if (ch != '/') {
711-
if (caseSensitive) {
712-
buff[p++] = ch;
713-
} else {
711+
if (ignoreCase) {
714712
char low = Character.toLowerCase(ch);
715713
if (low != ch) {
716714
modified = true;
717715
}
718716
buff[p++] = low;
717+
} else {
718+
buff[p++] = ch;
719719
}
720720
} else if (i == 0 || path.charAt(i - 1) != '/') {
721721
buff[p++] = ch;

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

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,18 @@
66
package io.jooby;
77

88
/**
9-
* Router options.
9+
* Router matching options. Specify whenever ignore case and trailing slash. Options:
10+
*
11+
* - ignoreCase: Indicates whenever routing algorithm does case-sensitive matching or not on
12+
* incoming request path.
13+
*
14+
* - ignoreTrailingSlash: Indicates whenever a trailing slash is ignored or not on incoming request
15+
* path.
1016
*
1117
* <pre>{@code
1218
* {
1319
* setRouterOptions(new RouterOptions()
14-
* .setCaseSensitive(false)
20+
* .setIgnoreCase(true)
1521
* )
1622
* }
1723
* }</pre>
@@ -20,34 +26,35 @@
2026
* @since 2.0.0
2127
*/
2228
public class RouterOptions {
23-
private boolean caseSensitive = true;
29+
private boolean ignoreCase;
2430

25-
private boolean ignoreTrailingSlash = true;
31+
private boolean ignoreTrailingSlash;
2632

2733
/**
28-
* Indicates whenever routing algorithm does case-sensitive matching or not on path pattern.
34+
* Indicates whenever routing algorithm does case-sensitive matching or not on incoming request
35+
* path.
36+
*
2937
* This flag is on by default, so <code>/FOO</code> and <code>/foo</code> are not the same.
3038
*
3139
* @return Whenever do case-sensitive matching.
3240
*/
33-
public boolean isCaseSensitive() {
34-
return caseSensitive;
41+
public boolean isIgnoreCase() {
42+
return ignoreCase;
3543
}
3644

3745
/**
3846
* Turn on/off case-sensitive matching.
3947
*
40-
* @param caseSensitive True for case-sensitive matching.
48+
* @param ignoreCase True for ignore case while matching incoming request.
4149
* @return This options.
4250
*/
43-
public RouterOptions setCaseSensitive(boolean caseSensitive) {
44-
this.caseSensitive = caseSensitive;
51+
public RouterOptions setIgnoreCase(boolean ignoreCase) {
52+
this.ignoreCase = ignoreCase;
4553
return this;
4654
}
4755

4856
/**
49-
* Indicates whenever a trailing slash is ignored or not. This enabled by default so <code>/foo</code>
50-
* and <code>/foo/</code> represent the same route/handler.
57+
* Indicates whenever a trailing slash is ignored or not on incoming request path.
5158
*
5259
* @return Whenever trailing slash on path pattern is ignored.
5360
*/

jooby/src/main/java/io/jooby/internal/$Chi.java

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -602,27 +602,6 @@ public void destroy() {
602602

603603
private Node root = new Node();
604604

605-
private boolean caseSensitive;
606-
607-
private boolean ignoreTrailingSlash;
608-
609-
public $Chi(boolean caseSensitive, boolean ignoreTrailingSlash) {
610-
setCaseSensitive(caseSensitive);
611-
setIgnoreTrailingSlash(ignoreTrailingSlash);
612-
}
613-
614-
public $Chi() {
615-
this(true, true);
616-
}
617-
618-
public void setCaseSensitive(boolean caseSensitive) {
619-
this.caseSensitive = caseSensitive;
620-
}
621-
622-
public void setIgnoreTrailingSlash(boolean ignoreTrailingSlash) {
623-
this.ignoreTrailingSlash = ignoreTrailingSlash;
624-
}
625-
626605
public void insert(String method, String pattern, Route route) {
627606
String baseCatchAll = baseCatchAll(pattern);
628607
if (baseCatchAll.length() > 1) {
@@ -653,9 +632,8 @@ public void insert(Route route) {
653632
root.destroy();
654633
}
655634

656-
public RouterMatch find(Context context, Renderer renderer, List<RadixTree> more) {
635+
public RouterMatch find(Context context, String path, Renderer renderer, List<RadixTree> more) {
657636
String method = context.getMethod();
658-
String path = Router.normalizePath(context.pathString(), caseSensitive, ignoreTrailingSlash);
659637
RouterMatch result = new RouterMatch();
660638
Route route = root.findRoute(result, method, path);
661639
if (route != null) {
@@ -664,7 +642,7 @@ public RouterMatch find(Context context, Renderer renderer, List<RadixTree> more
664642
if (more != null) {
665643
// expand search
666644
for (RadixTree tree : more) {
667-
RouterMatch match = tree.find(context, renderer, null);
645+
RouterMatch match = tree.find(context, path, renderer, null);
668646
if (match.matches) {
669647
return match;
670648
}

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

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,19 @@
88
import io.jooby.Context;
99
import io.jooby.Renderer;
1010
import io.jooby.Route;
11+
import io.jooby.Router;
1112

1213
import java.util.List;
1314
import java.util.function.Predicate;
1415

1516
interface RadixTree {
1617
void insert(String method, String pattern, Route route);
1718

18-
RouterMatch find(Context context, Renderer renderer, List<RadixTree> more);
19+
RouterMatch find(Context context, String path, Renderer renderer, List<RadixTree> more);
20+
21+
default RouterMatch find(Context context, Renderer renderer, List<RadixTree> more) {
22+
return find(context, context.pathString(), renderer, more);
23+
}
1924

2025
default RadixTree with(Predicate<Context> predicate) {
2126
return new RadixTree() {
@@ -24,7 +29,8 @@ default RadixTree with(Predicate<Context> predicate) {
2429
}
2530

2631
@Override
27-
public RouterMatch find(Context context, Renderer renderer, List<RadixTree> more) {
32+
public RouterMatch find(Context context, String path, Renderer renderer,
33+
List<RadixTree> more) {
2834
if (!predicate.test(context)) {
2935
return new RouterMatch()
3036
.missing(context.getMethod(), context.pathString(), renderer);
@@ -38,5 +44,24 @@ public RouterMatch find(Context context, Renderer renderer, List<RadixTree> more
3844
};
3945
}
4046

47+
default RadixTree options(boolean ignoreCase, boolean ignoreTrailingSlash) {
48+
return new RadixTree() {
49+
@Override public void insert(String method, String pattern, Route route) {
50+
RadixTree.this.insert(method, pattern, route);
51+
}
52+
53+
@Override public RouterMatch find(Context context, String path, Renderer renderer,
54+
List<RadixTree> more) {
55+
return RadixTree.this
56+
.find(context, Router.normalizePath(path, ignoreCase, ignoreTrailingSlash), renderer,
57+
more);
58+
}
59+
60+
@Override public void destroy() {
61+
RadixTree.this.destroy();
62+
}
63+
};
64+
}
65+
4166
void destroy();
4267
}

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

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ public Stack executor(Executor executor) {
112112

113113
private RouterOptions options = new RouterOptions();
114114

115-
private $Chi chi = new $Chi(options.isCaseSensitive(), options.isIgnoreTrailingSlash());
115+
private RadixTree chi = new $Chi();
116116

117117
private LinkedList<Stack> stack = new LinkedList<>();
118118

@@ -164,8 +164,6 @@ private void defaultParser() {
164164

165165
@Nonnull @Override public Router setRouterOptions(@Nonnull RouterOptions options) {
166166
this.options = options;
167-
chi.setCaseSensitive(options.isCaseSensitive());
168-
chi.setIgnoreTrailingSlash(options.isIgnoreTrailingSlash());
169167
return this;
170168
}
171169

@@ -177,7 +175,7 @@ private void defaultParser() {
177175
if (routes.size() > 0) {
178176
throw new IllegalStateException("Base path must be set before adding any routes.");
179177
}
180-
this.basePath = normalizePath(basePath, options.isCaseSensitive(), true);
178+
this.basePath = normalizePath(basePath, false, true);
181179
return this;
182180
}
183181

@@ -195,8 +193,7 @@ private void defaultParser() {
195193

196194
@Nonnull @Override
197195
public Router use(@Nonnull Predicate<Context> predicate, @Nonnull Router router) {
198-
RadixTree tree = new $Chi(options.isCaseSensitive(), options.isIgnoreTrailingSlash())
199-
.with(predicate);
196+
RadixTree tree = new $Chi().with(predicate);
200197
if (trees == null) {
201198
trees = new ArrayList<>();
202199
}
@@ -208,7 +205,7 @@ public Router use(@Nonnull Predicate<Context> predicate, @Nonnull Router router)
208205
}
209206

210207
@Nonnull @Override public Router use(@Nonnull String path, @Nonnull Router router) {
211-
String prefix = normalizePath(path, options.isCaseSensitive(), true);
208+
String prefix = normalizePath(path, false, true);
212209
if (prefix.equals("/")) {
213210
prefix = "";
214211
}
@@ -327,14 +324,10 @@ public Route route(@Nonnull String method, @Nonnull String pattern,
327324

328325
private Route defineRoute(@Nonnull String method, @Nonnull String pattern,
329326
@Nonnull Route.Handler handler, RadixTree tree) {
330-
/** Make sure router options are in sync: */
331-
chi.setCaseSensitive(options.isCaseSensitive());
332-
chi.setIgnoreTrailingSlash(options.isIgnoreTrailingSlash());
333-
334327
/** Pattern: */
335-
StringBuilder pat = new StringBuilder();
336-
stack.stream().filter(it -> it.pattern != null).forEach(it -> pat.append(it.pattern));
337-
pat.append(pattern);
328+
StringBuilder patternBuff = new StringBuilder();
329+
stack.stream().filter(it -> it.pattern != null).forEach(it -> patternBuff.append(it.pattern));
330+
patternBuff.append(pattern);
338331

339332
/** Before: */
340333
Route.Before before = stack.stream()
@@ -352,24 +345,22 @@ private Route defineRoute(@Nonnull String method, @Nonnull String pattern,
352345
.reduce(null, (it, next) -> it == null ? next : it.then(next));
353346

354347
/** Route: */
355-
String safePattern = normalizePath(pat.toString(), options.isCaseSensitive(),
356-
options.isIgnoreTrailingSlash());
348+
String safePattern = Router.normalizePath(patternBuff.toString(), false, true);
357349
Route route = new Route(method, safePattern, handler);
358350
route.setPathKeys(Router.pathKeys(safePattern));
359351
route.setBefore(before);
360352
route.setAfter(after);
361353
route.setDecorator(decorator);
362354
route.setRenderer(renderer);
363355
route.setParsers(parsers);
364-
//null, handler, before, decorator, after, renderer,
365-
//parsers);
356+
366357
Stack stack = this.stack.peekLast();
367358
if (stack.executor != null) {
368359
routeExecutor.put(route, stack.executor);
369360
}
370361
String routePattern = normalizePath(basePath == null
371362
? safePattern
372-
: basePath + safePattern, options.isCaseSensitive(), options.isIgnoreTrailingSlash());
363+
: basePath + safePattern, false, true);
373364
if (method.equals("*")) {
374365
METHODS.forEach(m -> tree.insert(m, routePattern, route));
375366
} else {
@@ -401,6 +392,10 @@ private Route defineRoute(@Nonnull String method, @Nonnull String pattern,
401392
.compute(source.getLoader(), route, mode, executor, handlers);
402393
route.setPipeline(pipeline);
403394
}
395+
// router options
396+
if (options.isIgnoreCase() || options.isIgnoreTrailingSlash()) {
397+
chi = chi.options(options.isIgnoreCase(), options.isIgnoreTrailingSlash());
398+
}
404399
// unwrap executor
405400
worker = ((ForwardingExecutor) worker).executor;
406401
this.stack.forEach(Stack::clear);
@@ -535,7 +530,7 @@ private Stack push() {
535530
}
536531

537532
private Stack push(String pattern) {
538-
Stack stack = new Stack(normalizePath(pattern, options.isCaseSensitive(), true));
533+
Stack stack = new Stack(normalizePath(pattern, false, true));
539534
if (this.stack.size() > 0) {
540535
Stack parent = this.stack.getLast();
541536
stack.executor = parent.executor;

jooby/src/test/java/io/jooby/RoutePathTest.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public void normalize() {
2626

2727
assertEquals("/foo/bar", Router.normalizePath("/foo/bar", false, true));
2828

29-
assertEquals("/fOo/bAr", Router.normalizePath("/fOo/bAr", true, true));
29+
assertEquals("/foo/bar", Router.normalizePath("/fOo/bAr", true, true));
3030

3131
assertEquals("/foo/bar", Router.normalizePath("/foo/bar/", false, true));
3232

@@ -38,13 +38,13 @@ public void normalize() {
3838

3939
assertEquals("/foo/bar", Router.normalizePath("/foo//bar", false, true));
4040

41-
assertEquals("/foo/bar", Router.normalizePath("/foo/Bar", false, false));
41+
assertEquals("/foo/Bar", Router.normalizePath("/foo/Bar", false, false));
4242

43-
assertEquals("/foo/Bar", Router.normalizePath("/foo/Bar/", true, true));
43+
assertEquals("/foo/bar", Router.normalizePath("/foo/Bar/", true, true));
4444

45-
assertEquals("/foo/Bar/", Router.normalizePath("/foo/Bar/", true, false));
45+
assertEquals("/foo/bar/", Router.normalizePath("/foo/Bar/", true, false));
4646

47-
assertEquals("/foo/bar/", Router.normalizePath("/foo/Bar///", false, false));
47+
assertEquals("/foo/Bar/", Router.normalizePath("/foo/Bar///", false, false));
4848

4949
assertEquals("/foo/bar", Router.normalizePath("/foo/bar", false, true));
5050
}

jooby/src/test/java/io/jooby/internal/ChiTest.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ private Context ctx(String path) {
4040
@Test
4141
public void routeCase() {
4242
$Chi router = new $Chi();
43-
router.setIgnoreTrailingSlash(false);
4443
Route foo = route("GET", "/abcd", stringHandler("foo"));
4544
Route foos = route("GET", "/abcd/", stringHandler("foo/"));
4645
router.insert(foo);

0 commit comments

Comments
 (0)