Skip to content

Commit

Permalink
Issue #2767 - WebSocket Policy on JSR356 ClientContainer not represen…
Browse files Browse the repository at this point in the history
…ted correctly

+ Added Client unit tests for large messages
+ Re-enabled Server unit tests for large messages
+ Added more Server unit tests for large messages
+ In case of JSR356 Server with policy (and Behavior of SERVER)
  is controlling javax.websocker.server.ServerContainer
  and a user chooses to use that ServerContainer to
  connect to a remote websocket endpoint (using ServerContainer
  as a client), then the policy is delegated down to the
  Client Container with a different behavior (only).

Signed-off-by: Joakim Erdfelt <joakim.erdfelt@gmail.com>
  • Loading branch information
joakime committed Aug 6, 2018
1 parent 8eb11a5 commit 9a4b780
Show file tree
Hide file tree
Showing 18 changed files with 1,053 additions and 90 deletions.
Expand Up @@ -406,7 +406,7 @@ public Set<Session> getOpenSessions()
@Override
public WebSocketPolicy getPolicy()
{
return scopeDelegate.getPolicy();
return client.getPolicy();
}

@Override
Expand Down Expand Up @@ -482,10 +482,11 @@ public void setAsyncSendTimeout(long ms)
@Override
public void setDefaultMaxBinaryMessageBufferSize(int max)
{
// overall message limit (used in non-streaming)
client.getPolicy().setMaxBinaryMessageSize(max);
// incoming streaming buffer size
client.setMaxBinaryMessageBufferSize(max);

// bump overall message limit (used in non-streaming)
client.getPolicy().setMaxBinaryMessageSize(max);
}

@Override
Expand All @@ -497,9 +498,10 @@ public void setDefaultMaxSessionIdleTimeout(long ms)
@Override
public void setDefaultMaxTextMessageBufferSize(int max)
{
// overall message limit (used in non-streaming)
client.getPolicy().setMaxTextMessageSize(max);
// incoming streaming buffer size
client.setMaxTextMessageBufferSize(max);

// bump overall message limit (used in non-streaming)
client.getPolicy().setMaxTextMessageSize(max);
}
}
Expand Up @@ -328,7 +328,11 @@ public void removeMessageHandler(MessageHandler handler)
@Override
public void setMaxBinaryMessageBufferSize(int length)
{
// incoming streaming buffer size
getPolicy().setMaxBinaryMessageBufferSize(length);

// bump overall message limit (used in non-streaming)
getPolicy().setMaxBinaryMessageSize(length);
}

@Override
Expand All @@ -341,7 +345,11 @@ public void setMaxIdleTimeout(long milliseconds)
@Override
public void setMaxTextMessageBufferSize(int length)
{
// incoming streaming buffer size
getPolicy().setMaxTextMessageBufferSize(length);

// bump overall message limit (used in non-streaming)
getPolicy().setMaxTextMessageSize(length);
}

public void setPathParameters(Map<String, String> pathParams)
Expand Down
Expand Up @@ -26,6 +26,7 @@
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.api.BatchMode;
import org.eclipse.jetty.websocket.api.RemoteEndpoint;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.api.WebSocketAdapter;

/**
Expand Down Expand Up @@ -78,4 +79,14 @@ public void onWebSocketText(String message)
throw new RuntimeIOException(x);
}
}

@Override
public void onWebSocketClose(int statusCode, String reason)
{
super.onWebSocketClose(statusCode, reason);
if (statusCode != StatusCode.NORMAL)
{
LOG.warn("Closed {} {}", statusCode, reason);
}
}
}
@@ -0,0 +1,105 @@
//
// ========================================================================
// Copyright (c) 1995-2018 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.jsr356;

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;

import java.net.URI;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

import javax.websocket.ContainerProvider;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.websocket.api.WebSocketBehavior;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.api.util.WSURI;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

public class LargeMessageTest
{
private static final int LARGER_THAN_DEFAULT_SIZE;
private Server server;

static
{
WebSocketPolicy defaultPolicy = new WebSocketPolicy(WebSocketBehavior.CLIENT);
LARGER_THAN_DEFAULT_SIZE = defaultPolicy.getMaxTextMessageSize() * 3;
}

@Before
public void startServer() throws Exception
{
server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(0);
server.addConnector(connector);

// This handler is expected to handle echoing of 2MB messages (max)
EchoHandler echoHandler = new EchoHandler();

ContextHandler context = new ContextHandler();
context.setContextPath("/");
context.setHandler(echoHandler);
server.setHandler(context);

server.start();
}

@After
public void stopServer() throws Exception
{
server.stop();
}

@SuppressWarnings("Duplicates")
@Test
public void testLargeEcho_AsEndpointInstance() throws Exception
{
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
server.addBean(container); // allow to shutdown with server

container.setDefaultMaxTextMessageBufferSize(LARGER_THAN_DEFAULT_SIZE);

EndpointEchoClient echoer = new EndpointEchoClient();
Assert.assertThat(echoer,instanceOf(javax.websocket.Endpoint.class));

URI wsUri = WSURI.toWebsocket(server.getURI()).resolve("/");

// Issue connect using instance of class that extends Endpoint
Session session = container.connectToServer(echoer,wsUri);
byte buf[] = new byte[LARGER_THAN_DEFAULT_SIZE];
Arrays.fill(buf, (byte)'x');
String message = new String(buf, UTF_8);
session.getBasicRemote().sendText(message);

String echoed = echoer.textCapture.messages.poll(1, TimeUnit.SECONDS);
assertThat("Echoed", echoed, is(message));
}
}
Expand Up @@ -20,76 +20,79 @@

import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.toolchain.test.TestingDir;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.eclipse.jetty.websocket.common.test.Timeouts;
import org.eclipse.jetty.websocket.jsr356.server.samples.echo.LargeEchoConfiguredSocket;
import org.eclipse.jetty.websocket.jsr356.server.samples.echo.LargeEchoAnnotatedSocket;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.BeforeClass;
import org.junit.Test;

/**
* Test Echo of Large messages, targeting the {@link javax.websocket.Session#setMaxTextMessageBufferSize(int)} functionality
* Test Echo of Large messages, targeting the {@code @OnMessage(maxMessage=###)} functionality
*/
@Ignore
public class LargeAnnotatedTest
{
@Rule
public TestingDir testdir = new TestingDir();
private static WSServer server;

public ByteBufferPool bufferPool = new MappedByteBufferPool();
@BeforeClass
public static void startServer() throws Exception
{
Path testDir = MavenTestingUtils.getTargetTestingPath(LargeOnOpenSessionConfiguredTest.class.getSimpleName());

server = new WSServer(testDir,"app");
server.createWebInf();
server.copyEndpoint(LargeEchoAnnotatedSocket.class);

server.start();
}

@AfterClass
public static void stopServer()
{
server.stop();
}

@SuppressWarnings("Duplicates")
@Test
public void testEcho() throws Exception
{
WSServer wsb = new WSServer(testdir,"app");
wsb.createWebInf();
wsb.copyEndpoint(LargeEchoConfiguredSocket.class);
URI uri = server.getServerBaseURI();

WebAppContext webapp = server.createWebAppContext();
server.deployWebapp(webapp);
// wsb.dump();

WebSocketClient client = new WebSocketClient();
try
{
wsb.start();
URI uri = wsb.getServerBaseURI();

WebAppContext webapp = wsb.createWebAppContext();
wsb.deployWebapp(webapp);
// wsb.dump();
client.getPolicy().setMaxTextMessageSize(128*1024);
client.start();
JettyEchoSocket clientEcho = new JettyEchoSocket();
Future<Session> foo = client.connect(clientEcho,uri.resolve("echo/large"));

WebSocketClient client = new WebSocketClient(bufferPool);
try
{
client.getPolicy().setMaxTextMessageSize(128*1024);
client.start();
JettyEchoSocket clientEcho = new JettyEchoSocket();
Future<Session> foo = client.connect(clientEcho,uri.resolve("echo/large"));
// wait for connect
foo.get(1,TimeUnit.SECONDS);
// The message size should be bigger than default, but smaller than the limit that LargeEchoSocket specifies
byte txt[] = new byte[100 * 1024];
Arrays.fill(txt,(byte)'o');
String msg = new String(txt,StandardCharsets.UTF_8);
clientEcho.sendMessage(msg);
LinkedBlockingQueue<String> msgs = clientEcho.incomingMessages;
Assert.assertEquals("Expected message",msg,msgs.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT));
}
finally
{
client.stop();
}
// wait for connect
foo.get(1,TimeUnit.SECONDS);
// The message size should be bigger than default, but smaller than the limit that LargeEchoSocket specifies
byte txt[] = new byte[100 * 1024];
Arrays.fill(txt,(byte)'o');
String msg = new String(txt,StandardCharsets.UTF_8);
clientEcho.sendMessage(msg);
LinkedBlockingQueue<String> msgs = clientEcho.incomingMessages;
Assert.assertEquals("Expected message",msg,msgs.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT));
}
finally
{
wsb.stop();
client.stop();
}
}
}
@@ -0,0 +1,39 @@
//
// ========================================================================
// Copyright (c) 1995-2018 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.jsr356.server;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.eclipse.jetty.websocket.jsr356.JettyClientContainerProvider;

public class LargeClientContainerInitAsServerListener implements ServletContextListener
{
@Override
public void contextInitialized(ServletContextEvent sce)
{
JettyClientContainerProvider.useServerContainer(true);
}

@Override
public void contextDestroyed(ServletContextEvent sce)
{
/* ignore */
}
}

0 comments on commit 9a4b780

Please sign in to comment.