diff --git a/vertx-core/src/main/java/io/vertx/core/net/impl/tcp/NetSocketImpl.java b/vertx-core/src/main/java/io/vertx/core/net/impl/tcp/NetSocketImpl.java index a78cbd8137b..daeddeaadcf 100644 --- a/vertx-core/src/main/java/io/vertx/core/net/impl/tcp/NetSocketImpl.java +++ b/vertx-core/src/main/java/io/vertx/core/net/impl/tcp/NetSocketImpl.java @@ -17,6 +17,7 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPromise; import io.netty.handler.ssl.SslHandler; +import io.netty.handler.stream.ChunkedWriteHandler; import io.vertx.core.Future; import io.vertx.core.Handler; import io.vertx.core.buffer.Buffer; @@ -169,6 +170,11 @@ private Future sslUpgrade(String serverName, SSLOptions sslOptions, ByteBu chctx.pipeline().addFirst("handshaker", handshaker); chctx.pipeline().addFirst("ssl", sslHandler); } + if (chctx.pipeline().get("chunkedWriter") == null) { + // The connection can no longer use zero-copy, sendFile needs a ChunkedWriteHandler to consume the + // chunked file it writes - the pipeline was set up without one since the channel was not encrypted + chctx.pipeline().addBefore(chctx.name(), "chunkedWriter", new ChunkedWriteHandler()); + } channelPromise.addListener(p); doPause(); } else { diff --git a/vertx-core/src/test/java/io/vertx/tests/net/NetTest.java b/vertx-core/src/test/java/io/vertx/tests/net/NetTest.java index c00503bef0e..9fba88b19b3 100755 --- a/vertx-core/src/test/java/io/vertx/tests/net/NetTest.java +++ b/vertx-core/src/test/java/io/vertx/tests/net/NetTest.java @@ -2480,6 +2480,70 @@ public void sendFileServerToClient(Checkpoint checkpoint) throws Exception { sock.write("foo"); } + @Test + public void testSendFileAfterTlsUpgrade() throws Exception { + File dir = testFolder.newFolder(); + int size = 64 * 1024; + String content = String.valueOf('a').repeat(size); + File f = setupFile(dir.toString(), "upgraded.dat", content); + Promise sent = Promise.promise(); + server.connectHandler(socket -> { + socket.upgradeToSsl(new ServerSSLOptions().setKeyCertOptions(Cert.SERVER_JKS.get())) + .compose(v -> socket.sendFile(f.getAbsolutePath())) + .onComplete(sent); + }); + server.listen(1234, "localhost").await(); + NetSocket socket = client.connect(new ConnectOptions() + .setPort(1234) + .setHost("localhost") + .setSsl(true) + .setSslOptions(new ClientSSLOptions() + .setHostnameVerificationAlgorithm("") + .setTrustAll(true))).await(); + Buffer received = Buffer.buffer(); + Promise done = Promise.promise(); + socket.handler(buff -> { + received.appendBuffer(buff); + if (received.length() == size) { + done.tryComplete(); + } + }); + sent.future().await(); + done.future().await(); + socket.close().await(); + server.close().await(); + assertEquals(content, received.toString()); + } + + @Test + public void testSendFileFromClientAfterTlsUpgrade() throws Exception { + File dir = testFolder.newFolder(); + int size = 64 * 1024; + String content = String.valueOf('a').repeat(size); + File f = setupFile(dir.toString(), "upgraded-client.dat", content); + Buffer received = Buffer.buffer(); + Promise done = Promise.promise(); + server.connectHandler(socket -> { + socket.upgradeToSsl(new ServerSSLOptions().setKeyCertOptions(Cert.SERVER_JKS.get())) + .onSuccess(v -> socket.handler(buff -> { + received.appendBuffer(buff); + if (received.length() == size) { + done.tryComplete(); + } + })); + }); + server.listen(1234, "localhost").await(); + NetSocket socket = client.connect(1234, "localhost").await(); + socket.upgradeToSsl(new ClientSSLOptions() + .setHostnameVerificationAlgorithm("") + .setTrustAll(true)).await(); + socket.sendFile(f.getAbsolutePath()).await(); + done.future().await(); + socket.close().await(); + server.close().await(); + assertEquals(content, received.toString()); + } + @Test public void testSendFileDirectory() throws Exception { File fDir = testFolder.newFolder();