From d0d8ffbcfe76fee815584ad48fe42fdbbc1c94ad Mon Sep 17 00:00:00 2001 From: Thomas Segismont Date: Wed, 2 Jul 2025 16:21:22 +0200 Subject: [PATCH] Documentation must indicate when a BodyHandler is required (#2759) Instructions were missing for CSRF, SockJS and FormLogin handlers. Signed-off-by: Thomas Segismont --- vertx-web/src/main/asciidoc/index.adoc | 22 ++++++++++++------- .../src/main/java/examples/WebExamples.java | 9 +++++++- .../ext/web/handler/impl/CSRFHandlerImpl.java | 2 +- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/vertx-web/src/main/asciidoc/index.adoc b/vertx-web/src/main/asciidoc/index.adoc index e4d7aa4d0c..b6edeed809 100644 --- a/vertx-web/src/main/asciidoc/index.adoc +++ b/vertx-web/src/main/asciidoc/index.adoc @@ -1282,6 +1282,8 @@ basic authentication handler. You will also need to setup handlers to serve your actual login page, and a handler to handle the actual login itself. To handle the login we provide a prebuilt handler {@link io.vertx.ext.web.handler.FormLoginHandler} for the purpose. +IMPORTANT: The {@link io.vertx.ext.web.handler.FormLoginHandler} requires a {@link io.vertx.ext.web.handler.BodyHandler} to read `POST` requests content. + Here's an example of a simple app, using a redirect auth handler on the default redirect url `/loginpage`. [source,$lang] @@ -2241,12 +2243,11 @@ Please see the https://github.com/sockjs/sockjs-client[SockJS website] for more === SockJS handler -Vert.x provides an out of the box handler called {@link io.vertx.ext.web.handler.sockjs.SockJSHandler} for -using SockJS in your Vert.x-Web applications. +Vert.x provides an out-of-the-box handler called {@link io.vertx.ext.web.handler.sockjs.SockJSHandler} for using SockJS in your Vert.x-Web applications. You should create one handler per SockJS application using {@link io.vertx.ext.web.handler.sockjs.SockJSHandler#create}. -You can also specify configuration options when creating the instance. The configuration options are described with -an instance of {@link io.vertx.ext.web.handler.sockjs.SockJSHandlerOptions}. +You can also specify configuration options when creating the instance. +The configuration options are described with an instance of {@link io.vertx.ext.web.handler.sockjs.SockJSHandlerOptions}. [source,$lang] ---- @@ -2267,13 +2268,16 @@ is loaded using {@link io.vertx.ext.web.handler.sockjs.SockJSSocket#routingConte the users and sessions accessible through {@link io.vertx.ext.web.handler.sockjs.SockJSSocket#webSession()} and {@link io.vertx.ext.web.handler.sockjs.SockJSSocket#webUser()}. -Here's an example of a simple SockJS handler that simply echoes back any back any data that it reads: +Here's an example of a simple SockJS handler that simply echoes back any data that it reads: [source,$lang] ---- {@link examples.WebExamples#example44} ---- +IMPORTANT: The {@link io.vertx.ext.web.handler.sockjs.SockJSHandler} requires a {@link io.vertx.ext.web.handler.BodyHandler} to read `POST` requests content. +This is useful when WebSockets are not available (disabled by intermediate proxies or by configuration). + === The client side In client side JavaScript you use the SockJS client side library to make connections. For convenience the package is @@ -2656,6 +2660,8 @@ CSRF or sometimes also known as XSRF is a technique by which an unauthorized sit Vert.x-Web includes a handler {@link io.vertx.ext.web.handler.CSRFHandler} that you can use to prevent cross site request forgery requests. +IMPORTANT: The {@link io.vertx.ext.web.handler.CSRFHandler} requires a {@link io.vertx.ext.web.handler.BodyHandler} to read the content of requests having an unsafe method (`POST`, `PUT`, ...etc.) + On each get request under this handler a cookie is added to the response with a unique token. Clients are then expected to return this token back in a header. Since cookies are sent it is required that the cookie handler is also present on the router. @@ -2671,8 +2677,7 @@ header was present in the Form attributes under the same name as the header, e.g ---- -It is the responsibility of the user to fill in the right value for the form field. Users who prefer to use an HTML -only solution can fill this value by fetching the the token value from the routing context under the key `X-XSRF-TOKEN` +It is the responsibility of the user to fill in the right value for the form field. Users who prefer to use an HTML only solution can fill this value by fetching the token value from the routing context under the key `X-XSRF-TOKEN` or the header name they have chosen during the instantiation of the `CSRFHandler` object. [source,$lang] @@ -2680,7 +2685,8 @@ or the header name they have chosen during the instantiation of the `CSRFHandler {@link examples.WebExamples#example54} ---- -Note that this handler is session aware. If there is a session available the form parameter or header might be omited +Note that this handler is session aware. +If there is a session available the form parameter or header might be omitted during the `POST` action as it will be read from the session. This also implies that tokens will only be regenerated on session upgrades. diff --git a/vertx-web/src/main/java/examples/WebExamples.java b/vertx-web/src/main/java/examples/WebExamples.java index 531bc54d82..c68e56492f 100644 --- a/vertx-web/src/main/java/examples/WebExamples.java +++ b/vertx-web/src/main/java/examples/WebExamples.java @@ -852,7 +852,9 @@ public void example39(Vertx vertx, AuthenticationProvider authProvider, Router r // Handle the actual login // One of your pages must POST form login data - router.post("/login").handler(FormLoginHandler.create(authProvider)); + router.post("/login") + .handler(BodyHandler.create()) + .handler(FormLoginHandler.create(authProvider)); // Set a static server to serve static resources, e.g. the login page router.route().handler(StaticHandler.create()); @@ -980,6 +982,9 @@ public void example44(Vertx vertx) { SockJSHandler sockJSHandler = SockJSHandler.create(vertx, options); + // Required to handle SockJS traffic when WebSockets are not available + router.post("/myapp/*").handler(BodyHandler.create()); + router.route("/myapp/*") .subRouter(sockJSHandler.socketHandler(sockJSSocket -> { @@ -1274,6 +1279,8 @@ public void example53(Vertx vertx) { public void example54(Vertx vertx, Router router) { + // Required to handle request having an unsafe method (`POST`, `PUT`, ...etc.) + router.route().handler(BodyHandler.create()); router.route().handler(CSRFHandler.create(vertx, "abracadabra")); router.route().handler(ctx -> { diff --git a/vertx-web/src/main/java/io/vertx/ext/web/handler/impl/CSRFHandlerImpl.java b/vertx-web/src/main/java/io/vertx/ext/web/handler/impl/CSRFHandlerImpl.java index 5c8b5a0453..a86e693116 100644 --- a/vertx-web/src/main/java/io/vertx/ext/web/handler/impl/CSRFHandlerImpl.java +++ b/vertx-web/src/main/java/io/vertx/ext/web/handler/impl/CSRFHandlerImpl.java @@ -267,7 +267,7 @@ private void handleUnsafeMethod(RoutingContext ctx) { if (ctx.body().available()) { header = ctx.request().getFormAttribute(headerName); } else { - ctx.fail(new VertxException("BodyHandler is required to process POST requests", true)); + ctx.fail(new VertxException("BodyHandler is required to process unsafe methods", true)); return; } }