org.eclipse.jetty.websocket.common.WebSocketSession Maven / Gradle / Ivy
//
// ========================================================================
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.websocket.common;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.jetty.util.MultiMap;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.UrlEncoded;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.component.Dumpable;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.api.CloseStatus;
import org.eclipse.jetty.websocket.api.RemoteEndpoint;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.api.SuspendToken;
import org.eclipse.jetty.websocket.api.UpgradeRequest;
import org.eclipse.jetty.websocket.api.UpgradeResponse;
import org.eclipse.jetty.websocket.api.WebSocketException;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.api.extensions.ExtensionFactory;
import org.eclipse.jetty.websocket.api.extensions.Frame;
import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
import org.eclipse.jetty.websocket.api.extensions.OutgoingFrames;
import org.eclipse.jetty.websocket.common.events.EventDriver;
@ManagedObject
public class WebSocketSession extends ContainerLifeCycle implements Session, IncomingFrames
{
private static final Logger LOG = Log.getLogger(WebSocketSession.class);
private final URI requestURI;
private final EventDriver websocket;
private final LogicalConnection connection;
private ExtensionFactory extensionFactory;
private long maximumMessageSize;
private String protocolVersion;
private long timeout;
private Map parameterMap = new HashMap<>();
private WebSocketRemoteEndpoint remote;
private IncomingFrames incomingHandler;
private OutgoingFrames outgoingHandler;
private WebSocketPolicy policy;
private UpgradeRequest upgradeRequest;
private UpgradeResponse upgradeResponse;
public WebSocketSession(URI requestURI, EventDriver websocket, LogicalConnection connection)
{
if (requestURI == null)
{
throw new RuntimeException("Request URI cannot be null");
}
this.requestURI = requestURI;
this.websocket = websocket;
this.connection = connection;
this.outgoingHandler = connection;
this.incomingHandler = websocket;
// Get the parameter map (use the jetty MultiMap to do this right)
MultiMap params = new MultiMap<>();
String query = requestURI.getQuery();
if (StringUtil.isNotBlank(query))
{
UrlEncoded.decodeTo(query,params,StringUtil.__UTF8_CHARSET,-1);
}
for (String name : params.keySet())
{
List valueList = params.getValues(name);
String valueArr[] = new String[valueList.size()];
valueArr = valueList.toArray(valueArr);
parameterMap.put(name,valueArr);
}
}
@Override
public void close() throws IOException
{
connection.close();
}
@Override
public void close(CloseStatus closeStatus)
{
this.close(closeStatus.getCode(),closeStatus.getPhrase());
}
@Override
public void close(int statusCode, String reason)
{
connection.close(statusCode,reason);
websocket.onClose(new CloseInfo(statusCode,reason));
}
/**
* Harsh disconnect
*/
@Override
public void disconnect()
{
connection.disconnect();
// notify of harsh disconnect
websocket.onClose(new CloseInfo(StatusCode.NO_CLOSE,"Harsh disconnect"));
}
@Override
public void dump(Appendable out, String indent) throws IOException
{
super.dump(out,indent);
out.append(indent).append(" +- incomingHandler : ");
if (incomingHandler instanceof Dumpable)
{
((Dumpable)incomingHandler).dump(out,indent + " ");
}
else
{
out.append(incomingHandler.toString()).append('\n');
}
out.append(indent).append(" +- outgoingHandler : ");
if (outgoingHandler instanceof Dumpable)
{
((Dumpable)outgoingHandler).dump(out,indent + " ");
}
else
{
out.append(outgoingHandler.toString()).append('\n');
}
}
public LogicalConnection getConnection()
{
return connection;
}
public ExtensionFactory getExtensionFactory()
{
return extensionFactory;
}
/**
* The idle timeout in seconds
*/
@Override
public long getIdleTimeout()
{
return timeout;
}
@ManagedAttribute(readonly = true)
public IncomingFrames getIncomingHandler()
{
return incomingHandler;
}
@Override
public InetSocketAddress getLocalAddress()
{
return connection.getLocalAddress();
}
@Override
public long getMaximumMessageSize()
{
return maximumMessageSize;
}
@ManagedAttribute(readonly = true)
public OutgoingFrames getOutgoingHandler()
{
return outgoingHandler;
}
@Override
public WebSocketPolicy getPolicy()
{
return policy;
}
@Override
public String getProtocolVersion()
{
return protocolVersion;
}
@Override
public RemoteEndpoint getRemote()
{
if (!isOpen())
{
throw new WebSocketException("Session has not been opened yet");
}
return remote;
}
@Override
public InetSocketAddress getRemoteAddress()
{
return remote.getInetSocketAddress();
}
@Override
public UpgradeRequest getUpgradeRequest()
{
return this.upgradeRequest;
}
@Override
public UpgradeResponse getUpgradeResponse()
{
return this.upgradeResponse;
}
/**
* Incoming Errors from Parser
*/
@Override
public void incomingError(WebSocketException e)
{
if (connection.getIOState().isInputClosed())
{
return; // input is closed
}
// Forward Errors to User WebSocket Object
websocket.incomingError(e);
}
/**
* Incoming Raw Frames from Parser
*/
@Override
public void incomingFrame(Frame frame)
{
if (connection.getIOState().isInputClosed())
{
return; // input is closed
}
// Forward Frames Through Extension List
incomingHandler.incomingFrame(frame);
}
@Override
public boolean isOpen()
{
if (this.connection == null)
{
return false;
}
return this.connection.isOpen();
}
@Override
public boolean isSecure()
{
if (upgradeRequest == null)
{
throw new IllegalStateException("No valid UpgradeRequest yet");
}
URI requestURI = upgradeRequest.getRequestURI();
return "wss".equalsIgnoreCase(requestURI.getScheme());
}
/**
* Open/Activate the session
*
* @throws IOException
*/
public void open()
{
if (remote != null)
{
// already opened
return;
}
// Connect remote
remote = new WebSocketRemoteEndpoint(connection,outgoingHandler);
// Open WebSocket
websocket.openSession(this);
if (LOG.isDebugEnabled())
{
LOG.debug("open -> {}",dump());
}
}
public void setExtensionFactory(ExtensionFactory extensionFactory)
{
this.extensionFactory = extensionFactory;
}
/**
* Set the timeout in seconds
*/
@Override
public void setIdleTimeout(long seconds)
{
this.timeout = seconds;
}
@Override
public void setMaximumMessageSize(long length)
{
this.maximumMessageSize = length;
}
public void setOutgoingHandler(OutgoingFrames outgoing)
{
this.outgoingHandler = outgoing;
}
public void setPolicy(WebSocketPolicy policy)
{
this.policy = policy;
}
public void setUpgradeRequest(UpgradeRequest request)
{
this.upgradeRequest = request;
}
public void setUpgradeResponse(UpgradeResponse response)
{
this.upgradeResponse = response;
}
@Override
public SuspendToken suspend()
{
// TODO Auto-generated method stub
return null;
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append("WebSocketSession[");
builder.append("websocket=").append(websocket);
builder.append(",behavior=").append(policy.getBehavior());
builder.append(",connection=").append(connection);
builder.append(",remote=").append(remote);
builder.append(",incoming=").append(incomingHandler);
builder.append(",outgoing=").append(outgoingHandler);
builder.append("]");
return builder.toString();
}
}