433793 - WebSocket / empty protocol list in ServerEndpointConfig.Configurator when using non-exact header name
+ Marking header (and parameter) maps as case-insensitive.
This commit is contained in:
parent
8e957b5a23
commit
5635f02235
|
@ -25,6 +25,7 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import javax.websocket.Extension;
|
import javax.websocket.Extension;
|
||||||
import javax.websocket.HandshakeResponse;
|
import javax.websocket.HandshakeResponse;
|
||||||
|
@ -130,6 +131,38 @@ public class ConfiguratorTest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class ProtocolsConfigurator extends ServerEndpointConfig.Configurator
|
||||||
|
{
|
||||||
|
public static AtomicReference<String> seenProtocols = new AtomicReference<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response)
|
||||||
|
{
|
||||||
|
super.modifyHandshake(sec,request,response);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNegotiatedSubprotocol(List<String> supported, List<String> requested)
|
||||||
|
{
|
||||||
|
LOG.warn(new Throwable());
|
||||||
|
String seen = QuoteUtil.join(requested,",");
|
||||||
|
seenProtocols.compareAndSet(null,seen);
|
||||||
|
return super.getNegotiatedSubprotocol(supported,requested);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ServerEndpoint(value = "/protocols", configurator = ProtocolsConfigurator.class)
|
||||||
|
public static class ProtocolsSocket
|
||||||
|
{
|
||||||
|
@OnMessage
|
||||||
|
public String onMessage(Session session, String msg)
|
||||||
|
{
|
||||||
|
StringBuilder response = new StringBuilder();
|
||||||
|
response.append("Requested Protocols: [").append(ProtocolsConfigurator.seenProtocols.get()).append("]");
|
||||||
|
return response.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static Server server;
|
private static Server server;
|
||||||
private static URI baseServerUri;
|
private static URI baseServerUri;
|
||||||
|
|
||||||
|
@ -149,6 +182,7 @@ public class ConfiguratorTest
|
||||||
container.addEndpoint(CaptureHeadersSocket.class);
|
container.addEndpoint(CaptureHeadersSocket.class);
|
||||||
container.addEndpoint(EmptySocket.class);
|
container.addEndpoint(EmptySocket.class);
|
||||||
container.addEndpoint(NoExtensionsSocket.class);
|
container.addEndpoint(NoExtensionsSocket.class);
|
||||||
|
container.addEndpoint(ProtocolsSocket.class);
|
||||||
|
|
||||||
server.start();
|
server.start();
|
||||||
String host = connector.getHost();
|
String host = connector.getHost();
|
||||||
|
@ -215,4 +249,96 @@ public class ConfiguratorTest
|
||||||
Assert.assertThat("Frame Response", frame.getPayloadAsUTF8(), is("Request Header [X-Dummy]: \"Bogus\""));
|
Assert.assertThat("Frame Response", frame.getPayloadAsUTF8(), is("Request Header [X-Dummy]: \"Bogus\""));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of Sec-WebSocket-Protocol, as seen in RFC-6455, 1 protocol
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testProtocol_Single() throws Exception
|
||||||
|
{
|
||||||
|
URI uri = baseServerUri.resolve("/protocols");
|
||||||
|
ProtocolsConfigurator.seenProtocols.set(null);
|
||||||
|
|
||||||
|
try (BlockheadClient client = new BlockheadClient(uri))
|
||||||
|
{
|
||||||
|
client.addHeader("Sec-WebSocket-Protocol: echo\r\n");
|
||||||
|
client.connect();
|
||||||
|
client.sendStandardRequest();
|
||||||
|
client.expectUpgradeResponse();
|
||||||
|
|
||||||
|
client.write(new TextFrame().setPayload("getProtocols"));
|
||||||
|
EventQueue<WebSocketFrame> frames = client.readFrames(1,1,TimeUnit.SECONDS);
|
||||||
|
WebSocketFrame frame = frames.poll();
|
||||||
|
Assert.assertThat("Frame Response", frame.getPayloadAsUTF8(), is("Requested Protocols: [\"echo\"]"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of Sec-WebSocket-Protocol, as seen in RFC-6455, 3 protocols
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testProtocol_Triple() throws Exception
|
||||||
|
{
|
||||||
|
URI uri = baseServerUri.resolve("/protocols");
|
||||||
|
ProtocolsConfigurator.seenProtocols.set(null);
|
||||||
|
|
||||||
|
try (BlockheadClient client = new BlockheadClient(uri))
|
||||||
|
{
|
||||||
|
client.addHeader("Sec-WebSocket-Protocol: echo, chat, status\r\n");
|
||||||
|
client.connect();
|
||||||
|
client.sendStandardRequest();
|
||||||
|
client.expectUpgradeResponse();
|
||||||
|
|
||||||
|
client.write(new TextFrame().setPayload("getProtocols"));
|
||||||
|
EventQueue<WebSocketFrame> frames = client.readFrames(1,1,TimeUnit.SECONDS);
|
||||||
|
WebSocketFrame frame = frames.poll();
|
||||||
|
Assert.assertThat("Frame Response", frame.getPayloadAsUTF8(), is("Requested Protocols: [\"echo\",\"chat\",\"status\"]"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of Sec-WebSocket-Protocol, using all lowercase header
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testProtocol_LowercaseHeader() throws Exception
|
||||||
|
{
|
||||||
|
URI uri = baseServerUri.resolve("/protocols");
|
||||||
|
ProtocolsConfigurator.seenProtocols.set(null);
|
||||||
|
|
||||||
|
try (BlockheadClient client = new BlockheadClient(uri))
|
||||||
|
{
|
||||||
|
client.addHeader("sec-websocket-protocol: echo, chat, status\r\n");
|
||||||
|
client.connect();
|
||||||
|
client.sendStandardRequest();
|
||||||
|
client.expectUpgradeResponse();
|
||||||
|
|
||||||
|
client.write(new TextFrame().setPayload("getProtocols"));
|
||||||
|
EventQueue<WebSocketFrame> frames = client.readFrames(1,1,TimeUnit.SECONDS);
|
||||||
|
WebSocketFrame frame = frames.poll();
|
||||||
|
Assert.assertThat("Frame Response", frame.getPayloadAsUTF8(), is("Requested Protocols: [\"echo\",\"chat\",\"status\"]"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of Sec-WebSocket-Protocol, using non-spec case header
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testProtocol_AltHeaderCase() throws Exception
|
||||||
|
{
|
||||||
|
URI uri = baseServerUri.resolve("/protocols");
|
||||||
|
ProtocolsConfigurator.seenProtocols.set(null);
|
||||||
|
|
||||||
|
try (BlockheadClient client = new BlockheadClient(uri))
|
||||||
|
{
|
||||||
|
client.addHeader("Sec-Websocket-Protocol: echo, chat, status\r\n");
|
||||||
|
client.connect();
|
||||||
|
client.sendStandardRequest();
|
||||||
|
client.expectUpgradeResponse();
|
||||||
|
|
||||||
|
client.write(new TextFrame().setPayload("getProtocols"));
|
||||||
|
EventQueue<WebSocketFrame> frames = client.readFrames(1,1,TimeUnit.SECONDS);
|
||||||
|
WebSocketFrame frame = frames.poll();
|
||||||
|
Assert.assertThat("Frame Response", frame.getPayloadAsUTF8(), is("Requested Protocols: [\"echo\",\"chat\",\"status\"]"));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,8 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
import javax.servlet.AsyncContext;
|
import javax.servlet.AsyncContext;
|
||||||
import javax.servlet.DispatcherType;
|
import javax.servlet.DispatcherType;
|
||||||
import javax.servlet.RequestDispatcher;
|
import javax.servlet.RequestDispatcher;
|
||||||
|
@ -68,8 +70,8 @@ public class UpgradeHttpServletRequest implements HttpServletRequest
|
||||||
private final String remoteUser;
|
private final String remoteUser;
|
||||||
private final Principal principal;
|
private final Principal principal;
|
||||||
|
|
||||||
private final Map<String, List<String>> headers = new HashMap<>(8);
|
private final Map<String, List<String>> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||||
private final Map<String, String[]> parameters = new HashMap<>(2);
|
private final Map<String, String[]> parameters = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||||
private final Map<String, Object> attributes = new HashMap<>(2);
|
private final Map<String, Object> attributes = new HashMap<>(2);
|
||||||
private final List<Locale> locales = new ArrayList<>(2);
|
private final List<Locale> locales = new ArrayList<>(2);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue