Continuing refactoring of websocket-server by commenting out no longer available classes (no more red)
This commit is contained in:
parent
ec51481c02
commit
dc68d30b4b
|
@ -0,0 +1,29 @@
|
|||
package org.eclipse.jetty.websocket.server;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.eclipse.jetty.io.AbstractAsyncConnection;
|
||||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
|
||||
public class AsyncWebSocketConnection extends AbstractAsyncConnection
|
||||
{
|
||||
// TODO: track extensions? (only those that need to operate at this level?)
|
||||
// TODO: track generic WebSocket.Connection (for API access)?
|
||||
|
||||
public AsyncWebSocketConnection(AsyncEndPoint endp, Executor executor)
|
||||
{
|
||||
super(endp,executor);
|
||||
}
|
||||
|
||||
public AsyncWebSocketConnection(AsyncEndPoint endp, Executor executor, boolean executeOnlyFailure)
|
||||
{
|
||||
super(endp,executor,executeOnlyFailure);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFillable()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
|
@ -19,11 +19,11 @@
|
|||
// 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
|
||||
// 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.
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
|
||||
package org.eclipse.jetty.websocket.server;
|
||||
|
@ -36,30 +36,37 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||
import org.eclipse.jetty.websocket.server.WebSocketFactory.Acceptor;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketBehavior;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
|
||||
public abstract class WebSocketHandler extends HandlerWrapper implements WebSocketFactory.Acceptor
|
||||
public abstract class WebSocketHandler extends HandlerWrapper implements WebSocketServerFactory.Acceptor
|
||||
{
|
||||
private final WebSocketFactory _webSocketFactory=new WebSocketFactory(this,32*1024);
|
||||
|
||||
public WebSocketFactory getWebSocketFactory()
|
||||
private final WebSocketServerFactory webSocketFactory;
|
||||
|
||||
public WebSocketHandler()
|
||||
{
|
||||
return _webSocketFactory;
|
||||
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
|
||||
webSocketFactory = new WebSocketServerFactory(this,policy);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
if (_webSocketFactory.acceptWebSocket(request,response) || response.isCommitted())
|
||||
return;
|
||||
super.handle(target,baseRequest,request,response);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean checkOrigin(HttpServletRequest request, String origin)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public WebSocketServerFactory getWebSocketFactory()
|
||||
{
|
||||
return webSocketFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
if (webSocketFactory.acceptWebSocket(request,response) || response.isCommitted())
|
||||
{
|
||||
return;
|
||||
}
|
||||
super.handle(target,baseRequest,request,response);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,17 +21,19 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpParser;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
import org.eclipse.jetty.server.HttpConnection;
|
||||
import org.eclipse.jetty.util.QuotedStringTokenizer;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.WebSocket;
|
||||
import org.eclipse.jetty.websocket.WebSocketConnectionRFC6455;
|
||||
import org.eclipse.jetty.websocket.WebSocket.Connection;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.extensions.Extension;
|
||||
import org.eclipse.jetty.websocket.extensions.deflate.DeflateFrameExtension;
|
||||
import org.eclipse.jetty.websocket.extensions.fragment.FragmentExtension;
|
||||
|
@ -40,13 +42,19 @@ import org.eclipse.jetty.websocket.extensions.identity.IdentityExtension;
|
|||
/**
|
||||
* Factory to create WebSocket connections
|
||||
*/
|
||||
public class WebSocketFactory extends AbstractLifeCycle
|
||||
public class WebSocketServerFactory extends AbstractLifeCycle
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(WebSocketFactory.class);
|
||||
private final Queue<WebSocketServletConnection> connections = new ConcurrentLinkedQueue<WebSocketServletConnection>();
|
||||
|
||||
public interface Acceptor
|
||||
{
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* <p>Checks the origin of an incoming WebSocket handshake request.</p>
|
||||
* @param request the incoming HTTP upgrade request
|
||||
* @param origin the origin URI
|
||||
* @return boolean to indicate that the origin is acceptable.
|
||||
*/
|
||||
boolean checkOrigin(HttpServletRequest request, String origin);
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* <p>Factory method that applications needs to implement to return a
|
||||
|
@ -56,16 +64,10 @@ public class WebSocketFactory extends AbstractLifeCycle
|
|||
* @return a new {@link WebSocket} object that will handle websocket events.
|
||||
*/
|
||||
WebSocket doWebSocketConnect(HttpServletRequest request, String protocol);
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* <p>Checks the origin of an incoming WebSocket handshake request.</p>
|
||||
* @param request the incoming HTTP upgrade request
|
||||
* @param origin the origin URI
|
||||
* @return boolean to indicate that the origin is acceptable.
|
||||
*/
|
||||
boolean checkOrigin(HttpServletRequest request, String origin);
|
||||
}
|
||||
private static final Logger LOG = Log.getLogger(WebSocketServerFactory.class);
|
||||
|
||||
private final Queue<WebSocketServletConnection> connections = new ConcurrentLinkedQueue<WebSocketServletConnection>();
|
||||
|
||||
private final Map<String,Class<? extends Extension>> _extensionClasses = new HashMap<String, Class<? extends Extension>>();
|
||||
{
|
||||
|
@ -75,204 +77,12 @@ public class WebSocketFactory extends AbstractLifeCycle
|
|||
}
|
||||
|
||||
private final Acceptor _acceptor;
|
||||
private WebSocketBuffers _buffers;
|
||||
private int _maxIdleTime = 300000;
|
||||
private int _maxTextMessageSize = 16 * 1024;
|
||||
private int _maxBinaryMessageSize = -1;
|
||||
private WebSocketPolicy policy;
|
||||
|
||||
public WebSocketFactory(Acceptor acceptor)
|
||||
public WebSocketServerFactory(Acceptor acceptor, WebSocketPolicy policy)
|
||||
{
|
||||
this(acceptor, 64 * 1024);
|
||||
}
|
||||
|
||||
public WebSocketFactory(Acceptor acceptor, int bufferSize)
|
||||
{
|
||||
_buffers = new WebSocketBuffers(bufferSize);
|
||||
_acceptor = acceptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A modifiable map of extension name to extension class
|
||||
*/
|
||||
public Map<String,Class<? extends Extension>> getExtensionClassesMap()
|
||||
{
|
||||
return _extensionClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maxIdleTime.
|
||||
*
|
||||
* @return the maxIdleTime
|
||||
*/
|
||||
public long getMaxIdleTime()
|
||||
{
|
||||
return _maxIdleTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maxIdleTime.
|
||||
*
|
||||
* @param maxIdleTime the maxIdleTime to set
|
||||
*/
|
||||
public void setMaxIdleTime(int maxIdleTime)
|
||||
{
|
||||
_maxIdleTime = maxIdleTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bufferSize.
|
||||
*
|
||||
* @return the bufferSize
|
||||
*/
|
||||
public int getBufferSize()
|
||||
{
|
||||
return _buffers.getBufferSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bufferSize.
|
||||
*
|
||||
* @param bufferSize the bufferSize to set
|
||||
*/
|
||||
public void setBufferSize(int bufferSize)
|
||||
{
|
||||
if (bufferSize != getBufferSize())
|
||||
_buffers = new WebSocketBuffers(bufferSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The initial maximum text message size (in characters) for a connection
|
||||
*/
|
||||
public int getMaxTextMessageSize()
|
||||
{
|
||||
return _maxTextMessageSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the initial maximum text message size for a connection. This can be changed by
|
||||
* the application calling {@link WebSocket.Connection#setMaxTextMessageSize(int)}.
|
||||
* @param maxTextMessageSize The default maximum text message size (in characters) for a connection
|
||||
*/
|
||||
public void setMaxTextMessageSize(int maxTextMessageSize)
|
||||
{
|
||||
_maxTextMessageSize = maxTextMessageSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The initial maximum binary message size (in bytes) for a connection
|
||||
*/
|
||||
public int getMaxBinaryMessageSize()
|
||||
{
|
||||
return _maxBinaryMessageSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the initial maximum binary message size for a connection. This can be changed by
|
||||
* the application calling {@link WebSocket.Connection#setMaxBinaryMessageSize(int)}.
|
||||
* @param maxBinaryMessageSize The default maximum binary message size (in bytes) for a connection
|
||||
*/
|
||||
public void setMaxBinaryMessageSize(int maxBinaryMessageSize)
|
||||
{
|
||||
_maxBinaryMessageSize = maxBinaryMessageSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
closeConnections();
|
||||
}
|
||||
|
||||
/**
|
||||
* Upgrade the request/response to a WebSocket Connection.
|
||||
* <p>This method will not normally return, but will instead throw a
|
||||
* UpgradeConnectionException, to exit HTTP handling and initiate
|
||||
* WebSocket handling of the connection.
|
||||
*
|
||||
* @param request The request to upgrade
|
||||
* @param response The response to upgrade
|
||||
* @param websocket The websocket handler implementation to use
|
||||
* @param protocol The websocket protocol
|
||||
* @throws IOException in case of I/O errors
|
||||
*/
|
||||
public void upgrade(HttpServletRequest request, HttpServletResponse response, WebSocket websocket, String protocol)
|
||||
throws IOException
|
||||
{
|
||||
if (!"websocket".equalsIgnoreCase(request.getHeader("Upgrade")))
|
||||
throw new IllegalStateException("!Upgrade:websocket");
|
||||
if (!"HTTP/1.1".equals(request.getProtocol()))
|
||||
throw new IllegalStateException("!HTTP/1.1");
|
||||
|
||||
int draft = request.getIntHeader("Sec-WebSocket-Version");
|
||||
if (draft < 0) {
|
||||
// Old pre-RFC version specifications (header not present in RFC-6455)
|
||||
draft = request.getIntHeader("Sec-WebSocket-Draft");
|
||||
}
|
||||
AbstractHttpConnection http = AbstractHttpConnection.getCurrentConnection();
|
||||
if (http instanceof BlockingHttpConnection)
|
||||
throw new IllegalStateException("Websockets not supported on blocking connectors");
|
||||
ConnectedEndPoint endp = (ConnectedEndPoint)http.getEndPoint();
|
||||
|
||||
List<String> extensions_requested = new ArrayList<String>();
|
||||
@SuppressWarnings("unchecked")
|
||||
Enumeration<String> e = request.getHeaders("Sec-WebSocket-Extensions");
|
||||
while (e.hasMoreElements())
|
||||
{
|
||||
QuotedStringTokenizer tok = new QuotedStringTokenizer(e.nextElement(),",");
|
||||
while (tok.hasMoreTokens())
|
||||
{
|
||||
extensions_requested.add(tok.nextToken());
|
||||
}
|
||||
}
|
||||
|
||||
final WebSocketServletConnection connection;
|
||||
switch (draft)
|
||||
{
|
||||
case WebSocketConnectionRFC6455.VERSION: // RFC 6455 Version
|
||||
{
|
||||
List<Extension> extensions = initExtensions(extensions_requested, 8 - WebSocketConnectionRFC6455.OP_EXT_DATA, 16 - WebSocketConnectionRFC6455.OP_EXT_CTRL, 3);
|
||||
connection = new WebSocketServletConnectionRFC6455(this, websocket, endp, _buffers, http.getTimeStamp(), _maxIdleTime, protocol, extensions, draft);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
LOG.warn("Unsupported Websocket version: " + draft);
|
||||
// Per RFC 6455 - 4.4 - Supporting Multiple Versions of WebSocket Protocol
|
||||
// Using the examples as outlined
|
||||
response.setHeader("Sec-WebSocket-Version", "13, 8, 6, 0");
|
||||
throw new HttpException(400, "Unsupported websocket version specification: " + draft);
|
||||
}
|
||||
}
|
||||
|
||||
addConnection(connection);
|
||||
|
||||
// Set the defaults
|
||||
connection.getConnection().setMaxBinaryMessageSize(_maxBinaryMessageSize);
|
||||
connection.getConnection().setMaxTextMessageSize(_maxTextMessageSize);
|
||||
|
||||
// Let the connection finish processing the handshake
|
||||
connection.handshake(request, response, protocol);
|
||||
response.flushBuffer();
|
||||
|
||||
// Give the connection any unused data from the HTTP connection.
|
||||
connection.fillBuffersFrom(((HttpParser)http.getParser()).getHeaderBuffer());
|
||||
connection.fillBuffersFrom(((HttpParser)http.getParser()).getBodyBuffer());
|
||||
|
||||
// Tell jetty about the new connection
|
||||
LOG.debug("Websocket upgrade {} {} {} {}",request.getRequestURI(),draft,protocol,connection);
|
||||
request.setAttribute("org.eclipse.jetty.io.Connection", connection);
|
||||
}
|
||||
|
||||
protected String[] parseProtocols(String protocol)
|
||||
{
|
||||
if (protocol == null)
|
||||
return new String[]{null};
|
||||
protocol = protocol.trim();
|
||||
if (protocol == null || protocol.length() == 0)
|
||||
return new String[]{null};
|
||||
String[] passed = protocol.split("\\s*,\\s*");
|
||||
String[] protocols = new String[passed.length + 1];
|
||||
System.arraycopy(passed, 0, protocols, 0, passed.length);
|
||||
return protocols;
|
||||
this._acceptor = acceptor;
|
||||
this.policy = policy;
|
||||
}
|
||||
|
||||
public boolean acceptWebSocket(HttpServletRequest request, HttpServletResponse response)
|
||||
|
@ -282,7 +92,9 @@ public class WebSocketFactory extends AbstractLifeCycle
|
|||
{
|
||||
String origin = request.getHeader("Origin");
|
||||
if (origin==null)
|
||||
{
|
||||
origin = request.getHeader("Sec-WebSocket-Origin");
|
||||
}
|
||||
if (!_acceptor.checkOrigin(request,origin))
|
||||
{
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN);
|
||||
|
@ -295,7 +107,7 @@ public class WebSocketFactory extends AbstractLifeCycle
|
|||
@SuppressWarnings("unchecked")
|
||||
Enumeration<String> protocols = request.getHeaders("Sec-WebSocket-Protocol");
|
||||
String protocol=null;
|
||||
while (protocol==null && protocols!=null && protocols.hasMoreElements())
|
||||
while ((protocol==null) && (protocols!=null) && protocols.hasMoreElements())
|
||||
{
|
||||
String candidate = protocols.nextElement();
|
||||
for (String p : parseProtocols(candidate))
|
||||
|
@ -329,6 +141,43 @@ public class WebSocketFactory extends AbstractLifeCycle
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean addConnection(WebSocketServletConnection connection)
|
||||
{
|
||||
return isRunning() && connections.add(connection);
|
||||
}
|
||||
|
||||
protected void closeConnections()
|
||||
{
|
||||
for (WebSocketServletConnection connection : connections)
|
||||
{
|
||||
// TODO connection.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
closeConnections();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A modifiable map of extension name to extension class
|
||||
*/
|
||||
public Map<String,Class<? extends Extension>> getExtensionClassesMap()
|
||||
{
|
||||
return _extensionClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the policy in use for WebSockets.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public WebSocketPolicy getPolicy()
|
||||
{
|
||||
return policy;
|
||||
}
|
||||
|
||||
public List<Extension> initExtensions(List<String> requested,int maxDataOpcodes,int maxControlOpcodes,int maxReservedBits)
|
||||
{
|
||||
|
@ -349,7 +198,9 @@ public class WebSocketFactory extends AbstractLifeCycle
|
|||
Extension extension = newExtension(extName);
|
||||
|
||||
if (extension==null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (extension.init(parameters))
|
||||
{
|
||||
|
@ -367,7 +218,9 @@ public class WebSocketFactory extends AbstractLifeCycle
|
|||
{
|
||||
Class<? extends Extension> extClass = _extensionClasses.get(name);
|
||||
if (extClass!=null)
|
||||
{
|
||||
return extClass.newInstance();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -377,9 +230,21 @@ public class WebSocketFactory extends AbstractLifeCycle
|
|||
return null;
|
||||
}
|
||||
|
||||
protected boolean addConnection(WebSocketServletConnection connection)
|
||||
protected String[] parseProtocols(String protocol)
|
||||
{
|
||||
return isRunning() && connections.add(connection);
|
||||
if (protocol == null)
|
||||
{
|
||||
return new String[]{null};
|
||||
}
|
||||
protocol = protocol.trim();
|
||||
if ((protocol == null) || (protocol.length() == 0))
|
||||
{
|
||||
return new String[]{null};
|
||||
}
|
||||
String[] passed = protocol.split("\\s*,\\s*");
|
||||
String[] protocols = new String[passed.length + 1];
|
||||
System.arraycopy(passed, 0, protocols, 0, passed.length);
|
||||
return protocols;
|
||||
}
|
||||
|
||||
protected boolean removeConnection(WebSocketServletConnection connection)
|
||||
|
@ -387,9 +252,89 @@ public class WebSocketFactory extends AbstractLifeCycle
|
|||
return connections.remove(connection);
|
||||
}
|
||||
|
||||
protected void closeConnections()
|
||||
/**
|
||||
* Upgrade the request/response to a WebSocket Connection.
|
||||
* <p>This method will not normally return, but will instead throw a
|
||||
* UpgradeConnectionException, to exit HTTP handling and initiate
|
||||
* WebSocket handling of the connection.
|
||||
*
|
||||
* @param request The request to upgrade
|
||||
* @param response The response to upgrade
|
||||
* @param websocket The websocket handler implementation to use
|
||||
* @param protocol The websocket protocol
|
||||
* @throws IOException in case of I/O errors
|
||||
*/
|
||||
public void upgrade(HttpServletRequest request, HttpServletResponse response, WebSocket websocket, String protocol)
|
||||
throws IOException
|
||||
{
|
||||
for (WebSocketServletConnection connection : connections)
|
||||
connection.shutdown();
|
||||
if (!"websocket".equalsIgnoreCase(request.getHeader("Upgrade")))
|
||||
{
|
||||
throw new IllegalStateException("!Upgrade:websocket");
|
||||
}
|
||||
if (!"HTTP/1.1".equals(request.getProtocol()))
|
||||
{
|
||||
throw new IllegalStateException("!HTTP/1.1");
|
||||
}
|
||||
|
||||
int draft = request.getIntHeader("Sec-WebSocket-Version");
|
||||
if (draft < 0) {
|
||||
// Old pre-RFC version specifications (header not present in RFC-6455)
|
||||
draft = request.getIntHeader("Sec-WebSocket-Draft");
|
||||
}
|
||||
HttpConnection http = HttpConnection.getCurrentConnection();
|
||||
AsyncEndPoint endp = http.getEndPoint();
|
||||
|
||||
List<String> extensions_requested = new ArrayList<String>();
|
||||
@SuppressWarnings("unchecked")
|
||||
Enumeration<String> e = request.getHeaders("Sec-WebSocket-Extensions");
|
||||
while (e.hasMoreElements())
|
||||
{
|
||||
QuotedStringTokenizer tok = new QuotedStringTokenizer(e.nextElement(),",");
|
||||
while (tok.hasMoreTokens())
|
||||
{
|
||||
extensions_requested.add(tok.nextToken());
|
||||
}
|
||||
}
|
||||
|
||||
final WebSocketServletConnection connection;
|
||||
switch (draft)
|
||||
{
|
||||
case org.eclipse.jetty.websocket.api.WebSocket.VERSION: // RFC 6455 Version
|
||||
{
|
||||
// List<Extension> extensions = initExtensions(extensions_requested,
|
||||
// 8 - WebSocketConnectionRFC6455.OP_EXT_DATA,
|
||||
// 16 - WebSocketConnectionRFC6455.OP_EXT_CTRL,
|
||||
// 3);
|
||||
// connection = new WebSocketServletConnectionRFC6455(this, websocket, endp, _buffers, http.getTimeStamp(), _maxIdleTime, protocol, extensions, draft);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
LOG.warn("Unsupported Websocket version: " + draft);
|
||||
// Per RFC 6455 - 4.4 - Supporting Multiple Versions of WebSocket Protocol
|
||||
// Using the examples as outlined
|
||||
response.setHeader("Sec-WebSocket-Version", "" + org.eclipse.jetty.websocket.api.WebSocket.VERSION /*+ ", 0"*/);
|
||||
response.setStatus(HttpStatus.BAD_REQUEST_400);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// addConnection(connection);
|
||||
|
||||
// Set the defaults
|
||||
// connection.getConnection().setMaxBinaryMessageSize(_maxBinaryMessageSize);
|
||||
// connection.getConnection().setMaxTextMessageSize(_maxTextMessageSize);
|
||||
|
||||
// Let the connection finish processing the handshake
|
||||
// connection.handshake(request, response, protocol);
|
||||
response.flushBuffer();
|
||||
|
||||
// Give the connection any unused data from the HTTP connection.
|
||||
// connection.fillBuffersFrom(((HttpParser)http.getParser()).getHeaderBuffer());
|
||||
// connection.fillBuffersFrom(((HttpParser)http.getParser()).getBodyBuffer());
|
||||
|
||||
// Tell jetty about the new connection
|
||||
// LOG.debug("Websocket upgrade {} {} {} {}",request.getRequestURI(),draft,protocol,connection);
|
||||
// request.setAttribute("org.eclipse.jetty.io.Connection", connection);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2011 Intalio, Inc.
|
||||
* Copyright (c) 2011 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
|
||||
|
@ -13,22 +13,11 @@
|
|||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*******************************************************************************/
|
||||
// ========================================================================
|
||||
// Copyright (c) 2010 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.server;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -36,9 +25,9 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.server.WebSocketFactory.Acceptor;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketBehavior;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Servlet to upgrade connections to WebSocket
|
||||
* <p/>
|
||||
|
@ -58,12 +47,30 @@ import org.eclipse.jetty.websocket.server.WebSocketFactory.Acceptor;
|
|||
* that a websocket may be accept before closing.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class WebSocketServlet extends HttpServlet implements WebSocketFactory.Acceptor
|
||||
public abstract class WebSocketServlet extends HttpServlet implements WebSocketServerFactory.Acceptor
|
||||
{
|
||||
private final Logger LOG = Log.getLogger(getClass());
|
||||
private WebSocketFactory _webSocketFactory;
|
||||
private WebSocketServerFactory webSocketFactory;
|
||||
|
||||
@Override
|
||||
public boolean checkOrigin(HttpServletRequest request, String origin)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
try
|
||||
{
|
||||
webSocketFactory.stop();
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
LOG.ignore(x);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see javax.servlet.GenericServlet#init()
|
||||
*/
|
||||
|
@ -73,24 +80,27 @@ public abstract class WebSocketServlet extends HttpServlet implements WebSocketF
|
|||
try
|
||||
{
|
||||
String bs = getInitParameter("bufferSize");
|
||||
_webSocketFactory = new WebSocketFactory(this, bs == null ? 8192 : Integer.parseInt(bs));
|
||||
_webSocketFactory.start();
|
||||
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
|
||||
if(bs != null) {
|
||||
policy.setBufferSize(Integer.parseInt(bs));
|
||||
}
|
||||
|
||||
String max = getInitParameter("maxIdleTime");
|
||||
if (max != null)
|
||||
_webSocketFactory.setMaxIdleTime(Integer.parseInt(max));
|
||||
if (max != null) {
|
||||
policy.setMaxIdleTime(Integer.parseInt(max));
|
||||
}
|
||||
|
||||
max = getInitParameter("maxTextMessageSize");
|
||||
if (max != null)
|
||||
_webSocketFactory.setMaxTextMessageSize(Integer.parseInt(max));
|
||||
if (max != null) {
|
||||
policy.setMaxTextMessageSize(Integer.parseInt(max));
|
||||
}
|
||||
|
||||
max = getInitParameter("maxBinaryMessageSize");
|
||||
if (max != null)
|
||||
_webSocketFactory.setMaxBinaryMessageSize(Integer.parseInt(max));
|
||||
}
|
||||
catch (ServletException x)
|
||||
{
|
||||
throw x;
|
||||
if (max != null) {
|
||||
policy.setMaxBinaryMessageSize(Integer.parseInt(max));
|
||||
}
|
||||
|
||||
webSocketFactory = new WebSocketServerFactory(this,policy);
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
|
@ -98,35 +108,16 @@ public abstract class WebSocketServlet extends HttpServlet implements WebSocketF
|
|||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
|
||||
*/
|
||||
@Override
|
||||
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
||||
{
|
||||
if (_webSocketFactory.acceptWebSocket(request, response) || response.isCommitted())
|
||||
if (webSocketFactory.acceptWebSocket(request,response) || response.isCommitted())
|
||||
{
|
||||
return;
|
||||
}
|
||||
super.service(request, response);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean checkOrigin(HttpServletRequest request, String origin)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
try
|
||||
{
|
||||
_webSocketFactory.stop();
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
LOG.ignore(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,12 +16,12 @@
|
|||
package org.eclipse.jetty.websocket.server;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.websocket.WebSocketConnection;
|
||||
|
||||
public interface WebSocketServletConnection extends WebSocketConnection
|
||||
public interface WebSocketServletConnection /* extends WebSocketConnection */
|
||||
{
|
||||
void handshake(HttpServletRequest request, HttpServletResponse response, String subprotocol) throws IOException;
|
||||
}
|
||||
|
|
|
@ -16,25 +16,22 @@
|
|||
package org.eclipse.jetty.websocket.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.websocket.WebSocket;
|
||||
import org.eclipse.jetty.websocket.WebSocketConnectionRFC6455;
|
||||
import org.eclipse.jetty.websocket.extensions.Extension;
|
||||
|
||||
public class WebSocketServletConnectionRFC6455 extends WebSocketConnectionRFC6455 implements WebSocketServletConnection
|
||||
public class WebSocketServletConnectionRFC6455 /* extends WebSocketConnectionRFC6455 implements WebSocketServletConnection */
|
||||
{
|
||||
private final WebSocketFactory factory;
|
||||
private /* final */ WebSocketServerFactory factory;
|
||||
|
||||
public WebSocketServletConnectionRFC6455(WebSocketFactory factory, WebSocket websocket, EndPoint endpoint, WebSocketBuffers buffers, long timestamp, int maxIdleTime, String protocol,
|
||||
/*
|
||||
public WebSocketServletConnectionRFC6455(WebSocketServerFactory factory, WebSocket websocket, EndPoint endpoint, WebSocketBuffers buffers, long timestamp, int maxIdleTime, String protocol,
|
||||
List<Extension> extensions, int draft) throws IOException
|
||||
{
|
||||
super(websocket,endpoint,buffers,timestamp,maxIdleTime,protocol,extensions,draft);
|
||||
this.factory = factory;
|
||||
}
|
||||
*/
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void handshake(HttpServletRequest request, HttpServletResponse response, String subprotocol) throws IOException
|
||||
|
@ -43,27 +40,31 @@ public class WebSocketServletConnectionRFC6455 extends WebSocketConnectionRFC645
|
|||
|
||||
response.setHeader("Upgrade","WebSocket");
|
||||
response.addHeader("Connection","Upgrade");
|
||||
response.addHeader("Sec-WebSocket-Accept",hashKey(key));
|
||||
// response.addHeader("Sec-WebSocket-Accept",hashKey(key));
|
||||
if (subprotocol != null)
|
||||
{
|
||||
response.addHeader("Sec-WebSocket-Protocol",subprotocol);
|
||||
}
|
||||
|
||||
/*
|
||||
for (Extension ext : getExtensions())
|
||||
{
|
||||
response.addHeader("Sec-WebSocket-Extensions",ext.getParameterizedName());
|
||||
}
|
||||
*/
|
||||
|
||||
response.sendError(101);
|
||||
|
||||
onFrameHandshake();
|
||||
onWebSocketOpen();
|
||||
// onFrameHandshake();
|
||||
// onWebSocketOpen();
|
||||
}
|
||||
|
||||
/*
|
||||
@Override
|
||||
public void onClose()
|
||||
{
|
||||
super.onClose();
|
||||
factory.removeConnection(this);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -22,34 +22,385 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.eclipse.jetty.server.SelectChannelConnector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ResourceHandler;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.WebSocket;
|
||||
import org.eclipse.jetty.websocket.WebSocketConnectionRFC6455;
|
||||
import org.eclipse.jetty.websocket.WebSocket.Connection;
|
||||
import org.eclipse.jetty.websocket.WebSocket.FrameConnection;
|
||||
import org.eclipse.jetty.websocket.WebSocket.OnBinaryMessage;
|
||||
import org.eclipse.jetty.websocket.WebSocket.OnControl;
|
||||
import org.eclipse.jetty.websocket.WebSocket.OnFrame;
|
||||
import org.eclipse.jetty.websocket.WebSocket.OnTextMessage;
|
||||
import org.eclipse.jetty.websocket.api.OpCode;
|
||||
|
||||
public class TestServer extends Server
|
||||
{
|
||||
class TestEchoAssembleWebSocket extends TestWebSocket
|
||||
{
|
||||
|
||||
@Override
|
||||
public void onMessage(byte[] data, int offset, int length)
|
||||
{
|
||||
super.onMessage(data,offset,length);
|
||||
try
|
||||
{
|
||||
getConnection().sendMessage(data,offset,length);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(final String data)
|
||||
{
|
||||
super.onMessage(data);
|
||||
try
|
||||
{
|
||||
getConnection().sendMessage(data);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(Connection connection)
|
||||
{
|
||||
super.onOpen(connection);
|
||||
connection.setMaxTextMessageSize(64*1024);
|
||||
connection.setMaxBinaryMessageSize(64*1024);
|
||||
}
|
||||
}
|
||||
|
||||
class TestEchoBroadcastPingWebSocket extends TestEchoBroadcastWebSocket
|
||||
{
|
||||
Thread _keepAlive; // A dedicated thread is not a good way to do this
|
||||
CountDownLatch _latch = new CountDownLatch(1);
|
||||
|
||||
@Override
|
||||
public void onClose(int code, String message)
|
||||
{
|
||||
_latch.countDown();
|
||||
super.onClose(code,message);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onControl(byte controlCode, byte[] data, int offset, int length)
|
||||
{
|
||||
if (controlCode==OpCode.PONG.getCode())
|
||||
{
|
||||
System.err.println("Pong "+getConnection());
|
||||
}
|
||||
return super.onControl(controlCode,data,offset,length);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onHandshake(final FrameConnection connection)
|
||||
{
|
||||
super.onHandshake(connection);
|
||||
_keepAlive=new Thread()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
while(!_latch.await(10,TimeUnit.SECONDS))
|
||||
{
|
||||
System.err.println("Ping "+connection);
|
||||
byte[] data = { (byte)1, (byte) 2, (byte) 3 };
|
||||
connection.sendControl(OpCode.PING.getCode(),data,0,data.length);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
_keepAlive.start();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
class TestEchoBroadcastWebSocket extends TestWebSocket
|
||||
{
|
||||
@Override
|
||||
public void onClose(int code,String message)
|
||||
{
|
||||
super.onClose(code,message);
|
||||
_broadcast.remove(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(byte[] data, int offset, int length)
|
||||
{
|
||||
super.onMessage(data,offset,length);
|
||||
for (TestWebSocket ws : _broadcast)
|
||||
{
|
||||
try
|
||||
{
|
||||
ws.getConnection().sendMessage(data,offset,length);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
_broadcast.remove(ws);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(final String data)
|
||||
{
|
||||
super.onMessage(data);
|
||||
for (TestWebSocket ws : _broadcast)
|
||||
{
|
||||
try
|
||||
{
|
||||
ws.getConnection().sendMessage(data);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
_broadcast.remove(ws);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(Connection connection)
|
||||
{
|
||||
super.onOpen(connection);
|
||||
_broadcast.add(this);
|
||||
}
|
||||
}
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
class TestEchoFragmentWebSocket extends TestWebSocket
|
||||
{
|
||||
@Override
|
||||
public void onMessage(byte[] data, int offset, int length)
|
||||
{
|
||||
super.onMessage(data,offset,length);
|
||||
try
|
||||
{
|
||||
getConnection().sendFrame((byte)0x0,getConnection().binaryOpcode(),data,offset,length/2);
|
||||
getConnection().sendFrame((byte)0x8,getConnection().binaryOpcode(),data,offset+(length/2),length-(length/2));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(final String message)
|
||||
{
|
||||
super.onMessage(message);
|
||||
try
|
||||
{
|
||||
byte[] data = message.getBytes(StringUtil.__UTF8);
|
||||
int offset=0;
|
||||
int length=data.length;
|
||||
getConnection().sendFrame((byte)0x0,getConnection().textOpcode(),data,offset,length/2);
|
||||
getConnection().sendFrame((byte)0x8,getConnection().textOpcode(),data,offset+(length/2),length-(length/2));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(Connection connection)
|
||||
{
|
||||
super.onOpen(connection);
|
||||
connection.setMaxTextMessageSize(64*1024);
|
||||
connection.setMaxBinaryMessageSize(64*1024);
|
||||
}
|
||||
}
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
class TestEchoWebSocket extends TestWebSocket
|
||||
{
|
||||
@Override
|
||||
public boolean onFrame(byte flags, byte opcode, byte[] data, int offset, int length)
|
||||
{
|
||||
super.onFrame(flags,opcode,data,offset,length);
|
||||
try
|
||||
{
|
||||
if (!getConnection().isControl(opcode))
|
||||
{
|
||||
getConnection().sendFrame(flags,opcode,data,offset,length);
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(Connection connection)
|
||||
{
|
||||
super.onOpen(connection);
|
||||
connection.setMaxTextMessageSize(-1);
|
||||
connection.setMaxBinaryMessageSize(-1);
|
||||
}
|
||||
}
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
class TestWebSocket implements WebSocket, WebSocket.OnFrame, WebSocket.OnBinaryMessage, WebSocket.OnTextMessage, WebSocket.OnControl
|
||||
{
|
||||
protected FrameConnection _connection;
|
||||
|
||||
public FrameConnection getConnection()
|
||||
{
|
||||
return _connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(int code,String message)
|
||||
{
|
||||
if (_verbose)
|
||||
{
|
||||
System.err.printf("%s#onDisonnect %d %s\n",this.getClass().getSimpleName(),code,message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onControl(byte controlCode, byte[] data, int offset, int length)
|
||||
{
|
||||
if (_verbose)
|
||||
{
|
||||
System.err.printf("%s#onControl %s %s\n",this.getClass().getSimpleName(),TypeUtil.toHexString(controlCode),TypeUtil.toHexString(data,offset,length));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onFrame(byte flags, byte opcode, byte[] data, int offset, int length)
|
||||
{
|
||||
if (_verbose)
|
||||
{
|
||||
System.err.printf("%s#onFrame %s|%s %s\n",this.getClass().getSimpleName(),TypeUtil.toHexString(flags),TypeUtil.toHexString(opcode),TypeUtil.toHexString(data,offset,length));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHandshake(FrameConnection connection)
|
||||
{
|
||||
if (_verbose)
|
||||
{
|
||||
System.err.printf("%s#onHandshake %s %s\n",this.getClass().getSimpleName(),connection,connection.getClass().getSimpleName());
|
||||
}
|
||||
_connection = connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(byte[] data, int offset, int length)
|
||||
{
|
||||
if (_verbose)
|
||||
{
|
||||
System.err.printf("%s#onMessage %s\n",this.getClass().getSimpleName(),TypeUtil.toHexString(data,offset,length));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(String data)
|
||||
{
|
||||
if (_verbose)
|
||||
{
|
||||
System.err.printf("%s#onMessage %s\n",this.getClass().getSimpleName(),data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(Connection connection)
|
||||
{
|
||||
if (_verbose)
|
||||
{
|
||||
System.err.printf("%s#onOpen %s %s\n",this.getClass().getSimpleName(),connection,connection.getProtocol());
|
||||
}
|
||||
}
|
||||
}
|
||||
private static final Logger LOG = Log.getLogger(TestServer.class);
|
||||
|
||||
public static void main(String... args)
|
||||
{
|
||||
try
|
||||
{
|
||||
int port=8080;
|
||||
boolean verbose=false;
|
||||
String docroot="src/test/webapp";
|
||||
|
||||
for (int i=0;i<args.length;i++)
|
||||
{
|
||||
String a=args[i];
|
||||
if ("-p".equals(a)||"--port".equals(a))
|
||||
{
|
||||
port=Integer.parseInt(args[++i]);
|
||||
}
|
||||
else if ("-v".equals(a)||"--verbose".equals(a))
|
||||
{
|
||||
verbose=true;
|
||||
}
|
||||
else if ("-d".equals(a)||"--docroot".equals(a))
|
||||
{
|
||||
docroot=args[++i];
|
||||
}
|
||||
else if (a.startsWith("-"))
|
||||
{
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TestServer server = new TestServer(port);
|
||||
server.setVerbose(verbose);
|
||||
server.setResourceBase(docroot);
|
||||
server.start();
|
||||
server.join();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void usage()
|
||||
{
|
||||
System.err.println("java -cp CLASSPATH "+TestServer.class+" [ OPTIONS ]");
|
||||
System.err.println(" -p|--port PORT (default 8080)");
|
||||
System.err.println(" -v|--verbose ");
|
||||
System.err.println(" -d|--docroot file (default 'src/test/webapp')");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
boolean _verbose;
|
||||
|
||||
WebSocket _websocket;
|
||||
SelectChannelConnector _connector;
|
||||
WebSocketHandler _wsHandler;
|
||||
ResourceHandler _rHandler;
|
||||
ConcurrentLinkedQueue<TestWebSocket> _broadcast = new ConcurrentLinkedQueue<TestWebSocket>();
|
||||
|
||||
SelectChannelConnector _connector;
|
||||
|
||||
WebSocketHandler _wsHandler;
|
||||
|
||||
ResourceHandler _rHandler;
|
||||
|
||||
ConcurrentLinkedQueue<TestWebSocket> _broadcast = new ConcurrentLinkedQueue<TestWebSocket>();
|
||||
|
||||
|
||||
public TestServer(int port)
|
||||
{
|
||||
_connector = new SelectChannelConnector();
|
||||
|
@ -58,6 +409,7 @@ public class TestServer extends Server
|
|||
addConnector(_connector);
|
||||
_wsHandler = new WebSocketHandler()
|
||||
{
|
||||
@Override
|
||||
public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol)
|
||||
{
|
||||
if ("org.ietf.websocket.test-echo".equals(protocol) || "echo".equals(protocol) || "lws-mirror-protocol".equals(protocol))
|
||||
|
@ -96,25 +448,7 @@ public class TestServer extends Server
|
|||
_wsHandler.setHandler(_rHandler);
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isVerbose()
|
||||
{
|
||||
return _verbose;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setVerbose(boolean verbose)
|
||||
{
|
||||
_verbose = verbose;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setResourceBase(String dir)
|
||||
{
|
||||
_rHandler.setResourceBase(dir);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public String getResourceBase()
|
||||
{
|
||||
|
@ -122,331 +456,21 @@ public class TestServer extends Server
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
class TestWebSocket implements WebSocket, WebSocket.OnFrame, WebSocket.OnBinaryMessage, WebSocket.OnTextMessage, WebSocket.OnControl
|
||||
public boolean isVerbose()
|
||||
{
|
||||
protected FrameConnection _connection;
|
||||
|
||||
public FrameConnection getConnection()
|
||||
{
|
||||
return _connection;
|
||||
}
|
||||
|
||||
public void onOpen(Connection connection)
|
||||
{
|
||||
if (_verbose)
|
||||
System.err.printf("%s#onOpen %s %s\n",this.getClass().getSimpleName(),connection,connection.getProtocol());
|
||||
}
|
||||
|
||||
public void onHandshake(FrameConnection connection)
|
||||
{
|
||||
if (_verbose)
|
||||
System.err.printf("%s#onHandshake %s %s\n",this.getClass().getSimpleName(),connection,connection.getClass().getSimpleName());
|
||||
_connection = connection;
|
||||
}
|
||||
return _verbose;
|
||||
}
|
||||
|
||||
public void onClose(int code,String message)
|
||||
{
|
||||
if (_verbose)
|
||||
System.err.printf("%s#onDisonnect %d %s\n",this.getClass().getSimpleName(),code,message);
|
||||
}
|
||||
|
||||
public boolean onFrame(byte flags, byte opcode, byte[] data, int offset, int length)
|
||||
{
|
||||
if (_verbose)
|
||||
System.err.printf("%s#onFrame %s|%s %s\n",this.getClass().getSimpleName(),TypeUtil.toHexString(flags),TypeUtil.toHexString(opcode),TypeUtil.toHexString(data,offset,length));
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onControl(byte controlCode, byte[] data, int offset, int length)
|
||||
{
|
||||
if (_verbose)
|
||||
System.err.printf("%s#onControl %s %s\n",this.getClass().getSimpleName(),TypeUtil.toHexString(controlCode),TypeUtil.toHexString(data,offset,length));
|
||||
return false;
|
||||
}
|
||||
|
||||
public void onMessage(String data)
|
||||
{
|
||||
if (_verbose)
|
||||
System.err.printf("%s#onMessage %s\n",this.getClass().getSimpleName(),data);
|
||||
}
|
||||
|
||||
public void onMessage(byte[] data, int offset, int length)
|
||||
{
|
||||
if (_verbose)
|
||||
System.err.printf("%s#onMessage %s\n",this.getClass().getSimpleName(),TypeUtil.toHexString(data,offset,length));
|
||||
}
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setResourceBase(String dir)
|
||||
{
|
||||
_rHandler.setResourceBase(dir);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
class TestEchoWebSocket extends TestWebSocket
|
||||
public void setVerbose(boolean verbose)
|
||||
{
|
||||
@Override
|
||||
public void onOpen(Connection connection)
|
||||
{
|
||||
super.onOpen(connection);
|
||||
connection.setMaxTextMessageSize(-1);
|
||||
connection.setMaxBinaryMessageSize(-1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onFrame(byte flags, byte opcode, byte[] data, int offset, int length)
|
||||
{
|
||||
super.onFrame(flags,opcode,data,offset,length);
|
||||
try
|
||||
{
|
||||
if (!getConnection().isControl(opcode))
|
||||
getConnection().sendFrame(flags,opcode,data,offset,length);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
class TestEchoBroadcastPingWebSocket extends TestEchoBroadcastWebSocket
|
||||
{
|
||||
Thread _keepAlive; // A dedicated thread is not a good way to do this
|
||||
CountDownLatch _latch = new CountDownLatch(1);
|
||||
|
||||
@Override
|
||||
public void onHandshake(final FrameConnection connection)
|
||||
{
|
||||
super.onHandshake(connection);
|
||||
_keepAlive=new Thread()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
while(!_latch.await(10,TimeUnit.SECONDS))
|
||||
{
|
||||
System.err.println("Ping "+connection);
|
||||
byte[] data = { (byte)1, (byte) 2, (byte) 3 };
|
||||
connection.sendControl(WebSocketConnectionRFC6455.OP_PING,data,0,data.length);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
_keepAlive.start();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onControl(byte controlCode, byte[] data, int offset, int length)
|
||||
{
|
||||
if (controlCode==WebSocketConnectionRFC6455.OP_PONG)
|
||||
System.err.println("Pong "+getConnection());
|
||||
return super.onControl(controlCode,data,offset,length);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onClose(int code, String message)
|
||||
{
|
||||
_latch.countDown();
|
||||
super.onClose(code,message);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
class TestEchoBroadcastWebSocket extends TestWebSocket
|
||||
{
|
||||
@Override
|
||||
public void onOpen(Connection connection)
|
||||
{
|
||||
super.onOpen(connection);
|
||||
_broadcast.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(int code,String message)
|
||||
{
|
||||
super.onClose(code,message);
|
||||
_broadcast.remove(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(byte[] data, int offset, int length)
|
||||
{
|
||||
super.onMessage(data,offset,length);
|
||||
for (TestWebSocket ws : _broadcast)
|
||||
{
|
||||
try
|
||||
{
|
||||
ws.getConnection().sendMessage(data,offset,length);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
_broadcast.remove(ws);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(final String data)
|
||||
{
|
||||
super.onMessage(data);
|
||||
for (TestWebSocket ws : _broadcast)
|
||||
{
|
||||
try
|
||||
{
|
||||
ws.getConnection().sendMessage(data);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
_broadcast.remove(ws);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
class TestEchoAssembleWebSocket extends TestWebSocket
|
||||
{
|
||||
|
||||
@Override
|
||||
public void onOpen(Connection connection)
|
||||
{
|
||||
super.onOpen(connection);
|
||||
connection.setMaxTextMessageSize(64*1024);
|
||||
connection.setMaxBinaryMessageSize(64*1024);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(byte[] data, int offset, int length)
|
||||
{
|
||||
super.onMessage(data,offset,length);
|
||||
try
|
||||
{
|
||||
getConnection().sendMessage(data,offset,length);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(final String data)
|
||||
{
|
||||
super.onMessage(data);
|
||||
try
|
||||
{
|
||||
getConnection().sendMessage(data);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
class TestEchoFragmentWebSocket extends TestWebSocket
|
||||
{
|
||||
@Override
|
||||
public void onOpen(Connection connection)
|
||||
{
|
||||
super.onOpen(connection);
|
||||
connection.setMaxTextMessageSize(64*1024);
|
||||
connection.setMaxBinaryMessageSize(64*1024);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(byte[] data, int offset, int length)
|
||||
{
|
||||
super.onMessage(data,offset,length);
|
||||
try
|
||||
{
|
||||
getConnection().sendFrame((byte)0x0,getConnection().binaryOpcode(),data,offset,length/2);
|
||||
getConnection().sendFrame((byte)0x8,getConnection().binaryOpcode(),data,offset+length/2,length-length/2);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(final String message)
|
||||
{
|
||||
super.onMessage(message);
|
||||
try
|
||||
{
|
||||
byte[] data = message.getBytes(StringUtil.__UTF8);
|
||||
int offset=0;
|
||||
int length=data.length;
|
||||
getConnection().sendFrame((byte)0x0,getConnection().textOpcode(),data,offset,length/2);
|
||||
getConnection().sendFrame((byte)0x8,getConnection().textOpcode(),data,offset+length/2,length-length/2);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void usage()
|
||||
{
|
||||
System.err.println("java -cp CLASSPATH "+TestServer.class+" [ OPTIONS ]");
|
||||
System.err.println(" -p|--port PORT (default 8080)");
|
||||
System.err.println(" -v|--verbose ");
|
||||
System.err.println(" -d|--docroot file (default 'src/test/webapp')");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
public static void main(String... args)
|
||||
{
|
||||
try
|
||||
{
|
||||
int port=8080;
|
||||
boolean verbose=false;
|
||||
String docroot="src/test/webapp";
|
||||
|
||||
for (int i=0;i<args.length;i++)
|
||||
{
|
||||
String a=args[i];
|
||||
if ("-p".equals(a)||"--port".equals(a))
|
||||
port=Integer.parseInt(args[++i]);
|
||||
else if ("-v".equals(a)||"--verbose".equals(a))
|
||||
verbose=true;
|
||||
else if ("-d".equals(a)||"--docroot".equals(a))
|
||||
docroot=args[++i];
|
||||
else if (a.startsWith("-"))
|
||||
usage();
|
||||
}
|
||||
|
||||
|
||||
TestServer server = new TestServer(port);
|
||||
server.setVerbose(verbose);
|
||||
server.setResourceBase(docroot);
|
||||
server.start();
|
||||
server.join();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
_verbose = verbose;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -15,26 +15,23 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.jetty.websocket.server;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.SelectChannelConnector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClientFactory;
|
||||
import org.eclipse.jetty.websocket.servlet.helper.CaptureSocket;
|
||||
import org.eclipse.jetty.websocket.servlet.helper.MessageSender;
|
||||
import org.eclipse.jetty.websocket.servlet.helper.WebSocketCaptureServlet;
|
||||
import org.eclipse.jetty.websocket.server.helper.CaptureSocket;
|
||||
import org.eclipse.jetty.websocket.server.helper.MessageSender;
|
||||
import org.eclipse.jetty.websocket.server.helper.WebSocketCaptureServlet;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
/**
|
||||
* WebSocketCommTest - to test reported undelivered messages in bug <a
|
||||
* href="https://jira.codehaus.org/browse/JETTY-1463">JETTY-1463</a>
|
||||
|
@ -42,6 +39,7 @@ import static org.hamcrest.Matchers.notNullValue;
|
|||
public class WebSocketCommTest
|
||||
{
|
||||
private Server server;
|
||||
private SelectChannelConnector connector;
|
||||
private WebSocketCaptureServlet servlet;
|
||||
private URI serverUri;
|
||||
|
||||
|
@ -49,7 +47,9 @@ public class WebSocketCommTest
|
|||
public void startServer() throws Exception
|
||||
{
|
||||
// Configure Server
|
||||
server = new Server(0);
|
||||
server = new Server();
|
||||
connector = new SelectChannelConnector();
|
||||
server.addConnector(connector);
|
||||
|
||||
ServletContextHandler context = new ServletContextHandler();
|
||||
context.setContextPath("/");
|
||||
|
@ -62,13 +62,12 @@ public class WebSocketCommTest
|
|||
// Start Server
|
||||
server.start();
|
||||
|
||||
Connector conn = server.getConnectors()[0];
|
||||
String host = conn.getHost();
|
||||
String host = connector.getHost();
|
||||
if (host == null)
|
||||
{
|
||||
host = "localhost";
|
||||
}
|
||||
int port = conn.getLocalPort();
|
||||
int port = connector.getLocalPort();
|
||||
serverUri = new URI(String.format("ws://%s:%d/",host,port));
|
||||
System.out.printf("Server URI: %s%n",serverUri);
|
||||
}
|
||||
|
@ -89,12 +88,12 @@ public class WebSocketCommTest
|
|||
@Test
|
||||
public void testSendTextMessages() throws Exception
|
||||
{
|
||||
WebSocketClientFactory clientFactory = new WebSocketClientFactory();
|
||||
clientFactory.start();
|
||||
// WebSocketClientFactory clientFactory = new WebSocketClientFactory();
|
||||
// clientFactory.start();
|
||||
|
||||
WebSocketClient wsc = clientFactory.newWebSocketClient();
|
||||
// WebSocketClient wsc = clientFactory.newWebSocketClient();
|
||||
MessageSender sender = new MessageSender();
|
||||
wsc.open(serverUri,sender);
|
||||
// wsc.open(serverUri,sender);
|
||||
|
||||
try
|
||||
{
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.jetty.websocket.server;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
|
@ -22,37 +24,177 @@ import java.io.InputStreamReader;
|
|||
import java.io.OutputStreamWriter;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.net.Socket;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.eclipse.jetty.io.bio.SocketEndPoint;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
import org.eclipse.jetty.io.StandardByteBufferPool;
|
||||
import org.eclipse.jetty.server.SelectChannelConnector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.eclipse.jetty.websocket.WebSocket;
|
||||
import org.eclipse.jetty.websocket.WebSocketGeneratorRFC6455;
|
||||
import org.eclipse.jetty.websocket.WebSocket.Connection;
|
||||
import org.eclipse.jetty.websocket.WebSocket.OnTextMessage;
|
||||
import org.eclipse.jetty.websocket.masks.FixedMasker;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketHandler;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketBehavior;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.frames.BaseFrame;
|
||||
import org.eclipse.jetty.websocket.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.generator.Generator;
|
||||
import org.eclipse.jetty.websocket.parser.Parser;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class WebSocketLoadRFC6455Test
|
||||
{
|
||||
private static class EchoWebSocket implements WebSocket.OnTextMessage
|
||||
{
|
||||
private volatile Connection outbound;
|
||||
|
||||
@Override
|
||||
public void onClose(int closeCode, String message)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(String data)
|
||||
{
|
||||
try
|
||||
{
|
||||
// System.err.println(">> "+data);
|
||||
outbound.sendMessage(data);
|
||||
}
|
||||
catch (IOException x)
|
||||
{
|
||||
outbound.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(Connection outbound)
|
||||
{
|
||||
this.outbound = outbound;
|
||||
}
|
||||
}
|
||||
private class WebSocketClient implements Runnable
|
||||
{
|
||||
private final Socket socket;
|
||||
private final BufferedWriter output;
|
||||
private final BufferedReader input;
|
||||
private final int iterations;
|
||||
private final CountDownLatch latch;
|
||||
private/* final */AsyncEndPoint _endp;
|
||||
private final Generator _generator;
|
||||
private final Parser _parser;
|
||||
private final Parser.Listener _handler = new Parser.Listener()
|
||||
{
|
||||
/*
|
||||
* public void close(int code,String message) { }
|
||||
*
|
||||
* public void onFrame(byte flags, byte opcode, ByteBuffer buffer) { _response=buffer; }
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void onFrame(BaseFrame frame)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketException(WebSocketException e)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
};
|
||||
private volatile ByteBuffer _response;
|
||||
|
||||
public WebSocketClient(String host, int port, int readTimeout, CountDownLatch latch, int iterations) throws IOException
|
||||
{
|
||||
this.latch = latch;
|
||||
socket = new Socket(host, port);
|
||||
socket.setSoTimeout(readTimeout);
|
||||
output = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "ISO-8859-1"));
|
||||
input = new BufferedReader(new InputStreamReader(socket.getInputStream(), "ISO-8859-1"));
|
||||
this.iterations = iterations;
|
||||
|
||||
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.CLIENT);
|
||||
|
||||
// _endp=new SocketEndPoint(socket);
|
||||
StandardByteBufferPool bufferPool = new StandardByteBufferPool();
|
||||
_generator = new Generator(bufferPool,policy);
|
||||
_parser = new Parser(policy);
|
||||
|
||||
}
|
||||
|
||||
public void close() throws IOException
|
||||
{
|
||||
socket.close();
|
||||
}
|
||||
|
||||
private void open() throws IOException
|
||||
{
|
||||
output.write("GET /chat HTTP/1.1\r\n"+
|
||||
"Host: server.example.com\r\n"+
|
||||
"Upgrade: websocket\r\n"+
|
||||
"Connection: Upgrade\r\n"+
|
||||
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"+
|
||||
"Sec-WebSocket-Origin: http://example.com\r\n"+
|
||||
"Sec-WebSocket-Protocol: onConnect\r\n" +
|
||||
"Sec-WebSocket-Version: 7\r\n"+
|
||||
"\r\n");
|
||||
output.flush();
|
||||
|
||||
String responseLine = input.readLine();
|
||||
assertTrue(responseLine.startsWith("HTTP/1.1 101 Switching Protocols"));
|
||||
// Read until we find an empty line, which signals the end of the http response
|
||||
String line;
|
||||
while ((line = input.readLine()) != null)
|
||||
{
|
||||
if (line.length() == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
String message = "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF";
|
||||
for (int i = 0; i < iterations; ++i)
|
||||
{
|
||||
TextFrame txt = new TextFrame();
|
||||
txt.setData(message);
|
||||
ByteBuffer buf = _generator.generate(txt);
|
||||
|
||||
// TODO: Send it
|
||||
// TODO: Receive response
|
||||
|
||||
Assert.assertEquals(message,_response.toString());
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
throw new RuntimeException(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Server _server;
|
||||
private static Connector _connector;
|
||||
|
||||
private static SelectChannelConnector _connector;
|
||||
|
||||
@BeforeClass
|
||||
public static void startServer() throws Exception
|
||||
|
@ -68,6 +210,7 @@ public class WebSocketLoadRFC6455Test
|
|||
|
||||
WebSocketHandler wsHandler = new WebSocketHandler()
|
||||
{
|
||||
@Override
|
||||
public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol)
|
||||
{
|
||||
return new EchoWebSocket();
|
||||
|
@ -105,16 +248,20 @@ public class WebSocketLoadRFC6455Test
|
|||
|
||||
//long start = System.nanoTime();
|
||||
for (WebSocketClient client : clients)
|
||||
{
|
||||
threadPool.execute(client);
|
||||
}
|
||||
|
||||
int parallelism = ManagementFactory.getOperatingSystemMXBean().getAvailableProcessors();
|
||||
long maxTimePerIteration = 5;
|
||||
assertTrue(latch.await(iterations * (count / parallelism + 1) * maxTimePerIteration, TimeUnit.MILLISECONDS));
|
||||
assertTrue(latch.await(iterations * ((count / parallelism) + 1) * maxTimePerIteration, TimeUnit.MILLISECONDS));
|
||||
//long end = System.nanoTime();
|
||||
// System.err.println("Elapsed: " + TimeUnit.NANOSECONDS.toMillis(end - start) + " ms");
|
||||
|
||||
for (WebSocketClient client : clients)
|
||||
{
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -122,125 +269,4 @@ public class WebSocketLoadRFC6455Test
|
|||
assertTrue(threadPool.awaitTermination(2, TimeUnit.SECONDS));
|
||||
}
|
||||
}
|
||||
|
||||
private static class EchoWebSocket implements WebSocket.OnTextMessage
|
||||
{
|
||||
private volatile Connection outbound;
|
||||
|
||||
public void onOpen(Connection outbound)
|
||||
{
|
||||
this.outbound = outbound;
|
||||
}
|
||||
|
||||
public void onMessage(String data)
|
||||
{
|
||||
try
|
||||
{
|
||||
// System.err.println(">> "+data);
|
||||
outbound.sendMessage(data);
|
||||
}
|
||||
catch (IOException x)
|
||||
{
|
||||
outbound.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
public void onClose(int closeCode, String message)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private class WebSocketClient implements Runnable
|
||||
{
|
||||
private final Socket socket;
|
||||
private final BufferedWriter output;
|
||||
private final BufferedReader input;
|
||||
private final int iterations;
|
||||
private final CountDownLatch latch;
|
||||
private final SocketEndPoint _endp;
|
||||
private final WebSocketGeneratorRFC6455 _generator;
|
||||
private final WebSocketParserRFC6455 _parser;
|
||||
private final WebSocketParser.FrameHandler _handler = new WebSocketParser.FrameHandler()
|
||||
{
|
||||
public void onFrame(byte flags, byte opcode, ByteBuffer buffer)
|
||||
{
|
||||
_response=buffer;
|
||||
}
|
||||
|
||||
public void close(int code,String message)
|
||||
{
|
||||
}
|
||||
};
|
||||
private volatile ByteBuffer _response;
|
||||
|
||||
public WebSocketClient(String host, int port, int readTimeout, CountDownLatch latch, int iterations) throws IOException
|
||||
{
|
||||
this.latch = latch;
|
||||
socket = new Socket(host, port);
|
||||
socket.setSoTimeout(readTimeout);
|
||||
output = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "ISO-8859-1"));
|
||||
input = new BufferedReader(new InputStreamReader(socket.getInputStream(), "ISO-8859-1"));
|
||||
this.iterations = iterations;
|
||||
|
||||
_endp=new SocketEndPoint(socket);
|
||||
_generator = new WebSocketGeneratorRFC6455(new WebSocketBuffers(32*1024),_endp,new FixedMasker());
|
||||
_parser = new WebSocketParserRFC6455(new WebSocketBuffers(32*1024),_endp,_handler,false);
|
||||
|
||||
}
|
||||
|
||||
private void open() throws IOException
|
||||
{
|
||||
output.write("GET /chat HTTP/1.1\r\n"+
|
||||
"Host: server.example.com\r\n"+
|
||||
"Upgrade: websocket\r\n"+
|
||||
"Connection: Upgrade\r\n"+
|
||||
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"+
|
||||
"Sec-WebSocket-Origin: http://example.com\r\n"+
|
||||
"Sec-WebSocket-Protocol: onConnect\r\n" +
|
||||
"Sec-WebSocket-Version: 7\r\n"+
|
||||
"\r\n");
|
||||
output.flush();
|
||||
|
||||
String responseLine = input.readLine();
|
||||
assertTrue(responseLine.startsWith("HTTP/1.1 101 Switching Protocols"));
|
||||
// Read until we find an empty line, which signals the end of the http response
|
||||
String line;
|
||||
while ((line = input.readLine()) != null)
|
||||
if (line.length() == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
String message = "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF";
|
||||
for (int i = 0; i < iterations; ++i)
|
||||
{
|
||||
byte[] data = message.getBytes(StringUtil.__UTF8);
|
||||
_generator.addFrame((byte)0x8,WebSocketConnectionRFC6455.OP_TEXT,data,0,data.length);
|
||||
_generator.flush();
|
||||
|
||||
//System.err.println("-> "+message);
|
||||
|
||||
_response=null;
|
||||
while(_response==null)
|
||||
_parser.parseNext();
|
||||
//System.err.println("<- "+_response);
|
||||
Assert.assertEquals(message,_response.toString());
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
catch (IOException x)
|
||||
{
|
||||
throw new RuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void close() throws IOException
|
||||
{
|
||||
socket.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -16,10 +16,10 @@
|
|||
package org.eclipse.jetty.websocket.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
|
@ -28,12 +28,6 @@ import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
|||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.eclipse.jetty.websocket.WebSocket;
|
||||
import org.eclipse.jetty.websocket.WebSocket.Connection;
|
||||
import org.eclipse.jetty.websocket.WebSocket.OnTextMessage;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClientFactory;
|
||||
import org.eclipse.jetty.websocket.masks.ZeroMasker;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketHandler;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
@ -43,9 +37,51 @@ public class WebSocketOverSSLTest
|
|||
private Server _server;
|
||||
private int _port;
|
||||
private QueuedThreadPool _threadPool;
|
||||
private WebSocketClientFactory _wsFactory;
|
||||
// private WebSocketClientFactory _wsFactory;
|
||||
private WebSocket.Connection _connection;
|
||||
|
||||
@After
|
||||
public void destroy() throws Exception
|
||||
{
|
||||
if (_connection != null)
|
||||
{
|
||||
_connection.close();
|
||||
}
|
||||
|
||||
// if (_wsFactory != null)
|
||||
// _wsFactory.stop();
|
||||
|
||||
if (_threadPool != null)
|
||||
{
|
||||
_threadPool.stop();
|
||||
}
|
||||
|
||||
if (_server != null)
|
||||
{
|
||||
_server.stop();
|
||||
_server.join();
|
||||
}
|
||||
}
|
||||
|
||||
private void startClient(final WebSocket webSocket) throws Exception
|
||||
{
|
||||
Assert.assertTrue(_server.isStarted());
|
||||
|
||||
_threadPool = new QueuedThreadPool();
|
||||
_threadPool.setName("wsc-" + _threadPool.getName());
|
||||
_threadPool.start();
|
||||
|
||||
// _wsFactory = new WebSocketClientFactory(_threadPool, new ZeroMasker());
|
||||
// SslContextFactory cf = _wsFactory.getSslContextFactory();
|
||||
// cf.setKeyStorePath(MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath());
|
||||
// cf.setKeyStorePassword("storepwd");
|
||||
// cf.setKeyManagerPassword("keypwd");
|
||||
// _wsFactory.start();
|
||||
|
||||
// WebSocketClient client = new WebSocketClient(_wsFactory);
|
||||
// _connection = client.open(new URI("wss://localhost:" + _port), webSocket).get(5, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void startServer(final WebSocket webSocket) throws Exception
|
||||
{
|
||||
_server = new Server();
|
||||
|
@ -57,6 +93,7 @@ public class WebSocketOverSSLTest
|
|||
cf.setKeyManagerPassword("keypwd");
|
||||
_server.setHandler(new WebSocketHandler()
|
||||
{
|
||||
@Override
|
||||
public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol)
|
||||
{
|
||||
return webSocket;
|
||||
|
@ -66,42 +103,71 @@ public class WebSocketOverSSLTest
|
|||
_port = connector.getLocalPort();
|
||||
}
|
||||
|
||||
private void startClient(final WebSocket webSocket) throws Exception
|
||||
@Test
|
||||
public void testManyMessages() throws Exception
|
||||
{
|
||||
Assert.assertTrue(_server.isStarted());
|
||||
|
||||
_threadPool = new QueuedThreadPool();
|
||||
_threadPool.setName("wsc-" + _threadPool.getName());
|
||||
_threadPool.start();
|
||||
|
||||
_wsFactory = new WebSocketClientFactory(_threadPool, new ZeroMasker());
|
||||
SslContextFactory cf = _wsFactory.getSslContextFactory();
|
||||
cf.setKeyStorePath(MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath());
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
_wsFactory.start();
|
||||
|
||||
WebSocketClient client = new WebSocketClient(_wsFactory);
|
||||
_connection = client.open(new URI("wss://localhost:" + _port), webSocket).get(5, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@After
|
||||
public void destroy() throws Exception
|
||||
{
|
||||
if (_connection != null)
|
||||
_connection.close();
|
||||
|
||||
if (_wsFactory != null)
|
||||
_wsFactory.stop();
|
||||
|
||||
if (_threadPool != null)
|
||||
_threadPool.stop();
|
||||
|
||||
if (_server != null)
|
||||
startServer(new WebSocket.OnTextMessage()
|
||||
{
|
||||
_server.stop();
|
||||
_server.join();
|
||||
private Connection connection;
|
||||
|
||||
@Override
|
||||
public void onClose(int closeCode, String message)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(String data)
|
||||
{
|
||||
try
|
||||
{
|
||||
connection.sendMessage(data);
|
||||
}
|
||||
catch (IOException x)
|
||||
{
|
||||
x.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(Connection connection)
|
||||
{
|
||||
this.connection = connection;
|
||||
}
|
||||
});
|
||||
int count = 1000;
|
||||
final CountDownLatch clientLatch = new CountDownLatch(count);
|
||||
startClient(new WebSocket.OnTextMessage()
|
||||
{
|
||||
@Override
|
||||
public void onClose(int closeCode, String message)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(String data)
|
||||
{
|
||||
clientLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(Connection connection)
|
||||
{
|
||||
}
|
||||
});
|
||||
|
||||
char[] chars = new char[256];
|
||||
Arrays.fill(chars, 'x');
|
||||
String message = new String(chars);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
_connection.sendMessage(message);
|
||||
}
|
||||
|
||||
Assert.assertTrue(clientLatch.await(20, TimeUnit.SECONDS));
|
||||
|
||||
// While messages may have all arrived, the SSL close alert
|
||||
// may be in the way so give some time for it to be processed.
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -113,11 +179,12 @@ public class WebSocketOverSSLTest
|
|||
{
|
||||
private Connection connection;
|
||||
|
||||
public void onOpen(Connection connection)
|
||||
@Override
|
||||
public void onClose(int closeCode, String message)
|
||||
{
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(String data)
|
||||
{
|
||||
try
|
||||
|
@ -132,24 +199,29 @@ public class WebSocketOverSSLTest
|
|||
}
|
||||
}
|
||||
|
||||
public void onClose(int closeCode, String message)
|
||||
@Override
|
||||
public void onOpen(Connection connection)
|
||||
{
|
||||
this.connection = connection;
|
||||
}
|
||||
});
|
||||
final CountDownLatch clientLatch = new CountDownLatch(1);
|
||||
startClient(new WebSocket.OnTextMessage()
|
||||
{
|
||||
public void onOpen(Connection connection)
|
||||
@Override
|
||||
public void onClose(int closeCode, String message)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(String data)
|
||||
{
|
||||
Assert.assertEquals(message, data);
|
||||
clientLatch.countDown();
|
||||
}
|
||||
|
||||
public void onClose(int closeCode, String message)
|
||||
@Override
|
||||
public void onOpen(Connection connection)
|
||||
{
|
||||
}
|
||||
});
|
||||
|
@ -158,63 +230,4 @@ public class WebSocketOverSSLTest
|
|||
Assert.assertTrue(serverLatch.await(5, TimeUnit.SECONDS));
|
||||
Assert.assertTrue(clientLatch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManyMessages() throws Exception
|
||||
{
|
||||
startServer(new WebSocket.OnTextMessage()
|
||||
{
|
||||
private Connection connection;
|
||||
|
||||
public void onOpen(Connection connection)
|
||||
{
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
public void onMessage(String data)
|
||||
{
|
||||
try
|
||||
{
|
||||
connection.sendMessage(data);
|
||||
}
|
||||
catch (IOException x)
|
||||
{
|
||||
x.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void onClose(int closeCode, String message)
|
||||
{
|
||||
}
|
||||
});
|
||||
int count = 1000;
|
||||
final CountDownLatch clientLatch = new CountDownLatch(count);
|
||||
startClient(new WebSocket.OnTextMessage()
|
||||
{
|
||||
public void onOpen(Connection connection)
|
||||
{
|
||||
}
|
||||
|
||||
public void onMessage(String data)
|
||||
{
|
||||
clientLatch.countDown();
|
||||
}
|
||||
|
||||
public void onClose(int closeCode, String message)
|
||||
{
|
||||
}
|
||||
});
|
||||
|
||||
char[] chars = new char[256];
|
||||
Arrays.fill(chars, 'x');
|
||||
String message = new String(chars);
|
||||
for (int i = 0; i < count; ++i)
|
||||
_connection.sendMessage(message);
|
||||
|
||||
Assert.assertTrue(clientLatch.await(20, TimeUnit.SECONDS));
|
||||
|
||||
// While messages may have all arrived, the SSL close alert
|
||||
// may be in the way so give some time for it to be processed.
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,13 +16,17 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.server;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.eclipse.jetty.server.SelectChannelConnector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.websocket.WebSocket;
|
||||
import org.eclipse.jetty.websocket.WebSocket.Connection;
|
||||
import org.eclipse.jetty.websocket.WebSocket.OnTextMessage;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
@ -32,15 +36,16 @@ public class WebSocketRedeployTest
|
|||
private Server server;
|
||||
private ServletContextHandler context;
|
||||
private String uri;
|
||||
private WebSocketClientFactory wsFactory;
|
||||
|
||||
// private WebSocketClientFactory wsFactory;
|
||||
|
||||
@After
|
||||
public void destroy() throws Exception
|
||||
{
|
||||
if (wsFactory != null)
|
||||
{
|
||||
wsFactory.stop();
|
||||
}
|
||||
// if (wsFactory != null)
|
||||
// {
|
||||
// wsFactory.stop();
|
||||
// }
|
||||
if (server != null)
|
||||
{
|
||||
server.stop();
|
||||
|
@ -52,7 +57,7 @@ public class WebSocketRedeployTest
|
|||
{
|
||||
server = new Server();
|
||||
SelectChannelConnector connector = new SelectChannelConnector();
|
||||
// connector.setPort(8080);
|
||||
// connector.setPort(8080);
|
||||
server.addConnector(connector);
|
||||
|
||||
HandlerCollection handlers = new HandlerCollection();
|
||||
|
@ -63,6 +68,7 @@ public class WebSocketRedeployTest
|
|||
|
||||
WebSocketServlet servlet = new WebSocketServlet()
|
||||
{
|
||||
@Override
|
||||
public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol)
|
||||
{
|
||||
return webSocket;
|
||||
|
@ -75,8 +81,8 @@ public class WebSocketRedeployTest
|
|||
|
||||
uri = "ws://localhost:" + connector.getLocalPort() + contextPath + servletPath;
|
||||
|
||||
wsFactory = new WebSocketClientFactory();
|
||||
wsFactory.start();
|
||||
// wsFactory = new WebSocketClientFactory();
|
||||
// wsFactory.start();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -104,30 +110,30 @@ public class WebSocketRedeployTest
|
|||
}
|
||||
});
|
||||
|
||||
WebSocketClient client = wsFactory.newWebSocketClient();
|
||||
client.open(new URI(uri), new WebSocket.OnTextMessage()
|
||||
{
|
||||
@Override
|
||||
public void onClose(int closeCode, String message)
|
||||
{
|
||||
closeLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(String data)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(Connection connection)
|
||||
{
|
||||
openLatch.countDown();
|
||||
}
|
||||
}, 5, TimeUnit.SECONDS);
|
||||
// WebSocketClient client = wsFactory.newWebSocketClient();
|
||||
// client.open(new URI(uri), new WebSocket.OnTextMessage()
|
||||
// {
|
||||
// @Override
|
||||
// public void onClose(int closeCode, String message)
|
||||
// {
|
||||
// closeLatch.countDown();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onMessage(String data)
|
||||
// {
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onOpen(Connection connection)
|
||||
// {
|
||||
// openLatch.countDown();
|
||||
// }
|
||||
// }, 5, TimeUnit.SECONDS);
|
||||
|
||||
Assert.assertTrue(openLatch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
wsFactory.stop();
|
||||
// wsFactory.stop();
|
||||
|
||||
Assert.assertTrue(closeLatch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
@ -157,26 +163,26 @@ public class WebSocketRedeployTest
|
|||
}
|
||||
});
|
||||
|
||||
WebSocketClient client = wsFactory.newWebSocketClient();
|
||||
client.open(new URI(uri), new WebSocket.OnTextMessage()
|
||||
{
|
||||
@Override
|
||||
public void onClose(int closeCode, String message)
|
||||
{
|
||||
closeLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(String data)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(Connection connection)
|
||||
{
|
||||
openLatch.countDown();
|
||||
}
|
||||
}, 5, TimeUnit.SECONDS);
|
||||
// WebSocketClient client = wsFactory.newWebSocketClient();
|
||||
// client.open(new URI(uri), new WebSocket.OnTextMessage()
|
||||
// {
|
||||
// @Override
|
||||
// public void onClose(int closeCode, String message)
|
||||
// {
|
||||
// closeLatch.countDown();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onMessage(String data)
|
||||
// {
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onOpen(Connection connection)
|
||||
// {
|
||||
// openLatch.countDown();
|
||||
// }
|
||||
// }, 5, TimeUnit.SECONDS);
|
||||
|
||||
Assert.assertTrue(openLatch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
|
|
|
@ -15,20 +15,14 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.SelectChannelConnector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.websocket.WebSocket;
|
||||
import org.eclipse.jetty.websocket.WebSocketGeneratorRFC6455Test;
|
||||
import org.eclipse.jetty.websocket.WebSocketParserRFC6455Test;
|
||||
import org.eclipse.jetty.websocket.WebSocket.Connection;
|
||||
import org.eclipse.jetty.websocket.WebSocket.OnTextMessage;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClientFactory;
|
||||
import org.eclipse.jetty.websocket.servlet.helper.MessageSender;
|
||||
import org.eclipse.jetty.websocket.servlet.helper.WebSocketServlet;
|
||||
import org.eclipse.jetty.websocket.server.helper.MessageSender;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
|
@ -43,20 +37,27 @@ import org.junit.Test;
|
|||
*/
|
||||
public class WebSocketServletRFCTest
|
||||
{
|
||||
@SuppressWarnings("serial")
|
||||
private static class RFCServlet extends WebSocketServlet
|
||||
{
|
||||
@Override
|
||||
public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol)
|
||||
{
|
||||
return new RFCSocket();
|
||||
}
|
||||
}
|
||||
|
||||
private static class RFCSocket implements WebSocket, WebSocket.OnTextMessage
|
||||
{
|
||||
private Connection conn;
|
||||
|
||||
public void onOpen(Connection connection)
|
||||
{
|
||||
this.conn = connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(int closeCode, String message)
|
||||
{
|
||||
this.conn = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(String data)
|
||||
{
|
||||
// Test the RFC 6455 close code 1011 that should close
|
||||
|
@ -77,25 +78,25 @@ public class WebSocketServletRFCTest
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class RFCServlet extends WebSocketServlet
|
||||
{
|
||||
public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol)
|
||||
@Override
|
||||
public void onOpen(Connection connection)
|
||||
{
|
||||
return new RFCSocket();
|
||||
this.conn = connection;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static Server server;
|
||||
private static SelectChannelConnector connector;
|
||||
private static URI serverUri;
|
||||
|
||||
@BeforeClass
|
||||
public static void startServer() throws Exception
|
||||
{
|
||||
// Configure Server
|
||||
server = new Server(0);
|
||||
server = new Server();
|
||||
connector = new SelectChannelConnector();
|
||||
server.addConnector(connector);
|
||||
|
||||
ServletContextHandler context = new ServletContextHandler();
|
||||
context.setContextPath("/");
|
||||
|
@ -107,13 +108,12 @@ public class WebSocketServletRFCTest
|
|||
// Start Server
|
||||
server.start();
|
||||
|
||||
Connector conn = server.getConnectors()[0];
|
||||
String host = conn.getHost();
|
||||
String host = connector.getHost();
|
||||
if (host == null)
|
||||
{
|
||||
host = "localhost";
|
||||
}
|
||||
int port = conn.getLocalPort();
|
||||
int port = connector.getLocalPort();
|
||||
serverUri = new URI(String.format("ws://%s:%d/",host,port));
|
||||
System.out.printf("Server URI: %s%n",serverUri);
|
||||
}
|
||||
|
@ -131,6 +131,59 @@ public class WebSocketServletRFCTest
|
|||
}
|
||||
}
|
||||
|
||||
private String readResponseHeader(InputStream in) throws IOException
|
||||
{
|
||||
InputStreamReader isr = new InputStreamReader(in);
|
||||
BufferedReader reader = new BufferedReader(isr);
|
||||
StringBuilder header = new StringBuilder();
|
||||
// Read the response header
|
||||
String line = reader.readLine();
|
||||
Assert.assertNotNull(line);
|
||||
Assert.assertThat(line,startsWith("HTTP/1.1 "));
|
||||
header.append(line).append("\r\n");
|
||||
while ((line = reader.readLine()) != null)
|
||||
{
|
||||
if (line.trim().length() == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
header.append(line).append("\r\n");
|
||||
}
|
||||
return header.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the requirement of responding with server terminated close code 1011 when there is an unhandled (internal
|
||||
* server error) being produced by the extended WebSocketServlet.
|
||||
*/
|
||||
@Test
|
||||
public void testResponseOnInternalError() throws Exception
|
||||
{
|
||||
// WebSocketClientFactory clientFactory = new WebSocketClientFactory();
|
||||
// clientFactory.start();
|
||||
|
||||
// WebSocketClient wsc = clientFactory.newWebSocketClient();
|
||||
MessageSender sender = new MessageSender();
|
||||
// wsc.open(serverUri,sender);
|
||||
|
||||
try
|
||||
{
|
||||
sender.awaitConnect();
|
||||
|
||||
sender.sendMessage("CRASH");
|
||||
|
||||
// Give servlet 500 millisecond to process messages
|
||||
TimeUnit.MILLISECONDS.sleep(500);
|
||||
|
||||
Assert.assertThat("WebSocket should be closed",sender.isConnected(),is(false));
|
||||
Assert.assertThat("WebSocket close clode",sender.getCloseCode(),is(1011));
|
||||
}
|
||||
finally
|
||||
{
|
||||
sender.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the requirement of responding with an http 400 when using a Sec-WebSocket-Version that is unsupported.
|
||||
*/
|
||||
|
@ -177,57 +230,4 @@ public class WebSocketServletRFCTest
|
|||
socket.close();
|
||||
}
|
||||
}
|
||||
|
||||
private String readResponseHeader(InputStream in) throws IOException
|
||||
{
|
||||
InputStreamReader isr = new InputStreamReader(in);
|
||||
BufferedReader reader = new BufferedReader(isr);
|
||||
StringBuilder header = new StringBuilder();
|
||||
// Read the response header
|
||||
String line = reader.readLine();
|
||||
Assert.assertNotNull(line);
|
||||
Assert.assertThat(line,startsWith("HTTP/1.1 "));
|
||||
header.append(line).append("\r\n");
|
||||
while ((line = reader.readLine()) != null)
|
||||
{
|
||||
if (line.trim().length() == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
header.append(line).append("\r\n");
|
||||
}
|
||||
return header.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the requirement of responding with server terminated close code 1011 when there is an unhandled (internal
|
||||
* server error) being produced by the extended WebSocketServlet.
|
||||
*/
|
||||
@Test
|
||||
public void testResponseOnInternalError() throws Exception
|
||||
{
|
||||
WebSocketClientFactory clientFactory = new WebSocketClientFactory();
|
||||
clientFactory.start();
|
||||
|
||||
WebSocketClient wsc = clientFactory.newWebSocketClient();
|
||||
MessageSender sender = new MessageSender();
|
||||
wsc.open(serverUri,sender);
|
||||
|
||||
try
|
||||
{
|
||||
sender.awaitConnect();
|
||||
|
||||
sender.sendMessage("CRASH");
|
||||
|
||||
// Give servlet 500 millisecond to process messages
|
||||
TimeUnit.MILLISECONDS.sleep(500);
|
||||
|
||||
Assert.assertThat("WebSocket should be closed",sender.isConnected(),is(false));
|
||||
Assert.assertThat("WebSocket close clode",sender.getCloseCode(),is(1011));
|
||||
}
|
||||
finally
|
||||
{
|
||||
sender.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.jetty.websocket.server.helper;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -25,13 +27,12 @@ import java.net.InetSocketAddress;
|
|||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.io.ByteArrayBuffer;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.junit.Assert;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
public class SafariD00
|
||||
{
|
||||
private URI uri;
|
||||
|
@ -63,6 +64,11 @@ public class SafariD00
|
|||
return socket;
|
||||
}
|
||||
|
||||
public void disconnect() throws IOException
|
||||
{
|
||||
socket.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue an Http websocket (Draft-0) upgrade request using the Safari particulars.
|
||||
*
|
||||
|
@ -126,7 +132,7 @@ public class SafariD00
|
|||
len += (msg.length() + 2);
|
||||
}
|
||||
|
||||
ByteArrayBuffer buf = new ByteArrayBuffer(len);
|
||||
ByteBuffer buf = ByteBuffer.allocate(len);
|
||||
|
||||
for (String msg : msgs)
|
||||
{
|
||||
|
@ -135,12 +141,7 @@ public class SafariD00
|
|||
buf.put((byte)0xFF);
|
||||
}
|
||||
|
||||
out.write(buf.array());
|
||||
BufferUtil.writeTo(buf,out);
|
||||
out.flush();
|
||||
}
|
||||
|
||||
public void disconnect() throws IOException
|
||||
{
|
||||
socket.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,9 +24,9 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.websocket.WebSocket;
|
||||
import org.eclipse.jetty.websocket.servlet.helper.WebSocketServlet;
|
||||
import org.eclipse.jetty.websocket.server.WebSocketServlet;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@SuppressWarnings("serial")
|
||||
public class WebSocketCaptureServlet extends WebSocketServlet
|
||||
{
|
||||
public List<CaptureSocket> captures = new ArrayList<CaptureSocket>();;
|
||||
|
@ -37,6 +37,7 @@ public class WebSocketCaptureServlet extends WebSocketServlet
|
|||
resp.sendError(404);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol)
|
||||
{
|
||||
CaptureSocket capture = new CaptureSocket();
|
||||
|
|
Loading…
Reference in New Issue