Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ public RoutingContextInternal setMatchFailure(int matchFailure) {
return decoratedContext.setMatchFailure(matchFailure);
}

@Override
public RoutingContextInternal addAllowedMethods(java.util.Set<HttpMethod> allowedMethods) {
return decoratedContext.addAllowedMethods(allowedMethods);
}

@Override
public RoutingContextInternal addAllowedContentTypes(java.util.Set<MIMEHeader> allowedContentTypes) {
return decoratedContext.addAllowedContentTypes(allowedContentTypes);
}

@Override
public int addBodyEndHandler(Handler<Void> handler) {
return decoratedContext.addBodyEndHandler(handler);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,18 @@ public synchronized RoutingContextInternal setMatchFailure(int matchFailure) {
return this;
}

@Override
public synchronized RoutingContextInternal addAllowedMethods(Set<HttpMethod> allowedMethods) {
this.allowedMethods.addAll(allowedMethods);
return this;
}

@Override
public synchronized RoutingContextInternal addAllowedContentTypes(Set<MIMEHeader> allowedContentTypes) {
this.allowedContentTypes.addAll(allowedContentTypes);
return this;
}

@Override
public String mountPoint() {
return mountPoint;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,22 @@ public interface RoutingContextInternal extends RoutingContext {
*/
RoutingContextInternal setMatchFailure(int matchFailure);

/**
* adds allowed methods to the context for 405 responses.
*
* @param allowedMethods the allowed methods to add
* @return fluent self
*/
RoutingContextInternal addAllowedMethods(java.util.Set<io.vertx.core.http.HttpMethod> allowedMethods);

/**
* adds allowed content types to the context for 415 responses.
*
* @param allowedContentTypes the allowed content types to add
* @return fluent self
*/
RoutingContextInternal addAllowedContentTypes(java.util.Set<io.vertx.ext.web.MIMEHeader> allowedContentTypes);

/**
* @return the current router this context is being routed through. All routingContext is associated with a router and
* never returns null.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,10 @@ public UserContext userContext() {
public void next() {
if (!super.iterateNext()) {
// We didn't route request to anything so go to parent,
// but also propagate the current status
// but also propagate the current status and accumulated allowed methods/content types
inner.setMatchFailure(matchFailure);
inner.addAllowedMethods(allowedMethods);
inner.addAllowedContentTypes(allowedContentTypes);
inner.next();
}
}
Expand Down
63 changes: 63 additions & 0 deletions vertx-web/src/test/java/io/vertx/ext/web/tests/SubRouterTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -784,4 +784,67 @@ private void assertRouterErrorHandlers(String name, Router router, HttpResponseS
router.errorHandler(status.code(), ctx -> ctx.response().setStatusCode(status.code()).end(handlerKey));
testRequest(HttpMethod.GET, path, status.code(), status.reasonPhrase(), handlerKey);
}

@Test
public void testSubRouterConsumes() throws Exception {
Router subRouter = Router.router(vertx);

router.route("/api*").subRouter(subRouter);

subRouter.route("/resource").consumes("application/json").handler(rc -> rc.response().end("OK"));

// Test successful content type match
testRequestWithContentType(HttpMethod.POST, "/api/resource", "application/json", 200, "OK");

// Test 415 response - Accept header should contain allowed content type from sub-router
testRequestWithContentType(HttpMethod.POST, "/api/resource", "text/xml", 415, "Unsupported Media Type",
res -> assertEquals("application/json", res.getHeader("Accept")));
}

@Test
public void testSubRouterConsumesMultiple() throws Exception {
Router subRouter = Router.router(vertx);

router.route("/api*").subRouter(subRouter);

subRouter.route("/resource")
.consumes("application/json")
.consumes("text/html; charset=utf-8")
.handler(rc -> rc.response().end("OK"));

// Test successful content type match
testRequestWithContentType(HttpMethod.POST, "/api/resource", "application/json", 200, "OK");
testRequestWithContentType(HttpMethod.POST, "/api/resource", "text/html; charset=utf-8", 200, "OK");

// Test 415 response - Accept header should contain both allowed content types from sub-router
testRequestWithContentType(HttpMethod.POST, "/api/resource", "text/xml", 415, "Unsupported Media Type",
res -> {
String acceptHeader = res.getHeader("Accept");
assertNotNull(acceptHeader);
assertTrue(acceptHeader.contains("application/json"));
assertTrue(acceptHeader.contains("text/html; charset=utf-8"));
});
}

@Test
public void testSubRouterMethodNotAllowed() throws Exception {
Router subRouter = Router.router(vertx);

router.route("/api*").subRouter(subRouter);

subRouter.post("/resource").handler(rc -> rc.response().end("OK"));
subRouter.put("/resource").handler(rc -> rc.response().end("OK"));

// Test successful method match
testRequest(HttpMethod.POST, "/api/resource", 200, "OK");
testRequest(HttpMethod.PUT, "/api/resource", 200, "OK");

// Test 405 response - Allow header should contain allowed methods from sub-router
testRequest(HttpMethod.GET, "/api/resource", null, res -> {
String allowHeader = res.getHeader("Allow");
assertNotNull(allowHeader);
assertTrue(allowHeader.contains("POST"));
assertTrue(allowHeader.contains("PUT"));
}, 405, "Method Not Allowed", null);
}
}
Loading