444771 - JSR356 / EndPointConfig.userProperties are not unique per

endpoint upgrade 

+ Adding testcase & implementation which honors the
ServerEndpointConfig.userProperties copy at an earlier point.
This commit is contained in:
Joakim Erdfelt 2014-09-22 11:59:43 -07:00 committed by Simone Bordet
parent 65cae13b1e
commit e93247de42
3 changed files with 98 additions and 8 deletions

View File

@ -54,14 +54,14 @@ public class BasicServerEndpointConfig implements ServerEndpointConfig
public BasicServerEndpointConfig(ServerEndpointConfig copy)
{
// immutable concepts
this.endpointClass = copy.getEndpointClass();
this.path = copy.getPath();
this.decoders = new ArrayList<>(copy.getDecoders());
this.encoders = new ArrayList<>(copy.getEncoders());
this.subprotocols = new ArrayList<>(copy.getSubprotocols());
this.extensions = new ArrayList<>(copy.getExtensions());
this.userProperties = new HashMap<>(copy.getUserProperties());
this.decoders = copy.getDecoders();
this.encoders = copy.getEncoders();
this.subprotocols = copy.getSubprotocols();
this.extensions = copy.getExtensions();
if (copy.getConfigurator() != null)
{
this.configurator = copy.getConfigurator();
@ -70,6 +70,9 @@ public class BasicServerEndpointConfig implements ServerEndpointConfig
{
this.configurator = BasicServerEndpointConfigurator.INSTANCE;
}
// mutable concepts
this.userProperties = new HashMap<>(copy.getUserProperties());
}
@Override

View File

@ -56,8 +56,14 @@ public class JsrCreator implements WebSocketCreator
JsrHandshakeRequest hsreq = new JsrHandshakeRequest(req);
JsrHandshakeResponse hsresp = new JsrHandshakeResponse(resp);
// Get raw config, as defined when the endpoint was added to the container
ServerEndpointConfig config = metadata.getConfig();
// Establish a copy of the config, so that the UserProperties are unique
// per upgrade request.
config = new BasicServerEndpointConfig(config);
// Get Configurator from config object (not guaranteed to be unique per endpoint upgrade)
ServerEndpointConfig.Configurator configurator = config.getConfigurator();
// modify handshake

View File

@ -18,12 +18,16 @@
package org.eclipse.jetty.websocket.jsr356.server;
import static org.hamcrest.Matchers.*;
import java.net.URI;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import javax.websocket.Extension;
import javax.websocket.HandshakeResponse;
import javax.websocket.OnMessage;
@ -49,9 +53,6 @@ import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
public class ConfiguratorTest
{
private static final Logger LOG = Log.getLogger(ConfiguratorTest.class);
@ -161,6 +162,48 @@ public class ConfiguratorTest
return response.toString();
}
}
public static class UniqueUserPropsConfigurator extends ServerEndpointConfig.Configurator
{
private AtomicInteger upgradeCount = new AtomicInteger(0);
@Override
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response)
{
int upgradeNum = upgradeCount.addAndGet(1);
LOG.debug("Upgrade Num: {}", upgradeNum);
sec.getUserProperties().put("upgradeNum",Integer.toString(upgradeNum));
switch(upgradeNum) {
case 1: sec.getUserProperties().put("apple", "fruit from tree"); break;
case 2: sec.getUserProperties().put("blueberry", "fruit from bush"); break;
case 3: sec.getUserProperties().put("strawberry", "fruit from annual"); break;
default: sec.getUserProperties().put("fruit"+upgradeNum, "placeholder"); break;
}
super.modifyHandshake(sec,request,response);
}
}
@ServerEndpoint(value = "/unique-user-props", configurator = UniqueUserPropsConfigurator.class)
public static class UniqueUserPropsSocket
{
@OnMessage
public String onMessage(Session session, String msg)
{
String value = (String)session.getUserProperties().get(msg);
StringBuilder response = new StringBuilder();
response.append("Requested User Property: [").append(msg).append("] = ");
if (value == null)
{
response.append("<null>");
}
else
{
response.append('"').append(value).append('"');
}
return response.toString();
}
}
private static Server server;
private static URI baseServerUri;
@ -182,6 +225,7 @@ public class ConfiguratorTest
container.addEndpoint(EmptySocket.class);
container.addEndpoint(NoExtensionsSocket.class);
container.addEndpoint(ProtocolsSocket.class);
container.addEndpoint(UniqueUserPropsSocket.class);
server.start();
String host = connector.getHost();
@ -250,6 +294,43 @@ public class ConfiguratorTest
}
}
@Test
public void testUniqueUserPropsConfigurator() throws Exception
{
URI uri = baseServerUri.resolve("/unique-user-props");
// First request
try (BlockheadClient client = new BlockheadClient(uri))
{
client.connect();
client.sendStandardRequest();
client.expectUpgradeResponse();
client.write(new TextFrame().setPayload("apple"));
EventQueue<WebSocketFrame> frames = client.readFrames(1,1,TimeUnit.SECONDS);
WebSocketFrame frame = frames.poll();
Assert.assertThat("Frame Response", frame.getPayloadAsUTF8(), is("Requested User Property: [apple] = \"fruit from tree\""));
}
// Second request
try (BlockheadClient client = new BlockheadClient(uri))
{
client.connect();
client.sendStandardRequest();
client.expectUpgradeResponse();
client.write(new TextFrame().setPayload("apple"));
client.write(new TextFrame().setPayload("blueberry"));
EventQueue<WebSocketFrame> frames = client.readFrames(2,1,TimeUnit.SECONDS);
WebSocketFrame frame = frames.poll();
// should have no value
Assert.assertThat("Frame Response", frame.getPayloadAsUTF8(), is("Requested User Property: [apple] = <null>"));
frame = frames.poll();
Assert.assertThat("Frame Response", frame.getPayloadAsUTF8(), is("Requested User Property: [blueberry] = \"fruit from bush\""));
}
}
/**
* Test of Sec-WebSocket-Protocol, as seen in RFC-6455, 1 protocol
*/