We should provide the functionality whereby a user can cause a "server redirect", i.e. the request can be rerouted with (optionally) a different method and path.
E.g.
routingContext.reroute(HttpMethod.GET, "/newpath");
This is a router level redirect right? It doesn't mean you can't do a normal HTTP header based redirect already, but rather you want to add a quick way to say "this route redirects here". (for clarity, asking)
this is a redirect inside the framework itself, for HTTP redirects you just need to use the right status codes, 30x. 301, 302, 307, etc...
The danger here is that once we allow changing the request method, say from a get to a POST, we might be opening the door for CSRF attacks since browsers are not blocking the request based on the method and a apparently safe GET becomes a POST/PUT/DELETE.
I start learning to use Vert.x with the guide https://vertx.io/docs/guide-for-java-devs and when I am testing the application with Junit5 this part of my code, who redirect to edit page, does not work in my test:
Code:
private void createNewPageHandler(final RoutingContext context) {
String name = context.request().getParam("name").toLowerCase();
//Primero buscamos si ya existe la pagina
dbService.fetchPageByName(name, reply -> {
if(reply.succeeded()) {
JsonObject body = reply.result();
if(body.getBoolean("found")) {
//Si existe dirigimos a su pagina
context.response()
.setStatusCode(303)
.putHeader("Location", "/wiki/"+body.getString("id"))
.end();
} else {
//Si no existe creamos la pagina
String id = UUID.randomUUID().toString();
String creationDate = LocalDateTime.now()
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSS"));
dbService.createPage(id, name, creationDate, create -> {
if(create.succeeded()) {
context.response()
.setStatusCode(303)
.putHeader("Location", "/wiki/"+id)
.end();
} else {
LOG.error("El servicio de DB no ha respondido correctamente", reply.cause());
context.fail(create.cause());
}
});
}
} else {
LOG.error("El servicio de DB no ha respondido correctamente", reply.cause());
context.fail(reply.cause());
}
});
}
Test:
@Test
@DisplayName("📃️ Add new page")
void add_page(VertxTestContext testContext) {
WebClient webClient = WebClient.create(vertx);
vertx.deployVerticle(new MainVerticle(), options, testContext.succeeding(id -> {
MultiMap form = MultiMap.caseInsensitiveMultiMap();
form.set("name", "test");
webClient.post(8080, "localhost", "/create")
.followRedirects(true)
.as(BodyCodec.string())
.sendForm(form, testContext.succeeding(resp -> {
testContext.verify(() -> {
assertThat(resp.statusCode(), is(200));
assertThat(resp.body(), containsString("<title>Edit page</title>"));
testContext.completeNow();
});
}));
}));
}
The test were blocking in the redirect, and I changed the redirect with context.reroute(HttpMethod.GET, "/wiki/"+id); and test works.
I only share it in case other people have the same problem.
@rodrimmb setting the status 3xx is a client side redirect, so the server returns that status code and a header named Location and your browser usually will make a new request with the location from the previous response Location header.
When you use the api reroute(...) then it's a internal (at server side) redirect, in the same request, the process for handling it, restarts using the given url.
@jponge can you verify if the guide test is correct?
Thanks I'll look into it next week
I'm not strictly following the guide, I'm use other tools (gradle instead maven and Junit5 instead Junit4) and also I change some functionality. But in the guide you use to redirect:
context.response().setStatusCode(303);
context.response().putHeader("Location", "/");
context.response().end();
I understand that is better use context.reroute(HttpMethod.GET, "/"); to avoid CSRF attacks, is that right?
Looking at step 9 where there is a call to reroute: works fine, the redirection is server-side and completely transparent to the client.
Looking at step 1 where we do use a 303 redirect, the client is indeed told to perform a redirect, here when creating a new page:
Redirect Response
303 See Other
Location: /wiki/Hello
Why are client-side redirects not handled automatically by the web client? My expectation is that vertx would just do the redirect and wouldn't return the 30x status code, especially when I enable manually setFollowRedirects in the web client options. Am I missing something?
Most helpful comment
this is a redirect inside the framework itself, for HTTP redirects you just need to use the right status codes, 30x. 301, 302, 307, etc...
The danger here is that once we allow changing the request method, say from a get to a POST, we might be opening the door for CSRF attacks since browsers are not blocking the request based on the method and a apparently safe GET becomes a POST/PUT/DELETE.