diff --git a/vertx-web/src/main/asciidoc/index.adoc b/vertx-web/src/main/asciidoc/index.adoc index d2661b65d4..e0e033ae91 100644 --- a/vertx-web/src/main/asciidoc/index.adoc +++ b/vertx-web/src/main/asciidoc/index.adoc @@ -2549,8 +2549,8 @@ follow the bridge wire protocol and look like this: ---- { "type": "err", - "failureType": "socketException", - "message": "optionally a message from the exception being raised" + "failureType": "SOCKET_EXCEPTION", + "message": "A message from the exception being raised" } ---- diff --git a/vertx-web/src/main/java/io/vertx/ext/web/handler/sockjs/impl/EventBusBridgeImpl.java b/vertx-web/src/main/java/io/vertx/ext/web/handler/sockjs/impl/EventBusBridgeImpl.java index 6cdce3c59b..f3f113f6b7 100644 --- a/vertx-web/src/main/java/io/vertx/ext/web/handler/sockjs/impl/EventBusBridgeImpl.java +++ b/vertx-web/src/main/java/io/vertx/ext/web/handler/sockjs/impl/EventBusBridgeImpl.java @@ -80,13 +80,13 @@ private void handleSocketData(SockJSSocket sock, Buffer data, Map { String address = msg.getString("address"); if (address == null) { - replyError(sock, "missing_address"); + replyError(sock, "MISSING_ADDRESS", "Message address is missing"); return; } doSendOrPub(send, sock, address, msg); - }, () -> replyError(sock, "rejected")); + }, () -> replyError(sock, "REJECTED", "Message is rejected")); } private boolean checkMaxHandlers(SockJSSocket sock, SockInfo info) { @@ -177,7 +177,7 @@ private boolean checkMaxHandlers(SockJSSocket sock, SockInfo info) { return true; } else { LOG.warn("Refusing to register as max_handlers_per_socket reached already"); - replyError(sock, "max_handlers_reached"); + replyError(sock, "HANDLERS_MAX_LIMIT", "Registration handlers exceed the maximum limit"); return false; } } @@ -192,11 +192,11 @@ private void internalHandleRegister(SockJSSocket sock, JsonObject rawMsg, Map maxAddressLength) { LOG.warn("Refusing to register as address length > max_address_length"); - replyError(sock, "max_address_length_reached"); + replyError(sock, "ADDRESS_MAX_LENGTH", "Address exceeds maximum length"); return; } Match match = checkMatches(false, address, null); @@ -206,7 +206,7 @@ private void internalHandleRegister(SockJSSocket sock, JsonObject rawMsg, Map new BridgeEventImpl(BridgeEventType.REGISTERED, rawMsg, sock)); } else { LOG.warn("Cannot register handler for address " + address, ar.cause()); - replyError(sock, "registration_failure"); + replyError(sock, "ADDRESS_REGISTRATION", "Address registration is failed"); } }); } else { @@ -255,9 +255,9 @@ private void internalHandleRegister(SockJSSocket sock, JsonObject rawMsg, Map replyError(sock, "rejected")); + }, () -> replyError(sock, "REJECTED", "Message is rejected")); } private void internalHandleUnregister(SockJSSocket sock, JsonObject rawMsg, Map> registrations) { @@ -265,7 +265,7 @@ private void internalHandleUnregister(SockJSSocket sock, JsonObject rawMsg, Map< () -> { String address = rawMsg.getString("address"); if (address == null) { - replyError(sock, "missing_address"); + replyError(sock, "MISSING_ADDRESS","Message address is missing"); return; } Match match = checkMatches(false, address, null); @@ -280,9 +280,9 @@ private void internalHandleUnregister(SockJSSocket sock, JsonObject rawMsg, Map< if (LOG.isDebugEnabled()) { LOG.debug("Cannot unregister handler for address " + address + " because there is no inbound match"); } - replyError(sock, "access_denied"); + replyError(sock, "ACCESS_DENIED", "Address access is denied"); } - }, () -> replyError(sock, "rejected")); + }, () -> replyError(sock, "REJECTED", "Message is rejected")); } private void internalHandlePing(final SockJSSocket sock) { @@ -317,7 +317,7 @@ public void handle(final SockJSSocket sock) { checkCallHook(() -> new BridgeEventImpl(BridgeEventType.SOCKET_IDLE, null, sock), // We didn't receive a ping in time so close the socket ((SockJSSocketBase) sock)::closeAfterSessionExpired, - () -> replyError(sock, "rejected")); + () -> replyError(sock, "REJECTED", "Message is rejected")); } }); SockInfo sockInfo = new SockInfo(); @@ -334,9 +334,11 @@ private void handleSocketClosed(SockJSSocket sock, Map> registrations) { LOG.error("SockJSSocket exception", err); clearSocketState(sock, registrations); - final JsonObject msg = new JsonObject().put("type", "err").put("failureType", "socketException"); + final JsonObject msg = new JsonObject().put("type", "err").put("failureCode", -1).put("failureType", "SOCKET_EXCEPTION"); if (err != null) { msg.put("message", err.getMessage()); + } else { + msg.put("message", "A socket exception occurred while attempting to establish or maintain a network connection"); } checkCallHook(() -> new BridgeEventImpl(BridgeEventType.SOCKET_ERROR, msg, sock)); } @@ -408,7 +410,7 @@ private void doSendOrPub(boolean send, SockJSSocket sock, String address, if (replyAddress != null && replyAddress.length() > 36) { // vertx-eventbus.js ids are always 36 chars LOG.error("Will not send message, reply address is > 36 chars"); - replyError(sock, "invalid_reply_address"); + replyError(sock, "INVALID_REPLY_ADDRESS", "Reply address is invalid"); return; } final boolean debug = LOG.isDebugEnabled(); @@ -431,19 +433,19 @@ private void doSendOrPub(boolean send, SockJSSocket sock, String address, if (ok) { checkAndSend(send, address, body, headers, sock, replyAddress, awaitingReply); } else { - replyError(sock, "access_denied"); + replyError(sock, "ACCESS_DENIED", "Address access is denied"); if (debug) { LOG.debug("Inbound message for address " + address + " rejected because is not authorised"); } } }) .onFailure(err -> { - replyError(sock, "auth_error"); + replyError(sock, "AUTHZ", "Authorization failed"); LOG.error("Error in performing authorization", err); }); } else { // no web session - replyError(sock, "not_logged_in"); + replyError(sock, "AUTHN", "Authentication is required"); if (debug) { LOG.debug("Inbound message for address " + address + " rejected because it requires auth and user is not authenticated"); @@ -454,7 +456,7 @@ private void doSendOrPub(boolean send, SockJSSocket sock, String address, } } else { // inbound match failed - replyError(sock, "access_denied"); + replyError(sock, "ACCESS_DENIED", "Address access is denied"); if (debug) { LOG.debug("Inbound message for address " + address + " rejected because there is no match"); } @@ -590,8 +592,12 @@ private boolean regexMatches(String matchRegex, String address) { return m.matches(); } - private static void replyError(SockJSSocket sock, String err) { - JsonObject envelope = new JsonObject().put("type", "err").put("body", err); + private static void replyError(SockJSSocket sock, String type, String message) { + JsonObject envelope = new JsonObject() + .put("type", "err") + .put("failureCode", -1) + .put("failureType", type) + .put("message", message); sock.write(buffer(envelope.encode())); } diff --git a/vertx-web/src/test/java/io/vertx/ext/web/tests/handler/EventbusBridgeTest.java b/vertx-web/src/test/java/io/vertx/ext/web/tests/handler/EventbusBridgeTest.java index c435838929..97c1a71158 100644 --- a/vertx-web/src/test/java/io/vertx/ext/web/tests/handler/EventbusBridgeTest.java +++ b/vertx-web/src/test/java/io/vertx/ext/web/tests/handler/EventbusBridgeTest.java @@ -213,7 +213,7 @@ public void testHookSendRejected() throws Exception { } })); testError(new JsonObject().put("type", "send").put("address", addr).put("body", "foobar"), - "rejected"); + "REJECTED", "Message is rejected"); await(); } @@ -228,7 +228,7 @@ public void testHookSendMissingAddress() throws Exception { be.complete(true); })); testError(new JsonObject().put("type", "send").put("address", addr).put("body", "foobar"), - "missing_address"); + "MISSING_ADDRESS", "Message address is missing"); await(); } @@ -284,7 +284,7 @@ public void testHookPubRejected() throws Exception { } })); testError(new JsonObject().put("type", "publish").put("address", addr).put("body", "foobar"), - "rejected"); + "REJECTED", "Message is rejected"); await(); } @@ -299,7 +299,7 @@ public void testHookPublishMissingAddress() throws Exception { be.complete(true); })); testError(new JsonObject().put("type", "publish").put("address", addr).put("body", "foobar"), - "missing_address"); + "MISSING_ADDRESS", "Message address is missing"); await(); } @@ -333,7 +333,7 @@ public void testHookRegisterRejected() throws Exception { } })); testError(new JsonObject().put("type", "register").put("address", addr), - "rejected"); + "REJECTED", "Message is rejected"); await(); } @@ -348,7 +348,7 @@ public void testHookRegisterMissingAddress() throws Exception { be.complete(true); })); testError(new JsonObject().put("type", "register").put("address", addr).put("body", "foobar"), - "missing_address"); + "MISSING_ADDRESS", "Message address is missing"); await(); } @@ -468,7 +468,7 @@ public void testHookUnregisterRejected() throws Exception { } })); testError(new JsonObject().put("type", "unregister").put("address", addr), - "rejected"); + "REJECTED", "Message is rejected"); await(); } @@ -483,7 +483,7 @@ public void testHookUnregisterMissingAddress() throws Exception { be.complete(true); })); testError(new JsonObject().put("type", "unregister").put("address", addr).put("body", "foobar"), - "missing_address"); + "MISSING_ADDRESS", "Message address is missing"); await(); } @@ -624,28 +624,28 @@ public void testUnregisterAllAccess() throws Exception { public void testInvalidType() throws Exception { router.route("/eventbus/*").subRouter( sockJS.bridge(allAccessOptions)); - testError(new JsonObject().put("type", "wibble").put("address", "addr"), "invalid_type"); + testError(new JsonObject().put("type", "wibble").put("address", "addr"), "INVALID_TYPE", "Invalid message type"); } @Test public void testInvalidJson() throws Exception { router.route("/eventbus/*").subRouter( sockJS.bridge(allAccessOptions)); - testError("oqiwjdioqwjdoiqjwd", "invalid_json"); + testError("oqiwjdioqwjdoiqjwd", "INVALID_JSON", "Malformed JSON"); } @Test public void testMissingType() throws Exception { router.route("/eventbus/*").subRouter( sockJS.bridge(allAccessOptions)); - testError(new JsonObject().put("address", "someaddress"), "missing_type"); + testError(new JsonObject().put("address", "someaddress"), "MISSING_TYPE", "Message type is missing"); } @Test public void testMissingAddress() throws Exception { router.route("/eventbus/*").subRouter( sockJS.bridge(allAccessOptions)); - testError(new JsonObject().put("type", "send").put("body", "hello world"), "missing_address"); + testError(new JsonObject().put("type", "send").put("body", "hello world"), "MISSING_ADDRESS", "Message address is missing"); } @Test @@ -653,7 +653,7 @@ public void testSendNotPermittedDefaultOptions() throws Exception { router.route("/eventbus/*").subRouter( sockJS.bridge(defaultOptions)); testError(new JsonObject().put("type", "send").put("address", addr).put("body", "hello world"), - "access_denied"); + "ACCESS_DENIED", "Address access is denied"); } @Test @@ -663,7 +663,7 @@ public void testSendPermittedAllowAddress() throws Exception { sockJS.bridge(defaultOptions.addInboundPermitted(new PermittedOptions().setAddress(addr)))); testSend(addr, "foobar"); testError(new JsonObject().put("type", "send").put("address", "allow2").put("body", "blah"), - "access_denied"); + "ACCESS_DENIED", "Address access is denied"); } @Test @@ -674,7 +674,7 @@ public void testSendPermittedAllowAddressRe() throws Exception { testSend("allow1", "foobar"); testSend("allow2", "foobar"); testError(new JsonObject().put("type", "send").put("address", "hello").put("body", "blah"), - "access_denied"); + "ACCESS_DENIED", "Address access is denied"); } @Test @@ -687,7 +687,7 @@ public void testSendPermittedMultipleAddresses() throws Exception { testSend("allow1", "foobar"); testSend("allow2", "foobar"); testError(new JsonObject().put("type", "send").put("address", "allow3").put("body", "blah"), - "access_denied"); + "ACCESS_DENIED", "Address access is denied"); } @Test @@ -702,7 +702,7 @@ public void testSendPermittedMultipleAddressRe() throws Exception { testSend("ballow1", "foobar"); testSend("ballow2", "foobar"); testError(new JsonObject().put("type", "send").put("address", "hello").put("body", "blah"), - "access_denied"); + "ACCESS_DENIED", "Address access is denied"); } @Test @@ -716,9 +716,9 @@ public void testSendPermittedMixedAddressRe() throws Exception { testSend("ballow1", "foobar"); testSend("ballow2", "foobar"); testError(new JsonObject().put("type", "send").put("address", "hello").put("body", "blah"), - "access_denied"); + "ACCESS_DENIED", "Address access is denied"); testError(new JsonObject().put("type", "send").put("address", "allow2").put("body", "blah"), - "access_denied"); + "ACCESS_DENIED", "Address access is denied"); } @Test @@ -732,7 +732,7 @@ public void testSendPermittedStructureMatch() throws Exception { testSend(addr, json1); json1.remove("fib"); testError(new JsonObject().put("type", "send").put("address", addr).put("body", json1), - "access_denied"); + "ACCESS_DENIED", "Address access is denied"); } @Test @@ -746,9 +746,9 @@ public void testSendPermittedStructureMatchWithAddress() throws Exception { testSend(addr, json1); json1.remove("fib"); testError(new JsonObject().put("type", "send").put("address", addr).put("body", json1), - "access_denied"); + "ACCESS_DENIED", "Address access is denied"); testError(new JsonObject().put("type", "send").put("address", "otheraddress").put("body", json1), - "access_denied"); + "ACCESS_DENIED", "Address access is denied"); } @Test @@ -758,7 +758,7 @@ public void testRegisterPermittedAllowAddress() throws Exception { sockJS.bridge(defaultOptions.addOutboundPermitted(new PermittedOptions().setAddress(addr)))); testReceive(addr, "foobar"); testError(new JsonObject().put("type", "register").put("address", "allow2").put("body", "blah"), - "access_denied"); + "ACCESS_DENIED", "Address access is denied"); } @Test @@ -769,7 +769,7 @@ public void testRegisterPermittedAllowAddressRe() throws Exception { testReceive("allow1", "foobar"); testReceive("allow2", "foobar"); testError(new JsonObject().put("type", "register").put("address", "hello").put("body", "blah"), - "access_denied"); + "ACCESS_DENIED", "Address access is denied"); } @Test @@ -782,7 +782,7 @@ public void testRegisterPermittedMultipleAddresses() throws Exception { testReceive("allow1", "foobar"); testReceive("allow2", "foobar"); testError(new JsonObject().put("type", "register").put("address", "allow3").put("body", "blah"), - "access_denied"); + "ACCESS_DENIED", "Address access is denied"); } @Test @@ -797,7 +797,7 @@ public void testRegisterPermittedMultipleAddressRe() throws Exception { testReceive("ballow1", "foobar"); testReceive("ballow2", "foobar"); testError(new JsonObject().put("type", "register").put("address", "hello").put("body", "blah"), - "access_denied"); + "ACCESS_DENIED", "Address access is denied"); } @Test @@ -811,9 +811,9 @@ public void testRegisterPermittedMixedAddressRe() throws Exception { testReceive("ballow1", "foobar"); testReceive("ballow2", "foobar"); testError(new JsonObject().put("type", "register").put("address", "hello").put("body", "blah"), - "access_denied"); + "ACCESS_DENIED", "Address access is denied"); testError(new JsonObject().put("type", "register").put("address", "allow2").put("body", "blah"), - "access_denied"); + "ACCESS_DENIED", "Address access is denied"); } @Test @@ -1044,7 +1044,7 @@ public void testRegisterNotPermittedDefaultOptions() throws Exception { router.route("/eventbus/*").subRouter( sockJS.bridge(defaultOptions)); testError(new JsonObject().put("type", "register").put("address", addr), - "access_denied"); + "ACCESS_DENIED", "Address access is denied"); } @Test @@ -1052,7 +1052,7 @@ public void testUnregisterNotPermittedDefaultOptions() throws Exception { router.route("/eventbus/*").subRouter( sockJS.bridge(defaultOptions)); testError(new JsonObject().put("type", "unregister").put("address", addr), - "access_denied"); + "ACCESS_DENIED", "Address access is denied"); } @Test @@ -1092,11 +1092,13 @@ public void testMaxHandlersPerSocket() throws Exception { }); client.errorHandler(received -> { - Object rec = received.getValue("body"); + Object rec = received.getValue("failureType"); int c = cnt.getAndIncrement(); if (c == 0) { assertEquals("err", received.getString("type")); - assertEquals("max_handlers_reached", rec); + assertEquals(-1, received.getInteger("failureCode").intValue()); + assertEquals("HANDLERS_MAX_LIMIT", rec); + assertEquals("Registration handlers exceed the maximum limit", received.getString("message")); } else if (c >= maxHandlers + 1) { fail("Called too many times"); } @@ -1124,7 +1126,9 @@ public void testMaxAddressLength() throws Exception { client.errorHandler(received -> { assertEquals("err", received.getString("type")); - assertEquals("max_address_length_reached", received.getString("body")); + assertEquals(-1, received.getInteger("failureCode").intValue()); + assertEquals("ADDRESS_MAX_LENGTH", received.getString("failureType")); + assertEquals("Address exceeds maximum length", received.getString("message")); client.close().onComplete(onSuccess(v2 -> latch.countDown())); }); @@ -1138,7 +1142,7 @@ public void testMaxAddressLength() throws Exception { public void testSendRequiresAuthorityNotLoggedIn() throws Exception { router.route("/eventbus/*").subRouter( sockJS.bridge(defaultOptions.addInboundPermitted(new PermittedOptions().setAddress(addr).setRequiredAuthority("admin")))); - testError(new JsonObject().put("type", "send").put("address", addr).put("body", "foo"), "not_logged_in"); + testError(new JsonObject().put("type", "send").put("address", addr).put("body", "foo"), "AUTHN", "Authentication is required"); } @Test @@ -1164,7 +1168,7 @@ public void testSendRequiresAuthorityHasnotAuthority() throws Exception { router.route("/eventbus/*") .handler(addLoginHandler(authProvider)) .subRouter(sockJS); - testError(new JsonObject().put("type", "send").put("address", addr).put("body", "foo"), "access_denied"); + testError(new JsonObject().put("type", "send").put("address", addr).put("body", "foo"), "ACCESS_DENIED", "Address access is denied"); } private AuthenticationHandler addLoginHandler(AuthenticationProvider authProvider) { @@ -1183,7 +1187,7 @@ public void testInvalidClientReplyAddress() throws Exception { router.route("/eventbus/*").subRouter( sockJS.bridge(allAccessOptions)); testError(new JsonObject().put("type", "send").put("address", addr).put("body", "foo") - .put("replyAddress", "thishasmorethan36characters__________"), "invalid_reply_address"); + .put("replyAddress", "thishasmorethan36characters__________"), "INVALID_REPLY_ADDRESS", "Reply address is invalid"); } @Test @@ -1254,17 +1258,19 @@ public void testPermittedOptionsJson() { assertEquals(match, options.getMatch()); } - private void testError(JsonObject msg, String expectedErr) throws Exception { - testError(msg.encode(), expectedErr); + private void testError(JsonObject msg, String expectedType, String expectedMessage) throws Exception { + testError(msg.encode(), expectedType, expectedMessage); } - private void testError(String msg, String expectedErr) throws Exception { + private void testError(String msg, String expectedType, String expectedMessage) throws Exception { CountDownLatch latch = new CountDownLatch(1); BridgeClient client = new BridgeClient(super.wsClient, transport); client.errorHandler(received -> { - assertEquals(expectedErr, received.getString("body")); + assertEquals(-1, received.getInteger("failureCode").intValue()); + assertEquals(expectedType, received.getString("failureType")); + assertEquals(expectedMessage, received.getString("message")); latch.countDown(); }); client.connect(websocketURI) diff --git a/vertx-web/src/test/java/io/vertx/ext/web/tests/handler/sockjs/SockJSHandlerTest.java b/vertx-web/src/test/java/io/vertx/ext/web/tests/handler/sockjs/SockJSHandlerTest.java index d6993a41ac..4dc2286fc6 100644 --- a/vertx-web/src/test/java/io/vertx/ext/web/tests/handler/sockjs/SockJSHandlerTest.java +++ b/vertx-web/src/test/java/io/vertx/ext/web/tests/handler/sockjs/SockJSHandlerTest.java @@ -493,7 +493,9 @@ public void testInvalidMessageCode() { if (!frame.isClose()) { JsonObject msg = new JsonObject(frame.binaryData()); assertEquals("err", msg.getString("type")); - assertEquals("invalid_json", msg.getString("body")); + assertEquals(-1, msg.getInteger("failureCode").intValue()); + assertEquals("INVALID_JSON", msg.getString("failureType")); + assertEquals("Malformed JSON", msg.getString("message")); testComplete(); ws.close(); }