| // |
| // ======================================================================== |
| // Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // and Apache License v2.0 which accompanies this distribution. |
| // |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // The Apache License v2.0 is available at |
| // http://www.opensource.org/licenses/apache2.0.php |
| // |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| // |
| |
| package org.eclipse.jetty.websocket.server; |
| |
| import static org.hamcrest.Matchers.containsString; |
| import static org.hamcrest.Matchers.is; |
| import static org.junit.Assert.assertThat; |
| |
| import java.nio.ByteBuffer; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Random; |
| import java.util.concurrent.Future; |
| import java.util.concurrent.TimeUnit; |
| |
| import org.eclipse.jetty.websocket.api.Session; |
| import org.eclipse.jetty.websocket.api.WebSocketPolicy; |
| import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig; |
| import org.eclipse.jetty.websocket.client.ClientUpgradeRequest; |
| import org.eclipse.jetty.websocket.client.WebSocketClient; |
| import org.eclipse.jetty.websocket.common.test.LeakTrackingBufferPoolRule; |
| import org.eclipse.jetty.websocket.common.util.Sha1Sum; |
| import org.eclipse.jetty.websocket.server.helper.CaptureSocket; |
| import org.eclipse.jetty.websocket.server.helper.EchoServlet; |
| import org.junit.After; |
| import org.junit.Assert; |
| import org.junit.Assume; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.Parameterized; |
| import org.junit.runners.Parameterized.Parameters; |
| |
| @RunWith(Parameterized.class) |
| public class PerMessageDeflateExtensionTest |
| { |
| private static enum TestCaseMessageSize |
| { |
| TINY(10), |
| SMALL(1024), |
| MEDIUM(10*1024), |
| LARGE(100*1024), |
| HUGE(1024*1024); |
| |
| private int size; |
| |
| private TestCaseMessageSize(int size) |
| { |
| this.size = size; |
| } |
| } |
| |
| @Parameters(name = "{0} ({3}) (Input Buffer Size: {4} bytes)") |
| public static List<Object[]> modes() |
| { |
| List<Object[]> modes = new ArrayList<>(); |
| |
| for(TestCaseMessageSize size: TestCaseMessageSize.values()) |
| { |
| modes.add(new Object[] { "Normal HTTP/WS", false, "ws", size, -1 }); |
| modes.add(new Object[] { "Encrypted HTTPS/WSS", true, "wss", size, -1 }); |
| int altInputBufSize = 15*1024; |
| modes.add(new Object[] { "Normal HTTP/WS", false, "ws", size, altInputBufSize }); |
| modes.add(new Object[] { "Encrypted HTTPS/WSS", true, "wss", size, altInputBufSize }); |
| } |
| |
| return modes; |
| } |
| |
| @Rule |
| public LeakTrackingBufferPoolRule bufferPool = new LeakTrackingBufferPoolRule("Test"); |
| |
| private SimpleServletServer server; |
| private String scheme; |
| private int msgSize; |
| private int inputBufferSize; |
| |
| public PerMessageDeflateExtensionTest(String mode, boolean sslMode, String scheme, TestCaseMessageSize msgSize, int bufferSize) throws Exception |
| { |
| server = new SimpleServletServer(new EchoServlet()); |
| server.enableSsl(sslMode); |
| server.start(); |
| |
| this.scheme = scheme; |
| this.msgSize = msgSize.size; |
| this.inputBufferSize = bufferSize; |
| } |
| |
| @After |
| public void stopServer() |
| { |
| server.stop(); |
| } |
| |
| /** |
| * Default configuration for permessage-deflate |
| * @throws Exception on test failure |
| */ |
| @Test |
| public void testPerMessageDeflateDefault() throws Exception |
| { |
| Assume.assumeTrue("Server has permessage-deflate registered", |
| server.getWebSocketServletFactory().getExtensionFactory().isAvailable("permessage-deflate")); |
| |
| Assert.assertThat("server scheme",server.getServerUri().getScheme(),is(scheme)); |
| |
| int binBufferSize = (int) (msgSize * 1.5); |
| |
| WebSocketPolicy serverPolicy = server.getWebSocketServletFactory().getPolicy(); |
| |
| // Ensure binBufferSize is sane (not smaller then other buffers) |
| binBufferSize = Math.max(binBufferSize,serverPolicy.getMaxBinaryMessageSize()); |
| binBufferSize = Math.max(binBufferSize,serverPolicy.getMaxBinaryMessageBufferSize()); |
| binBufferSize = Math.max(binBufferSize,this.inputBufferSize); |
| |
| serverPolicy.setMaxBinaryMessageSize(binBufferSize); |
| serverPolicy.setMaxBinaryMessageBufferSize(binBufferSize); |
| |
| WebSocketClient client = new WebSocketClient(server.getSslContextFactory(),null,bufferPool); |
| WebSocketPolicy clientPolicy = client.getPolicy(); |
| clientPolicy.setMaxBinaryMessageSize(binBufferSize); |
| clientPolicy.setMaxBinaryMessageBufferSize(binBufferSize); |
| if (inputBufferSize > 0) |
| { |
| clientPolicy.setInputBufferSize(inputBufferSize); |
| } |
| |
| try |
| { |
| client.start(); |
| // Make sure the read times out if there are problems with the implementation |
| client.setMaxIdleTimeout(TimeUnit.SECONDS.toMillis(15)); |
| |
| CaptureSocket clientSocket = new CaptureSocket(); |
| ClientUpgradeRequest request = new ClientUpgradeRequest(); |
| request.addExtensions("permessage-deflate"); |
| request.setSubProtocols("echo"); |
| |
| Future<Session> fut = client.connect(clientSocket,server.getServerUri(),request); |
| |
| // Wait for connect |
| Session session = fut.get(30,TimeUnit.SECONDS); |
| |
| assertThat("Response.extensions",getNegotiatedExtensionList(session),containsString("permessage-deflate")); |
| |
| // Create message |
| byte msg[] = new byte[msgSize]; |
| Random rand = new Random(); |
| rand.setSeed(8080); |
| rand.nextBytes(msg); |
| |
| // Calculate sha1 |
| String sha1 = Sha1Sum.calculate(msg); |
| |
| // Client sends first message |
| session.getRemote().sendBytes(ByteBuffer.wrap(msg)); |
| |
| clientSocket.messages.awaitEventCount(1,5,TimeUnit.SECONDS); |
| String echoMsg = clientSocket.messages.poll(); |
| Assert.assertThat("Echo'd Message",echoMsg,is("binary[sha1="+sha1+"]")); |
| } |
| finally |
| { |
| client.stop(); |
| } |
| } |
| |
| private String getNegotiatedExtensionList(Session session) |
| { |
| StringBuilder actual = new StringBuilder(); |
| actual.append('['); |
| |
| boolean delim = false; |
| for (ExtensionConfig ext : session.getUpgradeResponse().getExtensions()) |
| { |
| if (delim) |
| actual.append(", "); |
| actual.append(ext.getName()); |
| delim = true; |
| } |
| actual.append(']'); |
| |
| return actual.toString(); |
| } |
| } |