393473 - Add support for JSR-356 (javax.websocket) draft

+ Restarting branch, copying over work from November with new JSR-356
   Draft 012 api in mind.
This commit is contained in:
Joakim Erdfelt 2013-02-12 16:19:35 -07:00
parent 9ae3c94b22
commit 43231d8451
38 changed files with 1029 additions and 87 deletions

View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-parent</artifactId>
<version>9.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>javax-websocket-client-impl</artifactId>
<name>Jetty :: Websocket :: javax.websocket :: Client Implementation</name>
<properties>
<bundle-symbolic-name>${project.groupId}.javax.websocket</bundle-symbolic-name>
</properties>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.drafts</groupId>
<artifactId>javax.websocket-client-api</artifactId>
<version>0.0.012.draft-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-test-helper</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<id>ban-java-servlet-api</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<bannedDependencies>
<includes>
<include>javax.servlet</include>
<include>servletapi</include>
<include>org.eclipse.jetty.orbit:javax.servlet</include>
<include>org.mortbay.jetty:servlet-api</include>
<include>jetty:servlet-api</include>
</includes>
</bannedDependencies>
</rules>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,115 @@
//
// ========================================================================
// 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;
import java.net.URI;
import java.util.Set;
import javax.websocket.ClientEndpointConfiguration;
import javax.websocket.DeploymentException;
import javax.websocket.Endpoint;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
public class JettyWebSocketContainer implements WebSocketContainer
{
@Override
public Session connectToServer(Class<? extends Endpoint> endpointClass, ClientEndpointConfiguration cec, URI path) throws DeploymentException
{
// TODO Auto-generated method stub
return null;
}
@Override
public Session connectToServer(Class<?> annotatedEndpointClass, URI path) throws DeploymentException
{
// TODO Auto-generated method stub
return null;
}
@Override
public long getDefaultAsyncSendTimeout()
{
// TODO Auto-generated method stub
return 0;
}
@Override
public int getDefaultMaxBinaryMessageBufferSize()
{
// TODO Auto-generated method stub
return 0;
}
@Override
public int getDefaultMaxTextMessageBufferSize()
{
// TODO Auto-generated method stub
return 0;
}
@Override
public Set<String> getInstalledExtensions()
{
// TODO Auto-generated method stub
return null;
}
@Override
public long getMaxSessionIdleTimeout()
{
// TODO Auto-generated method stub
return 0;
}
@Override
public void setAsyncSendTimeout(long timeoutmillis)
{
// TODO Auto-generated method stub
}
@Override
public void setDefaultMaxBinaryMessageBufferSize(int max)
{
// TODO Auto-generated method stub
}
@Override
public void setDefaultMaxTextMessageBufferSize(int max)
{
// TODO Auto-generated method stub
}
@Override
public void setMaxSessionIdleTimeout(long timeout)
{
// TODO Auto-generated method stub
}
@Override
public void setMaxTextMessageBufferSize(long max)
{
// TODO Auto-generated method stub
}
}

View File

@ -0,0 +1,43 @@
//
// ========================================================================
// 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;
import javax.websocket.ContainerProvider;
import javax.websocket.WebSocketContainer;
public class JsrContainerProvider extends ContainerProvider
{
private final JettyWebSocketContainer websocketContainer;
public JsrContainerProvider()
{
websocketContainer = new JettyWebSocketContainer();
}
@SuppressWarnings("unchecked")
@Override
protected <T> T getContainer(Class<T> containerClass)
{
if (WebSocketContainer.class.isAssignableFrom(containerClass))
{
return (T)websocketContainer;
}
return null;
}
}

View File

@ -0,0 +1,82 @@
//
// ========================================================================
// 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;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.websocket.Extension;
import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
public class JsrExtension implements Extension
{
private static class JsrParameter implements Extension.Parameter
{
private String name;
private String value;
private JsrParameter(String key, String value)
{
this.name = key;
this.value = value;
}
@Override
public String getName()
{
return this.name;
}
@Override
public String getValue()
{
return this.value;
}
}
private final String name;
private List<Parameter> parameters;
public JsrExtension(ExtensionConfig cfg)
{
this.name = cfg.getName();
this.parameters = new ArrayList<>();
if (cfg.getParameters() != null)
{
for (Map.Entry<String, String> entry : cfg.getParameters().entrySet())
{
parameters.add(new JsrParameter(entry.getKey(), entry.getValue()));
}
}
}
@Override
public String getName()
{
return name;
}
@Override
public List<Parameter> getParameters()
{
return parameters;
}
}

View File

@ -0,0 +1,173 @@
//
// ========================================================================
// 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;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.nio.ByteBuffer;
import java.util.concurrent.Future;
import javax.websocket.EncodeException;
import javax.websocket.RemoteEndpoint;
import javax.websocket.SendHandler;
import javax.websocket.SendResult;
public class JsrRemoteEndpoint implements RemoteEndpoint
{
private final org.eclipse.jetty.websocket.api.RemoteEndpoint jettyRemote;
protected JsrRemoteEndpoint(org.eclipse.jetty.websocket.api.RemoteEndpoint endpoint)
{
this.jettyRemote = endpoint;
}
@Override
public void flushBatch() throws IOException
{
// TODO Auto-generated method stub
}
@Override
public long getAsyncSendTimeout()
{
// TODO Auto-generated method stub
return 0;
}
@Override
public boolean getBatchingAllowed()
{
// TODO Auto-generated method stub
return false;
}
@Override
public OutputStream getSendStream() throws IOException
{
// TODO Auto-generated method stub
return null;
}
@Override
public Writer getSendWriter() throws IOException
{
// TODO Auto-generated method stub
return null;
}
@Override
public void sendBytes(ByteBuffer data) throws IOException
{
jettyRemote.sendBytes(data);
}
@Override
public void sendBytesByCompletion(ByteBuffer data, SendHandler completion)
{
// TODO Auto-generated method stub
}
@Override
public Future<SendResult> sendBytesByFuture(ByteBuffer data)
{
Future<Void> jettyFuture = jettyRemote.sendBytesByFuture(data);
return new JsrSendResultFuture(jettyFuture);
}
@Override
public void sendObject(Object o) throws IOException, EncodeException
{
// TODO Auto-generated method stub
}
@Override
public void sendObjectByCompletion(Object o, SendHandler handler)
{
// TODO Auto-generated method stub
}
@Override
public Future<SendResult> sendObjectByFuture(Object o)
{
// TODO Auto-generated method stub
return null;
}
@Override
public void sendPartialBytes(ByteBuffer partialByte, boolean isLast) throws IOException
{
jettyRemote.sendPartialBytes(partialByte,isLast);
}
@Override
public void sendPartialString(String partialMessage, boolean isLast) throws IOException
{
jettyRemote.sendPartialString(partialMessage,isLast);
}
@Override
public void sendPing(ByteBuffer applicationData) throws IOException, IllegalArgumentException
{
jettyRemote.sendPing(applicationData);
}
@Override
public void sendPong(ByteBuffer applicationData) throws IOException, IllegalArgumentException
{
jettyRemote.sendPong(applicationData);
}
@Override
public void sendString(String text) throws IOException
{
jettyRemote.sendString(text);
}
@Override
public void sendStringByCompletion(String text, SendHandler completion)
{
// TODO Auto-generated method stub
}
@Override
public Future<SendResult> sendStringByFuture(String text)
{
Future<Void> jettyFuture = jettyRemote.sendStringByFuture(text);
return new JsrSendResultFuture(jettyFuture);
}
@Override
public void setAsyncSendTimeout(long timeoutmillis)
{
// TODO Auto-generated method stub
}
@Override
public void setBatchingAllowed(boolean allowed)
{
// TODO Auto-generated method stub
}
}

View File

@ -0,0 +1,71 @@
//
// ========================================================================
// 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;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.websocket.SendResult;
public class JsrSendResultFuture implements Future<SendResult>
{
private final Future<Void> jettyFuture;
public JsrSendResultFuture(Future<Void> jettyFuture)
{
this.jettyFuture = jettyFuture;
}
@Override
public boolean cancel(boolean mayInterruptIfRunning)
{
// TODO Auto-generated method stub
return false;
}
@Override
public boolean isCancelled()
{
// TODO Auto-generated method stub
return false;
}
@Override
public boolean isDone()
{
// TODO Auto-generated method stub
return false;
}
@Override
public SendResult get() throws InterruptedException, ExecutionException
{
// TODO Auto-generated method stub
return null;
}
@Override
public SendResult get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
{
// TODO Auto-generated method stub
return null;
}
}

View File

@ -0,0 +1,232 @@
//
// ========================================================================
// 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;
import java.io.IOException;
import java.net.URI;
import java.security.Principal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.websocket.CloseReason;
import javax.websocket.Extension;
import javax.websocket.MessageHandler;
import javax.websocket.RemoteEndpoint;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
import org.eclipse.jetty.websocket.common.WebSocketSession;
public class JsrSession implements Session
{
private final JettyWebSocketContainer container;
/** Jetty API Session Impl */
private final WebSocketSession jettySession;
private final String id;
private List<Extension> negotiatedExtensions;
private Map<String, List<String>> jsrParameterMap;
private JsrRemoteEndpoint remote;
protected JsrSession(JettyWebSocketContainer container, WebSocketSession session, String id)
{
this.container = container;
this.jettySession = session;
this.id = id;
}
@Override
public void addMessageHandler(MessageHandler listener) throws IllegalStateException
{
// TODO Auto-generated method stub
}
@Override
public void close(CloseReason closeStatus) throws IOException
{
jettySession.close(closeStatus.getCloseCode().getCode(),closeStatus.getReasonPhrase());
}
@Override
public WebSocketContainer getContainer()
{
return this.container;
}
@Override
public String getId()
{
return this.id;
}
@Override
public int getMaxBinaryMessageBufferSize()
{
return jettySession.getPolicy().getMaxBinaryMessageSize();
}
@Override
public int getMaxTextMessageBufferSize()
{
return jettySession.getPolicy().getMaxTextMessageSize();
}
@Override
public Set<MessageHandler> getMessageHandlers()
{
// TODO Auto-generated method stub
return null;
}
@Override
public List<Extension> getNegotiatedExtensions()
{
if (negotiatedExtensions == null)
{
negotiatedExtensions = new ArrayList<Extension>();
for (ExtensionConfig cfg : jettySession.getUpgradeResponse().getExtensions())
{
negotiatedExtensions.add(new JsrExtension(cfg));
}
}
return negotiatedExtensions;
}
@Override
public String getNegotiatedSubprotocol()
{
return jettySession.getUpgradeResponse().getAcceptedSubProtocol();
}
@Override
public Set<Session> getOpenSessions()
{
// TODO Auto-generated method stub
return null;
}
@Override
public Map<String, String> getPathParameters()
{
// TODO Auto-generated method stub
return null;
}
@Override
public String getQueryString()
{
return jettySession.getUpgradeRequest().getRequestURI().getQuery();
}
@Override
public Map<String, List<String>> getRequestParameterMap()
{
return jettySession.getUpgradeRequest().getParameterMap();
}
@Override
public URI getRequestURI()
{
return jettySession.getUpgradeRequest().getRequestURI();
}
@Override
public long getTimeout()
{
return jettySession.getIdleTimeout();
}
@Override
public Principal getUserPrincipal()
{
// TODO Auto-generated method stub
return null;
}
@Override
public Map<String, Object> getUserProperties()
{
// TODO Auto-generated method stub
return null;
}
@Override
public void removeMessageHandler(MessageHandler handler)
{
// TODO Auto-generated method stub
}
@Override
public void setMaxBinaryMessageBufferSize(int length)
{
// TODO Auto-generated method stub
}
@Override
public void setMaxTextMessageBufferSize(int length)
{
// TODO Auto-generated method stub
}
@Override
public void setTimeout(long milliseconds)
{
jettySession.setIdleTimeout(milliseconds);
}
@Override
public void close() throws IOException
{
jettySession.close();
}
@Override
public String getProtocolVersion()
{
return jettySession.getProtocolVersion();
}
@Override
public RemoteEndpoint getRemote()
{
if (remote == null)
{
remote = new JsrRemoteEndpoint(jettySession.getRemote());
}
return remote;
}
@Override
public boolean isOpen()
{
return jettySession.isOpen();
}
@Override
public boolean isSecure()
{
return jettySession.isSecure();
}
}

View File

@ -0,0 +1 @@
org.eclipse.jetty.websocket.jsr356.JettyContainerProvider

View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-parent</artifactId>
<version>9.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>javax-websocket-server-impl</artifactId>
<name>Jetty :: Websocket :: javax.websocket.server :: Server Implementation</name>
<properties>
<bundle-symbolic-name>${project.groupId}.javax.websocket.server</bundle-symbolic-name>
</properties>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>javax-websocket-client-impl</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.drafts</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>0.0.012.draft-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-test-helper</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<id>ban-java-servlet-api</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<bannedDependencies>
<includes>
<include>javax.servlet</include>
<include>servletapi</include>
<include>org.eclipse.jetty.orbit:javax.servlet</include>
<include>org.mortbay.jetty:servlet-api</include>
<include>jetty:servlet-api</include>
</includes>
</bannedDependencies>
</rules>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -18,6 +18,8 @@
<module>websocket-client</module>
<module>websocket-server</module>
<module>websocket-servlet</module>
<module>javax-websocket-client-impl</module>
<module>javax-websocket-server-impl</module>
</modules>
<build>

View File

@ -106,13 +106,6 @@ public interface Session extends Closeable
*/
public InetSocketAddress getLocalAddress();
/**
* The maximum total length of messages, text or binary, that this Session can handle.
*
* @return the message size
*/
long getMaximumMessageSize();
/**
* Access the (now read-only) {@link WebSocketPolicy} in use for this connection.
*
@ -178,11 +171,6 @@ public interface Session extends Closeable
*/
void setIdleTimeout(long ms);
/**
* Sets the maximum total length of messages, text or binary, that this Session can handle.
*/
void setMaximumMessageSize(long length);
/**
* Suspend a the incoming read events on the connection.
*

View File

@ -36,7 +36,7 @@ public class UpgradeRequest
private List<ExtensionConfig> extensions = new ArrayList<>();
private List<HttpCookie> cookies = new ArrayList<>();
private Map<String, List<String>> headers = new HashMap<>();
private Map<String, String[]> parameters = new HashMap<>();
private Map<String, List<String>> parameters = new HashMap<>();
private Object session;
private String httpVersion;
private String method;
@ -175,7 +175,7 @@ public class UpgradeRequest
*
* @return a unmodifiable map of query parameters of the request.
*/
public Map<String, String[]> getParameterMap()
public Map<String, List<String>> getParameterMap()
{
return Collections.unmodifiableMap(parameters);
}
@ -244,7 +244,7 @@ public class UpgradeRequest
this.method = method;
}
protected void setParameterMap(Map<String, String[]> parameters)
protected void setParameterMap(Map<String, List<String>> parameters)
{
this.parameters.clear();
this.parameters.putAll(parameters);

View File

@ -40,7 +40,14 @@ public class WebSocketPolicy
* <p>
* Default: 65536 (64 K)
*/
private long maxMessageSize = 64 * KB;
private int maxTextMessageSize = 64 * KB;
/**
* The maximum size of a binary message during parsing/generating.
* <p>
* Default: 65536 (64 K)
*/
private int maxBinaryMessageSize = 64 * KB;
/**
* The time in ms (milliseconds) that a websocket may be idle before closing.
@ -66,14 +73,26 @@ public class WebSocketPolicy
this.behavior = behavior;
}
public void assertValidMessageSize(int requestedSize)
public void assertValidBinaryMessageSize(int requestedSize)
{
if (maxMessageSize > 0)
if (maxBinaryMessageSize > 0)
{
// validate it
if (requestedSize > maxMessageSize)
if (requestedSize > maxBinaryMessageSize)
{
throw new MessageTooLargeException("Requested message size [" + requestedSize + "] exceeds maximum size [" + maxMessageSize + "]");
throw new MessageTooLargeException("Binary message size [" + requestedSize + "] exceeds maximum size [" + maxBinaryMessageSize + "]");
}
}
}
public void assertValidTextMessageSize(int requestedSize)
{
if (maxTextMessageSize > 0)
{
// validate it
if (requestedSize > maxTextMessageSize)
{
throw new MessageTooLargeException("Text message size [" + requestedSize + "] exceeds maximum size [" + maxTextMessageSize + "]");
}
}
}
@ -82,7 +101,8 @@ public class WebSocketPolicy
{
WebSocketPolicy clone = new WebSocketPolicy(this.behavior);
clone.idleTimeout = this.idleTimeout;
clone.maxMessageSize = this.maxMessageSize;
clone.maxTextMessageSize = this.maxTextMessageSize;
clone.maxBinaryMessageSize = this.maxBinaryMessageSize;
clone.inputBufferSize = this.inputBufferSize;
return clone;
}
@ -102,9 +122,14 @@ public class WebSocketPolicy
return inputBufferSize;
}
public long getMaxMessageSize()
public int getMaxBinaryMessageSize()
{
return maxMessageSize;
return maxBinaryMessageSize;
}
public int getMaxTextMessageSize()
{
return maxTextMessageSize;
}
public void setIdleTimeout(long idleTimeout)
@ -117,8 +142,13 @@ public class WebSocketPolicy
this.inputBufferSize = inputBufferSize;
}
public void setMaxMessageSize(long maxMessageSize)
public void setMaxBinaryMessageSize(int maxBinaryMessageSize)
{
this.maxMessageSize = maxMessageSize;
this.maxBinaryMessageSize = maxBinaryMessageSize;
}
public void setMaxTextMessageSize(int maxTextMessageSize)
{
this.maxTextMessageSize = maxTextMessageSize;
}
}

View File

@ -35,7 +35,9 @@ public @interface WebSocket
{
int inputBufferSize() default -2;
int maxBinaryMessageSize() default -2;
int maxIdleTime() default -2;
int maxMessageSize() default -2;
int maxTextMessageSize() default -2;
}

View File

@ -21,6 +21,7 @@ package org.eclipse.jetty.websocket.client;
import java.net.CookieStore;
import java.net.HttpCookie;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@ -215,7 +216,7 @@ public class ClientUpgradeRequest extends UpgradeRequest
super.setRequestURI(uri);
// parse parameter map
Map<String, String[]> pmap = new HashMap<>();
Map<String, List<String>> pmap = new HashMap<>();
String query = uri.getQuery();
@ -229,12 +230,14 @@ public class ClientUpgradeRequest extends UpgradeRequest
List<String> values = params.getValues(key);
if (values == null)
{
pmap.put(key,new String[0]);
pmap.put(key,new ArrayList<String>());
}
else
{
int len = values.size();
pmap.put(key,values.toArray(new String[len]));
// break link to original
List<String> copy = new ArrayList<>();
copy.addAll(values);
pmap.put(key,copy);
}
}

View File

@ -22,6 +22,8 @@ import static org.hamcrest.Matchers.*;
import java.net.InetSocketAddress;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
@ -249,15 +251,15 @@ public class WebSocketClientTest
UpgradeRequest req = session.getUpgradeRequest();
Assert.assertThat("Upgrade Request",req,notNullValue());
Map<String, String[]> parameterMap = req.getParameterMap();
Map<String, List<String>> parameterMap = req.getParameterMap();
Assert.assertThat("Parameter Map",parameterMap,notNullValue());
Assert.assertThat("Parameter[snack]",parameterMap.get("snack"),is(new String[]
{ "cashews" }));
Assert.assertThat("Parameter[amount]",parameterMap.get("amount"),is(new String[]
{ "handful" }));
Assert.assertThat("Parameter[brand]",parameterMap.get("brand"),is(new String[]
{ "off" }));
Assert.assertThat("Parameter[snack]",parameterMap.get("snack"),is(Arrays.asList(new String[]
{ "cashews" })));
Assert.assertThat("Parameter[amount]",parameterMap.get("amount"),is(Arrays.asList(new String[]
{ "handful" })));
Assert.assertThat("Parameter[brand]",parameterMap.get("brand"),is(Arrays.asList(new String[]
{ "off" })));
Assert.assertThat("Parameter[cost]",parameterMap.get("cost"),nullValue());
}

View File

@ -37,7 +37,7 @@ import org.eclipse.jetty.websocket.client.WebSocketClient;
*/
public class SimpleEchoClient
{
@WebSocket(maxMessageSize = 64 * 1024)
@WebSocket(maxTextMessageSize = 64 * 1024)
public static class SimpleEchoSocket
{
private final CountDownLatch closeLatch;

View File

@ -57,6 +57,13 @@ public interface LogicalConnection extends OutgoingFrames, SuspendToken
*/
void disconnect();
/**
* Get the read/write idle timeout.
*
* @return the idle timeout in milliseconds
*/
public long getIdleTimeout();
/**
* Get the IOState of the connection.
*
@ -109,6 +116,16 @@ public interface LogicalConnection extends OutgoingFrames, SuspendToken
*/
boolean isReading();
/**
* Set the read/write idle timeout for new operations (in milliseconds)
* <p>
* This idle timeout cannot be garunteed to take immediate effect for any active read/write actions.
* New read/write actions will have this new idle timeout.
*
* @param ms idle timeout in milliseconds
*/
public void setIdleTimeout(long ms);
/**
* Set where the connection should send the incoming frames to.
* <p>

View File

@ -98,7 +98,6 @@ public class Parser
// OMG! Sanity Check! DO NOT WANT! Won't anyone think of the memory!
throw new MessageTooLargeException("[int-sane!] cannot handle payload lengths larger than " + Integer.MAX_VALUE);
}
policy.assertValidMessageSize((int)len);
switch (frame.getOpCode())
{
@ -116,6 +115,12 @@ public class Parser
+ WebSocketFrame.MAX_CONTROL_PAYLOAD + "]");
}
break;
case OpCode.TEXT:
policy.assertValidTextMessageSize((int)len);
break;
case OpCode.BINARY:
policy.assertValidBinaryMessageSize((int)len);
break;
}
}

View File

@ -57,9 +57,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Inc
private final EventDriver websocket;
private final LogicalConnection connection;
private ExtensionFactory extensionFactory;
private long maximumMessageSize;
private String protocolVersion;
private long timeout;
private Map<String, String[]> parameterMap = new HashMap<>();
private WebSocketRemoteEndpoint remote;
private IncomingFrames incomingHandler;
@ -164,13 +162,10 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Inc
return extensionFactory;
}
/**
* The idle timeout in seconds
*/
@Override
public long getIdleTimeout()
{
return timeout;
return connection.getIdleTimeout();
}
@ManagedAttribute(readonly = true)
@ -185,12 +180,6 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Inc
return connection.getLocalAddress();
}
@Override
public long getMaximumMessageSize()
{
return maximumMessageSize;
}
@ManagedAttribute(readonly = true)
public OutgoingFrames getOutgoingHandler()
{
@ -319,19 +308,10 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Inc
this.extensionFactory = extensionFactory;
}
/**
* Set the timeout in seconds
*/
@Override
public void setIdleTimeout(long seconds)
public void setIdleTimeout(long ms)
{
this.timeout = seconds;
}
@Override
public void setMaximumMessageSize(long length)
{
this.maximumMessageSize = length;
connection.setIdleTimeout(ms);
}
public void setOutgoingHandler(OutgoingFrames outgoing)

View File

@ -49,9 +49,13 @@ public class AnnotatedEventDriver extends EventDriver
WebSocket anno = websocket.getClass().getAnnotation(WebSocket.class);
// Setup the policy
if (anno.maxMessageSize() > 0)
if (anno.maxTextMessageSize() > 0)
{
this.policy.setMaxMessageSize(anno.maxMessageSize());
this.policy.setMaxTextMessageSize(anno.maxTextMessageSize());
}
if (anno.maxBinaryMessageSize() > 0)
{
this.policy.setMaxTextMessageSize(anno.maxBinaryMessageSize());
}
if (anno.inputBufferSize() > 0)
{

View File

@ -97,6 +97,13 @@ public class MuxChannel implements LogicalConnection, IncomingFrames, SuspendTok
return channelId;
}
@Override
public long getIdleTimeout()
{
// TODO Auto-generated method stub
return 0;
}
@Override
public IOState getIOState()
{
@ -205,6 +212,13 @@ public class MuxChannel implements LogicalConnection, IncomingFrames, SuspendTok
}
}
@Override
public void setIdleTimeout(long ms)
{
// TODO Auto-generated method stub
}
@Override
public void setNextIncomingFrames(IncomingFrames incoming)
{

View File

@ -314,6 +314,12 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
return generator;
}
@Override
public long getIdleTimeout()
{
return getEndPoint().getIdleTimeout();
}
@Override
public IOState getIOState()
{
@ -517,6 +523,12 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
this.extensions = extensions;
}
@Override
public void setIdleTimeout(long ms)
{
getEndPoint().setIdleTimeout(ms);
}
@Override
public void setInputBufferSize(int inputBufferSize)
{

View File

@ -67,7 +67,7 @@ public class MessageInputStream extends InputStream implements MessageAppender
return;
}
driver.getPolicy().assertValidMessageSize(size + payload.remaining());
driver.getPolicy().assertValidBinaryMessageSize(size + payload.remaining());
size += payload.remaining();
synchronized (buf)

View File

@ -61,7 +61,7 @@ public class MessageReader extends Reader implements MessageAppender
return;
}
driver.getPolicy().assertValidMessageSize(size + payload.remaining());
driver.getPolicy().assertValidTextMessageSize(size + payload.remaining());
size += payload.remaining();
synchronized (utf)

View File

@ -54,7 +54,7 @@ public class SimpleBinaryMessage implements MessageAppender
return;
}
onEvent.getPolicy().assertValidMessageSize(size + payload.remaining());
onEvent.getPolicy().assertValidBinaryMessageSize(size + payload.remaining());
size += payload.remaining();
BufferUtil.writeTo(payload,out);

View File

@ -53,7 +53,7 @@ public class SimpleTextMessage implements MessageAppender
return;
}
onEvent.getPolicy().assertValidMessageSize(size + payload.remaining());
onEvent.getPolicy().assertValidTextMessageSize(size + payload.remaining());
size += payload.remaining();
// allow for fast fail of BAD utf (incomplete utf will trigger on messageComplete)

View File

@ -25,7 +25,7 @@ import org.eclipse.jetty.websocket.api.annotations.WebSocket;
/**
* Example EchoSocket using Annotations.
*/
@WebSocket(maxMessageSize = 64 * 1024)
@WebSocket(maxTextMessageSize = 64 * 1024)
public class AnnotatedEchoSocket
{
@OnWebSocketMessage

View File

@ -38,14 +38,14 @@ public class TextPayloadParserTest
{
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
// Artificially small buffer/payload
policy.setMaxMessageSize(1024);
policy.setMaxTextMessageSize(1024);
byte utf[] = new byte[2048];
Arrays.fill(utf,(byte)'a');
Assert.assertThat("Must be a medium length payload",utf.length,allOf(greaterThan(0x7E),lessThan(0xFFFF)));
ByteBuffer buf = ByteBuffer.allocate(utf.length + 8);
buf.put((byte)0x81);
buf.put((byte)0x81); // text frame, fin = true
buf.put((byte)(0x80 | 0x7E)); // 0x7E == 126 (a 2 byte payload length)
buf.putShort((short)utf.length);
MaskedByteBuffer.putMask(buf);
@ -80,7 +80,7 @@ public class TextPayloadParserTest
Assert.assertThat("Must be a long length payload",utf.length,greaterThan(0xFFFF));
ByteBuffer buf = ByteBuffer.allocate(utf.length + 32);
buf.put((byte)0x81);
buf.put((byte)0x81); // text frame, fin = true
buf.put((byte)(0x80 | 0x7F)); // 0x7F == 127 (a 8 byte payload length)
buf.putLong(utf.length);
MaskedByteBuffer.putMask(buf);
@ -88,7 +88,7 @@ public class TextPayloadParserTest
buf.flip();
WebSocketPolicy policy = WebSocketPolicy.newServerPolicy();
policy.setMaxMessageSize(100000);
policy.setMaxTextMessageSize(100000);
Parser parser = new UnitParser(policy);
IncomingFramesCapture capture = new IncomingFramesCapture();
parser.setIncomingFramesHandler(capture);

View File

@ -451,7 +451,7 @@ public class TestABCase1_1
expected.flip();
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.CLIENT);
policy.setMaxMessageSize(length);
policy.setMaxTextMessageSize(length);
Parser parser = new UnitParser(policy);
IncomingFramesCapture capture = new IncomingFramesCapture();
parser.setIncomingFramesHandler(capture);
@ -488,7 +488,7 @@ public class TestABCase1_1
expected.flip();
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.CLIENT);
policy.setMaxMessageSize(length);
policy.setMaxTextMessageSize(length);
Parser parser = new UnitParser(policy);
IncomingFramesCapture capture = new IncomingFramesCapture();
parser.setIncomingFramesHandler(capture);

View File

@ -466,7 +466,7 @@ public class TestABCase1_2
expected.flip();
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.CLIENT);
policy.setMaxMessageSize(length);
policy.setMaxBinaryMessageSize(length);
Parser parser = new UnitParser(policy);
IncomingFramesCapture capture = new IncomingFramesCapture();
parser.setIncomingFramesHandler(capture);
@ -503,7 +503,7 @@ public class TestABCase1_2
expected.flip();
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.CLIENT);
policy.setMaxMessageSize(length);
policy.setMaxBinaryMessageSize(length);
Parser parser = new UnitParser(policy);
IncomingFramesCapture capture = new IncomingFramesCapture();
parser.setIncomingFramesHandler(capture);

View File

@ -74,6 +74,13 @@ public class LocalWebSocketConnection implements LogicalConnection, IncomingFram
open = false;
}
@Override
public long getIdleTimeout()
{
// TODO Auto-generated method stub
return 0;
}
public IncomingFrames getIncoming()
{
return incoming;
@ -148,6 +155,13 @@ public class LocalWebSocketConnection implements LogicalConnection, IncomingFram
{
}
@Override
public void setIdleTimeout(long ms)
{
// TODO Auto-generated method stub
}
@Override
public void setNextIncomingFrames(IncomingFrames incoming)
{

View File

@ -50,7 +50,15 @@ public class ServletWebSocketRequest extends UpgradeRequest
setHttpVersion(request.getProtocol());
// Copy parameters
super.setParameterMap(request.getParameterMap());
Map<String, List<String>> pmap = new HashMap<>();
if (request.getParameterMap() != null)
{
for (Map.Entry<String, String[]> entry : request.getParameterMap().entrySet())
{
pmap.put(entry.getKey(),Arrays.asList(entry.getValue()));
}
}
super.setParameterMap(pmap);
// Copy Cookies
cookieMap = new HashMap<String, String>();

View File

@ -36,7 +36,8 @@ public class ABServlet extends WebSocketServlet
// Test cases 9.x uses BIG frame sizes, let policy handle them.
int bigFrameSize = 20 * MBYTE;
factory.getPolicy().setMaxMessageSize(bigFrameSize);
factory.getPolicy().setMaxTextMessageSize(bigFrameSize);
factory.getPolicy().setMaxBinaryMessageSize(bigFrameSize);
factory.register(ABSocket.class);
}

View File

@ -87,7 +87,8 @@ public class Fuzzer
int bigMessageSize = 20 * MBYTE;
policy.setMaxMessageSize(bigMessageSize);
policy.setMaxTextMessageSize(bigMessageSize);
policy.setMaxBinaryMessageSize(bigMessageSize);
this.client = new BlockheadClient(policy,testcase.getServer().getServerUri());
this.generator = testcase.getLaxGenerator();

View File

@ -29,7 +29,7 @@ import org.eclipse.jetty.websocket.api.annotations.WebSocket;
/**
* Example Socket for echoing back Big data using the Annotation techniques along with stateless techniques.
*/
@WebSocket(maxMessageSize = 64 * 1024)
@WebSocket(maxTextMessageSize = 64 * 1024, maxBinaryMessageSize = 64 * 1024)
public class BigEchoSocket
{
private static final Logger LOG = Log.getLogger(BigEchoSocket.class);

View File

@ -18,6 +18,7 @@
package org.eclipse.jetty.websocket.server.helper;
import java.util.List;
import java.util.Map;
import org.eclipse.jetty.util.log.Log;
@ -52,11 +53,11 @@ public class SessionSocket
{
if (message.startsWith("getParameterMap"))
{
Map<String, String[]> parameterMap = session.getUpgradeRequest().getParameterMap();
Map<String, List<String>> parameterMap = session.getUpgradeRequest().getParameterMap();
int idx = message.indexOf('|');
String key = message.substring(idx + 1);
String values[] = parameterMap.get(key);
List<String> values = parameterMap.get(key);
if (values == null)
{

View File

@ -69,8 +69,11 @@ import org.eclipse.jetty.websocket.api.annotations.WebSocket;
* <dt>maxIdleTime</dt>
* <dd>set the time in ms that a websocket may be idle before closing<br>
*
* <dt>maxMessagesSize</dt>
* <dd>set the size in bytes that a websocket may be accept before closing<br>
* <dt>maxTextMessageSize</dt>
* <dd>set the size in UTF-8 bytes that a websocket may be accept as a Text Message before closing<br>
*
* <dt>maxBinaryMessageSize</dt>
* <dd>set the size in bytes that a websocket may be accept as a Binary Message before closing<br>
*
* <dt>inputBufferSize</dt>
* <dd>set the size in bytes of the buffer used to read raw bytes from the network layer<br>
@ -105,10 +108,16 @@ public abstract class WebSocketServlet extends HttpServlet
policy.setIdleTimeout(Long.parseLong(max));
}
max = getInitParameter("maxMessageSize");
max = getInitParameter("maxTextMessageSize");
if (max != null)
{
policy.setMaxMessageSize(Long.parseLong(max));
policy.setMaxTextMessageSize(Integer.parseInt(max));
}
max = getInitParameter("maxBinaryMessageSize");
if (max != null)
{
policy.setMaxBinaryMessageSize(Integer.parseInt(max));
}
max = getInitParameter("inputBufferSize");