Skip to content

Commit dbb324c

Browse files
committed
Add HTTP Trace support
1 parent ca033c5 commit dbb324c

File tree

5 files changed

+86
-10
lines changed

5 files changed

+86
-10
lines changed

jooby/src/main/java/io/jooby/Route.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import java.util.List;
2020
import java.util.Map;
2121
import java.util.Set;
22-
import java.util.stream.Stream;
2322

2423
/**
2524
* Route contains information about the HTTP method, path pattern, which content types consumes and
@@ -307,7 +306,7 @@ public interface Handler extends Serializable {
307306

308307
private static final Map EMPTY_MAP = Collections.emptyMap();
309308

310-
private Map<String, MessageDecoder> parsers = EMPTY_MAP;
309+
private Map<String, MessageDecoder> decoders = EMPTY_MAP;
311310

312311
private final String pattern;
313312

@@ -626,7 +625,7 @@ public Route(@Nonnull String method, @Nonnull String pattern, @Nonnull Handler h
626625
* @return MessageDecoder.
627626
*/
628627
public @Nonnull MessageDecoder decoder(@Nonnull MediaType contentType) {
629-
return parsers.getOrDefault(contentType.getValue(), MessageDecoder.UNSUPPORTED_MEDIA_TYPE);
628+
return decoders.getOrDefault(contentType.getValue(), MessageDecoder.UNSUPPORTED_MEDIA_TYPE);
630629
}
631630

632631
/**
@@ -635,7 +634,7 @@ public Route(@Nonnull String method, @Nonnull String pattern, @Nonnull Handler h
635634
* @return Message decoders.
636635
*/
637636
public @Nonnull Map<String, MessageDecoder> getDecoders() {
638-
return parsers;
637+
return decoders;
639638
}
640639

641640
/**
@@ -645,30 +644,38 @@ public Route(@Nonnull String method, @Nonnull String pattern, @Nonnull Handler h
645644
* @return This route.
646645
*/
647646
public @Nonnull Route setDecoders(@Nonnull Map<String, MessageDecoder> decoders) {
648-
this.parsers = decoders;
647+
this.decoders = decoders;
649648
return this;
650649
}
651650

652651
public boolean isHttpOptions() {
653652
return supportedMethod != null && supportedMethod.contains(Router.OPTIONS);
654653
}
655654

656-
public @Nonnull Route setSupports(String... httpMethods) {
655+
public boolean isHttpTrace() {
656+
return supportedMethod != null && supportedMethod.contains(Router.TRACE);
657+
}
658+
659+
public @Nonnull Route setHttpOptions(boolean enabled) {
657660
if (supportedMethod == null) {
658661
supportedMethod = new HashSet<>();
659662
}
660-
Stream.of(httpMethods).forEach(m -> supportedMethod.add(m.toUpperCase()));
663+
if (enabled) {
664+
supportedMethod.add(Router.OPTIONS);
665+
} else {
666+
supportedMethod.remove(Router.OPTIONS);
667+
}
661668
return this;
662669
}
663670

664-
public @Nonnull Route setHttpOptions(boolean enabled) {
671+
public @Nonnull Route setHttpTrace(boolean enabled) {
665672
if (supportedMethod == null) {
666673
supportedMethod = new HashSet<>();
667674
}
668675
if (enabled) {
669-
supportedMethod.add(Router.OPTIONS);
676+
supportedMethod.add(Router.TRACE);
670677
} else {
671-
supportedMethod.remove(Router.OPTIONS);
678+
supportedMethod.remove(Router.TRACE);
672679
}
673680
return this;
674681
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* Jooby https://jooby.io
3+
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
4+
* Copyright 2014 Edgar Espina
5+
*/
6+
package io.jooby;
7+
8+
import javax.annotation.Nonnull;
9+
import java.util.List;
10+
import java.util.Map;
11+
import java.util.stream.Collectors;
12+
13+
public class TraceHandler implements Route.Decorator {
14+
@Nonnull @Override public Route.Handler apply(@Nonnull Route.Handler next) {
15+
return ctx -> {
16+
if (ctx.getMethod().equals(Router.TRACE)) {
17+
// Handle trace
18+
String CRLF = "\r\n";
19+
StringBuilder buffer = new StringBuilder(Router.TRACE).append(" ").append(ctx.pathString())
20+
.append(" ").append(ctx.getProtocol());
21+
22+
for (Map.Entry<String, List<String>> entry : ctx.headerMultimap().entrySet()) {
23+
buffer.append(CRLF).append(entry.getKey()).append(": ")
24+
.append(entry.getValue().stream().collect(Collectors.joining(", ")));
25+
}
26+
27+
buffer.append(CRLF);
28+
29+
ctx.setResponseType("message/http");
30+
return ctx.send(buffer.toString());
31+
} else {
32+
return next.apply(ctx);
33+
}
34+
};
35+
}
36+
37+
@Nonnull @Override public Route.Decorator setRoute(@Nonnull Route route) {
38+
route.setHttpTrace(true);
39+
return this;
40+
}
41+
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,8 @@ private Route defineRoute(@Nonnull String method, @Nonnull String pattern,
380380
tree.insert(route.getMethod(), routePattern, route);
381381
if (route.isHttpOptions()) {
382382
tree.insert(Router.OPTIONS, routePattern, route);
383+
} else if (route.isHttpTrace()) {
384+
tree.insert(Router.TRACE, routePattern, route);
383385
}
384386
routes.add(route);
385387

tests/src/test/java/io/jooby/FeaturedTest.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2701,6 +2701,26 @@ public void options() {
27012701
});
27022702
}
27032703

2704+
@Test
2705+
public void trace() {
2706+
new JoobyRunner(app -> {
2707+
app.decorator(new TraceHandler());
2708+
2709+
app.get("/foo", Context::pathString);
2710+
}).ready(client -> {
2711+
client.trace("/foo", rsp -> {
2712+
assertEquals(StatusCode.OK.value(), rsp.code());
2713+
assertEquals("message/http", rsp.header("Content-Type"));
2714+
assertTrue(rsp.body().string().startsWith("TRACE /foo HTTP/1.1"));
2715+
});
2716+
2717+
client.get("/foo", rsp -> {
2718+
assertEquals(StatusCode.OK.value(), rsp.code());
2719+
assertEquals("/foo", rsp.body().string());
2720+
});
2721+
});
2722+
}
2723+
27042724
private static String readText(Path file) {
27052725
try {
27062726
return new String(Files.readAllBytes(file), StandardCharsets.UTF_8);

tests/src/test/java/io/jooby/WebClient.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,13 @@ public void options(String path, SneakyThrows.Consumer<Response> callback) {
9595
options(path).execute(callback);
9696
}
9797

98+
public Request trace(String path) {
99+
return invoke("TRACE", path, null);
100+
}
98101

102+
public void trace(String path, SneakyThrows.Consumer<Response> callback) {
103+
trace(path).execute(callback);
104+
}
99105

100106
public Request post(String path) {
101107
return post(path, EMPTY_BODY);

0 commit comments

Comments
 (0)