416763 - WebSocket / Jsr Session.getPathParameters() is empty
+ Ensuring this works as intended with new test case
This commit is contained in:
parent
714bbf943a
commit
50d98ab527
|
@ -89,6 +89,7 @@ public class JsrSession extends WebSocketSession implements javax.websocket.Sess
|
|||
this.messageHandlerFactory = new MessageHandlerFactory();
|
||||
this.wrappers = new MessageHandlerWrapper[MessageType.values().length];
|
||||
this.messageHandlerSet = new HashSet<>();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -51,37 +51,64 @@ public class AnnotatedServerEndpointConfig implements ServerEndpointConfig
|
|||
|
||||
public AnnotatedServerEndpointConfig(Class<?> endpointClass, ServerEndpoint anno, ServerEndpointConfig baseConfig) throws DeploymentException
|
||||
{
|
||||
List<Class<? extends Decoder>> compositeDecoders = new ArrayList<>();
|
||||
List<Class<? extends Encoder>> compositeEncoders = new ArrayList<>();
|
||||
List<String> compositeSubProtocols = new ArrayList<>();
|
||||
|
||||
Configurator configr = null;
|
||||
|
||||
// Copy from base config
|
||||
if (baseConfig != null)
|
||||
{
|
||||
compositeDecoders.addAll(baseConfig.getDecoders());
|
||||
compositeEncoders.addAll(baseConfig.getEncoders());
|
||||
compositeSubProtocols.addAll(baseConfig.getSubprotocols());
|
||||
configr = baseConfig.getConfigurator();
|
||||
}
|
||||
|
||||
// now add from annotations
|
||||
compositeDecoders.addAll(Arrays.asList(anno.decoders()));
|
||||
compositeEncoders.addAll(Arrays.asList(anno.encoders()));
|
||||
compositeSubProtocols.addAll(Arrays.asList(anno.subprotocols()));
|
||||
// Decoders (favor provided config over annotation)
|
||||
if (baseConfig != null && baseConfig.getDecoders() != null && baseConfig.getDecoders().size() > 0)
|
||||
{
|
||||
this.decoders = Collections.unmodifiableList(baseConfig.getDecoders());
|
||||
}
|
||||
else
|
||||
{
|
||||
this.decoders = Collections.unmodifiableList(Arrays.asList(anno.decoders()));
|
||||
}
|
||||
|
||||
// Create unmodifiable lists
|
||||
this.decoders = Collections.unmodifiableList(compositeDecoders);
|
||||
this.encoders = Collections.unmodifiableList(compositeEncoders);
|
||||
this.subprotocols = Collections.unmodifiableList(compositeSubProtocols);
|
||||
// Encoders (favor provided config over annotation)
|
||||
if (baseConfig != null && baseConfig.getEncoders() != null && baseConfig.getEncoders().size() > 0)
|
||||
{
|
||||
this.encoders = Collections.unmodifiableList(baseConfig.getEncoders());
|
||||
}
|
||||
else
|
||||
{
|
||||
this.encoders = Collections.unmodifiableList(Arrays.asList(anno.encoders()));
|
||||
}
|
||||
|
||||
// Sub Protocols (favor provided config over annotation)
|
||||
if (baseConfig != null && baseConfig.getSubprotocols() != null && baseConfig.getSubprotocols().size() > 0)
|
||||
{
|
||||
this.subprotocols = Collections.unmodifiableList(baseConfig.getSubprotocols());
|
||||
}
|
||||
else
|
||||
{
|
||||
this.subprotocols = Collections.unmodifiableList(Arrays.asList(anno.subprotocols()));
|
||||
}
|
||||
|
||||
// Path (favor provided config over annotation)
|
||||
if (baseConfig != null && baseConfig.getPath() != null && baseConfig.getPath().length() > 0)
|
||||
{
|
||||
this.path = baseConfig.getPath();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.path = anno.value();
|
||||
}
|
||||
|
||||
// supplied by init lifecycle
|
||||
this.extensions = new ArrayList<>();
|
||||
this.path = anno.value();
|
||||
// always what is passed in
|
||||
this.endpointClass = endpointClass;
|
||||
// no userProperties in annotation
|
||||
// UserProperties in annotation
|
||||
this.userProperties = new HashMap<>();
|
||||
if (baseConfig != null && baseConfig.getUserProperties() != null && baseConfig.getUserProperties().size() > 0)
|
||||
{
|
||||
userProperties.putAll(baseConfig.getUserProperties());
|
||||
}
|
||||
|
||||
if (anno.configurator() == null)
|
||||
{
|
||||
|
|
|
@ -91,7 +91,6 @@ public class ServerContainer extends ClientContainer implements javax.websocket.
|
|||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("addEndpoint({}) path={} endpoint={}",config,config.getPath(),config.getEndpointClass());
|
||||
LOG.debug("Occurred from stack",new Throwable("stack"));
|
||||
}
|
||||
ServerEndpointMetadata metadata = getServerEndpointMetadata(config.getEndpointClass(),config);
|
||||
addEndpoint(metadata);
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2013 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 java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.websocket.Endpoint;
|
||||
import javax.websocket.server.ServerApplicationConfig;
|
||||
import javax.websocket.server.ServerEndpointConfig;
|
||||
|
||||
public class SessionAltConfig implements ServerApplicationConfig
|
||||
{
|
||||
@Override
|
||||
public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> endpointClasses)
|
||||
{
|
||||
Set<ServerEndpointConfig> configs = new HashSet<>();
|
||||
Class<?> endpointClass = SessionInfoSocket.class;
|
||||
configs.add(ServerEndpointConfig.Builder.create(endpointClass,"/info/{a}/").build());
|
||||
configs.add(ServerEndpointConfig.Builder.create(endpointClass,"/info/{a}/{b}/").build());
|
||||
configs.add(ServerEndpointConfig.Builder.create(endpointClass,"/info/{a}/{b}/{c}/").build());
|
||||
configs.add(ServerEndpointConfig.Builder.create(endpointClass,"/info/{a}/{b}/{c}/{d}/").build());
|
||||
return configs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scanned)
|
||||
{
|
||||
Set<Class<?>> annotated = new HashSet<>();
|
||||
annotated.add(SessionInfoSocket.class);
|
||||
return annotated;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2013 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 java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.websocket.OnMessage;
|
||||
import javax.websocket.Session;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
|
||||
@ServerEndpoint(value = "/info/")
|
||||
public class SessionInfoSocket
|
||||
{
|
||||
@OnMessage
|
||||
public String onMessage(Session session, String message)
|
||||
{
|
||||
if ("pathParams".equalsIgnoreCase(message))
|
||||
{
|
||||
StringBuilder ret = new StringBuilder();
|
||||
ret.append("pathParams");
|
||||
Map<String, String> pathParams = session.getPathParameters();
|
||||
if (pathParams == null)
|
||||
{
|
||||
ret.append("=<null>");
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.append('[').append(pathParams.size()).append(']');
|
||||
List<String> keys = new ArrayList<>();
|
||||
for (String key : pathParams.keySet())
|
||||
{
|
||||
keys.add(key);
|
||||
}
|
||||
Collections.sort(keys);
|
||||
for (String key : keys)
|
||||
{
|
||||
String value = pathParams.get(key);
|
||||
ret.append(": '").append(key).append("'=").append(value);
|
||||
}
|
||||
}
|
||||
return ret.toString();
|
||||
}
|
||||
|
||||
// simple echo
|
||||
return "echo:'" + message + "'";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2013 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 static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
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.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SessionTest
|
||||
{
|
||||
private static WSServer server;
|
||||
private static URI serverUri;
|
||||
|
||||
@BeforeClass
|
||||
public static void startServer() throws Exception
|
||||
{
|
||||
server = new WSServer(MavenTestingUtils.getTargetTestingDir(SessionTest.class.getSimpleName()),"app");
|
||||
server.copyWebInf("empty-web.xml");
|
||||
server.copyClass(SessionInfoSocket.class);
|
||||
server.copyClass(SessionAltConfig.class);
|
||||
server.start();
|
||||
serverUri = server.getServerBaseURI();
|
||||
|
||||
WebAppContext webapp = server.createWebAppContext();
|
||||
server.deployWebapp(webapp);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopServer()
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
|
||||
private void assertPathParams(String requestPath, String expectedResponse) throws Exception
|
||||
{
|
||||
WebSocketClient client = new WebSocketClient();
|
||||
try
|
||||
{
|
||||
client.start();
|
||||
JettyEchoSocket clientEcho = new JettyEchoSocket();
|
||||
Future<Session> future = client.connect(clientEcho,serverUri.resolve(requestPath));
|
||||
// wait for connect
|
||||
future.get(1,TimeUnit.SECONDS);
|
||||
clientEcho.sendMessage("pathParams");
|
||||
Queue<String> msgs = clientEcho.awaitMessages(1);
|
||||
Assert.assertThat("Expected message",msgs.poll(),is(expectedResponse));
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathParams_Empty() throws Exception
|
||||
{
|
||||
assertPathParams("info/","pathParams[0]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathParams_Single() throws Exception
|
||||
{
|
||||
assertPathParams("info/apple/","pathParams[1]: 'a'=apple");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathParams_Double() throws Exception
|
||||
{
|
||||
assertPathParams("info/apple/pear/","pathParams[2]: 'a'=apple: 'b'=pear");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathParams_Triple() throws Exception
|
||||
{
|
||||
assertPathParams("info/apple/pear/cherry/","pathParams[3]: 'a'=apple: 'b'=pear: 'c'=cherry");
|
||||
}
|
||||
}
|
|
@ -27,9 +27,6 @@ import java.util.Map;
|
|||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.util.MultiMap;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.UrlEncoded;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
|
@ -86,22 +83,6 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Inc
|
|||
this.incomingHandler = websocket;
|
||||
|
||||
this.connection.getIOState().addListener(this);
|
||||
|
||||
// Get the parameter map (use the jetty MultiMap to do this right)
|
||||
MultiMap<String> params = new MultiMap<>();
|
||||
String query = requestURI.getQuery();
|
||||
if (StringUtil.isNotBlank(query))
|
||||
{
|
||||
UrlEncoded.decodeTo(query,params,StringUtil.__UTF8_CHARSET,-1);
|
||||
}
|
||||
|
||||
for (String name : params.keySet())
|
||||
{
|
||||
List<String> valueList = params.getValues(name);
|
||||
String valueArr[] = new String[valueList.size()];
|
||||
valueArr = valueList.toArray(valueArr);
|
||||
parameterMap.put(name,valueArr);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -428,6 +409,22 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Inc
|
|||
{
|
||||
this.upgradeRequest = request;
|
||||
this.protocolVersion = request.getProtocolVersion();
|
||||
this.parameterMap.clear();
|
||||
if (request.getParameterMap() != null)
|
||||
{
|
||||
for (Map.Entry<String, List<String>> entry : request.getParameterMap().entrySet())
|
||||
{
|
||||
List<String> values = entry.getValue();
|
||||
if (values != null)
|
||||
{
|
||||
this.parameterMap.put(entry.getKey(),values.toArray(new String[values.size()]));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.parameterMap.put(entry.getKey(),new String[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setUpgradeResponse(UpgradeResponse response)
|
||||
|
|
Loading…
Reference in New Issue