427690 - Remove Mux Extension and related support.
This commit is contained in:
parent
66a19bd646
commit
b37c68db3b
|
@ -19,7 +19,6 @@
|
|||
<module>websocket-client</module>
|
||||
<module>websocket-server</module>
|
||||
<module>websocket-servlet</module>
|
||||
<module>websocket-mux-extension</module>
|
||||
<module>javax-websocket-client-impl</module>
|
||||
<module>javax-websocket-server-impl</module>
|
||||
</modules>
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-parent</artifactId>
|
||||
<version>9.1.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>websocket-mux-extension</artifactId>
|
||||
<name>Jetty :: Websocket :: Mux Extension</name>
|
||||
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.mux</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-test-helper</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>tests-jar</id>
|
||||
<goals>
|
||||
<goal>test-jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -1,65 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.WriteCallback;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.common.LogicalConnection;
|
||||
import org.eclipse.jetty.websocket.common.extensions.AbstractExtension;
|
||||
|
||||
/**
|
||||
* Multiplexing Extension for WebSockets.
|
||||
* <p>
|
||||
* Supporting <a href="https://tools.ietf.org/html/draft-ietf-hybi-websocket-multiplexing-08">draft-ietf-hybi-websocket-multiplexing-08</a> Specification.
|
||||
*/
|
||||
public abstract class AbstractMuxExtension extends AbstractExtension
|
||||
{
|
||||
private Muxer muxer;
|
||||
|
||||
public AbstractMuxExtension()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public abstract void configureMuxer(Muxer muxer);
|
||||
|
||||
@Override
|
||||
public void incomingFrame(Frame frame)
|
||||
{
|
||||
this.muxer.incomingFrame(frame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void outgoingFrame(Frame frame, WriteCallback callback)
|
||||
{
|
||||
/* do nothing here, allow Muxer to handle this aspect */
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConnection(LogicalConnection connection)
|
||||
{
|
||||
super.setConnection(connection);
|
||||
if (muxer != null)
|
||||
{
|
||||
throw new RuntimeException("Cannot reset muxer physical connection once established");
|
||||
}
|
||||
this.muxer = new Muxer(connection);
|
||||
configureMuxer(this.muxer);
|
||||
}
|
||||
}
|
|
@ -1,248 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.api.SuspendToken;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.WriteCallback;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.ConnectionState;
|
||||
import org.eclipse.jetty.websocket.common.LogicalConnection;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.common.io.IOState;
|
||||
import org.eclipse.jetty.websocket.common.io.IOState.ConnectionStateListener;
|
||||
|
||||
/**
|
||||
* MuxChannel, acts as WebSocketConnection for specific sub-channel.
|
||||
*/
|
||||
public class MuxChannel implements LogicalConnection, IncomingFrames, SuspendToken, ConnectionStateListener
|
||||
{
|
||||
private final long channelId;
|
||||
private final Muxer muxer;
|
||||
private final AtomicBoolean suspendToken;
|
||||
private IOState ioState;
|
||||
private WebSocketPolicy policy;
|
||||
private WebSocketSession session;
|
||||
private IncomingFrames incoming;
|
||||
|
||||
public MuxChannel(long channelId, Muxer muxer)
|
||||
{
|
||||
this.channelId = channelId;
|
||||
this.muxer = muxer;
|
||||
this.policy = muxer.getPolicy().clonePolicy();
|
||||
|
||||
this.suspendToken = new AtomicBoolean(false);
|
||||
this.ioState = new IOState();
|
||||
this.ioState.addListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor getExecutor()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
close(StatusCode.NORMAL,null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(int statusCode, String reason)
|
||||
{
|
||||
CloseInfo close = new CloseInfo(statusCode,reason);
|
||||
// TODO: disconnect callback?
|
||||
outgoingFrame(close.asFrame(),null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect()
|
||||
{
|
||||
// TODO: disconnect the virtual end-point?
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBufferPool getBufferPool()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public long getChannelId()
|
||||
{
|
||||
return channelId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getIdleTimeout()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IOState getIOState()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getLocalAddress()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMaxIdleTimeout()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebSocketPolicy getPolicy()
|
||||
{
|
||||
return policy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getRemoteAddress()
|
||||
{
|
||||
return muxer.getRemoteAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebSocketSession getSession()
|
||||
{
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Incoming exceptions from Muxer.
|
||||
*/
|
||||
@Override
|
||||
public void incomingError(Throwable e)
|
||||
{
|
||||
incoming.incomingError(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Incoming frames from Muxer
|
||||
*/
|
||||
@Override
|
||||
public void incomingFrame(Frame frame)
|
||||
{
|
||||
incoming.incomingFrame(frame);
|
||||
}
|
||||
|
||||
public boolean isActive()
|
||||
{
|
||||
return (ioState.isOpen());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen()
|
||||
{
|
||||
return isActive() && muxer.isOpen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReading()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void onClose()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionStateChange(ConnectionState state)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
public void onOpen()
|
||||
{
|
||||
this.ioState.onOpened();
|
||||
}
|
||||
|
||||
/**
|
||||
* Frames destined for the Muxer
|
||||
*/
|
||||
@Override
|
||||
public void outgoingFrame(Frame frame, WriteCallback callback)
|
||||
{
|
||||
muxer.output(channelId,frame,callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resume()
|
||||
{
|
||||
if (suspendToken.getAndSet(false))
|
||||
{
|
||||
// TODO: Start reading again. (how?)
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxIdleTimeout(long ms)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNextIncomingFrames(IncomingFrames incoming)
|
||||
{
|
||||
this.incoming = incoming;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSession(WebSocketSession session)
|
||||
{
|
||||
this.session = session;
|
||||
// session.setOutgoing(this);
|
||||
}
|
||||
|
||||
public void setSubProtocol(String subProtocol)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuspendToken suspend()
|
||||
{
|
||||
suspendToken.set(true);
|
||||
// TODO: how to suspend reading?
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux;
|
||||
|
||||
public interface MuxControlBlock
|
||||
{
|
||||
public int getOpCode();
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class MuxException extends WebSocketException
|
||||
{
|
||||
public MuxException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
public MuxException(String message, Throwable cause)
|
||||
{
|
||||
super(message,cause);
|
||||
}
|
||||
|
||||
public MuxException(Throwable cause)
|
||||
{
|
||||
super(cause);
|
||||
}
|
||||
}
|
|
@ -1,272 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.io.ArrayByteBufferPool;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.websocket.api.WriteCallback;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.api.extensions.OutgoingFrames;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.frames.BinaryFrame;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxAddChannelRequest;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxAddChannelResponse;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxDropChannel;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxFlowControl;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxNewChannelSlot;
|
||||
|
||||
/**
|
||||
* Generate Mux frames destined for the physical connection.
|
||||
*/
|
||||
public class MuxGenerator
|
||||
{
|
||||
private static final int CONTROL_BUFFER_SIZE = 2 * 1024;
|
||||
/** 4 bytes for channel ID + 1 for fin/rsv/opcode */
|
||||
private static final int DATA_FRAME_OVERHEAD = 5;
|
||||
private ByteBufferPool bufferPool;
|
||||
private OutgoingFrames outgoing;
|
||||
|
||||
public MuxGenerator()
|
||||
{
|
||||
this(new ArrayByteBufferPool());
|
||||
}
|
||||
|
||||
public MuxGenerator(ByteBufferPool bufferPool)
|
||||
{
|
||||
this.bufferPool = bufferPool;
|
||||
}
|
||||
|
||||
public void generate(long channelId, Frame frame, WriteCallback callback)
|
||||
{
|
||||
ByteBuffer muxPayload = bufferPool.acquire(frame.getPayloadLength() + DATA_FRAME_OVERHEAD,false);
|
||||
BufferUtil.flipToFill(muxPayload);
|
||||
|
||||
// start building mux payload
|
||||
writeChannelId(muxPayload,channelId);
|
||||
byte b = (byte)(frame.isFin()?0x80:0x00); // fin
|
||||
b |= (byte)(frame.isRsv1()?0x40:0x00); // rsv1
|
||||
b |= (byte)(frame.isRsv2()?0x20:0x00); // rsv2
|
||||
b |= (byte)(frame.isRsv3()?0x10:0x00); // rsv3
|
||||
b |= (byte)(frame.getOpCode() & 0x0F); // opcode
|
||||
muxPayload.put(b);
|
||||
BufferUtil.put(frame.getPayload(),muxPayload);
|
||||
|
||||
// build muxed frame
|
||||
WebSocketFrame muxFrame = new BinaryFrame();
|
||||
BufferUtil.flipToFlush(muxPayload,0);
|
||||
muxFrame.setPayload(muxPayload);
|
||||
// NOTE: the physical connection will handle masking rules for this frame.
|
||||
|
||||
// release original buffer (no longer needed)
|
||||
bufferPool.release(frame.getPayload());
|
||||
|
||||
// send muxed frame down to the physical connection.
|
||||
outgoing.outgoingFrame(muxFrame,callback);
|
||||
}
|
||||
|
||||
public void generate(WriteCallback callback,MuxControlBlock... blocks) throws IOException
|
||||
{
|
||||
if ((blocks == null) || (blocks.length <= 0))
|
||||
{
|
||||
return; // nothing to do
|
||||
}
|
||||
|
||||
ByteBuffer payload = bufferPool.acquire(CONTROL_BUFFER_SIZE,false);
|
||||
BufferUtil.flipToFill(payload);
|
||||
|
||||
writeChannelId(payload,0); // control channel
|
||||
|
||||
for (MuxControlBlock block : blocks)
|
||||
{
|
||||
switch (block.getOpCode())
|
||||
{
|
||||
case MuxOp.ADD_CHANNEL_REQUEST:
|
||||
{
|
||||
MuxAddChannelRequest op = (MuxAddChannelRequest)block;
|
||||
byte b = (byte)((op.getOpCode() & 0x07) << 5); // opcode
|
||||
b |= (byte)((op.getRsv() & 0x07) << 2); // rsv
|
||||
b |= (op.getEncoding() & 0x03); // enc
|
||||
payload.put(b); // opcode + rsv + enc
|
||||
writeChannelId(payload,op.getChannelId());
|
||||
write139Buffer(payload,op.getHandshake());
|
||||
break;
|
||||
}
|
||||
case MuxOp.ADD_CHANNEL_RESPONSE:
|
||||
{
|
||||
MuxAddChannelResponse op = (MuxAddChannelResponse)block;
|
||||
byte b = (byte)((op.getOpCode() & 0x07) << 5); // opcode
|
||||
b |= (op.isFailed()?0x10:0x00); // failure bit
|
||||
b |= (byte)((op.getRsv() & 0x03) << 2); // rsv
|
||||
b |= (op.getEncoding() & 0x03); // enc
|
||||
payload.put(b); // opcode + f + rsv + enc
|
||||
writeChannelId(payload,op.getChannelId());
|
||||
if (op.getHandshake() != null)
|
||||
{
|
||||
write139Buffer(payload,op.getHandshake());
|
||||
}
|
||||
else
|
||||
{
|
||||
// no handshake details
|
||||
write139Size(payload,0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MuxOp.DROP_CHANNEL:
|
||||
{
|
||||
MuxDropChannel op = (MuxDropChannel)block;
|
||||
byte b = (byte)((op.getOpCode() & 0x07) << 5); // opcode
|
||||
b |= (byte)(op.getRsv() & 0x1F); // rsv
|
||||
payload.put(b); // opcode + rsv
|
||||
writeChannelId(payload,op.getChannelId());
|
||||
write139Buffer(payload,op.asReasonBuffer());
|
||||
break;
|
||||
}
|
||||
case MuxOp.FLOW_CONTROL:
|
||||
{
|
||||
MuxFlowControl op = (MuxFlowControl)block;
|
||||
byte b = (byte)((op.getOpCode() & 0x07) << 5); // opcode
|
||||
b |= (byte)(op.getRsv() & 0x1F); // rsv
|
||||
payload.put(b); // opcode + rsv
|
||||
writeChannelId(payload,op.getChannelId());
|
||||
write139Size(payload,op.getSendQuotaSize());
|
||||
break;
|
||||
}
|
||||
case MuxOp.NEW_CHANNEL_SLOT:
|
||||
{
|
||||
MuxNewChannelSlot op = (MuxNewChannelSlot)block;
|
||||
byte b = (byte)((op.getOpCode() & 0x07) << 5); // opcode
|
||||
b |= (byte)(op.getRsv() & 0x0F) << 1; // rsv
|
||||
b |= (byte)(op.isFallback()?0x01:0x00); // fallback bit
|
||||
payload.put(b); // opcode + rsv + fallback bit
|
||||
write139Size(payload,op.getNumberOfSlots());
|
||||
write139Size(payload,op.getInitialSendQuota());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
BufferUtil.flipToFlush(payload,0);
|
||||
WebSocketFrame frame = new BinaryFrame();
|
||||
frame.setPayload(payload);
|
||||
outgoing.outgoingFrame(frame,callback);
|
||||
}
|
||||
|
||||
public OutgoingFrames getOutgoing()
|
||||
{
|
||||
return outgoing;
|
||||
}
|
||||
|
||||
public void setOutgoing(OutgoingFrames outgoing)
|
||||
{
|
||||
this.outgoing = outgoing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a 1/3/9 encoded size, then a byte buffer of that size.
|
||||
*
|
||||
* @param payload
|
||||
* @param buffer
|
||||
*/
|
||||
public void write139Buffer(ByteBuffer payload, ByteBuffer buffer)
|
||||
{
|
||||
write139Size(payload,buffer.remaining());
|
||||
writeBuffer(payload,buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a 1/3/9 encoded size.
|
||||
*
|
||||
* @param payload
|
||||
* @param size
|
||||
*/
|
||||
public void write139Size(ByteBuffer payload, long size)
|
||||
{
|
||||
if (size > 0xFF_FF)
|
||||
{
|
||||
// 9 byte encoded
|
||||
payload.put((byte)0x7F);
|
||||
payload.putLong(size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (size >= 0x7E)
|
||||
{
|
||||
// 3 byte encoded
|
||||
payload.put((byte)0x7E);
|
||||
payload.put((byte)(size >> 8));
|
||||
payload.put((byte)(size & 0xFF));
|
||||
return;
|
||||
}
|
||||
|
||||
// 1 byte (7 bit) encoded
|
||||
payload.put((byte)(size & 0x7F));
|
||||
}
|
||||
|
||||
public void writeBuffer(ByteBuffer payload, ByteBuffer buffer)
|
||||
{
|
||||
BufferUtil.put(buffer,payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write multiplexing channel id, using logical channel id encoding (of 1,2,3, or 4 octets)
|
||||
*
|
||||
* @param payload
|
||||
* @param channelId
|
||||
*/
|
||||
public void writeChannelId(ByteBuffer payload, long channelId)
|
||||
{
|
||||
if (channelId > 0x1F_FF_FF_FF)
|
||||
{
|
||||
throw new MuxException("Illegal Channel ID: too big");
|
||||
}
|
||||
|
||||
if (channelId > 0x1F_FF_FF)
|
||||
{
|
||||
// 29 bit channel id (4 bytes)
|
||||
payload.put((byte)(0xE0 | ((channelId >> 24) & 0x1F)));
|
||||
payload.put((byte)((channelId >> 16) & 0xFF));
|
||||
payload.put((byte)((channelId >> 8) & 0xFF));
|
||||
payload.put((byte)(channelId & 0xFF));
|
||||
return;
|
||||
}
|
||||
|
||||
if (channelId > 0x3F_FF)
|
||||
{
|
||||
// 21 bit channel id (3 bytes)
|
||||
payload.put((byte)(0xC0 | ((channelId >> 16) & 0x1F)));
|
||||
payload.put((byte)((channelId >> 8) & 0xFF));
|
||||
payload.put((byte)(channelId & 0xFF));
|
||||
return;
|
||||
}
|
||||
|
||||
if (channelId > 0x7F)
|
||||
{
|
||||
// 14 bit channel id (2 bytes)
|
||||
payload.put((byte)(0x80 | ((channelId >> 8) & 0x3F)));
|
||||
payload.put((byte)(channelId & 0xFF));
|
||||
return;
|
||||
}
|
||||
|
||||
// 7 bit channel id
|
||||
payload.put((byte)(channelId & 0x7F));
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux;
|
||||
|
||||
public final class MuxOp
|
||||
{
|
||||
public static final byte ADD_CHANNEL_REQUEST = 0;
|
||||
public static final byte ADD_CHANNEL_RESPONSE = 1;
|
||||
public static final byte FLOW_CONTROL = 2;
|
||||
public static final byte DROP_CHANNEL = 3;
|
||||
public static final byte NEW_CHANNEL_SLOT = 4;
|
||||
}
|
|
@ -1,410 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.common.OpCode;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxAddChannelRequest;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxAddChannelResponse;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxDropChannel;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxFlowControl;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxNewChannelSlot;
|
||||
|
||||
public class MuxParser
|
||||
{
|
||||
public static interface Listener
|
||||
{
|
||||
public void onMuxAddChannelRequest(MuxAddChannelRequest request);
|
||||
|
||||
public void onMuxAddChannelResponse(MuxAddChannelResponse response);
|
||||
|
||||
public void onMuxDropChannel(MuxDropChannel drop);
|
||||
|
||||
public void onMuxedFrame(MuxedFrame frame);
|
||||
|
||||
public void onMuxException(MuxException e);
|
||||
|
||||
public void onMuxFlowControl(MuxFlowControl flow);
|
||||
|
||||
public void onMuxNewChannelSlot(MuxNewChannelSlot slot);
|
||||
}
|
||||
|
||||
private final static Logger LOG = Log.getLogger(MuxParser.class);
|
||||
|
||||
private MuxedFrame muxframe = new MuxedFrame();
|
||||
private MuxParser.Listener events;
|
||||
private long channelId;
|
||||
|
||||
public MuxParser.Listener getEvents()
|
||||
{
|
||||
return events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the raw {@link WebSocketFrame} payload data for various Mux frames.
|
||||
*
|
||||
* @param frame
|
||||
* the WebSocketFrame to parse for mux payload
|
||||
*/
|
||||
public synchronized void parse(Frame frame)
|
||||
{
|
||||
if (events == null)
|
||||
{
|
||||
throw new RuntimeException("No " + MuxParser.Listener.class + " specified");
|
||||
}
|
||||
|
||||
if (!frame.hasPayload())
|
||||
{
|
||||
LOG.debug("No payload data, skipping");
|
||||
return; // nothing to parse
|
||||
}
|
||||
|
||||
if (frame.getOpCode() != OpCode.BINARY)
|
||||
{
|
||||
LOG.debug("Not a binary opcode (base frame), skipping");
|
||||
return; // not a binary opcode
|
||||
}
|
||||
|
||||
LOG.debug("Parsing Mux Payload of {}",frame);
|
||||
|
||||
try
|
||||
{
|
||||
ByteBuffer buffer = frame.getPayload().slice();
|
||||
|
||||
if (buffer.remaining() <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (frame.getOpCode() == OpCode.CONTINUATION)
|
||||
{
|
||||
muxframe.reset();
|
||||
muxframe.setFin(frame.isFin());
|
||||
muxframe.setFin(frame.isRsv1());
|
||||
muxframe.setFin(frame.isRsv2());
|
||||
muxframe.setFin(frame.isRsv3());
|
||||
muxframe.setIsContinuation();
|
||||
parseDataFramePayload(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
// new frame
|
||||
channelId = readChannelId(buffer);
|
||||
if (channelId == 0)
|
||||
{
|
||||
parseControlBlocks(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
parseDataFrame(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (MuxException e)
|
||||
{
|
||||
events.onMuxException(e);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
events.onMuxException(new MuxException(t));
|
||||
}
|
||||
}
|
||||
|
||||
private void parseControlBlocks(ByteBuffer buffer)
|
||||
{
|
||||
// process the remaining buffer here.
|
||||
while (buffer.remaining() > 0)
|
||||
{
|
||||
byte b = buffer.get();
|
||||
byte opc = (byte)((byte)(b >> 5) & 0xFF);
|
||||
b = (byte)(b & 0x1F);
|
||||
|
||||
try {
|
||||
switch (opc)
|
||||
{
|
||||
case MuxOp.ADD_CHANNEL_REQUEST:
|
||||
{
|
||||
MuxAddChannelRequest op = new MuxAddChannelRequest();
|
||||
op.setRsv((byte)((b & 0x1C) >> 2));
|
||||
op.setEncoding((byte)(b & 0x03));
|
||||
op.setChannelId(readChannelId(buffer));
|
||||
long handshakeSize = read139EncodedSize(buffer);
|
||||
op.setHandshake(readBlock(buffer,handshakeSize));
|
||||
events.onMuxAddChannelRequest(op);
|
||||
break;
|
||||
}
|
||||
case MuxOp.ADD_CHANNEL_RESPONSE:
|
||||
{
|
||||
MuxAddChannelResponse op = new MuxAddChannelResponse();
|
||||
op.setFailed((b & 0x10) != 0);
|
||||
op.setRsv((byte)((byte)(b & 0x0C) >> 2));
|
||||
op.setEncoding((byte)(b & 0x03));
|
||||
op.setChannelId(readChannelId(buffer));
|
||||
long handshakeSize = read139EncodedSize(buffer);
|
||||
op.setHandshake(readBlock(buffer,handshakeSize));
|
||||
events.onMuxAddChannelResponse(op);
|
||||
break;
|
||||
}
|
||||
case MuxOp.DROP_CHANNEL:
|
||||
{
|
||||
int rsv = (b & 0x1F);
|
||||
long channelId = readChannelId(buffer);
|
||||
long reasonSize = read139EncodedSize(buffer);
|
||||
ByteBuffer reasonBuf = readBlock(buffer,reasonSize);
|
||||
MuxDropChannel op = MuxDropChannel.parse(channelId,reasonBuf);
|
||||
op.setRsv(rsv);
|
||||
events.onMuxDropChannel(op);
|
||||
break;
|
||||
}
|
||||
case MuxOp.FLOW_CONTROL:
|
||||
{
|
||||
MuxFlowControl op = new MuxFlowControl();
|
||||
op.setRsv((byte)(b & 0x1F));
|
||||
op.setChannelId(readChannelId(buffer));
|
||||
op.setSendQuotaSize(read139EncodedSize(buffer));
|
||||
events.onMuxFlowControl(op);
|
||||
break;
|
||||
}
|
||||
case MuxOp.NEW_CHANNEL_SLOT:
|
||||
{
|
||||
MuxNewChannelSlot op = new MuxNewChannelSlot();
|
||||
op.setRsv((byte)((b & 0x1E) >> 1));
|
||||
op.setFallback((b & 0x01) != 0);
|
||||
op.setNumberOfSlots(read139EncodedSize(buffer));
|
||||
op.setInitialSendQuota(read139EncodedSize(buffer));
|
||||
events.onMuxNewChannelSlot(op);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
String err = String.format("Unknown Mux Control Code OPC [0x%X]",opc);
|
||||
throw new MuxException(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
LOG.warn(t);
|
||||
throw new MuxException(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void parseDataFrame(ByteBuffer buffer)
|
||||
{
|
||||
byte b = buffer.get();
|
||||
boolean fin = ((b & 0x80) != 0);
|
||||
boolean rsv1 = ((b & 0x40) != 0);
|
||||
boolean rsv2 = ((b & 0x20) != 0);
|
||||
boolean rsv3 = ((b & 0x10) != 0);
|
||||
byte opcode = (byte)(b & 0x0F);
|
||||
|
||||
if (opcode == OpCode.CONTINUATION)
|
||||
{
|
||||
muxframe.setIsContinuation();
|
||||
}
|
||||
else
|
||||
{
|
||||
muxframe.reset();
|
||||
muxframe.setOp(opcode);
|
||||
}
|
||||
|
||||
muxframe.setChannelId(channelId);
|
||||
muxframe.setFin(fin);
|
||||
muxframe.setRsv1(rsv1);
|
||||
muxframe.setRsv2(rsv2);
|
||||
muxframe.setRsv3(rsv3);
|
||||
|
||||
parseDataFramePayload(buffer);
|
||||
}
|
||||
|
||||
private void parseDataFramePayload(ByteBuffer buffer)
|
||||
{
|
||||
int capacity = buffer.remaining();
|
||||
ByteBuffer payload = ByteBuffer.allocate(capacity);
|
||||
payload.put(buffer);
|
||||
BufferUtil.flipToFlush(payload,0);
|
||||
muxframe.setPayload(payload);
|
||||
try
|
||||
{
|
||||
LOG.debug("notifyFrame() - {}",muxframe);
|
||||
events.onMuxedFrame(muxframe);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
LOG.warn(t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Per section <a href="https://tools.ietf.org/html/draft-ietf-hybi-websocket-multiplexing#section-9.1">9.1. Number Encoding in Multiplex Control
|
||||
* Blocks</a>, read the 1/3/9 byte length using <a href="https://tools.ietf.org/html/rfc6455#section-5.2">Section 5.2 of RFC 6455</a>.
|
||||
*
|
||||
* @param buffer
|
||||
* the buffer to read from
|
||||
* @return the decoded size
|
||||
* @throws MuxException
|
||||
* when the encoding does not make sense per the spec, or it is a value above {@link Long#MAX_VALUE}
|
||||
*/
|
||||
public long read139EncodedSize(ByteBuffer buffer)
|
||||
{
|
||||
long ret = -1;
|
||||
long minValue = 0x00; // used to validate minimum # of bytes (per spec)
|
||||
int cursor = 0;
|
||||
|
||||
byte b = buffer.get();
|
||||
ret = (b & 0x7F);
|
||||
|
||||
if (ret == 0x7F)
|
||||
{
|
||||
// 9 byte length
|
||||
ret = 0;
|
||||
minValue = 0xFF_FF;
|
||||
cursor = 8;
|
||||
}
|
||||
else if (ret == 0x7E)
|
||||
{
|
||||
// 3 byte length
|
||||
ret = 0;
|
||||
minValue = 0x7F;
|
||||
cursor = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 1 byte length
|
||||
// no validation of minimum bytes needed here
|
||||
return ret;
|
||||
}
|
||||
|
||||
// parse multi-byte length
|
||||
while (cursor > 0)
|
||||
{
|
||||
ret = ret << 8;
|
||||
b = buffer.get();
|
||||
ret |= (b & 0xFF);
|
||||
--cursor;
|
||||
}
|
||||
|
||||
// validate minimum value per spec.
|
||||
if (ret <= minValue)
|
||||
{
|
||||
String err = String.format("Invalid 1/3/9 length 0x%X (minimum value for chosen encoding is 0x%X)",ret,minValue);
|
||||
throw new MuxException(err);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private ByteBuffer readBlock(ByteBuffer buffer, long size)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (size > buffer.remaining())
|
||||
{
|
||||
String err = String.format("Truncated data, expected %,d byte(s), but only %,d byte(s) remain",size,buffer.remaining());
|
||||
throw new MuxException(err);
|
||||
}
|
||||
|
||||
if (size > Integer.MAX_VALUE)
|
||||
{
|
||||
String err = String.format("[Int-Sane!] Buffer size %,d is too large to be supported (max allowed is %,d)",size,Integer.MAX_VALUE);
|
||||
throw new MuxException(err);
|
||||
}
|
||||
|
||||
ByteBuffer ret = ByteBuffer.allocate((int)size);
|
||||
BufferUtil.put(buffer,ret);
|
||||
BufferUtil.flipToFlush(ret,0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read Channel ID using <a href="https://tools.ietf.org/html/draft-ietf-hybi-websocket-multiplexing#section-7">Section 7. Framing</a> techniques
|
||||
*
|
||||
* @param buffer
|
||||
* the buffer to parse from.
|
||||
* @return the channel Id
|
||||
* @throws MuxException
|
||||
* when the encoding does not make sense per the spec.
|
||||
*/
|
||||
public long readChannelId(ByteBuffer buffer)
|
||||
{
|
||||
long id = -1;
|
||||
long minValue = 0x00; // used to validate minimum # of bytes (per spec)
|
||||
byte b = buffer.get();
|
||||
int cursor = -1;
|
||||
if ((b & 0x80) == 0)
|
||||
{
|
||||
// 7 bit channel id
|
||||
// no validation of minimum bytes needed here
|
||||
return (b & 0x7F);
|
||||
}
|
||||
else if ((b & 0x40) == 0)
|
||||
{
|
||||
// 14 bit channel id
|
||||
id = (b & 0x3F);
|
||||
minValue = 0x7F;
|
||||
cursor = 1;
|
||||
}
|
||||
else if ((b & 0x20) == 0)
|
||||
{
|
||||
// 21 bit channel id
|
||||
id = (b & 0x1F);
|
||||
minValue = 0x3F_FF;
|
||||
cursor = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 29 bit channel id
|
||||
id = (b & 0x1F);
|
||||
minValue = 0x1F_FF_FF;
|
||||
cursor = 3;
|
||||
}
|
||||
|
||||
while (cursor > 0)
|
||||
{
|
||||
id = id << 8;
|
||||
b = buffer.get();
|
||||
id |= (b & 0xFF);
|
||||
--cursor;
|
||||
}
|
||||
|
||||
// validate minimum value per spec.
|
||||
if (id <= minValue)
|
||||
{
|
||||
String err = String.format("Invalid Channel ID 0x%X (minimum value for chosen encoding is 0x%X)",id,minValue);
|
||||
throw new MuxException(err);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setEvents(MuxParser.Listener events)
|
||||
{
|
||||
this.events = events;
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux;
|
||||
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxDropChannel;
|
||||
|
||||
public class MuxPhysicalConnectionException extends MuxException
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private MuxDropChannel drop;
|
||||
|
||||
public MuxPhysicalConnectionException(MuxDropChannel.Reason code, String phrase)
|
||||
{
|
||||
super(phrase);
|
||||
drop = new MuxDropChannel(0,code,phrase);
|
||||
}
|
||||
|
||||
public MuxPhysicalConnectionException(MuxDropChannel.Reason code, String phrase, Throwable t)
|
||||
{
|
||||
super(phrase,t);
|
||||
drop = new MuxDropChannel(0,code,phrase);
|
||||
}
|
||||
|
||||
public MuxDropChannel getMuxDropChannel()
|
||||
{
|
||||
return drop;
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.UpgradeRequest;
|
||||
|
||||
public class MuxRequest extends UpgradeRequest
|
||||
{
|
||||
public static final String HEADER_VALUE_DELIM="\"\\\n\r\t\f\b%+ ;=";
|
||||
|
||||
public static UpgradeRequest merge(UpgradeRequest baseReq, UpgradeRequest deltaReq)
|
||||
{
|
||||
MuxRequest req = new MuxRequest(baseReq);
|
||||
|
||||
// TODO: finish
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
private static String overlay(String val, String defVal)
|
||||
{
|
||||
if (val == null)
|
||||
{
|
||||
return defVal;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
public static UpgradeRequest parse(ByteBuffer handshake)
|
||||
{
|
||||
MuxRequest req = new MuxRequest();
|
||||
// TODO Auto-generated method stub
|
||||
return req;
|
||||
}
|
||||
|
||||
public MuxRequest()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public MuxRequest(UpgradeRequest copy)
|
||||
{
|
||||
super();
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.UpgradeResponse;
|
||||
|
||||
public class MuxResponse extends UpgradeResponse
|
||||
{
|
||||
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux;
|
||||
|
||||
import org.eclipse.jetty.websocket.common.OpCode;
|
||||
import org.eclipse.jetty.websocket.common.frames.DataFrame;
|
||||
|
||||
public class MuxedFrame extends DataFrame
|
||||
{
|
||||
private long channelId = -1;
|
||||
|
||||
public MuxedFrame()
|
||||
{
|
||||
super(OpCode.BINARY);
|
||||
}
|
||||
|
||||
public MuxedFrame(MuxedFrame frame)
|
||||
{
|
||||
super(frame);
|
||||
this.channelId = frame.channelId;
|
||||
}
|
||||
|
||||
public long getChannelId()
|
||||
{
|
||||
return channelId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
super.reset();
|
||||
this.channelId = -1;
|
||||
}
|
||||
|
||||
public void setChannelId(long channelId)
|
||||
{
|
||||
this.channelId = channelId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append(OpCode.name(getOpCode()));
|
||||
b.append('[');
|
||||
b.append("channel=").append(channelId);
|
||||
b.append(",len=").append(getPayloadLength());
|
||||
b.append(",fin=").append(isFin());
|
||||
b.append(",rsv=");
|
||||
b.append(isRsv1()?'1':'.');
|
||||
b.append(isRsv2()?'1':'.');
|
||||
b.append(isRsv3()?'1':'.');
|
||||
b.append(']');
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
public void setOp(byte opcode)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
|
@ -1,439 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.api.UpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.api.UpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketBehavior;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.WriteCallback;
|
||||
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.LogicalConnection;
|
||||
import org.eclipse.jetty.websocket.common.frames.ControlFrame;
|
||||
import org.eclipse.jetty.websocket.mux.add.MuxAddClient;
|
||||
import org.eclipse.jetty.websocket.mux.add.MuxAddServer;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxAddChannelRequest;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxAddChannelResponse;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxDropChannel;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxFlowControl;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxNewChannelSlot;
|
||||
|
||||
/**
|
||||
* Muxer responsible for managing sub-channels.
|
||||
* <p>
|
||||
* Maintains a 1 (incoming and outgoing mux encapsulated frames) to many (per-channel incoming/outgoing standard websocket frames) relationship, along with
|
||||
* routing of {@link MuxControlBlock} events.
|
||||
* <p>
|
||||
* Control Channel events (channel ID == 0) are handled by the Muxer.
|
||||
*/
|
||||
public class Muxer implements IncomingFrames, MuxParser.Listener
|
||||
{
|
||||
private static final int CONTROL_CHANNEL_ID = 0;
|
||||
|
||||
private static final Logger LOG = Log.getLogger(Muxer.class);
|
||||
|
||||
/**
|
||||
* Map of sub-channels, key is the channel Id.
|
||||
*/
|
||||
private Map<Long, MuxChannel> channels = new HashMap<Long, MuxChannel>();
|
||||
|
||||
private final WebSocketPolicy policy;
|
||||
private final LogicalConnection physicalConnection;
|
||||
private InetSocketAddress remoteAddress;
|
||||
/** Parsing frames destined for sub-channels */
|
||||
private MuxParser parser;
|
||||
/** Generating frames destined for physical connection */
|
||||
private MuxGenerator generator;
|
||||
private MuxAddServer addServer;
|
||||
private MuxAddClient addClient;
|
||||
/** The original request headers, used for delta encoded AddChannelRequest blocks */
|
||||
private UpgradeRequest physicalRequestHeaders;
|
||||
/** The original response headers, used for delta encoded AddChannelResponse blocks */
|
||||
private UpgradeResponse physicalResponseHeaders;
|
||||
|
||||
public Muxer(final LogicalConnection connection)
|
||||
{
|
||||
this.physicalConnection = connection;
|
||||
this.policy = connection.getPolicy().clonePolicy();
|
||||
this.parser = new MuxParser();
|
||||
this.parser.setEvents(this);
|
||||
this.generator = new MuxGenerator();
|
||||
}
|
||||
|
||||
public MuxAddClient getAddClient()
|
||||
{
|
||||
return addClient;
|
||||
}
|
||||
|
||||
public MuxAddServer getAddServer()
|
||||
{
|
||||
return addServer;
|
||||
}
|
||||
|
||||
public MuxChannel getChannel(long channelId, boolean create)
|
||||
{
|
||||
if (channelId == CONTROL_CHANNEL_ID)
|
||||
{
|
||||
throw new MuxPhysicalConnectionException(MuxDropChannel.Reason.UNKNOWN_MUX_CONTROL_BLOCK,"Invalid Channel ID");
|
||||
}
|
||||
|
||||
MuxChannel channel = channels.get(channelId);
|
||||
if (channel == null)
|
||||
{
|
||||
if (create)
|
||||
{
|
||||
channel = new MuxChannel(channelId,this);
|
||||
channels.put(channelId,channel);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new MuxPhysicalConnectionException(MuxDropChannel.Reason.UNKNOWN_MUX_CONTROL_BLOCK,"Unknown Channel ID");
|
||||
}
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
|
||||
public WebSocketPolicy getPolicy()
|
||||
{
|
||||
return policy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the remote address of the physical connection.
|
||||
*
|
||||
* @return the remote address of the physical connection
|
||||
*/
|
||||
public InetSocketAddress getRemoteAddress()
|
||||
{
|
||||
return this.remoteAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Incoming parser errors
|
||||
*/
|
||||
@Override
|
||||
public void incomingError(Throwable e)
|
||||
{
|
||||
MuxDropChannel.Reason reason = MuxDropChannel.Reason.PHYSICAL_CONNECTION_FAILED;
|
||||
String phrase = String.format("%s: %s", e.getClass().getName(), e.getMessage());
|
||||
mustFailPhysicalConnection(new MuxPhysicalConnectionException(reason,phrase));
|
||||
}
|
||||
|
||||
/**
|
||||
* Incoming mux encapsulated frames.
|
||||
*/
|
||||
@Override
|
||||
public void incomingFrame(Frame frame)
|
||||
{
|
||||
parser.parse(frame);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the muxer and the physical connection still open?
|
||||
*
|
||||
* @return true if open
|
||||
*/
|
||||
public boolean isOpen()
|
||||
{
|
||||
return physicalConnection.isOpen();
|
||||
}
|
||||
|
||||
public String mergeHeaders(List<String> physicalHeaders, String deltaHeaders)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Per spec, the physical connection must be failed.
|
||||
* <p>
|
||||
* <a href="https://tools.ietf.org/html/draft-ietf-hybi-websocket-multiplexing-08#section-18">Section 18. Fail the Physical Connection.</a>
|
||||
*
|
||||
* <blockquote> To _Fail the Physical Connection_, an endpoint MUST send a DropChannel multiplex control block with objective channel ID of 0 and drop
|
||||
* reason code in the range of 2000-2999, and then _Fail the WebSocket Connection_ on the physical connection with status code of 1011. </blockquote>
|
||||
*/
|
||||
private void mustFailPhysicalConnection(MuxPhysicalConnectionException muxe)
|
||||
{
|
||||
// TODO: stop muxer from receiving incoming sub-channel traffic.
|
||||
|
||||
MuxDropChannel drop = muxe.getMuxDropChannel();
|
||||
LOG.warn(muxe);
|
||||
try
|
||||
{
|
||||
generator.generate(null,drop);
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
LOG.warn("Unable to send mux DropChannel",ioe);
|
||||
}
|
||||
|
||||
String reason = "Mux[MUST FAIL]" + drop.getPhrase();
|
||||
reason = StringUtil.truncate(reason,ControlFrame.MAX_CONTROL_PAYLOAD);
|
||||
this.physicalConnection.close(StatusCode.SERVER_ERROR,reason);
|
||||
|
||||
// TODO: trigger abnormal close for all sub-channels.
|
||||
}
|
||||
|
||||
/**
|
||||
* Incoming mux control block, destined for the control channel (id 0)
|
||||
*/
|
||||
@Override
|
||||
public void onMuxAddChannelRequest(MuxAddChannelRequest request)
|
||||
{
|
||||
if (policy.getBehavior() == WebSocketBehavior.CLIENT)
|
||||
{
|
||||
throw new MuxPhysicalConnectionException(MuxDropChannel.Reason.UNKNOWN_MUX_CONTROL_BLOCK,"AddChannelRequest not allowed per spec");
|
||||
}
|
||||
|
||||
if (request.getRsv() != 0)
|
||||
{
|
||||
throw new MuxPhysicalConnectionException(MuxDropChannel.Reason.UNKNOWN_REQUEST_ENCODING,"RSV Not allowed to be set");
|
||||
}
|
||||
|
||||
// Pre-allocate channel.
|
||||
long channelId = request.getChannelId();
|
||||
MuxChannel channel = getChannel(channelId, true);
|
||||
|
||||
// submit to upgrade handshake process
|
||||
try
|
||||
{
|
||||
switch (request.getEncoding())
|
||||
{
|
||||
case MuxAddChannelRequest.IDENTITY_ENCODING:
|
||||
{
|
||||
UpgradeRequest idenReq = MuxRequest.parse(request.getHandshake());
|
||||
addServer.handshake(this,channel,idenReq);
|
||||
break;
|
||||
}
|
||||
case MuxAddChannelRequest.DELTA_ENCODING:
|
||||
{
|
||||
UpgradeRequest baseReq = addServer.getPhysicalHandshakeRequest();
|
||||
UpgradeRequest deltaReq = MuxRequest.parse(request.getHandshake());
|
||||
UpgradeRequest mergedReq = MuxRequest.merge(baseReq,deltaReq);
|
||||
|
||||
addServer.handshake(this,channel,mergedReq);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new MuxPhysicalConnectionException(MuxDropChannel.Reason.BAD_REQUEST,"Unrecognized request encoding");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (MuxPhysicalConnectionException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
throw new MuxPhysicalConnectionException(MuxDropChannel.Reason.BAD_REQUEST,"Unable to parse request",t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Incoming mux control block, destined for the control channel (id 0)
|
||||
*/
|
||||
@Override
|
||||
public void onMuxAddChannelResponse(MuxAddChannelResponse response)
|
||||
{
|
||||
if (policy.getBehavior() == WebSocketBehavior.SERVER)
|
||||
{
|
||||
throw new MuxPhysicalConnectionException(MuxDropChannel.Reason.UNKNOWN_MUX_CONTROL_BLOCK,"AddChannelResponse not allowed per spec");
|
||||
}
|
||||
|
||||
if (response.getRsv() != 0)
|
||||
{
|
||||
throw new MuxPhysicalConnectionException(MuxDropChannel.Reason.UNKNOWN_RESPONSE_ENCODING,"RSV Not allowed to be set");
|
||||
}
|
||||
|
||||
// Process channel
|
||||
long channelId = response.getChannelId();
|
||||
MuxChannel channel = getChannel(channelId,false);
|
||||
|
||||
// Process Response headers
|
||||
try
|
||||
{
|
||||
// Parse Response
|
||||
|
||||
// TODO: Sec-WebSocket-Accept header
|
||||
// TODO: Sec-WebSocket-Extensions header
|
||||
// TODO: Setup extensions
|
||||
// TODO: Setup sessions
|
||||
|
||||
// Trigger channel open
|
||||
channel.onOpen();
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
throw new MuxPhysicalConnectionException(MuxDropChannel.Reason.BAD_RESPONSE,"Unable to parse response",t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Incoming mux control block, destined for the control channel (id 0)
|
||||
*/
|
||||
@Override
|
||||
public void onMuxDropChannel(MuxDropChannel drop)
|
||||
{
|
||||
// Process channel
|
||||
long channelId = drop.getChannelId();
|
||||
MuxChannel channel = getChannel(channelId,false);
|
||||
|
||||
String reason = "Mux " + drop.toString();
|
||||
reason = StringUtil.truncate(reason,(ControlFrame.MAX_CONTROL_PAYLOAD - 2));
|
||||
channel.close(StatusCode.PROTOCOL,reason);
|
||||
// TODO: set channel to inactive?
|
||||
}
|
||||
|
||||
/**
|
||||
* Incoming mux-unwrapped frames, destined for a sub-channel
|
||||
*/
|
||||
@Override
|
||||
public void onMuxedFrame(MuxedFrame frame)
|
||||
{
|
||||
MuxChannel subchannel = channels.get(frame.getChannelId());
|
||||
subchannel.incomingFrame(frame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMuxException(MuxException e)
|
||||
{
|
||||
if (e instanceof MuxPhysicalConnectionException)
|
||||
{
|
||||
mustFailPhysicalConnection((MuxPhysicalConnectionException)e);
|
||||
}
|
||||
|
||||
LOG.warn(e);
|
||||
// TODO: handle other (non physical) mux exceptions how?
|
||||
}
|
||||
|
||||
/**
|
||||
* Incoming mux control block, destined for the control channel (id 0)
|
||||
*/
|
||||
@Override
|
||||
public void onMuxFlowControl(MuxFlowControl flow)
|
||||
{
|
||||
if (flow.getSendQuotaSize() > 0x7F_FF_FF_FF_FF_FF_FF_FFL)
|
||||
{
|
||||
throw new MuxPhysicalConnectionException(MuxDropChannel.Reason.SEND_QUOTA_OVERFLOW,"Send Quota Overflow");
|
||||
}
|
||||
|
||||
// Process channel
|
||||
long channelId = flow.getChannelId();
|
||||
MuxChannel channel = getChannel(channelId,false);
|
||||
|
||||
// TODO: set channel quota
|
||||
}
|
||||
|
||||
/**
|
||||
* Incoming mux control block, destined for the control channel (id 0)
|
||||
*/
|
||||
@Override
|
||||
public void onMuxNewChannelSlot(MuxNewChannelSlot slot)
|
||||
{
|
||||
if (policy.getBehavior() == WebSocketBehavior.SERVER)
|
||||
{
|
||||
throw new MuxPhysicalConnectionException(MuxDropChannel.Reason.UNKNOWN_MUX_CONTROL_BLOCK,"NewChannelSlot not allowed per spec");
|
||||
}
|
||||
|
||||
if (slot.isFallback())
|
||||
{
|
||||
if (slot.getNumberOfSlots() == 0)
|
||||
{
|
||||
throw new MuxPhysicalConnectionException(MuxDropChannel.Reason.UNKNOWN_MUX_CONTROL_BLOCK,"Cannot have 0 number of slots during fallback");
|
||||
}
|
||||
if (slot.getInitialSendQuota() == 0)
|
||||
{
|
||||
throw new MuxPhysicalConnectionException(MuxDropChannel.Reason.UNKNOWN_MUX_CONTROL_BLOCK,"Cannot have 0 initial send quota during fallback");
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: handle channel slot
|
||||
}
|
||||
|
||||
/**
|
||||
* Outgoing frame, without mux encapsulated payload.
|
||||
*/
|
||||
public void output(long channelId, Frame frame, WriteCallback callback)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("output({}, {})",channelId,frame,callback);
|
||||
}
|
||||
generator.generate(channelId,frame,callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an OP out the physical connection.
|
||||
*
|
||||
* @param op
|
||||
* the mux operation to write
|
||||
* @throws IOException
|
||||
*/
|
||||
public void output(MuxControlBlock op) throws IOException
|
||||
{
|
||||
generator.generate(null,op);
|
||||
}
|
||||
|
||||
public void setAddClient(MuxAddClient addClient)
|
||||
{
|
||||
this.addClient = addClient;
|
||||
}
|
||||
|
||||
public void setAddServer(MuxAddServer addServer)
|
||||
{
|
||||
this.addServer = addServer;
|
||||
}
|
||||
|
||||
public void setOutgoingFramesHandler(OutgoingFrames outgoing)
|
||||
{
|
||||
this.generator.setOutgoing(outgoing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the remote address of the physical connection.
|
||||
* <p>
|
||||
* This address made available to sub-channels.
|
||||
*
|
||||
* @param remoteAddress
|
||||
* the remote address
|
||||
*/
|
||||
public void setRemoteAddress(InetSocketAddress remoteAddress)
|
||||
{
|
||||
this.remoteAddress = remoteAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("Muxer[subChannels.size=%d]",channels.size());
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux.add;
|
||||
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxAddChannelResponse;
|
||||
|
||||
/**
|
||||
* Interface for Mux Client to handle receiving a AddChannelResponse
|
||||
*/
|
||||
public interface MuxAddClient
|
||||
{
|
||||
WebSocketSession createSession(MuxAddChannelResponse response);
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux.add;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.UpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.api.UpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.mux.MuxChannel;
|
||||
import org.eclipse.jetty.websocket.mux.MuxException;
|
||||
import org.eclipse.jetty.websocket.mux.Muxer;
|
||||
|
||||
/**
|
||||
* Server interface, for dealing with incoming AddChannelRequest / AddChannelResponse flows.
|
||||
*/
|
||||
public interface MuxAddServer
|
||||
{
|
||||
public UpgradeRequest getPhysicalHandshakeRequest();
|
||||
|
||||
public UpgradeResponse getPhysicalHandshakeResponse();
|
||||
|
||||
/**
|
||||
* Perform the handshake.
|
||||
*
|
||||
* @param channel
|
||||
* the channel to attach the {@link WebSocketSession} to.
|
||||
* @param requestHandshake
|
||||
* the request handshake (request headers)
|
||||
* @throws MuxException
|
||||
* if unable to handshake
|
||||
* @throws IOException
|
||||
* if unable to parse request headers
|
||||
*/
|
||||
void handshake(Muxer muxer, MuxChannel channel, UpgradeRequest request) throws MuxException, IOException;
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
/**
|
||||
* Jetty WebSocket Common : MUX Extension Add Channel Handling [<em>Unstable Early Draft</em>]
|
||||
*/
|
||||
package org.eclipse.jetty.websocket.mux.add;
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux.client;
|
||||
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.mux.add.MuxAddClient;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxAddChannelResponse;
|
||||
|
||||
public class MuxClientAddHandler implements MuxAddClient
|
||||
{
|
||||
@Override
|
||||
public WebSocketSession createSession(MuxAddChannelResponse response)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux.client;
|
||||
|
||||
import org.eclipse.jetty.websocket.mux.AbstractMuxExtension;
|
||||
import org.eclipse.jetty.websocket.mux.Muxer;
|
||||
|
||||
public class MuxClientExtension extends AbstractMuxExtension
|
||||
{
|
||||
@Override
|
||||
public void configureMuxer(Muxer muxer)
|
||||
{
|
||||
muxer.setAddClient(new MuxClientAddHandler());
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
/**
|
||||
* Jetty WebSocket Client : MUX Extension [<em>Unstable Early Draft</em>]
|
||||
*/
|
||||
package org.eclipse.jetty.websocket.mux.client;
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux.op;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.websocket.mux.MuxControlBlock;
|
||||
import org.eclipse.jetty.websocket.mux.MuxOp;
|
||||
|
||||
public class MuxAddChannelRequest implements MuxControlBlock
|
||||
{
|
||||
public static final byte IDENTITY_ENCODING = (byte)0x00;
|
||||
public static final byte DELTA_ENCODING = (byte)0x01;
|
||||
|
||||
private long channelId = -1;
|
||||
private byte encoding;
|
||||
private ByteBuffer handshake;
|
||||
private byte rsv;
|
||||
|
||||
public long getChannelId()
|
||||
{
|
||||
return channelId;
|
||||
}
|
||||
|
||||
public byte getEncoding()
|
||||
{
|
||||
return encoding;
|
||||
}
|
||||
|
||||
public ByteBuffer getHandshake()
|
||||
{
|
||||
return handshake;
|
||||
}
|
||||
|
||||
public long getHandshakeSize()
|
||||
{
|
||||
if (handshake == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return handshake.remaining();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpCode()
|
||||
{
|
||||
return MuxOp.ADD_CHANNEL_REQUEST;
|
||||
}
|
||||
|
||||
public byte getRsv()
|
||||
{
|
||||
return rsv;
|
||||
}
|
||||
|
||||
public boolean isDeltaEncoded()
|
||||
{
|
||||
return (encoding == DELTA_ENCODING);
|
||||
}
|
||||
|
||||
public boolean isIdentityEncoded()
|
||||
{
|
||||
return (encoding == IDENTITY_ENCODING);
|
||||
}
|
||||
|
||||
public void setChannelId(long channelId)
|
||||
{
|
||||
this.channelId = channelId;
|
||||
}
|
||||
|
||||
public void setEncoding(byte enc)
|
||||
{
|
||||
this.encoding = enc;
|
||||
}
|
||||
|
||||
public void setHandshake(ByteBuffer handshake)
|
||||
{
|
||||
if (handshake == null)
|
||||
{
|
||||
this.handshake = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.handshake = handshake.slice();
|
||||
}
|
||||
}
|
||||
|
||||
public void setHandshake(String rawstring)
|
||||
{
|
||||
setHandshake(BufferUtil.toBuffer(rawstring, StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
public void setRsv(byte rsv)
|
||||
{
|
||||
this.rsv = rsv;
|
||||
}
|
||||
}
|
|
@ -1,125 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux.op;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.websocket.mux.MuxControlBlock;
|
||||
import org.eclipse.jetty.websocket.mux.MuxOp;
|
||||
|
||||
public class MuxAddChannelResponse implements MuxControlBlock
|
||||
{
|
||||
public static final byte IDENTITY_ENCODING = (byte)0x00;
|
||||
public static final byte DELTA_ENCODING = (byte)0x01;
|
||||
|
||||
private long channelId;
|
||||
private byte encoding;
|
||||
private byte rsv;
|
||||
private boolean failed = false;
|
||||
private ByteBuffer handshake;
|
||||
|
||||
public long getChannelId()
|
||||
{
|
||||
return channelId;
|
||||
}
|
||||
|
||||
public byte getEncoding()
|
||||
{
|
||||
return encoding;
|
||||
}
|
||||
|
||||
public ByteBuffer getHandshake()
|
||||
{
|
||||
return handshake;
|
||||
}
|
||||
|
||||
public long getHandshakeSize()
|
||||
{
|
||||
if (handshake == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return handshake.remaining();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpCode()
|
||||
{
|
||||
return MuxOp.ADD_CHANNEL_RESPONSE;
|
||||
}
|
||||
|
||||
public byte getRsv()
|
||||
{
|
||||
return rsv;
|
||||
}
|
||||
|
||||
public boolean isDeltaEncoded()
|
||||
{
|
||||
return (encoding == DELTA_ENCODING);
|
||||
}
|
||||
|
||||
public boolean isFailed()
|
||||
{
|
||||
return failed;
|
||||
}
|
||||
|
||||
public boolean isIdentityEncoded()
|
||||
{
|
||||
return (encoding == IDENTITY_ENCODING);
|
||||
}
|
||||
|
||||
public void setChannelId(long channelId)
|
||||
{
|
||||
this.channelId = channelId;
|
||||
}
|
||||
|
||||
public void setEncoding(byte enc)
|
||||
{
|
||||
this.encoding = enc;
|
||||
}
|
||||
|
||||
public void setFailed(boolean failed)
|
||||
{
|
||||
this.failed = failed;
|
||||
}
|
||||
|
||||
public void setHandshake(ByteBuffer handshake)
|
||||
{
|
||||
if (handshake == null)
|
||||
{
|
||||
this.handshake = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.handshake = handshake.slice();
|
||||
}
|
||||
}
|
||||
|
||||
public void setHandshake(String responseHandshake)
|
||||
{
|
||||
setHandshake(BufferUtil.toBuffer(responseHandshake, StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
public void setRsv(byte rsv)
|
||||
{
|
||||
this.rsv = rsv;
|
||||
}
|
||||
}
|
|
@ -1,183 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux.op;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.websocket.mux.MuxControlBlock;
|
||||
import org.eclipse.jetty.websocket.mux.MuxOp;
|
||||
|
||||
public class MuxDropChannel implements MuxControlBlock
|
||||
{
|
||||
/**
|
||||
* Outlined in <a href="https://tools.ietf.org/html/draft-ietf-hybi-websocket-multiplexing-05#section-9.4.1">Section 9.4.1. Drop Reason Codes</a>
|
||||
*/
|
||||
public static enum Reason
|
||||
{
|
||||
// Normal Close : (1000-1999)
|
||||
NORMAL_CLOSURE(1000),
|
||||
|
||||
// Failures in Physical Connection : (2000-2999)
|
||||
PHYSICAL_CONNECTION_FAILED(2000),
|
||||
INVALID_ENCAPSULATING_MESSAGE(2001),
|
||||
CHANNEL_ID_TRUNCATED(2002),
|
||||
ENCAPSULATED_FRAME_TRUNCATED(2003),
|
||||
UNKNOWN_MUX_CONTROL_OPC(2004),
|
||||
UNKNOWN_MUX_CONTROL_BLOCK(2005),
|
||||
CHANNEL_ALREADY_EXISTS(2006),
|
||||
NEW_CHANNEL_SLOT_VIOLATION(2007),
|
||||
NEW_CHANNEL_SLOT_OVERFLOW(2008),
|
||||
BAD_REQUEST(2009),
|
||||
UNKNOWN_REQUEST_ENCODING(2010),
|
||||
BAD_RESPONSE(2011),
|
||||
UNKNOWN_RESPONSE_ENCODING(2012),
|
||||
|
||||
// Failures in Logical Connections : (3000-3999)
|
||||
LOGICAL_CHANNEL_FAILED(3000),
|
||||
SEND_QUOTA_VIOLATION(3005),
|
||||
SEND_QUOTA_OVERFLOW(3006),
|
||||
IDLE_TIMEOUT(3007),
|
||||
DROP_CHANNEL_ACK(3008),
|
||||
|
||||
// Other Peer Actions : (4000-4999)
|
||||
USE_ANOTHER_PHYSICAL_CONNECTION(4001),
|
||||
BUSY(4002);
|
||||
|
||||
private static final Map<Integer, Reason> codeMap;
|
||||
|
||||
static
|
||||
{
|
||||
codeMap = new HashMap<>();
|
||||
for (Reason r : values())
|
||||
{
|
||||
codeMap.put(r.getValue(),r);
|
||||
}
|
||||
}
|
||||
|
||||
public static Reason valueOf(int code)
|
||||
{
|
||||
return codeMap.get(code);
|
||||
}
|
||||
|
||||
private final int code;
|
||||
|
||||
private Reason(int code)
|
||||
{
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public int getValue()
|
||||
{
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
public static MuxDropChannel parse(long channelId, ByteBuffer payload)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
private final long channelId;
|
||||
private final Reason code;
|
||||
private String phrase;
|
||||
private int rsv;
|
||||
|
||||
/**
|
||||
* Normal Drop. no reason Phrase.
|
||||
*
|
||||
* @param channelId
|
||||
* the logical channel Id to perform drop against.
|
||||
*/
|
||||
public MuxDropChannel(long channelId)
|
||||
{
|
||||
this(channelId,Reason.NORMAL_CLOSURE,null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop with reason code and optional phrase
|
||||
*
|
||||
* @param channelId
|
||||
* the logical channel Id to perform drop against.
|
||||
* @param code
|
||||
* reason code
|
||||
* @param phrase
|
||||
* optional human readable phrase
|
||||
*/
|
||||
public MuxDropChannel(long channelId, int code, String phrase)
|
||||
{
|
||||
this(channelId, Reason.valueOf(code), phrase);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop with reason code and optional phrase
|
||||
*
|
||||
* @param channelId
|
||||
* the logical channel Id to perform drop against.
|
||||
* @param code
|
||||
* reason code
|
||||
* @param phrase
|
||||
* optional human readable phrase
|
||||
*/
|
||||
public MuxDropChannel(long channelId, Reason code, String phrase)
|
||||
{
|
||||
this.channelId = channelId;
|
||||
this.code = code;
|
||||
this.phrase = phrase;
|
||||
}
|
||||
|
||||
public ByteBuffer asReasonBuffer()
|
||||
{
|
||||
// TODO: convert to reason buffer
|
||||
return null;
|
||||
}
|
||||
|
||||
public long getChannelId()
|
||||
{
|
||||
return channelId;
|
||||
}
|
||||
|
||||
public Reason getCode()
|
||||
{
|
||||
return code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpCode()
|
||||
{
|
||||
return MuxOp.DROP_CHANNEL;
|
||||
}
|
||||
|
||||
public String getPhrase()
|
||||
{
|
||||
return phrase;
|
||||
}
|
||||
|
||||
public int getRsv()
|
||||
{
|
||||
return rsv;
|
||||
}
|
||||
|
||||
public void setRsv(int rsv)
|
||||
{
|
||||
this.rsv = rsv;
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux.op;
|
||||
|
||||
import org.eclipse.jetty.websocket.mux.MuxControlBlock;
|
||||
import org.eclipse.jetty.websocket.mux.MuxOp;
|
||||
|
||||
public class MuxFlowControl implements MuxControlBlock
|
||||
{
|
||||
private long channelId;
|
||||
private byte rsv;
|
||||
private long sendQuotaSize;
|
||||
|
||||
public long getChannelId()
|
||||
{
|
||||
return channelId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpCode()
|
||||
{
|
||||
return MuxOp.FLOW_CONTROL;
|
||||
}
|
||||
|
||||
public byte getRsv()
|
||||
{
|
||||
return rsv;
|
||||
}
|
||||
|
||||
public long getSendQuotaSize()
|
||||
{
|
||||
return sendQuotaSize;
|
||||
}
|
||||
|
||||
public void setChannelId(long channelId)
|
||||
{
|
||||
this.channelId = channelId;
|
||||
}
|
||||
|
||||
public void setRsv(byte rsv)
|
||||
{
|
||||
this.rsv = rsv;
|
||||
}
|
||||
|
||||
public void setSendQuotaSize(long sendQuotaSize)
|
||||
{
|
||||
this.sendQuotaSize = sendQuotaSize;
|
||||
}
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux.op;
|
||||
|
||||
import org.eclipse.jetty.websocket.mux.MuxControlBlock;
|
||||
import org.eclipse.jetty.websocket.mux.MuxOp;
|
||||
|
||||
public class MuxNewChannelSlot implements MuxControlBlock
|
||||
{
|
||||
private boolean fallback;
|
||||
private long initialSendQuota;
|
||||
private long numberOfSlots;
|
||||
private byte rsv;
|
||||
|
||||
public long getInitialSendQuota()
|
||||
{
|
||||
return initialSendQuota;
|
||||
}
|
||||
|
||||
public long getNumberOfSlots()
|
||||
{
|
||||
return numberOfSlots;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpCode()
|
||||
{
|
||||
return MuxOp.NEW_CHANNEL_SLOT;
|
||||
}
|
||||
|
||||
public byte getRsv()
|
||||
{
|
||||
return rsv;
|
||||
}
|
||||
|
||||
public boolean isFallback()
|
||||
{
|
||||
return fallback;
|
||||
}
|
||||
|
||||
public void setFallback(boolean fallback)
|
||||
{
|
||||
this.fallback = fallback;
|
||||
}
|
||||
|
||||
public void setInitialSendQuota(long initialSendQuota)
|
||||
{
|
||||
this.initialSendQuota = initialSendQuota;
|
||||
}
|
||||
|
||||
public void setNumberOfSlots(long numberOfSlots)
|
||||
{
|
||||
this.numberOfSlots = numberOfSlots;
|
||||
}
|
||||
|
||||
public void setRsv(byte rsv)
|
||||
{
|
||||
this.rsv = rsv;
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
/**
|
||||
* Jetty WebSocket Common : MUX Extension OpCode Handling [<em>Unstable Early Draft</em>]
|
||||
*/
|
||||
package org.eclipse.jetty.websocket.mux.op;
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
/**
|
||||
* Jetty WebSocket Common : MUX Extension Core [<em>Unstable Early Draft</em>]
|
||||
*/
|
||||
package org.eclipse.jetty.websocket.mux;
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux.server;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.server.ByteBufferQueuedHttpInput;
|
||||
|
||||
/**
|
||||
* HttpInput for Empty Http body sections.
|
||||
*/
|
||||
public class EmptyHttpInput extends ByteBufferQueuedHttpInput
|
||||
{
|
||||
@Override
|
||||
protected int get(ByteBuffer item, byte[] buffer, int offset, int length)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int remaining(ByteBuffer item)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux.server;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.HttpChannel;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
import org.eclipse.jetty.server.HttpInput;
|
||||
import org.eclipse.jetty.server.HttpTransport;
|
||||
|
||||
/**
|
||||
* Process incoming AddChannelRequest headers within the existing Jetty framework. Benefiting from Server container knowledge and various webapp configuration
|
||||
* knowledge.
|
||||
*/
|
||||
public class HttpChannelOverMux extends HttpChannel<ByteBuffer>
|
||||
{
|
||||
public HttpChannelOverMux(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInput<ByteBuffer> input)
|
||||
{
|
||||
super(connector,configuration,endPoint,transport,input);
|
||||
}
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux.server;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.http.HttpGenerator.ResponseInfo;
|
||||
import org.eclipse.jetty.server.HttpTransport;
|
||||
import org.eclipse.jetty.util.BlockingCallback;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.mux.MuxChannel;
|
||||
import org.eclipse.jetty.websocket.mux.Muxer;
|
||||
|
||||
/**
|
||||
* Take {@link ResponseInfo} objects and convert to bytes for response.
|
||||
*/
|
||||
public class HttpTransportOverMux implements HttpTransport
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(HttpTransportOverMux.class);
|
||||
private final BlockingCallback streamBlocker = new BlockingCallback();
|
||||
|
||||
public HttpTransportOverMux(Muxer muxer, MuxChannel channel)
|
||||
{
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completed()
|
||||
{
|
||||
LOG.debug("completed");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void send(ResponseInfo info, ByteBuffer responseBodyContent, boolean lastContent, Callback callback)
|
||||
{
|
||||
if (lastContent == false)
|
||||
{
|
||||
// throw error
|
||||
}
|
||||
|
||||
if (info.getContentLength() > 0)
|
||||
{
|
||||
// throw error
|
||||
}
|
||||
|
||||
// prepare the AddChannelResponse
|
||||
// TODO: look at HttpSender in jetty-client for generator loop logic
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(ByteBuffer responseBodyContent, boolean lastContent, Callback callback)
|
||||
{
|
||||
send(null,responseBodyContent, lastContent, callback);
|
||||
}
|
||||
}
|
|
@ -1,112 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux.server;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.websocket.api.UpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.api.UpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.mux.MuxChannel;
|
||||
import org.eclipse.jetty.websocket.mux.MuxException;
|
||||
import org.eclipse.jetty.websocket.mux.Muxer;
|
||||
import org.eclipse.jetty.websocket.mux.add.MuxAddServer;
|
||||
|
||||
/**
|
||||
* Handler for incoming MuxAddChannel requests.
|
||||
*/
|
||||
public class MuxAddHandler implements MuxAddServer
|
||||
{
|
||||
/** Represents physical connector */
|
||||
private Connector connector;
|
||||
|
||||
/** Used for local address */
|
||||
private EndPoint endPoint;
|
||||
|
||||
/** The original request handshake */
|
||||
private UpgradeRequest baseHandshakeRequest;
|
||||
|
||||
/** The original request handshake */
|
||||
private UpgradeResponse baseHandshakeResponse;
|
||||
|
||||
private int maximumHeaderSize = 32 * 1024;
|
||||
|
||||
@Override
|
||||
public UpgradeRequest getPhysicalHandshakeRequest()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UpgradeResponse getPhysicalHandshakeResponse()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An incoming MuxAddChannel request.
|
||||
*
|
||||
* @param muxer the muxer handling this
|
||||
* @param channel the
|
||||
* channel this request should be bound to
|
||||
* @param request
|
||||
* the incoming request headers (complete and merged if delta encoded)
|
||||
*/
|
||||
@Override
|
||||
public void handshake(Muxer muxer, MuxChannel channel, UpgradeRequest request) throws MuxException, IOException
|
||||
{
|
||||
// Need to call into HttpChannel to get the websocket properly setup.
|
||||
HttpTransportOverMux transport = new HttpTransportOverMux(muxer,channel);
|
||||
EmptyHttpInput input = new EmptyHttpInput();
|
||||
HttpConfiguration configuration = new HttpConfiguration();
|
||||
|
||||
HttpChannelOverMux httpChannel = new HttpChannelOverMux(//
|
||||
connector,configuration,endPoint,transport,input);
|
||||
|
||||
HttpMethod method = HttpMethod.fromString(request.getMethod());
|
||||
HttpVersion version = HttpVersion.fromString(request.getHttpVersion());
|
||||
httpChannel.startRequest(method,request.getMethod(),BufferUtil.toBuffer(request.getRequestURI().toASCIIString()),version);
|
||||
|
||||
for (String headerName : request.getHeaders().keySet())
|
||||
{
|
||||
HttpHeader header = HttpHeader.CACHE.getBest(headerName.getBytes(),0,headerName.length());
|
||||
for (String value : request.getHeaders().get(headerName))
|
||||
{
|
||||
httpChannel.parsedHeader(new HttpField(header,value));
|
||||
}
|
||||
}
|
||||
|
||||
httpChannel.headerComplete();
|
||||
httpChannel.messageComplete();
|
||||
httpChannel.run(); // calls into server for appropriate resource
|
||||
|
||||
// TODO: what's in request handshake is not enough to process the request.
|
||||
// like a partial http request. (consider this a AddChannelRequest failure)
|
||||
throw new MuxException("Not a valid request");
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux.server;
|
||||
|
||||
import org.eclipse.jetty.websocket.mux.AbstractMuxExtension;
|
||||
import org.eclipse.jetty.websocket.mux.Muxer;
|
||||
|
||||
public class MuxServerExtension extends AbstractMuxExtension
|
||||
{
|
||||
@Override
|
||||
public void configureMuxer(Muxer muxer)
|
||||
{
|
||||
muxer.setAddServer(new MuxAddHandler());
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
/**
|
||||
* Jetty WebSocket Server : MUX Extension [<em>Unstable Early Draft</em>]
|
||||
*/
|
||||
package org.eclipse.jetty.websocket.mux.server;
|
||||
|
|
@ -1 +0,0 @@
|
|||
org.eclipse.jetty.websocket.mux.client.MuxClientExtension
|
|
@ -1 +0,0 @@
|
|||
org.eclipse.jetty.websocket.mux.client.MuxServerExtension
|
|
@ -1,47 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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 examples.echo;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.WebSocketAdapter;
|
||||
|
||||
/**
|
||||
* Example EchoSocket using Adapter.
|
||||
*/
|
||||
public class AdapterEchoSocket extends WebSocketAdapter
|
||||
{
|
||||
@Override
|
||||
public void onWebSocketText(String message)
|
||||
{
|
||||
if (isConnected())
|
||||
{
|
||||
try
|
||||
{
|
||||
System.out.printf("Echoing back message [%s]%n",message);
|
||||
// echo the message back
|
||||
getRemote().sendString(message);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.WriteCallback;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.api.extensions.OutgoingFrames;
|
||||
|
||||
/**
|
||||
* Helpful utility class to parse arbitrary mux events from a physical connection's OutgoingFrames.
|
||||
*
|
||||
* @see MuxEncoder
|
||||
*/
|
||||
public class MuxDecoder extends MuxEventCapture implements OutgoingFrames
|
||||
{
|
||||
private MuxParser parser;
|
||||
|
||||
public MuxDecoder()
|
||||
{
|
||||
parser = new MuxParser();
|
||||
parser.setEvents(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void outgoingFrame(Frame frame, WriteCallback callback)
|
||||
{
|
||||
parser.parse(frame);
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.WriteCallback;
|
||||
import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
|
||||
import org.eclipse.jetty.websocket.api.extensions.OutgoingFrames;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.io.FramePipes;
|
||||
|
||||
/**
|
||||
* Helpful utility class to send arbitrary mux events into a physical connection's IncomingFrames.
|
||||
*
|
||||
* @see MuxDecoder
|
||||
*/
|
||||
public class MuxEncoder
|
||||
{
|
||||
public static MuxEncoder toIncoming(IncomingFrames incoming)
|
||||
{
|
||||
return new MuxEncoder(FramePipes.to(incoming));
|
||||
}
|
||||
|
||||
public static MuxEncoder toOutgoing(OutgoingFrames outgoing)
|
||||
{
|
||||
return new MuxEncoder(outgoing);
|
||||
}
|
||||
|
||||
private MuxGenerator generator;
|
||||
|
||||
private MuxEncoder(OutgoingFrames outgoing)
|
||||
{
|
||||
this.generator = new MuxGenerator();
|
||||
this.generator.setOutgoing(outgoing);
|
||||
}
|
||||
|
||||
public void frame(long channelId, WebSocketFrame frame) throws IOException
|
||||
{
|
||||
this.generator.generate(channelId,frame,null);
|
||||
}
|
||||
|
||||
public void op(MuxControlBlock op) throws IOException
|
||||
{
|
||||
WriteCallback callback = null;
|
||||
this.generator.generate(callback,op);
|
||||
}
|
||||
}
|
|
@ -1,137 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.common.OpCode;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxAddChannelRequest;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxAddChannelResponse;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxDropChannel;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxFlowControl;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxNewChannelSlot;
|
||||
import org.junit.Assert;
|
||||
|
||||
public class MuxEventCapture implements MuxParser.Listener
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(MuxEventCapture.class);
|
||||
|
||||
private LinkedList<MuxedFrame> frames = new LinkedList<>();
|
||||
private LinkedList<MuxControlBlock> ops = new LinkedList<>();
|
||||
private LinkedList<MuxException> errors = new LinkedList<>();
|
||||
|
||||
public void assertFrameCount(int expected)
|
||||
{
|
||||
Assert.assertThat("Frame Count",frames.size(), is(expected));
|
||||
}
|
||||
|
||||
public void assertHasFrame(byte opcode, long channelId, int expectedCount)
|
||||
{
|
||||
int actualCount = 0;
|
||||
|
||||
for (MuxedFrame frame : frames)
|
||||
{
|
||||
if (frame.getChannelId() == channelId)
|
||||
{
|
||||
if (frame.getOpCode() == opcode)
|
||||
{
|
||||
actualCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Assert.assertThat("Expected Count of " + OpCode.name(opcode) + " frames on Channel ID " + channelId,actualCount,is(expectedCount));
|
||||
}
|
||||
|
||||
public void assertHasOp(byte opCode, int expectedCount)
|
||||
{
|
||||
int actualCount = 0;
|
||||
for (MuxControlBlock block : ops)
|
||||
{
|
||||
if (block.getOpCode() == opCode)
|
||||
{
|
||||
actualCount++;
|
||||
}
|
||||
}
|
||||
Assert.assertThat("Op[" + opCode + "] count",actualCount,is(expectedCount));
|
||||
}
|
||||
|
||||
public LinkedList<MuxedFrame> getFrames()
|
||||
{
|
||||
return frames;
|
||||
}
|
||||
|
||||
public LinkedList<MuxControlBlock> getOps()
|
||||
{
|
||||
return ops;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMuxAddChannelRequest(MuxAddChannelRequest request)
|
||||
{
|
||||
ops.add(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMuxAddChannelResponse(MuxAddChannelResponse response)
|
||||
{
|
||||
ops.add(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMuxDropChannel(MuxDropChannel drop)
|
||||
{
|
||||
ops.add(drop);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMuxedFrame(MuxedFrame frame)
|
||||
{
|
||||
frames.add(new MuxedFrame(frame));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMuxException(MuxException e)
|
||||
{
|
||||
LOG.debug(e);
|
||||
errors.add(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMuxFlowControl(MuxFlowControl flow)
|
||||
{
|
||||
ops.add(flow);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMuxNewChannelSlot(MuxNewChannelSlot slot)
|
||||
{
|
||||
ops.add(slot);
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
frames.clear();
|
||||
ops.clear();
|
||||
}
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestName;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class MuxGeneratorWrite139SizeTest
|
||||
{
|
||||
private static MuxGenerator generator = new MuxGenerator();
|
||||
|
||||
@Parameters
|
||||
public static Collection<Object[]> data()
|
||||
{
|
||||
// Various good 1/3/9 encodings
|
||||
List<Object[]> data = new ArrayList<>();
|
||||
|
||||
// @formatter:off
|
||||
// - 1 byte tests
|
||||
data.add(new Object[]{ 0L, "00"});
|
||||
data.add(new Object[]{ 1L, "01"});
|
||||
data.add(new Object[]{ 2L, "02"});
|
||||
data.add(new Object[]{ 55L, "37"});
|
||||
data.add(new Object[]{125L, "7D"});
|
||||
|
||||
// - 3 byte tests
|
||||
data.add(new Object[]{0x00_80L, "7E0080"});
|
||||
data.add(new Object[]{0x00_ABL, "7E00AB"});
|
||||
data.add(new Object[]{0x00_FFL, "7E00FF"});
|
||||
data.add(new Object[]{0x3F_FFL, "7E3FFF"});
|
||||
|
||||
// - 9 byte tests
|
||||
data.add(new Object[]{0x00_00_01_FF_FFL, "7F000000000001FFFF"});
|
||||
data.add(new Object[]{0x00_00_FF_FF_FFL, "7F0000000000FFFFFF"});
|
||||
data.add(new Object[]{0x00_FF_FF_FF_FFL, "7F00000000FFFFFFFF"});
|
||||
data.add(new Object[]{0xFF_FF_FF_FF_FFL, "7F000000FFFFFFFFFF"});
|
||||
// @formatter:on
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@Rule
|
||||
public TestName testname = new TestName();
|
||||
|
||||
private long value;
|
||||
private String expectedHex;
|
||||
|
||||
public MuxGeneratorWrite139SizeTest(long value, String expectedHex)
|
||||
{
|
||||
this.value = value;
|
||||
this.expectedHex = expectedHex;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrite139Size()
|
||||
{
|
||||
System.err.printf("Running %s.%s - value: %,d%n",this.getClass().getName(),testname.getMethodName(),value);
|
||||
ByteBuffer bbuf = ByteBuffer.allocate(10);
|
||||
generator.write139Size(bbuf,value);
|
||||
BufferUtil.flipToFlush(bbuf,0);
|
||||
byte actual[] = BufferUtil.toArray(bbuf);
|
||||
String actualHex = TypeUtil.toHexString(actual).toUpperCase(Locale.ENGLISH);
|
||||
Assert.assertThat("1/3/9 encoded size of [" + value + "]",actualHex,is(expectedHex));
|
||||
}
|
||||
}
|
|
@ -1,101 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestName;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
/**
|
||||
* Tests of valid ChannelID generation
|
||||
*/
|
||||
@RunWith(Parameterized.class)
|
||||
public class MuxGeneratorWriteChannelIdTest
|
||||
{
|
||||
private static MuxGenerator generator = new MuxGenerator();
|
||||
|
||||
@Parameters
|
||||
public static Collection<Object[]> data()
|
||||
{
|
||||
// Various good Channel IDs
|
||||
List<Object[]> data = new ArrayList<>();
|
||||
|
||||
// @formatter:off
|
||||
// - 1 byte tests
|
||||
data.add(new Object[]{ 0L, "00"});
|
||||
data.add(new Object[]{ 1L, "01"});
|
||||
data.add(new Object[]{ 2L, "02"});
|
||||
data.add(new Object[]{ 55L, "37"});
|
||||
data.add(new Object[]{127L, "7F"});
|
||||
|
||||
// - 2 byte tests
|
||||
data.add(new Object[]{0x00_80L, "8080"});
|
||||
data.add(new Object[]{0x00_FFL, "80FF"});
|
||||
data.add(new Object[]{0x3F_FFL, "BFFF"});
|
||||
|
||||
// - 3 byte tests
|
||||
data.add(new Object[]{0x00_FF_FFL, "C0FFFF"});
|
||||
data.add(new Object[]{0x1F_FF_FFL, "DFFFFF"});
|
||||
|
||||
// - 3 byte tests
|
||||
data.add(new Object[]{0x00_FF_FF_FFL, "E0FFFFFF"});
|
||||
data.add(new Object[]{0x1F_FF_FF_FFL, "FFFFFFFF"});
|
||||
|
||||
// @formatter:on
|
||||
return data;
|
||||
}
|
||||
|
||||
@Rule
|
||||
public TestName testname = new TestName();
|
||||
|
||||
private long channelId;
|
||||
private String expectedHex;
|
||||
|
||||
public MuxGeneratorWriteChannelIdTest(long channelId, String expectedHex)
|
||||
{
|
||||
this.channelId = channelId;
|
||||
this.expectedHex = expectedHex;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadChannelId()
|
||||
{
|
||||
System.err.printf("Running %s.%s - channelId: %,d%n",this.getClass().getName(),testname.getMethodName(),channelId);
|
||||
ByteBuffer bbuf = ByteBuffer.allocate(10);
|
||||
generator.writeChannelId(bbuf,channelId);
|
||||
BufferUtil.flipToFlush(bbuf,0);
|
||||
byte actual[] = BufferUtil.toArray(bbuf);
|
||||
String actualHex = TypeUtil.toHexString(actual).toUpperCase(Locale.ENGLISH);
|
||||
Assert.assertThat("Channel ID [" + channelId + "]",actualHex,is(expectedHex));
|
||||
}
|
||||
}
|
|
@ -1,244 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.common.OpCode;
|
||||
import org.eclipse.jetty.websocket.common.Parser;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.extensions.AbstractExtension;
|
||||
import org.eclipse.jetty.websocket.mux.helper.IncomingFramesCapture;
|
||||
import org.eclipse.jetty.websocket.mux.helper.UnitParser;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
public class MuxParserRFCTest
|
||||
{
|
||||
public static class DummyMuxExtension extends AbstractMuxExtension
|
||||
{
|
||||
@Override
|
||||
public void configureMuxer(Muxer muxer)
|
||||
{
|
||||
/* nothing to do */
|
||||
}
|
||||
}
|
||||
|
||||
private LinkedList<WebSocketFrame> asFrames(byte[] buf)
|
||||
{
|
||||
IncomingFramesCapture capture = new IncomingFramesCapture();
|
||||
WebSocketPolicy policy = WebSocketPolicy.newClientPolicy();
|
||||
Parser parser = new UnitParser(policy);
|
||||
parser.setIncomingFramesHandler(capture);
|
||||
List<? extends AbstractExtension> muxList = Collections.singletonList(new DummyMuxExtension());
|
||||
parser.configureFromExtensions(muxList);
|
||||
ByteBuffer bbuf = ByteBuffer.wrap(buf);
|
||||
parser.parse(bbuf);
|
||||
|
||||
return capture.getFrames();
|
||||
}
|
||||
|
||||
private boolean isHexOnly(String part)
|
||||
{
|
||||
Pattern bytePat = Pattern.compile("(\\s*0x[0-9A-Fa-f]{2}+){1,}+");
|
||||
Matcher mat = bytePat.matcher(part);
|
||||
return mat.matches();
|
||||
}
|
||||
|
||||
private MuxEventCapture parseMuxFrames(LinkedList<WebSocketFrame> frames)
|
||||
{
|
||||
MuxParser parser = new MuxParser();
|
||||
MuxEventCapture capture = new MuxEventCapture();
|
||||
parser.setEvents(capture);
|
||||
for(Frame frame: frames) {
|
||||
parser.parse(frame);
|
||||
}
|
||||
return capture;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsHexOnly()
|
||||
{
|
||||
Assert.assertTrue(isHexOnly("0x00"));
|
||||
Assert.assertTrue(isHexOnly("0x00 0xaF"));
|
||||
Assert.assertFalse(isHexOnly("Hello World"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testRFCExample1() throws IOException
|
||||
{
|
||||
// Create RFC detailed frames
|
||||
byte buf[] = toByteArray("0x82 0x0d 0x01 0x81","Hello world");
|
||||
LinkedList<WebSocketFrame> frames = asFrames(buf);
|
||||
Assert.assertThat("Frame count",frames.size(),is(1));
|
||||
|
||||
// Have mux parse frames
|
||||
MuxEventCapture capture = parseMuxFrames(frames);
|
||||
capture.assertFrameCount(1);
|
||||
|
||||
MuxedFrame mux;
|
||||
|
||||
mux = capture.getFrames().pop();
|
||||
String prefix = "MuxFrame[0]";
|
||||
Assert.assertThat(prefix + ".channelId",mux.getChannelId(),is(1L));
|
||||
Assert.assertThat(prefix + ".fin",mux.isFin(),is(true));
|
||||
Assert.assertThat(prefix + ".rsv1",mux.isRsv1(),is(false));
|
||||
Assert.assertThat(prefix + ".rsv2",mux.isRsv2(),is(false));
|
||||
Assert.assertThat(prefix + ".rsv3",mux.isRsv3(),is(false));
|
||||
Assert.assertThat(prefix + ".masked",mux.isMasked(),is(false));
|
||||
Assert.assertThat(prefix + ".opcode",mux.getOpCode(),is(OpCode.TEXT));
|
||||
|
||||
String payload = mux.getPayloadAsUTF8();
|
||||
Assert.assertThat(prefix + ".payload/text",payload,is("Hello world"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testRFCExample2() throws IOException
|
||||
{
|
||||
// Create RFC detailed frames
|
||||
byte buf[] = toByteArray("0x02 0x07 0x01 0x81","Hello","0x80 0x06"," world");
|
||||
LinkedList<WebSocketFrame> frames = asFrames(buf);
|
||||
Assert.assertThat("Frame count",frames.size(),is(2));
|
||||
|
||||
// Have mux parse frames
|
||||
MuxEventCapture capture = parseMuxFrames(frames);
|
||||
capture.assertFrameCount(2);
|
||||
|
||||
MuxedFrame mux;
|
||||
|
||||
// Text Frame
|
||||
mux = capture.getFrames().get(0);
|
||||
String prefix = "MuxFrame[0]";
|
||||
Assert.assertThat(prefix + ".channelId",mux.getChannelId(),is(1L));
|
||||
// (BUG IN DRAFT) Assert.assertThat(prefix + ".fin",mux.isFin(),is(false));
|
||||
Assert.assertThat(prefix + ".rsv1",mux.isRsv1(),is(false));
|
||||
Assert.assertThat(prefix + ".rsv2",mux.isRsv2(),is(false));
|
||||
Assert.assertThat(prefix + ".rsv3",mux.isRsv3(),is(false));
|
||||
Assert.assertThat(prefix + ".masked",mux.isMasked(),is(false));
|
||||
Assert.assertThat(prefix + ".opcode",mux.getOpCode(),is(OpCode.TEXT));
|
||||
|
||||
String payload = mux.getPayloadAsUTF8();
|
||||
Assert.assertThat(prefix + ".payload/text",payload,is("Hello"));
|
||||
|
||||
// Continuation Frame
|
||||
mux = capture.getFrames().get(1);
|
||||
prefix = "MuxFrame[1]";
|
||||
// (BUG IN DRAFT) Assert.assertThat(prefix + ".channelId",mux.getChannelId(),is(1L));
|
||||
// (BUG IN DRAFT) Assert.assertThat(prefix + ".fin",mux.isFin(),is(true));
|
||||
Assert.assertThat(prefix + ".rsv1",mux.isRsv1(),is(false));
|
||||
Assert.assertThat(prefix + ".rsv2",mux.isRsv2(),is(false));
|
||||
Assert.assertThat(prefix + ".rsv3",mux.isRsv3(),is(false));
|
||||
Assert.assertThat(prefix + ".masked",mux.isMasked(),is(false));
|
||||
// (BUG IN DRAFT) Assert.assertThat(prefix + ".opcode",mux.getOpCode(),is(OpCode.BINARY));
|
||||
|
||||
payload = mux.getPayloadAsUTF8();
|
||||
Assert.assertThat(prefix + ".payload/text",payload,is(" world"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testRFCExample3() throws IOException
|
||||
{
|
||||
// Create RFC detailed frames
|
||||
byte buf[] = toByteArray("0x82 0x07 0x01 0x01","Hello","0x82 0x05 0x02 0x81","bye","0x82 0x08 0x01 0x80"," world");
|
||||
LinkedList<WebSocketFrame> frames = asFrames(buf);
|
||||
Assert.assertThat("Frame count",frames.size(),is(3));
|
||||
|
||||
// Have mux parse frames
|
||||
MuxEventCapture capture = parseMuxFrames(frames);
|
||||
capture.assertFrameCount(3);
|
||||
|
||||
MuxedFrame mux;
|
||||
|
||||
// Text Frame (Message 1)
|
||||
mux = capture.getFrames().pop();
|
||||
String prefix = "MuxFrame[0]";
|
||||
Assert.assertThat(prefix + ".channelId",mux.getChannelId(),is(1L));
|
||||
Assert.assertThat(prefix + ".fin",mux.isFin(),is(false));
|
||||
Assert.assertThat(prefix + ".rsv1",mux.isRsv1(),is(false));
|
||||
Assert.assertThat(prefix + ".rsv2",mux.isRsv2(),is(false));
|
||||
Assert.assertThat(prefix + ".rsv3",mux.isRsv3(),is(false));
|
||||
Assert.assertThat(prefix + ".masked",mux.isMasked(),is(false));
|
||||
Assert.assertThat(prefix + ".opcode",mux.getOpCode(),is(OpCode.TEXT));
|
||||
|
||||
String payload = mux.getPayloadAsUTF8();
|
||||
Assert.assertThat(prefix + ".payload/text",payload,is("Hello"));
|
||||
|
||||
// Text Frame (Message 2)
|
||||
mux = capture.getFrames().pop();
|
||||
prefix = "MuxFrame[1]";
|
||||
Assert.assertThat(prefix + ".channelId",mux.getChannelId(),is(2L));
|
||||
Assert.assertThat(prefix + ".fin",mux.isFin(),is(true));
|
||||
Assert.assertThat(prefix + ".rsv1",mux.isRsv1(),is(false));
|
||||
Assert.assertThat(prefix + ".rsv2",mux.isRsv2(),is(false));
|
||||
Assert.assertThat(prefix + ".rsv3",mux.isRsv3(),is(false));
|
||||
Assert.assertThat(prefix + ".masked",mux.isMasked(),is(false));
|
||||
Assert.assertThat(prefix + ".opcode",mux.getOpCode(),is(OpCode.TEXT));
|
||||
|
||||
payload = mux.getPayloadAsUTF8();
|
||||
Assert.assertThat(prefix + ".payload/text",payload,is("bye"));
|
||||
|
||||
// Continuation Frame (Message 1)
|
||||
mux = capture.getFrames().pop();
|
||||
prefix = "MuxFrame[2]";
|
||||
Assert.assertThat(prefix + ".channelId",mux.getChannelId(),is(1L));
|
||||
Assert.assertThat(prefix + ".fin",mux.isFin(),is(true));
|
||||
Assert.assertThat(prefix + ".rsv1",mux.isRsv1(),is(false));
|
||||
Assert.assertThat(prefix + ".rsv2",mux.isRsv2(),is(false));
|
||||
Assert.assertThat(prefix + ".rsv3",mux.isRsv3(),is(false));
|
||||
Assert.assertThat(prefix + ".masked",mux.isMasked(),is(false));
|
||||
Assert.assertThat(prefix + ".opcode",mux.getOpCode(),is(OpCode.TEXT));
|
||||
|
||||
payload = mux.getPayloadAsUTF8();
|
||||
Assert.assertThat(prefix + ".payload/text",payload,is(" world"));
|
||||
}
|
||||
|
||||
private byte[] toByteArray(String... parts) throws IOException
|
||||
{
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
for(String part: parts) {
|
||||
if (isHexOnly(part))
|
||||
{
|
||||
String hexonly = part.replaceAll("\\s*0x","");
|
||||
out.write(TypeUtil.fromHexString(hexonly));
|
||||
}
|
||||
else
|
||||
{
|
||||
out.write(part.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
return out.toByteArray();
|
||||
}
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestName;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
/**
|
||||
* Tests for bad 1/3/9 size encoding.
|
||||
*/
|
||||
@RunWith(Parameterized.class)
|
||||
public class MuxParserRead139Size_BadEncodingTest
|
||||
{
|
||||
private static MuxParser parser = new MuxParser();
|
||||
|
||||
@Parameters
|
||||
public static Collection<Object[]> data()
|
||||
{
|
||||
// Various bad 1/3/9 encodings
|
||||
// Violating "minimal number of bytes necessary" rule.
|
||||
List<Object[]> data = new ArrayList<>();
|
||||
|
||||
// @formatter:off
|
||||
// - 1 byte tests
|
||||
// all known 1 byte tests are valid
|
||||
|
||||
// - 3 byte tests
|
||||
data.add(new Object[]{"7E0000"});
|
||||
data.add(new Object[]{"7E0001"});
|
||||
data.add(new Object[]{"7E0012"});
|
||||
data.add(new Object[]{"7E0059"});
|
||||
// extra bytes (not related to 1/3/9 size)
|
||||
data.add(new Object[]{"7E0012345678"});
|
||||
|
||||
// - 9 byte tests
|
||||
data.add(new Object[]{"7F0000000000000000"});
|
||||
data.add(new Object[]{"7F0000000000000001"});
|
||||
data.add(new Object[]{"7F0000000000000012"});
|
||||
data.add(new Object[]{"7F0000000000001234"});
|
||||
data.add(new Object[]{"7F000000000000FFFF"});
|
||||
|
||||
// @formatter:on
|
||||
return data;
|
||||
}
|
||||
|
||||
@Rule
|
||||
public TestName testname = new TestName();
|
||||
|
||||
private String rawhex;
|
||||
private byte buf[];
|
||||
|
||||
public MuxParserRead139Size_BadEncodingTest(String rawhex)
|
||||
{
|
||||
this.rawhex = rawhex;
|
||||
this.buf = TypeUtil.fromHexString(rawhex);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRead139EncodedSize()
|
||||
{
|
||||
System.err.printf("Running %s.%s - hex: %s%n",this.getClass().getName(),testname.getMethodName(),rawhex);
|
||||
ByteBuffer bbuf = ByteBuffer.wrap(buf);
|
||||
try
|
||||
{
|
||||
parser.read139EncodedSize(bbuf);
|
||||
// unexpected path
|
||||
Assert.fail("Should have failed with an invalid parse");
|
||||
}
|
||||
catch (MuxException e)
|
||||
{
|
||||
// expected path
|
||||
Assert.assertThat(e.getMessage(),containsString("Invalid 1/3/9 length"));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestName;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class MuxParserRead139Size_GoodTest
|
||||
{
|
||||
private static MuxParser parser = new MuxParser();
|
||||
|
||||
@Parameters
|
||||
public static Collection<Object[]> data()
|
||||
{
|
||||
// Various good 1/3/9 encodings
|
||||
List<Object[]> data = new ArrayList<>();
|
||||
|
||||
// @formatter:off
|
||||
// - 1 byte tests
|
||||
data.add(new Object[]{"00", 0L});
|
||||
data.add(new Object[]{"01", 1L});
|
||||
data.add(new Object[]{"02", 2L});
|
||||
data.add(new Object[]{"37", 55L});
|
||||
data.add(new Object[]{"7D", 125L});
|
||||
// extra bytes (not related to 1/3/9 size)
|
||||
data.add(new Object[]{"37FF", 55L});
|
||||
data.add(new Object[]{"0123456789", 0x01L});
|
||||
|
||||
// - 3 byte tests
|
||||
data.add(new Object[]{"7E0080", 0x00_80L});
|
||||
data.add(new Object[]{"7E00AB", 0x00_ABL});
|
||||
data.add(new Object[]{"7E00FF", 0x00_FFL});
|
||||
data.add(new Object[]{"7E3FFF", 0x3F_FFL});
|
||||
// extra bytes (not related to 1/3/9 size)
|
||||
data.add(new Object[]{"7E0123456789", 0x01_23L});
|
||||
|
||||
// - 9 byte tests
|
||||
data.add(new Object[]{"7F000000000001FFFF", 0x00_00_01_FF_FFL});
|
||||
data.add(new Object[]{"7F0000000000FFFFFF", 0x00_00_FF_FF_FFL});
|
||||
data.add(new Object[]{"7F00000000FFFFFFFF", 0x00_FF_FF_FF_FFL});
|
||||
data.add(new Object[]{"7F000000FFFFFFFFFF", 0xFF_FF_FF_FF_FFL});
|
||||
|
||||
// @formatter:on
|
||||
return data;
|
||||
}
|
||||
|
||||
@Rule
|
||||
public TestName testname = new TestName();
|
||||
|
||||
private String rawhex;
|
||||
private byte buf[];
|
||||
private long expected;
|
||||
|
||||
public MuxParserRead139Size_GoodTest(String rawhex, long expected)
|
||||
{
|
||||
this.rawhex = rawhex;
|
||||
this.buf = TypeUtil.fromHexString(rawhex);
|
||||
this.expected = expected;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRead139EncodedSize()
|
||||
{
|
||||
System.err.printf("Running %s.%s - hex: %s%n",this.getClass().getName(),testname.getMethodName(),rawhex);
|
||||
ByteBuffer bbuf = ByteBuffer.wrap(buf);
|
||||
long actual = parser.read139EncodedSize(bbuf);
|
||||
Assert.assertThat("1/3/9 size from buffer [" + rawhex + "]",actual,is(expected));
|
||||
}
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestName;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
/**
|
||||
* Tests of Invalid ChannelID parsing
|
||||
*/
|
||||
@RunWith(Parameterized.class)
|
||||
public class MuxParserReadChannelId_BadEncodingTest
|
||||
{
|
||||
private static MuxParser parser = new MuxParser();
|
||||
|
||||
@Parameters
|
||||
public static Collection<Object[]> data()
|
||||
{
|
||||
// Various Invalid Encoded Channel IDs.
|
||||
// Violating "minimal number of bytes necessary" rule.
|
||||
List<Object[]> data = new ArrayList<>();
|
||||
|
||||
// @formatter:off
|
||||
// - 1 byte tests
|
||||
// all known 1 byte tests are valid
|
||||
|
||||
// - 2 byte tests
|
||||
data.add(new Object[]{"8000"});
|
||||
data.add(new Object[]{"8001"});
|
||||
data.add(new Object[]{"807F"});
|
||||
// extra bytes (not related to channelId)
|
||||
data.add(new Object[]{"8023456789"});
|
||||
|
||||
// - 3 byte tests
|
||||
data.add(new Object[]{"C00000"});
|
||||
data.add(new Object[]{"C01234"});
|
||||
data.add(new Object[]{"C03FFF"});
|
||||
|
||||
// - 3 byte tests
|
||||
data.add(new Object[]{"E0000000"});
|
||||
data.add(new Object[]{"E0000001"});
|
||||
data.add(new Object[]{"E01FFFFF"});
|
||||
|
||||
// @formatter:on
|
||||
return data;
|
||||
}
|
||||
|
||||
@Rule
|
||||
public TestName testname = new TestName();
|
||||
|
||||
private String rawhex;
|
||||
private byte buf[];
|
||||
|
||||
public MuxParserReadChannelId_BadEncodingTest(String rawhex)
|
||||
{
|
||||
this.rawhex = rawhex;
|
||||
this.buf = TypeUtil.fromHexString(rawhex);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadEncoding()
|
||||
{
|
||||
System.err.printf("Running %s.%s - hex: %s%n",this.getClass().getName(),testname.getMethodName(),rawhex);
|
||||
ByteBuffer bbuf = ByteBuffer.wrap(buf);
|
||||
try
|
||||
{
|
||||
parser.readChannelId(bbuf);
|
||||
// unexpected path
|
||||
Assert.fail("Should have failed with an invalid parse");
|
||||
}
|
||||
catch (MuxException e)
|
||||
{
|
||||
// expected path
|
||||
Assert.assertThat(e.getMessage(),containsString("Invalid Channel ID"));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestName;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
/**
|
||||
* Tests of valid ChannelID parsing
|
||||
*/
|
||||
@RunWith(Parameterized.class)
|
||||
public class MuxParserReadChannelId_GoodTest
|
||||
{
|
||||
private static MuxParser parser = new MuxParser();
|
||||
|
||||
@Parameters
|
||||
public static Collection<Object[]> data()
|
||||
{
|
||||
// Various good Channel IDs
|
||||
List<Object[]> data = new ArrayList<>();
|
||||
|
||||
// @formatter:off
|
||||
// - 1 byte tests
|
||||
data.add(new Object[]{"00", 0L});
|
||||
data.add(new Object[]{"01", 1L});
|
||||
data.add(new Object[]{"02", 2L});
|
||||
data.add(new Object[]{"7F", 127L});
|
||||
// extra bytes (not related to channelId)
|
||||
data.add(new Object[]{"37FF", 55L});
|
||||
data.add(new Object[]{"0123456789", 0x01L});
|
||||
|
||||
// - 2 byte tests
|
||||
data.add(new Object[]{"8080", 0x00_80L});
|
||||
data.add(new Object[]{"80FF", 0x00_FFL});
|
||||
data.add(new Object[]{"BFFF", 0x3F_FFL});
|
||||
// extra bytes (not related to channelId)
|
||||
data.add(new Object[]{"8123456789", 0x01_23L});
|
||||
|
||||
// - 3 byte tests
|
||||
data.add(new Object[]{"C0FFFF", 0x00_FF_FFL});
|
||||
data.add(new Object[]{"DFFFFF", 0x1F_FF_FFL});
|
||||
// extra bytes (not related to channelId)
|
||||
data.add(new Object[]{"C123456789", 0x01_23_45L});
|
||||
|
||||
// - 3 byte tests
|
||||
data.add(new Object[]{"E0FFFFFF", 0x00_FF_FF_FFL});
|
||||
data.add(new Object[]{"FFFFFFFF", 0x1F_FF_FF_FFL});
|
||||
// extra bytes (not related to channelId)
|
||||
data.add(new Object[]{"E123456789", 0x01_23_45_67L});
|
||||
|
||||
// @formatter:on
|
||||
return data;
|
||||
}
|
||||
|
||||
@Rule
|
||||
public TestName testname = new TestName();
|
||||
|
||||
private String rawhex;
|
||||
private byte buf[];
|
||||
private long expected;
|
||||
|
||||
public MuxParserReadChannelId_GoodTest(String rawhex, long expected)
|
||||
{
|
||||
this.rawhex = rawhex;
|
||||
this.buf = TypeUtil.fromHexString(rawhex);
|
||||
this.expected = expected;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadChannelId()
|
||||
{
|
||||
System.err.printf("Running %s.%s - hex: %s%n",this.getClass().getName(),testname.getMethodName(),rawhex);
|
||||
ByteBuffer bbuf = ByteBuffer.wrap(buf);
|
||||
long actual = parser.readChannelId(bbuf);
|
||||
Assert.assertThat("Channel ID from buffer [" + rawhex + "]",actual,is(expected));
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux.add;
|
||||
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxAddChannelResponse;
|
||||
|
||||
public class DummyMuxAddClient implements MuxAddClient
|
||||
{
|
||||
@Override
|
||||
public WebSocketSession createSession(MuxAddChannelResponse response)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux.add;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.UpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.api.UpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.common.SessionListener;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriver;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriverFactory;
|
||||
import org.eclipse.jetty.websocket.mux.MuxChannel;
|
||||
import org.eclipse.jetty.websocket.mux.MuxException;
|
||||
import org.eclipse.jetty.websocket.mux.Muxer;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxAddChannelResponse;
|
||||
|
||||
import examples.echo.AdapterEchoSocket;
|
||||
|
||||
/**
|
||||
* Dummy impl of MuxAddServer
|
||||
*/
|
||||
public class DummyMuxAddServer implements MuxAddServer
|
||||
{
|
||||
@SuppressWarnings("unused")
|
||||
private static final Logger LOG = Log.getLogger(DummyMuxAddServer.class);
|
||||
private AdapterEchoSocket echo;
|
||||
private WebSocketPolicy policy;
|
||||
private EventDriverFactory eventDriverFactory;
|
||||
|
||||
public DummyMuxAddServer()
|
||||
{
|
||||
this.policy = WebSocketPolicy.newServerPolicy();
|
||||
this.eventDriverFactory = new EventDriverFactory(policy);
|
||||
this.echo = new AdapterEchoSocket();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UpgradeRequest getPhysicalHandshakeRequest()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UpgradeResponse getPhysicalHandshakeResponse()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handshake(Muxer muxer, MuxChannel channel, UpgradeRequest request) throws MuxException, IOException
|
||||
{
|
||||
StringBuilder response = new StringBuilder();
|
||||
response.append("HTTP/1.1 101 Switching Protocols\r\n");
|
||||
response.append("Connection: upgrade\r\n");
|
||||
// not meaningful (per Draft 08) hresp.append("Upgrade: websocket\r\n");
|
||||
// not meaningful (per Draft 08) hresp.append("Sec-WebSocket-Accept: Kgo85/8KVE8YPONSeyhgL3GwqhI=\r\n");
|
||||
response.append("\r\n");
|
||||
|
||||
EventDriver websocket = this.eventDriverFactory.wrap(echo);
|
||||
WebSocketSession session = new WebSocketSession(request.getRequestURI(),websocket,channel, new SessionListener[0]);
|
||||
UpgradeResponse uresponse = new UpgradeResponse();
|
||||
uresponse.setAcceptedSubProtocol("echo");
|
||||
session.setUpgradeResponse(uresponse);
|
||||
channel.setSession(session);
|
||||
channel.setSubProtocol("echo");
|
||||
channel.onOpen();
|
||||
session.open();
|
||||
|
||||
MuxAddChannelResponse addChannelResponse = new MuxAddChannelResponse();
|
||||
addChannelResponse.setChannelId(channel.getChannelId());
|
||||
addChannelResponse.setEncoding(MuxAddChannelResponse.IDENTITY_ENCODING);
|
||||
addChannelResponse.setFailed(false);
|
||||
addChannelResponse.setHandshake(response.toString());
|
||||
|
||||
muxer.output(addChannelResponse);
|
||||
}
|
||||
}
|
|
@ -1,105 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux.add;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.mux.MuxChannel;
|
||||
import org.eclipse.jetty.websocket.mux.MuxDecoder;
|
||||
import org.eclipse.jetty.websocket.mux.MuxEncoder;
|
||||
import org.eclipse.jetty.websocket.mux.MuxOp;
|
||||
import org.eclipse.jetty.websocket.mux.Muxer;
|
||||
import org.eclipse.jetty.websocket.mux.helper.LocalWebSocketConnection;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxAddChannelRequest;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxAddChannelResponse;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestName;
|
||||
|
||||
public class MuxerAddClientTest
|
||||
{
|
||||
@Rule
|
||||
public TestName testname = new TestName();
|
||||
|
||||
@Test
|
||||
@Ignore("Interrim, not functional yet")
|
||||
public void testAddChannel_Client() throws Exception
|
||||
{
|
||||
// Client side physical socket
|
||||
LocalWebSocketConnection physical = new LocalWebSocketConnection(testname);
|
||||
physical.setPolicy(WebSocketPolicy.newClientPolicy());
|
||||
physical.open();
|
||||
|
||||
// Server Reader
|
||||
MuxDecoder serverRead = new MuxDecoder();
|
||||
|
||||
// Client side Muxer
|
||||
Muxer muxer = new Muxer(physical);
|
||||
DummyMuxAddClient addClient = new DummyMuxAddClient();
|
||||
muxer.setAddClient(addClient);
|
||||
muxer.setOutgoingFramesHandler(serverRead);
|
||||
|
||||
// Server Writer
|
||||
MuxEncoder serverWrite = MuxEncoder.toIncoming(physical);
|
||||
|
||||
// Build AddChannelRequest handshake data
|
||||
StringBuilder request = new StringBuilder();
|
||||
request.append("GET /echo HTTP/1.1\r\n");
|
||||
request.append("Host: localhost\r\n");
|
||||
request.append("Upgrade: websocket\r\n");
|
||||
request.append("Connection: Upgrade\r\n");
|
||||
request.append("Sec-WebSocket-Key: ZDTIRU5vU9xOfkg8JAgN3A==\r\n");
|
||||
request.append("Sec-WebSocket-Version: 13\r\n");
|
||||
request.append("\r\n");
|
||||
|
||||
// Build AddChannelRequest
|
||||
long channelId = 1L;
|
||||
MuxAddChannelRequest req = new MuxAddChannelRequest();
|
||||
req.setChannelId(channelId);
|
||||
req.setEncoding((byte)0);
|
||||
req.setHandshake(request.toString());
|
||||
|
||||
// Have client sent AddChannelRequest
|
||||
MuxChannel channel = muxer.getChannel(channelId,true);
|
||||
MuxEncoder clientWrite = MuxEncoder.toOutgoing(channel);
|
||||
clientWrite.op(req);
|
||||
|
||||
// Have server read request
|
||||
serverRead.assertHasOp(MuxOp.ADD_CHANNEL_REQUEST,1);
|
||||
|
||||
// prepare AddChannelResponse
|
||||
StringBuilder response = new StringBuilder();
|
||||
response.append("HTTP/1.1 101 Switching Protocols\r\n");
|
||||
response.append("Upgrade: websocket\r\n");
|
||||
response.append("Connection: upgrade\r\n");
|
||||
response.append("Sec-WebSocket-Accept: Kgo85/8KVE8YPONSeyhgL3GwqhI=\r\n");
|
||||
response.append("\r\n");
|
||||
|
||||
MuxAddChannelResponse resp = new MuxAddChannelResponse();
|
||||
resp.setChannelId(channelId);
|
||||
resp.setFailed(false);
|
||||
resp.setEncoding((byte)0);
|
||||
resp.setHandshake(resp.toString());
|
||||
|
||||
// Server writes add channel response
|
||||
serverWrite.op(resp);
|
||||
|
||||
// TODO: handle the upgrade on client side.
|
||||
}
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux.add;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.common.OpCode;
|
||||
import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.mux.MuxDecoder;
|
||||
import org.eclipse.jetty.websocket.mux.MuxEncoder;
|
||||
import org.eclipse.jetty.websocket.mux.MuxOp;
|
||||
import org.eclipse.jetty.websocket.mux.Muxer;
|
||||
import org.eclipse.jetty.websocket.mux.helper.LocalWebSocketConnection;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxAddChannelRequest;
|
||||
import org.eclipse.jetty.websocket.mux.op.MuxAddChannelResponse;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestName;
|
||||
|
||||
public class MuxerAddServerTest
|
||||
{
|
||||
@Rule
|
||||
public TestName testname = new TestName();
|
||||
|
||||
@Test
|
||||
@Ignore("Interrim, not functional yet")
|
||||
public void testAddChannel_Server() throws Exception
|
||||
{
|
||||
// Server side physical connection
|
||||
LocalWebSocketConnection physical = new LocalWebSocketConnection(testname);
|
||||
physical.setPolicy(WebSocketPolicy.newServerPolicy());
|
||||
physical.open();
|
||||
|
||||
// Client reader
|
||||
MuxDecoder clientRead = new MuxDecoder();
|
||||
|
||||
// Build up server side muxer.
|
||||
Muxer muxer = new Muxer(physical);
|
||||
DummyMuxAddServer addServer = new DummyMuxAddServer();
|
||||
muxer.setAddServer(addServer);
|
||||
muxer.setOutgoingFramesHandler(clientRead);
|
||||
|
||||
// Wire up physical connection to forward incoming frames to muxer
|
||||
physical.setNextIncomingFrames(muxer);
|
||||
|
||||
// Client simulator
|
||||
// Can inject mux encapsulated frames into physical connection as if from
|
||||
// physical connection.
|
||||
MuxEncoder clientWrite = MuxEncoder.toIncoming(physical);
|
||||
|
||||
// Build AddChannelRequest handshake data
|
||||
StringBuilder request = new StringBuilder();
|
||||
request.append("GET /echo HTTP/1.1\r\n");
|
||||
request.append("Host: localhost\r\n");
|
||||
request.append("Upgrade: websocket\r\n");
|
||||
request.append("Connection: Upgrade\r\n");
|
||||
request.append("Sec-WebSocket-Key: ZDTIRU5vU9xOfkg8JAgN3A==\r\n");
|
||||
request.append("Sec-WebSocket-Version: 13\r\n");
|
||||
request.append("\r\n");
|
||||
|
||||
// Build AddChannelRequest
|
||||
MuxAddChannelRequest req = new MuxAddChannelRequest();
|
||||
req.setChannelId(1);
|
||||
req.setEncoding((byte)0);
|
||||
req.setHandshake(request.toString());
|
||||
|
||||
// Have client sent AddChannelRequest
|
||||
clientWrite.op(req);
|
||||
|
||||
// Make sure client got AddChannelResponse
|
||||
clientRead.assertHasOp(MuxOp.ADD_CHANNEL_RESPONSE,1);
|
||||
MuxAddChannelResponse response = (MuxAddChannelResponse)clientRead.getOps().pop();
|
||||
Assert.assertThat("AddChannelResponse.channelId",response.getChannelId(),is(1L));
|
||||
Assert.assertThat("AddChannelResponse.failed",response.isFailed(),is(false));
|
||||
Assert.assertThat("AddChannelResponse.handshake",response.getHandshake(),notNullValue());
|
||||
Assert.assertThat("AddChannelResponse.handshakeSize",response.getHandshakeSize(),is(57L));
|
||||
|
||||
clientRead.reset();
|
||||
|
||||
// Send simple echo request
|
||||
clientWrite.frame(1,new TextFrame().setPayload("Hello World"));
|
||||
|
||||
// Test for echo response (is there a user echo websocket connected to the sub-channel?)
|
||||
clientRead.assertHasFrame(OpCode.TEXT,1L,1);
|
||||
}
|
||||
}
|
|
@ -1,143 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux.helper;
|
||||
|
||||
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
|
||||
import org.eclipse.jetty.websocket.common.OpCode;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.junit.Assert;
|
||||
|
||||
public class IncomingFramesCapture implements IncomingFrames
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(IncomingFramesCapture.class);
|
||||
|
||||
private LinkedList<WebSocketFrame> frames = new LinkedList<>();
|
||||
private LinkedList<Throwable> errors = new LinkedList<>();
|
||||
|
||||
public void assertErrorCount(int expectedCount)
|
||||
{
|
||||
Assert.assertThat("Captured error count",errors.size(),is(expectedCount));
|
||||
}
|
||||
|
||||
public void assertFrameCount(int expectedCount)
|
||||
{
|
||||
Assert.assertThat("Captured frame count",frames.size(),is(expectedCount));
|
||||
}
|
||||
|
||||
public void assertHasErrors(Class<? extends WebSocketException> errorType, int expectedCount)
|
||||
{
|
||||
Assert.assertThat(errorType.getSimpleName(),getErrorCount(errorType),is(expectedCount));
|
||||
}
|
||||
|
||||
public void assertHasFrame(byte op)
|
||||
{
|
||||
Assert.assertThat(OpCode.name(op),getFrameCount(op),greaterThanOrEqualTo(1));
|
||||
}
|
||||
|
||||
public void assertHasFrame(byte op, int expectedCount)
|
||||
{
|
||||
Assert.assertThat(OpCode.name(op),getFrameCount(op),is(expectedCount));
|
||||
}
|
||||
|
||||
public void assertHasNoFrames()
|
||||
{
|
||||
Assert.assertThat("Has no frames",frames.size(),is(0));
|
||||
}
|
||||
|
||||
public void assertNoErrors()
|
||||
{
|
||||
Assert.assertThat("Has no errors",errors.size(),is(0));
|
||||
}
|
||||
|
||||
public void dump()
|
||||
{
|
||||
System.err.printf("Captured %d incoming frames%n",frames.size());
|
||||
for (int i = 0; i < frames.size(); i++)
|
||||
{
|
||||
Frame frame = frames.get(i);
|
||||
System.err.printf("[%3d] %s%n",i,frame);
|
||||
System.err.printf(" %s%n",BufferUtil.toDetailString(frame.getPayload()));
|
||||
}
|
||||
}
|
||||
|
||||
public int getErrorCount(Class<? extends WebSocketException> errorType)
|
||||
{
|
||||
int count = 0;
|
||||
for (Throwable error : errors)
|
||||
{
|
||||
if (errorType.isInstance(error))
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public LinkedList<Throwable> getErrors()
|
||||
{
|
||||
return errors;
|
||||
}
|
||||
|
||||
public int getFrameCount(byte op)
|
||||
{
|
||||
int count = 0;
|
||||
for (WebSocketFrame frame : frames)
|
||||
{
|
||||
if (frame.getOpCode() == op)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public LinkedList<WebSocketFrame> getFrames()
|
||||
{
|
||||
return frames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incomingError(Throwable e)
|
||||
{
|
||||
LOG.debug(e);
|
||||
errors.add(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incomingFrame(Frame frame)
|
||||
{
|
||||
WebSocketFrame copy = WebSocketFrame.copy(frame);
|
||||
frames.add(copy);
|
||||
}
|
||||
|
||||
public int size()
|
||||
{
|
||||
return frames.size();
|
||||
}
|
||||
}
|
|
@ -1,250 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux.helper;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.thread.ExecutorThreadPool;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.api.SuspendToken;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.WriteCallback;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.ConnectionState;
|
||||
import org.eclipse.jetty.websocket.common.LogicalConnection;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.common.io.IOState;
|
||||
import org.eclipse.jetty.websocket.common.io.IOState.ConnectionStateListener;
|
||||
import org.junit.rules.TestName;
|
||||
|
||||
public class LocalWebSocketConnection implements LogicalConnection, IncomingFrames, ConnectionStateListener
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(LocalWebSocketConnection.class);
|
||||
private final String id;
|
||||
private final ByteBufferPool bufferPool;
|
||||
private final Executor executor;
|
||||
private WebSocketPolicy policy = WebSocketPolicy.newServerPolicy();
|
||||
private IncomingFrames incoming;
|
||||
private IOState ioState = new IOState();
|
||||
|
||||
public LocalWebSocketConnection()
|
||||
{
|
||||
this("anon");
|
||||
}
|
||||
|
||||
public LocalWebSocketConnection(String id)
|
||||
{
|
||||
this.id = id;
|
||||
this.bufferPool = new MappedByteBufferPool();
|
||||
this.executor = new ExecutorThreadPool();
|
||||
this.ioState.addListener(this);
|
||||
}
|
||||
|
||||
public LocalWebSocketConnection(TestName testname)
|
||||
{
|
||||
this(testname.getMethodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor getExecutor()
|
||||
{
|
||||
return executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
close(StatusCode.NORMAL,null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(int statusCode, String reason)
|
||||
{
|
||||
LOG.debug("close({}, {})",statusCode,reason);
|
||||
CloseInfo close = new CloseInfo(statusCode,reason);
|
||||
ioState.onCloseLocal(close);
|
||||
}
|
||||
|
||||
public void connect()
|
||||
{
|
||||
LOG.debug("connect()");
|
||||
ioState.onConnected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect()
|
||||
{
|
||||
LOG.debug("disconnect()");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBufferPool getBufferPool()
|
||||
{
|
||||
return this.bufferPool;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getIdleTimeout()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public IncomingFrames getIncoming()
|
||||
{
|
||||
return incoming;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IOState getIOState()
|
||||
{
|
||||
return ioState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getLocalAddress()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMaxIdleTimeout()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebSocketPolicy getPolicy()
|
||||
{
|
||||
return policy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getRemoteAddress()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebSocketSession getSession()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incomingError(Throwable e)
|
||||
{
|
||||
incoming.incomingError(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incomingFrame(Frame frame)
|
||||
{
|
||||
incoming.incomingFrame(frame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen()
|
||||
{
|
||||
return getIOState().isOpen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReading()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionStateChange(ConnectionState state)
|
||||
{
|
||||
LOG.debug("Connection State Change: {}",state);
|
||||
switch (state)
|
||||
{
|
||||
case CLOSED:
|
||||
this.disconnect();
|
||||
break;
|
||||
case CLOSING:
|
||||
if (ioState.wasRemoteCloseInitiated())
|
||||
{
|
||||
// send response close frame
|
||||
CloseInfo close = ioState.getCloseInfo();
|
||||
LOG.debug("write close frame: {}",close);
|
||||
ioState.onCloseLocal(close);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void open()
|
||||
{
|
||||
LOG.debug("open()");
|
||||
ioState.onOpened();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void outgoingFrame(Frame frame, WriteCallback callback)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resume()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxIdleTimeout(long ms)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNextIncomingFrames(IncomingFrames incoming)
|
||||
{
|
||||
this.incoming = incoming;
|
||||
}
|
||||
|
||||
public void setPolicy(WebSocketPolicy policy)
|
||||
{
|
||||
this.policy = policy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSession(WebSocketSession session)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuspendToken suspend()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s[%s]",LocalWebSocketConnection.class.getSimpleName(),id);
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux.helper;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.eclipse.jetty.websocket.common.SessionListener;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriver;
|
||||
import org.junit.rules.TestName;
|
||||
|
||||
public class LocalWebSocketSession extends WebSocketSession
|
||||
{
|
||||
private String id;
|
||||
private OutgoingFramesCapture outgoingCapture;
|
||||
|
||||
public LocalWebSocketSession(TestName testname, EventDriver driver)
|
||||
{
|
||||
super(URI.create("ws://localhost/LocalWebSocketSesssion/" + testname.getMethodName()),driver,new LocalWebSocketConnection(testname), new SessionListener[0]);
|
||||
this.id = testname.getMethodName();
|
||||
outgoingCapture = new OutgoingFramesCapture();
|
||||
setOutgoingHandler(outgoingCapture);
|
||||
}
|
||||
|
||||
public OutgoingFramesCapture getOutgoingCapture()
|
||||
{
|
||||
return outgoingCapture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s[%s]",LocalWebSocketSession.class.getSimpleName(),id);
|
||||
}
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux.helper;
|
||||
|
||||
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.websocket.api.WriteCallback;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.api.extensions.OutgoingFrames;
|
||||
import org.eclipse.jetty.websocket.common.OpCode;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.junit.Assert;
|
||||
|
||||
public class OutgoingFramesCapture implements OutgoingFrames
|
||||
{
|
||||
private LinkedList<WebSocketFrame> frames = new LinkedList<>();
|
||||
|
||||
public void assertFrameCount(int expectedCount)
|
||||
{
|
||||
Assert.assertThat("Captured frame count",frames.size(),is(expectedCount));
|
||||
}
|
||||
|
||||
public void assertHasFrame(byte op)
|
||||
{
|
||||
Assert.assertThat(OpCode.name(op),getFrameCount(op),greaterThanOrEqualTo(1));
|
||||
}
|
||||
|
||||
public void assertHasFrame(byte op, int expectedCount)
|
||||
{
|
||||
Assert.assertThat(OpCode.name(op),getFrameCount(op),is(expectedCount));
|
||||
}
|
||||
|
||||
public void assertHasNoFrames()
|
||||
{
|
||||
Assert.assertThat("Has no frames",frames.size(),is(0));
|
||||
}
|
||||
|
||||
public void dump()
|
||||
{
|
||||
System.out.printf("Captured %d outgoing writes%n",frames.size());
|
||||
for (int i = 0; i < frames.size(); i++)
|
||||
{
|
||||
Frame frame = frames.get(i);
|
||||
System.out.printf("[%3d] %s%n",i,frame);
|
||||
System.out.printf(" %s%n",BufferUtil.toDetailString(frame.getPayload()));
|
||||
}
|
||||
}
|
||||
|
||||
public int getFrameCount(byte op)
|
||||
{
|
||||
int count = 0;
|
||||
for (WebSocketFrame frame : frames)
|
||||
{
|
||||
if (frame.getOpCode() == op)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public LinkedList<WebSocketFrame> getFrames()
|
||||
{
|
||||
return frames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void outgoingFrame(Frame frame, WriteCallback callback)
|
||||
{
|
||||
WebSocketFrame copy = WebSocketFrame.copy(frame);
|
||||
frames.add(copy);
|
||||
if (callback != null)
|
||||
{
|
||||
callback.writeSuccess();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.mux.helper;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||
import org.eclipse.jetty.util.log.StacklessLogging;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.common.Parser;
|
||||
|
||||
public class UnitParser extends Parser
|
||||
{
|
||||
public UnitParser()
|
||||
{
|
||||
this(WebSocketPolicy.newServerPolicy());
|
||||
}
|
||||
|
||||
public UnitParser(ByteBufferPool bufferPool, WebSocketPolicy policy)
|
||||
{
|
||||
super(policy,bufferPool);
|
||||
}
|
||||
|
||||
public UnitParser(WebSocketPolicy policy)
|
||||
{
|
||||
this(new MappedByteBufferPool(),policy);
|
||||
}
|
||||
|
||||
private void parsePartial(ByteBuffer buf, int numBytes)
|
||||
{
|
||||
int len = Math.min(numBytes,buf.remaining());
|
||||
byte arr[] = new byte[len];
|
||||
buf.get(arr,0,len);
|
||||
this.parse(ByteBuffer.wrap(arr));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a buffer, but do so in a quiet fashion, squelching stacktraces if encountered.
|
||||
* <p>
|
||||
* Use if you know the parse will cause an exception and just don't wnat to make the test console all noisy.
|
||||
*/
|
||||
public void parseQuietly(ByteBuffer buf)
|
||||
{
|
||||
try (StacklessLogging supress = new StacklessLogging(Parser.class))
|
||||
{
|
||||
parse(buf);
|
||||
}
|
||||
catch (Exception ignore)
|
||||
{
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
|
||||
public void parseSlowly(ByteBuffer buf, int segmentSize)
|
||||
{
|
||||
while (buf.remaining() > 0)
|
||||
{
|
||||
parsePartial(buf,segmentSize);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||
org.eclipse.jetty.websocket.LEVEL=WARN
|
||||
# org.eclipse.jetty.websocket.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.websocket.protocol.Parser.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.websocket.protocol.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.websocket.io.payload.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.websocket.core.extensions.compress.LEVEL=DEBUG
|
Loading…
Reference in New Issue