@Override public void start() throws Exception { HttpClient client = vertx.createHttpClient( new HttpClientOptions() .setDefaultHost("localhost") .setDefaultPort(HTTPServerReproducer.PORT) .setKeepAlive(false)); vertx.setPeriodic( 1000, l -> { client .get("/") .handler( response -> { response.bodyHandler( buf -> { System.out.println( "Received: " + response.statusCode() + " - " + buf.toString()); }); }) .end(); }); }
@Test public void testWebsocketPauseAndResume() { client.close(); client = vertx.createHttpClient(new HttpClientOptions().setConnectTimeout(1000)); String path = "/some/path"; this.server = vertx.createHttpServer( new HttpServerOptions().setAcceptBacklog(1).setPort(HttpTestBase.DEFAULT_HTTP_PORT)); AtomicBoolean paused = new AtomicBoolean(); ReadStream<ServerWebSocket> stream = server.websocketStream(); stream.handler( ws -> { assertFalse(paused.get()); ws.writeMessage(Buffer.buffer("whatever")); ws.close(); }); server.listen( listenAR -> { assertTrue(listenAR.succeeded()); stream.pause(); paused.set(true); client .websocket(HttpTestBase.DEFAULT_HTTP_PORT, HttpTestBase.DEFAULT_HTTP_HOST, path) .exceptionHandler( err -> { assertTrue(paused.get()); assertTrue(err instanceof WebSocketHandshakeException); paused.set(false); stream.resume(); client.connectWebsocket( HttpTestBase.DEFAULT_HTTP_PORT, HttpTestBase.DEFAULT_HTTP_HOST, path, ws -> { ws.handler( buffer -> { assertEquals("whatever", buffer.toString("UTF-8")); ws.closeHandler( v2 -> { testComplete(); }); }); }); }) .handler(ws -> fail()); }); await(); }
private void testWriteMessage(int size, WebsocketVersion version) { String path = "/some/path"; byte[] expected = TestUtils.randomByteArray(size); server = vertx .createHttpServer(new HttpServerOptions().setPort(HttpTestBase.DEFAULT_HTTP_PORT)) .websocketHandler( ws -> { ws.writeMessage(Buffer.buffer(expected)); ws.close(); }); server.listen( ar -> { assertTrue(ar.succeeded()); client.connectWebsocket( HttpTestBase.DEFAULT_HTTP_PORT, HttpTestBase.DEFAULT_HTTP_HOST, path, null, version, ws -> { Buffer actual = Buffer.buffer(); ws.handler(actual::appendBuffer); ws.closeHandler( v -> { assertArrayEquals(expected, actual.getBytes()); testComplete(); }); }); }); await(); }
private void testReject(WebsocketVersion version) throws Exception { String path = "/some/path"; server = vertx .createHttpServer(new HttpServerOptions().setPort(HttpTestBase.DEFAULT_HTTP_PORT)) .websocketHandler( ws -> { assertEquals(path, ws.path()); ws.reject(); }); server.listen( ar -> { assertTrue(ar.succeeded()); client .websocket( HttpTestBase.DEFAULT_HTTP_PORT, HttpTestBase.DEFAULT_HTTP_HOST, path, null, version) .exceptionHandler(t -> testComplete()) .handler(ws -> fail("Should not be called")); }); await(); }
private void testInvalidSubProtocol(WebsocketVersion version) throws Exception { String path = "/some/path"; String subProtocol = "myprotocol"; server = vertx .createHttpServer( new HttpServerOptions() .setPort(HttpTestBase.DEFAULT_HTTP_PORT) .setWebsocketSubProtocol("invalid")) .websocketHandler(ws -> {}); server.listen( onSuccess( ar -> { client .websocket( HttpTestBase.DEFAULT_HTTP_PORT, HttpTestBase.DEFAULT_HTTP_HOST, path, null, version, subProtocol) .exceptionHandler( t -> { // Should fail testComplete(); }) .handler(ws -> {}); })); await(); }
@Test public void testClearClientHandlersOnEnd() { String path = "/some/path"; server = vertx .createHttpServer(new HttpServerOptions().setPort(HttpTestBase.DEFAULT_HTTP_PORT)) .websocketHandler(WebSocketBase::close); server.listen( ar -> { assertTrue(ar.succeeded()); client .websocket(HttpTestBase.DEFAULT_HTTP_PORT, HttpTestBase.DEFAULT_HTTP_HOST, path, null) .handler( ws -> { ws.endHandler( v -> { try { ws.endHandler(null); ws.exceptionHandler(null); ws.handler(null); } catch (Exception e) { fail( "Was expecting to set to null the handlers when the socket is closed"); return; } testComplete(); }); }); }); await(); }
@Test public void testEndHandlerCalled() { String path = "/some/path"; server = vertx .createHttpServer(new HttpServerOptions().setPort(HttpTestBase.DEFAULT_HTTP_PORT)) .websocketHandler(WebSocketBase::close); AtomicInteger doneCount = new AtomicInteger(); server.listen( ar -> { assertTrue(ar.succeeded()); client .websocket(HttpTestBase.DEFAULT_HTTP_PORT, HttpTestBase.DEFAULT_HTTP_HOST, path, null) .endHandler(done -> doneCount.incrementAndGet()) .handler( ws -> { assertEquals(0, doneCount.get()); ws.closeHandler( v -> { assertEquals(1, doneCount.get()); testComplete(); }); }); }); await(); }
public void request() { final HttpClientRequest httpRequest = client.request( method, proxyToUri.getPort(), proxyToUri.getHost(), uri, resp -> { headers = resp.headers(); code = resp.statusCode(); resp.handler(this.body::appendBuffer); resp.endHandler( end -> { if (code >= 200 && code < 300) { call(onSuccess); } else { call(onFailure); } call(onComplete); }); // TODO can we start writing without waiting the whole buffer? }); httpRequest.exceptionHandler( ex -> { logger.error(format("Got exception processing request: %s", ex.getMessage())); code = INTERNAL_SERVER_ERROR.code(); call(onFailure); call(onComplete); }); httpRequest.headers().setAll(headers); httpRequest.write(requestBody); httpRequest.end(); }
private void testContinuationWriteFromConnectHandler(WebsocketVersion version) throws Exception { String path = "/some/path"; String firstFrame = "AAA"; String continuationFrame = "BBB"; server = vertx .createHttpServer(new HttpServerOptions().setPort(HttpTestBase.DEFAULT_HTTP_PORT)) .requestHandler( req -> { NetSocket sock = getUpgradedNetSocket(req, path); // Let's write a Text frame raw Buffer buff = Buffer.buffer(); buff.appendByte((byte) 0x01); // Incomplete Text frame buff.appendByte((byte) firstFrame.length()); buff.appendString(firstFrame); sock.write(buff); buff = Buffer.buffer(); buff.appendByte((byte) (0x00 | 0x80)); // Complete continuation frame buff.appendByte((byte) continuationFrame.length()); buff.appendString(continuationFrame); sock.write(buff); }); server.listen( ar -> { assertTrue(ar.succeeded()); client.connectWebsocket( HttpTestBase.DEFAULT_HTTP_PORT, HttpTestBase.DEFAULT_HTTP_HOST, path, null, version, ws -> { AtomicBoolean receivedFirstFrame = new AtomicBoolean(); ws.frameHandler( received -> { Buffer receivedBuffer = Buffer.buffer(received.textData()); if (!received.isFinal()) { assertEquals(firstFrame, receivedBuffer.toString()); receivedFirstFrame.set(true); } else if (receivedFirstFrame.get() && received.isFinal()) { assertEquals(continuationFrame, receivedBuffer.toString()); ws.close(); testComplete(); } }); }); }); await(); }
protected void tearDown() throws Exception { client.close(); if (server != null) { CountDownLatch latch = new CountDownLatch(1); server.close( ar -> { assertTrue(ar.succeeded()); latch.countDown(); }); awaitLatch(latch); } super.tearDown(); }
private void testWSWriteStream(WebsocketVersion version) throws Exception { String path = "/some/path"; String query = "foo=bar&wibble=eek"; String uri = path + "?" + query; server = vertx .createHttpServer(new HttpServerOptions().setPort(HttpTestBase.DEFAULT_HTTP_PORT)) .websocketHandler( ws -> { assertEquals(uri, ws.uri()); assertEquals(path, ws.path()); assertEquals(query, ws.query()); assertEquals("Upgrade", ws.headers().get("Connection")); ws.handler(data -> ws.write(data)); }); server.listen( ar -> { assertTrue(ar.succeeded()); int bsize = 100; int sends = 10; client.connectWebsocket( HttpTestBase.DEFAULT_HTTP_PORT, HttpTestBase.DEFAULT_HTTP_HOST, path + "?" + query, null, version, ws -> { final Buffer received = Buffer.buffer(); ws.handler( data -> { received.appendBuffer(data); if (received.length() == bsize * sends) { ws.close(); testComplete(); } }); final Buffer sent = Buffer.buffer(); for (int i = 0; i < sends; i++) { Buffer buff = Buffer.buffer(TestUtils.randomByteArray(bsize)); ws.write(buff); sent.appendBuffer(buff); } }); }); await(); }
private void testValidSubProtocol(WebsocketVersion version) throws Exception { String path = "/some/path"; String subProtocol = "myprotocol"; Buffer buff = Buffer.buffer("AAA"); server = vertx .createHttpServer( new HttpServerOptions() .setPort(HttpTestBase.DEFAULT_HTTP_PORT) .setWebsocketSubProtocol(subProtocol)) .websocketHandler( ws -> { assertEquals(path, ws.path()); ws.writeFrame(WebSocketFrame.binaryFrame(buff, true)); }); server.listen( ar -> { assertTrue(ar.succeeded()); client.connectWebsocket( HttpTestBase.DEFAULT_HTTP_PORT, HttpTestBase.DEFAULT_HTTP_HOST, path, null, version, subProtocol, ws -> { final Buffer received = Buffer.buffer(); ws.handler( data -> { received.appendBuffer(data); if (received.length() == buff.length()) { assertEquals(buff, received); ws.close(); testComplete(); } }); }); }); await(); }
@Test // Let's manually handle the websocket handshake and write a frame to the client public void testHandleWSManually() throws Exception { String path = "/some/path"; String message = "here is some text data"; server = vertx .createHttpServer(new HttpServerOptions().setPort(HttpTestBase.DEFAULT_HTTP_PORT)) .requestHandler( req -> { NetSocket sock = getUpgradedNetSocket(req, path); // Let's write a Text frame raw Buffer buff = Buffer.buffer(); buff.appendByte((byte) 129); // Text frame buff.appendByte((byte) message.length()); buff.appendString(message); sock.write(buff); }); server.listen( ar -> { assertTrue(ar.succeeded()); client .websocket(HttpTestBase.DEFAULT_HTTP_PORT, HttpTestBase.DEFAULT_HTTP_HOST, path) .exceptionHandler(t -> fail(t.getMessage())) .handler( ws -> { ws.handler( buff -> { assertEquals(message, buff.toString("UTF-8")); testComplete(); }); }); }); await(); }
private void testWSFrames(boolean binary, WebsocketVersion version) throws Exception { String path = "/some/path"; String query = "foo=bar&wibble=eek"; String uri = path + "?" + query; // version 0 doesn't support continuations so we just send 1 frame per message int frames = version == WebsocketVersion.V00 ? 1 : 10; server = vertx .createHttpServer(new HttpServerOptions().setPort(HttpTestBase.DEFAULT_HTTP_PORT)) .websocketHandler( ws -> { assertEquals(uri, ws.uri()); assertEquals(path, ws.path()); assertEquals(query, ws.query()); assertEquals("Upgrade", ws.headers().get("Connection")); AtomicInteger count = new AtomicInteger(); ws.frameHandler( frame -> { if (count.get() == 0) { if (binary) { assertTrue(frame.isBinary()); assertFalse(frame.isText()); } else { assertFalse(frame.isBinary()); assertTrue(frame.isText()); } assertFalse(frame.isContinuation()); } else { assertFalse(frame.isBinary()); assertFalse(frame.isText()); assertTrue(frame.isContinuation()); } if (count.get() == frames - 1) { assertTrue(frame.isFinal()); } else { assertFalse(frame.isFinal()); } ws.writeFrame(frame); if (count.incrementAndGet() == frames) { count.set(0); } }); }); server.listen( ar -> { assertTrue(ar.succeeded()); int bsize = 100; int msgs = 10; client.connectWebsocket( HttpTestBase.DEFAULT_HTTP_PORT, HttpTestBase.DEFAULT_HTTP_HOST, path + "?" + query, null, version, ws -> { final List<Buffer> sent = new ArrayList<>(); final List<Buffer> received = new ArrayList<>(); AtomicReference<Buffer> currentReceived = new AtomicReference<>(Buffer.buffer()); ws.frameHandler( frame -> { // received.appendBuffer(frame.binaryData()); currentReceived.get().appendBuffer(frame.binaryData()); if (frame.isFinal()) { received.add(currentReceived.get()); currentReceived.set(Buffer.buffer()); } if (received.size() == msgs) { int pos = 0; for (Buffer rec : received) { assertEquals(rec, sent.get(pos++)); } testComplete(); } }); AtomicReference<Buffer> currentSent = new AtomicReference<>(Buffer.buffer()); for (int i = 0; i < msgs; i++) { for (int j = 0; j < frames; j++) { Buffer buff; WebSocketFrame frame; if (binary) { buff = Buffer.buffer(TestUtils.randomByteArray(bsize)); if (j == 0) { frame = WebSocketFrame.binaryFrame(buff, false); } else { frame = WebSocketFrame.continuationFrame(buff, j == frames - 1); } } else { String str = TestUtils.randomAlphaString(bsize); buff = Buffer.buffer(str); if (j == 0) { frame = WebSocketFrame.textFrame(str, false); } else { frame = WebSocketFrame.continuationFrame(buff, j == frames - 1); } } currentSent.get().appendBuffer(buff); ws.writeFrame(frame); if (j == frames - 1) { sent.add(currentSent.get()); currentSent.set(Buffer.buffer()); } } } }); }); await(); }
@Test public void testSharedServersRoundRobin() throws Exception { int numServers = 5; int numConnections = numServers * 100; List<HttpServer> servers = new ArrayList<>(); Set<HttpServer> connectedServers = new ConcurrentHashSet<>(); Map<HttpServer, Integer> connectCount = new ConcurrentHashMap<>(); CountDownLatch latchListen = new CountDownLatch(numServers); CountDownLatch latchConns = new CountDownLatch(numConnections); for (int i = 0; i < numServers; i++) { HttpServer theServer = vertx.createHttpServer(new HttpServerOptions().setPort(HttpTestBase.DEFAULT_HTTP_PORT)); servers.add(theServer); theServer .websocketHandler( ws -> { connectedServers.add(theServer); Integer cnt = connectCount.get(theServer); int icnt = cnt == null ? 0 : cnt; icnt++; connectCount.put(theServer, icnt); latchConns.countDown(); }) .listen( ar -> { if (ar.succeeded()) { latchListen.countDown(); } else { fail("Failed to bind server"); } }); } assertTrue(latchListen.await(10, TimeUnit.SECONDS)); // Create a bunch of connections CountDownLatch latchClient = new CountDownLatch(numConnections); for (int i = 0; i < numConnections; i++) { client.connectWebsocket( HttpTestBase.DEFAULT_HTTP_PORT, HttpTestBase.DEFAULT_HTTP_HOST, "/someuri", ws -> { ws.closeHandler(v -> latchClient.countDown()); ws.close(); }); } assertTrue(latchClient.await(10, TimeUnit.SECONDS)); assertTrue(latchConns.await(10, TimeUnit.SECONDS)); assertEquals(numServers, connectedServers.size()); for (HttpServer server : servers) { assertTrue(connectedServers.contains(server)); } assertEquals(numServers, connectCount.size()); for (int cnt : connectCount.values()) { assertEquals(numConnections / numServers, cnt); } CountDownLatch closeLatch = new CountDownLatch(numServers); for (HttpServer server : servers) { server.close( ar -> { assertTrue(ar.succeeded()); closeLatch.countDown(); }); } assertTrue(closeLatch.await(10, TimeUnit.SECONDS)); testComplete(); }
private void testTLS( KS clientCert, TS clientTrust, KS serverCert, TS serverTrust, boolean requireClientAuth, boolean serverUsesCrl, boolean clientTrustAll, boolean clientUsesCrl, boolean shouldPass, String... enabledCipherSuites) throws Exception { HttpClientOptions options = new HttpClientOptions(); options.setSsl(true); if (clientTrustAll) { options.setTrustAll(true); } if (clientUsesCrl) { options.addCrlPath(findFileOnClasspath("tls/ca/crl.pem")); } options.setTrustStoreOptions(getClientTrustOptions(clientTrust)); options.setKeyStoreOptions(getClientCertOptions(clientCert)); for (String suite : enabledCipherSuites) { options.addEnabledCipherSuite(suite); } client = vertx.createHttpClient(options); HttpServerOptions serverOptions = new HttpServerOptions(); serverOptions.setSsl(true); serverOptions.setTrustStoreOptions(getServerTrustOptions(serverTrust)); serverOptions.setKeyStoreOptions(getServerCertOptions(serverCert)); if (requireClientAuth) { serverOptions.setClientAuthRequired(true); } if (serverUsesCrl) { serverOptions.addCrlPath(findFileOnClasspath("tls/ca/crl.pem")); } for (String suite : enabledCipherSuites) { serverOptions.addEnabledCipherSuite(suite); } server = vertx.createHttpServer(serverOptions.setPort(4043)); server.websocketHandler( ws -> { ws.handler(ws::write); }); server.listen( ar -> { assertTrue(ar.succeeded()); client .websocket(4043, HttpTestBase.DEFAULT_HTTP_HOST, "/") .exceptionHandler( t -> { if (shouldPass) { t.printStackTrace(); fail("Should not throw exception"); } else { testComplete(); } }) .handler( ws -> { int size = 100; Buffer received = Buffer.buffer(); ws.handler( data -> { received.appendBuffer(data); if (received.length() == size) { ws.close(); testComplete(); } }); Buffer buff = Buffer.buffer(TestUtils.randomByteArray(size)); ws.writeFrame(WebSocketFrame.binaryFrame(buff, true)); }); }); await(); }