@Test public void testSharedServersRoundRobinButFirstStartAndStopServer() throws Exception { // Start and stop a server on the same port/host before hand to make sure it doesn't interact CountDownLatch latch = new CountDownLatch(1); HttpServer theServer = vertx.createHttpServer(new HttpServerOptions().setPort(DEFAULT_HTTP_PORT)); theServer.requestHandler(req -> { fail("Should not process request"); }).listen(onSuccess(s -> latch.countDown())); awaitLatch(latch); CountDownLatch closeLatch = new CountDownLatch(1); theServer.close(ar -> { assertTrue(ar.succeeded()); closeLatch.countDown(); }); assertTrue(closeLatch.await(10, TimeUnit.SECONDS)); testSharedServersRoundRobin(); }
@Test public void testInvalidChunkInHttpClientResponse() throws Exception { server.requestHandler(req -> { NetSocket so = req.netSocket(); so.write("HTTP/1.1 200 OK\r\n"); so.write("Transfer-Encoding: chunked\r\n"); so.write("\r\n"); so.write("invalid\r\n"); // Empty chunk }); AtomicInteger status = new AtomicInteger(); testHttpClientResponseDecodeError(err -> { switch (status.incrementAndGet()) { case 1: assertTrue(err instanceof NumberFormatException); break; case 2: assertTrue(err instanceof VertxException); assertTrue(err.getMessage().equals("Connection was closed")); testComplete(); break; } }); }
@Test public void testClosingVertxCloseSharedServers() throws Exception { int numServers = 2; Vertx vertx = Vertx.vertx(); List<HttpServerImpl> servers = new ArrayList<>(); for (int i = 0;i < numServers;i++) { HttpServer server = vertx.createHttpServer(createBaseServerOptions()).requestHandler(req -> { }); startServer(server); servers.add((HttpServerImpl) server); } CountDownLatch latch = new CountDownLatch(1); vertx.close(onSuccess(v -> { latch.countDown(); })); awaitLatch(latch); servers.forEach(server -> { assertTrue(server.isClosed()); }); }
@Test public void testInvalidTrailersInHttpClientResponse() throws Exception { server.requestHandler(req -> { NetSocket so = req.netSocket(); so.write("HTTP/1.1 200 OK\r\n"); so.write("Transfer-Encoding: chunked\r\n"); so.write("\r\n"); so.write("0\r\n"); // Empty chunk // Send large trailer for (int i = 0;i < 2000;i++) { so.write("01234567"); } }); AtomicInteger status = new AtomicInteger(); testHttpClientResponseDecodeError(err -> { switch (status.incrementAndGet()) { case 1: assertTrue(err instanceof TooLongFrameException); break; case 2: assertTrue(err instanceof VertxException); assertTrue(err.getMessage().equals("Connection was closed")); testComplete(); break; } }); }
private void testKeepAliveTimeout(HttpClientOptions options, int numReqs) throws Exception { startServer(); client.close(); client = vertx.createHttpClient(options.setPoolCleanerPeriod(1)); AtomicInteger respCount = new AtomicInteger(); for (int i = 0;i < numReqs;i++) { int current = 1 + i; client.getNow(DEFAULT_HTTP_PORT, DEFAULT_HTTP_HOST, DEFAULT_TEST_URI, onSuccess(resp -> { respCount.incrementAndGet(); if (current == numReqs) { long now = System.currentTimeMillis(); resp.request().connection().closeHandler(v -> { long timeout = System.currentTimeMillis() - now; int delta = 500; int low = 3000 - delta; int high = 3000 + delta; assertTrue("Expected actual close timeout " + timeout + " to be > " + low, low < timeout); assertTrue("Expected actual close timeout " + timeout + " + to be < " + high, timeout < high); testComplete(); }); } })); } await(); }
@Test public void testServerWebsocketIdleTimeout() { server.close(); server = vertx.createHttpServer(new HttpServerOptions().setIdleTimeout(1).setPort(DEFAULT_HTTP_PORT).setHost(DEFAULT_HTTP_HOST)); server.websocketHandler(ws -> {}).listen(ar -> { assertTrue(ar.succeeded()); client.websocket(DEFAULT_HTTP_PORT, DEFAULT_HTTP_HOST, "/", ws -> { ws.closeHandler(v -> testComplete()); }); }); await(); }
@Test public void testServerExceptionHandler() throws Exception { server.exceptionHandler(err -> { assertTrue(err instanceof TooLongFrameException); testComplete(); }); server.requestHandler(req -> { fail(); }); CountDownLatch listenLatch = new CountDownLatch(1); server.listen(onSuccess(s -> listenLatch.countDown())); awaitLatch(listenLatch); HttpClientRequest req = client.post(DEFAULT_HTTP_PORT, DEFAULT_HTTP_HOST, "/somepath", resp -> { }); req.putHeader("the_header", TestUtils.randomAlphaString(10000)); req.sendHead(); await(); }
@Test public void testIncorrectHttpVersion() throws Exception { server.requestHandler(req -> { NetSocket so = req.netSocket(); so.write(Buffer.buffer("HTTP/1.2 200 OK\r\nContent-Length:5\r\n\r\nHELLO")); so.close(); }); startServer(); AtomicBoolean a = new AtomicBoolean(); HttpClientRequest req = client.request(HttpMethod.GET, DEFAULT_HTTP_PORT, DEFAULT_HTTP_HOST, DEFAULT_TEST_URI, onFailure(err -> { if (a.compareAndSet(false, true)) { assertTrue("message " + err.getMessage() + " should contain HTTP/1.2", err.getMessage().contains("HTTP/1.2")); } })); req.exceptionHandler(err -> { fail("Should not be called"); }).putHeader("connection", "close") .connectionHandler(conn -> conn.closeHandler(v -> testComplete())) .end(); await(); }
@Test public void testServerOptionsCopiedBeforeUse() { server.close(); HttpServerOptions options = new HttpServerOptions().setHost(DEFAULT_HTTP_HOST).setPort(DEFAULT_HTTP_PORT); HttpServer server = vertx.createHttpServer(options); // Now change something - but server should still listen at previous port options.setPort(DEFAULT_HTTP_PORT + 1); server.requestHandler(req -> { req.response().end(); }); server.listen(ar -> { assertTrue(ar.succeeded()); client.request(HttpMethod.GET, DEFAULT_HTTP_PORT, DEFAULT_HTTP_HOST, "/uri", onSuccess(res -> { assertEquals(200, res.statusCode()); testComplete(); })).end(); }); await(); }
@Test public void testClientOptionsCopiedBeforeUse() { client.close(); server.requestHandler(req -> { req.response().end(); }); server.listen(ar -> { assertTrue(ar.succeeded()); HttpClientOptions options = new HttpClientOptions(); client = vertx.createHttpClient(options); // Now change something - but server should ignore this options.setSsl(true); client.request(HttpMethod.GET, DEFAULT_HTTP_PORT, DEFAULT_HTTP_HOST, "/uri", onSuccess(res -> { assertEquals(200, res.statusCode()); testComplete(); })).end(); }); await(); }
@Test public void testPoolNotExpiring() throws Exception { AtomicLong now = new AtomicLong(); server.requestHandler(req -> { req.response().end(); now.set(System.currentTimeMillis()); vertx.setTimer(2000, id -> { req.connection().close(); }); }); startServer(); client.close(); client = vertx.createHttpClient(new HttpClientOptions().setPoolCleanerPeriod(0).setKeepAliveTimeout(100)); client.getNow(DEFAULT_HTTP_PORT, DEFAULT_HTTP_HOST, DEFAULT_TEST_URI, onSuccess(resp -> { resp.endHandler(v1 -> { resp.request().connection().closeHandler(v2 -> { long time = System.currentTimeMillis() - now.get(); assertTrue("Was expecting " + time + " to be > 2000", time >= 2000); testComplete(); }); }); })); await(); }
conn.closeHandler(v -> { assertTrue(respBuff.toString().contains("501 Not Implemented")); client.close(); testComplete();
@Test public void testServerConnectionExceptionHandler() throws Exception { server.connectionHandler(conn -> { conn.exceptionHandler(err -> { assertTrue(err instanceof TooLongFrameException); testComplete(); }); }); server.requestHandler(req -> { req.response().end(); }); CountDownLatch listenLatch = new CountDownLatch(1); server.listen(onSuccess(s -> listenLatch.countDown())); awaitLatch(listenLatch); client.close(); client = vertx.createHttpClient(new HttpClientOptions().setMaxPoolSize(1)); client.getNow(DEFAULT_HTTP_PORT, DEFAULT_HTTP_HOST, "/somepath", resp1 -> { HttpClientRequest req = client.post(DEFAULT_HTTP_PORT, DEFAULT_HTTP_HOST, "/somepath", resp2 -> { }); req.putHeader("the_header", TestUtils.randomAlphaString(10000)); req.sendHead(); }); await(); }
@Test public void testMaxWaitQueueSizeIsRespected() throws Exception { client.close(); client = vertx.createHttpClient(new HttpClientOptions().setDefaultHost(DEFAULT_HTTP_HOST).setDefaultPort(DEFAULT_HTTP_PORT) .setPipelining(false).setMaxWaitQueueSize(0).setMaxPoolSize(2)); waitFor(3); Set<String> expected = new HashSet<>(Arrays.asList("/1", "/2")); server.requestHandler(req -> { assertTrue(expected.contains(req.path())); complete(); }); startServer(); HttpClientRequest req1 = client.get("/1", onFailure(err -> { })); HttpClientRequest req2 = client.get("/2", onFailure(resp -> { })); HttpClientRequest req3 = client.get("/3", onFailure(t -> { assertTrue("Incorrect exception: " + t.getClass().getName(), t instanceof ConnectionPoolTooBusyException); complete(); })); req1.end(); req2.end(); req3.end(); await(); }
@Test public void testDontReuseConnectionWhenResponseEndsDuringAnOngoingRequest() throws Exception { client.close(); client = vertx.createHttpClient(new HttpClientOptions().setMaxPoolSize(1).setPipelining(true).setKeepAlive(true)); server.requestHandler(req -> { req.response().end(); }); CountDownLatch serverLatch = new CountDownLatch(1); server.listen(ar -> { assertTrue(ar.succeeded()); serverLatch.countDown(); }); awaitLatch(serverLatch); HttpClientRequest req1 = client.get(DEFAULT_HTTP_PORT, DEFAULT_HTTP_HOST, "/", onSuccess(resp -> { resp.endHandler(v1 -> { // End request after the response ended vertx.setTimer(100, v2 -> { resp.request().end(); }); }); })); // Send head to the server and trigger the request handler req1.sendHead(); client.get(DEFAULT_HTTP_PORT, DEFAULT_HTTP_HOST, "/", resp -> { testComplete(); }).end(); await(); }
@Test public void testChunkedServerResponse() { server.requestHandler(req -> { HttpServerResponse resp = req.response(); resp.setChunked(true); assertTrue(resp.isChunked()); resp.write("the-chunk"); vertx.setTimer(1, id -> { resp.end(); }); }).listen(onSuccess(server -> { client.getNow(DEFAULT_HTTP_PORT, DEFAULT_HTTP_HOST, "/", onSuccess(res -> { assertEquals("chunked", res.getHeader("transfer-encoding")); res.bodyHandler(body -> { assertEquals("the-chunk", body.toString()); testComplete(); }); })); })); await(); }
resp.endHandler(v -> { assertEquals(expected, length[0]); assertTrue(System.currentTimeMillis() - now > 1000); testComplete(); });
@Test public void testDeferredRequestEnd() throws Exception { server.requestHandler(req -> { req.pause(); req.bodyHandler(body -> { assertTrue(req.isEnded()); req.response().end(body); }); vertx.setTimer(10, v -> { assertFalse(req.isEnded()); req.resume(); }); }); startServer(); Buffer expected = Buffer.buffer(TestUtils.randomAlphaString(1024)); client.post(DEFAULT_HTTP_PORT, DEFAULT_HTTP_HOST, "/", onSuccess(resp -> { resp.bodyHandler(body -> { assertEquals(expected, body); testComplete(); }); })).end(expected); await(); }
@Test public void testHttp10RequestNonKeepAliveConnectionClosed() throws Exception { client.close(); server.requestHandler(req -> { assertEquals(HttpVersion.HTTP_1_0, req.version()); assertNull(req.getHeader("Connection")); req.response().end(); assertTrue(req.response().closed()); }); server.listen(onSuccess(s -> { client = vertx.createHttpClient(new HttpClientOptions().setProtocolVersion(HttpVersion.HTTP_1_0).setKeepAlive(false)); HttpClientRequest req = client.request(HttpMethod.GET, DEFAULT_HTTP_PORT, DEFAULT_HTTP_HOST, DEFAULT_TEST_URI, onSuccess(resp -> { resp.endHandler(v -> { assertNull(resp.getHeader("Connection")); testComplete(); }); })); req.end(); })); await(); }
@Test public void testHttp11NonPersistentConnectionClosed() throws Exception { client.close(); server.requestHandler(req -> { assertEquals(HttpVersion.HTTP_1_1, req.version()); assertEquals(req.getHeader("Connection"), "close"); req.response().end(); assertTrue(req.response().closed()); }); server.listen(onSuccess(s -> { client = vertx.createHttpClient(new HttpClientOptions().setProtocolVersion(HttpVersion.HTTP_1_1).setKeepAlive(false)); HttpClientRequest req = client.request(HttpMethod.GET, DEFAULT_HTTP_PORT, DEFAULT_HTTP_HOST, DEFAULT_TEST_URI, onSuccess(resp -> { resp.endHandler(v -> { assertEquals(resp.getHeader("Connection"), "close"); testComplete(); }); })); req.end(); })); await(); }