Merge branch 'master' of ssh://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project

This commit is contained in:
Jan Bartel 2012-12-22 15:13:49 +11:00
commit c7b6ed72e8
70 changed files with 2246 additions and 1359 deletions

View File

@ -24,7 +24,6 @@ import java.nio.channels.AsynchronousCloseException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Queue; import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.RejectedExecutionException;
@ -42,6 +41,7 @@ import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.util.BlockingArrayQueue;
import org.eclipse.jetty.util.FuturePromise; import org.eclipse.jetty.util.FuturePromise;
import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.component.ContainerLifeCycle; import org.eclipse.jetty.util.component.ContainerLifeCycle;
@ -72,9 +72,16 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable
this.scheme = scheme; this.scheme = scheme;
this.host = host; this.host = host;
this.address = new InetSocketAddress(host, port); this.address = new InetSocketAddress(host, port);
this.requests = new ArrayBlockingQueue<>(client.getMaxRequestsQueuedPerDestination());
this.idleConnections = new ArrayBlockingQueue<>(client.getMaxConnectionsPerDestination()); int maxRequestsQueued = client.getMaxRequestsQueuedPerDestination();
this.activeConnections = new ArrayBlockingQueue<>(client.getMaxConnectionsPerDestination()); int capacity = Math.min(32, maxRequestsQueued);
this.requests = new BlockingArrayQueue<>(capacity, capacity, maxRequestsQueued);
int maxConnections = client.getMaxConnectionsPerDestination();
capacity = Math.min(8, maxConnections);
this.idleConnections = new BlockingArrayQueue<>(capacity, capacity, maxConnections);
this.activeConnections = new BlockingArrayQueue<>(capacity, capacity, maxConnections);
this.requestNotifier = new RequestNotifier(client); this.requestNotifier = new RequestNotifier(client);
this.responseNotifier = new ResponseNotifier(client); this.responseNotifier = new ResponseNotifier(client);

View File

@ -41,8 +41,10 @@ import org.eclipse.jetty.io.SelectorManager;
import org.eclipse.jetty.io.ssl.SslConnection; import org.eclipse.jetty.io.ssl.SslConnection;
import org.eclipse.jetty.io.ssl.SslConnection.DecryptedEndPoint; import org.eclipse.jetty.io.ssl.SslConnection.DecryptedEndPoint;
import org.eclipse.jetty.spdy.FlowControlStrategy; import org.eclipse.jetty.spdy.FlowControlStrategy;
import org.eclipse.jetty.spdy.api.GoAwayInfo;
import org.eclipse.jetty.spdy.api.Session; import org.eclipse.jetty.spdy.api.Session;
import org.eclipse.jetty.spdy.api.SessionFrameListener; import org.eclipse.jetty.spdy.api.SessionFrameListener;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.FuturePromise; import org.eclipse.jetty.util.FuturePromise;
import org.eclipse.jetty.util.component.ContainerLifeCycle; import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.ssl.SslContextFactory;
@ -265,7 +267,7 @@ public class SPDYClient
private void closeConnections() private void closeConnections()
{ {
for (Session session : sessions) for (Session session : sessions)
session.goAway(); session.goAway(new GoAwayInfo(), new Callback.Adapter());
sessions.clear(); sessions.clear();
} }

View File

@ -29,6 +29,7 @@ import org.eclipse.jetty.io.RuntimeIOException;
import org.eclipse.jetty.spdy.Controller; import org.eclipse.jetty.spdy.Controller;
import org.eclipse.jetty.spdy.ISession; import org.eclipse.jetty.spdy.ISession;
import org.eclipse.jetty.spdy.IdleListener; import org.eclipse.jetty.spdy.IdleListener;
import org.eclipse.jetty.spdy.api.GoAwayInfo;
import org.eclipse.jetty.spdy.parser.Parser; import org.eclipse.jetty.spdy.parser.Parser;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
@ -46,10 +47,10 @@ public class SPDYConnection extends AbstractConnection implements Controller, Id
public SPDYConnection(EndPoint endPoint, ByteBufferPool bufferPool, Parser parser, Executor executor) public SPDYConnection(EndPoint endPoint, ByteBufferPool bufferPool, Parser parser, Executor executor)
{ {
this(endPoint,bufferPool,parser,executor,8192); this(endPoint, bufferPool, parser, executor, 8192);
} }
public SPDYConnection(EndPoint endPoint, ByteBufferPool bufferPool, Parser parser, Executor executor,int bufferSize) public SPDYConnection(EndPoint endPoint, ByteBufferPool bufferPool, Parser parser, Executor executor, int bufferSize)
{ {
// Since SPDY is multiplexed, onFillable() must never block // Since SPDY is multiplexed, onFillable() must never block
// while calling application code. In fact, onFillable() // while calling application code. In fact, onFillable()
@ -60,7 +61,7 @@ public class SPDYConnection extends AbstractConnection implements Controller, Id
this.bufferPool = bufferPool; this.bufferPool = bufferPool;
this.parser = parser; this.parser = parser;
onIdle(true); onIdle(true);
this.bufferSize=bufferSize; this.bufferSize = bufferSize;
} }
@Override @Override
@ -165,7 +166,7 @@ public class SPDYConnection extends AbstractConnection implements Controller, Id
protected void goAway(ISession session) protected void goAway(ISession session)
{ {
if (session != null) if (session != null)
session.goAway(); session.goAway(new GoAwayInfo(), new Callback.Adapter());
} }
private void shutdown(ISession session) private void shutdown(ISession session)

View File

@ -18,6 +18,7 @@
package org.eclipse.jetty.spdy; package org.eclipse.jetty.spdy;
import org.eclipse.jetty.spdy.api.PushInfo;
import org.eclipse.jetty.spdy.api.SynInfo; import org.eclipse.jetty.spdy.api.SynInfo;
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
@ -30,8 +31,8 @@ public class PushSynInfo extends SynInfo
private int associatedStreamId; private int associatedStreamId;
public PushSynInfo(int associatedStreamId, SynInfo synInfo){ public PushSynInfo(int associatedStreamId, PushInfo pushInfo){
super(synInfo.getHeaders(), synInfo.isClose(), synInfo.getPriority()); super(pushInfo.getHeaders(), pushInfo.isClose());
this.associatedStreamId = associatedStreamId; this.associatedStreamId = associatedStreamId;
} }

View File

@ -33,9 +33,10 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@ -44,7 +45,9 @@ import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.spdy.api.ByteBufferDataInfo; import org.eclipse.jetty.spdy.api.ByteBufferDataInfo;
import org.eclipse.jetty.spdy.api.DataInfo; import org.eclipse.jetty.spdy.api.DataInfo;
import org.eclipse.jetty.spdy.api.GoAwayInfo; import org.eclipse.jetty.spdy.api.GoAwayInfo;
import org.eclipse.jetty.spdy.api.GoAwayReceivedInfo;
import org.eclipse.jetty.spdy.api.PingInfo; import org.eclipse.jetty.spdy.api.PingInfo;
import org.eclipse.jetty.spdy.api.PingResultInfo;
import org.eclipse.jetty.spdy.api.RstInfo; import org.eclipse.jetty.spdy.api.RstInfo;
import org.eclipse.jetty.spdy.api.SPDYException; import org.eclipse.jetty.spdy.api.SPDYException;
import org.eclipse.jetty.spdy.api.Session; import org.eclipse.jetty.spdy.api.Session;
@ -148,15 +151,18 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
} }
@Override @Override
public Future<Stream> syn(SynInfo synInfo, StreamFrameListener listener) public Stream syn(SynInfo synInfo, StreamFrameListener listener) throws ExecutionException, InterruptedException, TimeoutException
{ {
FuturePromise<Stream> result = new FuturePromise<>(); FuturePromise<Stream> result = new FuturePromise<>();
syn(synInfo,listener,0,TimeUnit.MILLISECONDS,result); syn(synInfo, listener, result);
return result; if (synInfo.getTimeout() > 0)
return result.get(synInfo.getTimeout(), synInfo.getUnit());
else
return result.get();
} }
@Override @Override
public void syn(SynInfo synInfo, StreamFrameListener listener, long timeout, TimeUnit unit, Promise<Stream> promise) public void syn(SynInfo synInfo, StreamFrameListener listener, Promise<Stream> promise)
{ {
// Synchronization is necessary. // Synchronization is necessary.
// SPEC v3, 2.3.1 requires that the stream creation be monotonically crescent // SPEC v3, 2.3.1 requires that the stream creation be monotonically crescent
@ -174,21 +180,24 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
// TODO: for SPDYv3 we need to support the "slot" argument // TODO: for SPDYv3 we need to support the "slot" argument
SynStreamFrame synStream = new SynStreamFrame(version, synInfo.getFlags(), streamId, associatedStreamId, synInfo.getPriority(), (short)0, synInfo.getHeaders()); SynStreamFrame synStream = new SynStreamFrame(version, synInfo.getFlags(), streamId, associatedStreamId, synInfo.getPriority(), (short)0, synInfo.getHeaders());
IStream stream = createStream(synStream, listener, true, promise); IStream stream = createStream(synStream, listener, true, promise);
generateAndEnqueueControlFrame(stream, synStream, timeout, unit, stream); generateAndEnqueueControlFrame(stream, synStream, synInfo.getTimeout(), synInfo.getUnit(), stream);
} }
flush(); flush();
} }
@Override @Override
public Future<Void> rst(RstInfo rstInfo) public void rst(RstInfo rstInfo) throws InterruptedException, ExecutionException, TimeoutException
{ {
FutureCallback result = new FutureCallback(); FutureCallback result = new FutureCallback();
rst(rstInfo,0,TimeUnit.MILLISECONDS,result); rst(rstInfo, result);
return result; if (rstInfo.getTimeout() > 0)
result.get(rstInfo.getTimeout(), rstInfo.getUnit());
else
result.get();
} }
@Override @Override
public void rst(RstInfo rstInfo, long timeout, TimeUnit unit, Callback callback) public void rst(RstInfo rstInfo, Callback callback)
{ {
// SPEC v3, 2.2.2 // SPEC v3, 2.2.2
if (goAwaySent.get()) if (goAwaySent.get())
@ -199,8 +208,8 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
{ {
int streamId = rstInfo.getStreamId(); int streamId = rstInfo.getStreamId();
IStream stream = streams.get(streamId); IStream stream = streams.get(streamId);
RstStreamFrame frame = new RstStreamFrame(version,streamId,rstInfo.getStreamStatus().getCode(version)); RstStreamFrame frame = new RstStreamFrame(version, streamId, rstInfo.getStreamStatus().getCode(version));
control(stream,frame,timeout,unit,callback); control(stream, frame, rstInfo.getTimeout(), rstInfo.getUnit(), callback);
if (stream != null) if (stream != null)
{ {
stream.process(frame); stream.process(frame);
@ -210,64 +219,74 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
} }
@Override @Override
public Future<Void> settings(SettingsInfo settingsInfo) public void settings(SettingsInfo settingsInfo) throws ExecutionException, InterruptedException, TimeoutException
{ {
FutureCallback result = new FutureCallback(); FutureCallback result = new FutureCallback();
settings(settingsInfo, 0, TimeUnit.MILLISECONDS, result); settings(settingsInfo, result);
return result; if (settingsInfo.getTimeout() > 0)
result.get(settingsInfo.getTimeout(), settingsInfo.getUnit());
else
result.get();
} }
@Override @Override
public void settings(SettingsInfo settingsInfo, long timeout, TimeUnit unit, Callback callback) public void settings(SettingsInfo settingsInfo, Callback callback)
{ {
SettingsFrame frame = new SettingsFrame(version,settingsInfo.getFlags(),settingsInfo.getSettings()); SettingsFrame frame = new SettingsFrame(version, settingsInfo.getFlags(), settingsInfo.getSettings());
control(null, frame, timeout, unit, callback); control(null, frame, settingsInfo.getTimeout(), settingsInfo.getUnit(), callback);
} }
@Override @Override
public Future<PingInfo> ping() public PingResultInfo ping(PingInfo pingInfo) throws ExecutionException, InterruptedException, TimeoutException
{ {
FuturePromise<PingInfo> result = new FuturePromise<>(); //TODO: find a better name for PingResultInfo
ping(0, TimeUnit.MILLISECONDS, result); FuturePromise<PingResultInfo> result = new FuturePromise<>();
return result; ping(pingInfo, result);
if (pingInfo.getTimeout() > 0)
return result.get(pingInfo.getTimeout(), pingInfo.getUnit());
else
return result.get();
} }
@Override @Override
public void ping(long timeout, TimeUnit unit, Promise<PingInfo> promise) public void ping(PingInfo pingInfo, Promise<PingResultInfo> promise)
{ {
int pingId = pingIds.getAndAdd(2); int pingId = pingIds.getAndAdd(2);
PingInfoCallback pingInfo = new PingInfoCallback(pingId, promise); PingInfoCallback pingInfoCallback = new PingInfoCallback(pingId, promise);
PingFrame frame = new PingFrame(version, pingId); PingFrame frame = new PingFrame(version, pingId);
control(null, frame, timeout, unit, pingInfo); control(null, frame, pingInfo.getTimeout(), pingInfo.getUnit(), pingInfoCallback);
} }
@Override @Override
public Future<Void> goAway() public void goAway(GoAwayInfo goAwayInfo) throws ExecutionException, InterruptedException, TimeoutException
{ {
return goAway(SessionStatus.OK); goAway(goAwayInfo, SessionStatus.OK);
} }
private Future<Void> goAway(SessionStatus sessionStatus) private void goAway(GoAwayInfo goAwayInfo, SessionStatus sessionStatus) throws ExecutionException, InterruptedException, TimeoutException
{ {
FutureCallback result = new FutureCallback(); FutureCallback result = new FutureCallback();
goAway(sessionStatus, 0, TimeUnit.MILLISECONDS, result); goAway(sessionStatus, goAwayInfo.getTimeout(), goAwayInfo.getUnit(), result);
return result; if (goAwayInfo.getTimeout() > 0)
result.get(goAwayInfo.getTimeout(), goAwayInfo.getUnit());
else
result.get();
} }
@Override @Override
public void goAway(long timeout, TimeUnit unit, Callback callback) public void goAway(GoAwayInfo goAwayInfo, Callback callback)
{ {
goAway(SessionStatus.OK, timeout, unit, callback); goAway(SessionStatus.OK, goAwayInfo.getTimeout(), goAwayInfo.getUnit(), callback);
} }
private void goAway(SessionStatus sessionStatus, long timeout, TimeUnit unit, Callback callback) private void goAway(SessionStatus sessionStatus, long timeout, TimeUnit unit, Callback callback)
{ {
if (goAwaySent.compareAndSet(false,true)) if (goAwaySent.compareAndSet(false, true))
{ {
if (!goAwayReceived.get()) if (!goAwayReceived.get())
{ {
GoAwayFrame frame = new GoAwayFrame(version,lastStreamId.get(),sessionStatus.getCode()); GoAwayFrame frame = new GoAwayFrame(version, lastStreamId.get(), sessionStatus.getCode());
control(null,frame,timeout,unit,callback); control(null, frame, timeout, unit, callback);
return; return;
} }
} }
@ -416,7 +435,7 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
{ {
RstInfo rstInfo = new RstInfo(streamId, StreamStatus.INVALID_STREAM); RstInfo rstInfo = new RstInfo(streamId, StreamStatus.INVALID_STREAM);
LOG.debug("Unknown stream {}", rstInfo); LOG.debug("Unknown stream {}", rstInfo);
rst(rstInfo); rst(rstInfo, new Callback.Adapter());
} }
else else
{ {
@ -437,7 +456,7 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
private void processData(final IStream stream, DataFrame frame, ByteBuffer data) private void processData(final IStream stream, DataFrame frame, ByteBuffer data)
{ {
ByteBufferDataInfo dataInfo = new ByteBufferDataInfo(data, frame.isClose(), frame.isCompress()) ByteBufferDataInfo dataInfo = new ByteBufferDataInfo(data, frame.isClose())
{ {
@Override @Override
public void consume(int delta) public void consume(int delta)
@ -456,15 +475,15 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
public void onStreamException(StreamException x) public void onStreamException(StreamException x)
{ {
notifyOnException(listener, x); notifyOnException(listener, x);
rst(new RstInfo(x.getStreamId(),x.getStreamStatus())); rst(new RstInfo(x.getStreamId(), x.getStreamStatus()), new Callback.Adapter());
} }
@Override @Override
public void onSessionException(SessionException x) public void onSessionException(SessionException x)
{ {
Throwable cause = x.getCause(); Throwable cause = x.getCause();
notifyOnException(listener,cause == null?x:cause); notifyOnException(listener, cause == null ? x : cause);
goAway(x.getSessionStatus()); goAway(x.getSessionStatus(), 0, TimeUnit.SECONDS, new Callback.Adapter());
} }
private void onSyn(SynStreamFrame frame) private void onSyn(SynStreamFrame frame)
@ -479,8 +498,8 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
stream.process(frame); stream.process(frame);
// Update the last stream id before calling the application (which may send a GO_AWAY) // Update the last stream id before calling the application (which may send a GO_AWAY)
updateLastStreamId(stream); updateLastStreamId(stream);
SynInfo synInfo = new SynInfo(frame.getHeaders(),frame.isClose(),frame.getPriority()); SynInfo synInfo = new SynInfo(frame.getHeaders(), frame.isClose(), frame.getPriority());
StreamFrameListener streamListener = notifyOnSyn(listener,stream,synInfo); StreamFrameListener streamListener = notifyOnSyn(listener, stream, synInfo);
stream.setStreamFrameListener(streamListener); stream.setStreamFrameListener(streamListener);
flush(); flush();
// The onSyn() listener may have sent a frame that closed the stream // The onSyn() listener may have sent a frame that closed the stream
@ -512,7 +531,14 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
throw new IllegalStateException("Duplicate stream id " + streamId); throw new IllegalStateException("Duplicate stream id " + streamId);
RstInfo rstInfo = new RstInfo(streamId, StreamStatus.PROTOCOL_ERROR); RstInfo rstInfo = new RstInfo(streamId, StreamStatus.PROTOCOL_ERROR);
LOG.debug("Duplicate stream, {}", rstInfo); LOG.debug("Duplicate stream, {}", rstInfo);
try
{
rst(rstInfo); rst(rstInfo);
}
catch (InterruptedException | ExecutionException | TimeoutException e)
{
e.printStackTrace(); // TODO: really catch???
}
return null; return null;
} }
else else
@ -589,13 +615,13 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
IStream stream = streams.get(streamId); IStream stream = streams.get(streamId);
if (stream == null) if (stream == null)
{ {
RstInfo rstInfo = new RstInfo(streamId,StreamStatus.INVALID_STREAM); RstInfo rstInfo = new RstInfo(streamId, StreamStatus.INVALID_STREAM);
LOG.debug("Unknown stream {}",rstInfo); LOG.debug("Unknown stream {}", rstInfo);
rst(rstInfo); rst(rstInfo, new Callback.Adapter());
} }
else else
{ {
processReply(stream,frame); processReply(stream, frame);
} }
} }
@ -613,7 +639,7 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
if (stream != null) if (stream != null)
stream.process(frame); stream.process(frame);
RstInfo rstInfo = new RstInfo(frame.getStreamId(),StreamStatus.from(frame.getVersion(),frame.getStatusCode())); RstInfo rstInfo = new RstInfo(frame.getStreamId(), StreamStatus.from(frame.getVersion(), frame.getStatusCode()));
notifyOnRst(listener, rstInfo); notifyOnRst(listener, rstInfo);
flush(); flush();
@ -640,8 +666,8 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
int pingId = frame.getPingId(); int pingId = frame.getPingId();
if (pingId % 2 == pingIds.get() % 2) if (pingId % 2 == pingIds.get() % 2)
{ {
PingInfo pingInfo = new PingInfo(frame.getPingId()); PingResultInfo pingResultInfo = new PingResultInfo(frame.getPingId());
notifyOnPing(listener, pingInfo); notifyOnPing(listener, pingResultInfo);
flush(); flush();
} }
else else
@ -654,8 +680,9 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
{ {
if (goAwayReceived.compareAndSet(false, true)) if (goAwayReceived.compareAndSet(false, true))
{ {
GoAwayInfo goAwayInfo = new GoAwayInfo(frame.getLastStreamId(),SessionStatus.from(frame.getStatusCode())); //TODO: Find a better name for GoAwayReceivedInfo
notifyOnGoAway(listener,goAwayInfo); GoAwayReceivedInfo goAwayReceivedInfo = new GoAwayReceivedInfo(frame.getLastStreamId(), SessionStatus.from(frame.getStatusCode()));
notifyOnGoAway(listener, goAwayReceivedInfo);
flush(); flush();
// SPDY does not require to send back a response to a GO_AWAY. // SPDY does not require to send back a response to a GO_AWAY.
// We notified the application of the last good stream id and // We notified the application of the last good stream id and
@ -669,13 +696,13 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
IStream stream = streams.get(streamId); IStream stream = streams.get(streamId);
if (stream == null) if (stream == null)
{ {
RstInfo rstInfo = new RstInfo(streamId,StreamStatus.INVALID_STREAM); RstInfo rstInfo = new RstInfo(streamId, StreamStatus.INVALID_STREAM);
LOG.debug("Unknown stream, {}",rstInfo); LOG.debug("Unknown stream, {}", rstInfo);
rst(rstInfo); rst(rstInfo, new Callback.Adapter());
} }
else else
{ {
processHeaders(stream,frame); processHeaders(stream, frame);
} }
} }
@ -713,7 +740,7 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
{ {
if (listener != null) if (listener != null)
{ {
LOG.debug("Invoking callback with {} on listener {}",x,listener); LOG.debug("Invoking callback with {} on listener {}", x, listener);
listener.onException(x); listener.onException(x);
} }
} }
@ -734,12 +761,12 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
{ {
if (listener == null) if (listener == null)
return null; return null;
LOG.debug("Invoking callback with {} on listener {}",synInfo,listener); LOG.debug("Invoking callback with {} on listener {}", synInfo, listener);
return listener.onSyn(stream,synInfo); return listener.onSyn(stream, synInfo);
} }
catch (Exception x) catch (Exception x)
{ {
LOG.info("Exception while notifying listener " + listener,x); LOG.info("Exception while notifying listener " + listener, x);
return null; return null;
} }
catch (Error x) catch (Error x)
@ -755,8 +782,8 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
{ {
if (listener != null) if (listener != null)
{ {
LOG.debug("Invoking callback with {} on listener {}",rstInfo,listener); LOG.debug("Invoking callback with {} on listener {}", rstInfo, listener);
listener.onRst(this,rstInfo); listener.onRst(this, rstInfo);
} }
} }
catch (Exception x) catch (Exception x)
@ -776,7 +803,7 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
{ {
if (listener != null) if (listener != null)
{ {
LOG.debug("Invoking callback with {} on listener {}",settingsInfo,listener); LOG.debug("Invoking callback with {} on listener {}", settingsInfo, listener);
listener.onSettings(this, settingsInfo); listener.onSettings(this, settingsInfo);
} }
} }
@ -791,14 +818,14 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
} }
} }
private void notifyOnPing(SessionFrameListener listener, PingInfo pingInfo) private void notifyOnPing(SessionFrameListener listener, PingResultInfo pingResultInfo)
{ {
try try
{ {
if (listener != null) if (listener != null)
{ {
LOG.debug("Invoking callback with {} on listener {}",pingInfo,listener); LOG.debug("Invoking callback with {} on listener {}", pingResultInfo, listener);
listener.onPing(this, pingInfo); listener.onPing(this, pingResultInfo);
} }
} }
catch (Exception x) catch (Exception x)
@ -812,14 +839,14 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
} }
} }
private void notifyOnGoAway(SessionFrameListener listener, GoAwayInfo goAwayInfo) private void notifyOnGoAway(SessionFrameListener listener, GoAwayReceivedInfo goAwayReceivedInfo)
{ {
try try
{ {
if (listener != null) if (listener != null)
{ {
LOG.debug("Invoking callback with {} on listener {}",goAwayInfo,listener); LOG.debug("Invoking callback with {} on listener {}", goAwayReceivedInfo, listener);
listener.onGoAway(this, goAwayInfo); listener.onGoAway(this, goAwayReceivedInfo);
} }
} }
catch (Exception x) catch (Exception x)
@ -879,10 +906,10 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
@Override @Override
public void data(IStream stream, DataInfo dataInfo, long timeout, TimeUnit unit, Callback callback) public void data(IStream stream, DataInfo dataInfo, long timeout, TimeUnit unit, Callback callback)
{ {
LOG.debug("Queuing {} on {}",dataInfo,stream); LOG.debug("Queuing {} on {}", dataInfo, stream);
DataFrameBytes frameBytes = new DataFrameBytes(stream,callback,dataInfo); DataFrameBytes frameBytes = new DataFrameBytes(stream, callback, dataInfo);
if (timeout > 0) if (timeout > 0)
frameBytes.task = scheduler.schedule(frameBytes,timeout,unit); frameBytes.task = scheduler.schedule(frameBytes, timeout, unit);
append(frameBytes); append(frameBytes);
flush(); flush();
} }
@ -937,14 +964,14 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
if (stream != null) if (stream != null)
stalledStreams.add(stream); stalledStreams.add(stream);
LOG.debug("Flush stalled for {}, {} frame(s) in queue",frameBytes,queue.size()); LOG.debug("Flush stalled for {}, {} frame(s) in queue", frameBytes, queue.size());
} }
if (buffer == null) if (buffer == null)
return; return;
flushing = true; flushing = true;
LOG.debug("Flushing {}, {} frame(s) in queue",frameBytes,queue.size()); LOG.debug("Flushing {}, {} frame(s) in queue", frameBytes, queue.size());
} }
write(buffer, frameBytes); write(buffer, frameBytes);
} }
@ -996,7 +1023,7 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
break; break;
++index; ++index;
} }
queue.add(index,frameBytes); queue.add(index, frameBytes);
} }
} }
@ -1008,8 +1035,8 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
{ {
if (controller != null) if (controller != null)
{ {
LOG.debug("Writing {} frame bytes of {}",buffer.remaining()); LOG.debug("Writing {} frame bytes of {}", buffer.remaining(), buffer.limit());
controller.write(buffer,callback); controller.write(buffer, callback);
} }
} }
@ -1053,7 +1080,8 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
@Override @Override
public String toString() public String toString()
{ {
return String.format("%s@%x{v%d,queuSize=%d,windowSize=%d,streams=%d}", getClass().getSimpleName(), hashCode(), version, queue.size(), getWindowSize(), streams.size()); return String.format("%s@%x{v%d,queueSize=%d,windowSize=%d,streams=%d}", getClass().getSimpleName(),
hashCode(), version, queue.size(), getWindowSize(), streams.size());
} }
@Override @Override
@ -1065,8 +1093,8 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
@Override @Override
public void dump(Appendable out, String indent) throws IOException public void dump(Appendable out, String indent) throws IOException
{ {
ContainerLifeCycle.dumpObject(out,this); ContainerLifeCycle.dumpObject(out, this);
ContainerLifeCycle.dump(out,indent,Collections.singletonList(controller),streams.values()); ContainerLifeCycle.dump(out, indent, Collections.singletonList(controller), streams.values());
} }
private class SessionInvoker extends ForkInvoker<Callback> private class SessionInvoker extends ForkInvoker<Callback>
@ -1177,7 +1205,7 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
synchronized (queue) synchronized (queue)
{ {
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("Completed write of {}, {} frame(s) in queue",this,queue.size()); LOG.debug("Completed write of {}, {} frame(s) in queue", this, queue.size());
flushing = false; flushing = false;
} }
complete(); complete();
@ -1194,8 +1222,8 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
failure = x; failure = x;
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
{ {
String logMessage = String.format("Failed write of %s, failing all %d frame(s) in queue",this,queue.size()); String logMessage = String.format("Failed write of %s, failing all %d frame(s) in queue", this, queue.size());
LOG.debug(logMessage,x); LOG.debug(logMessage, x);
} }
frameBytesToFail.addAll(queue); frameBytesToFail.addAll(queue);
queue.clear(); queue.clear();
@ -1214,7 +1242,7 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
private ControlFrameBytes(IStream stream, Callback callback, ControlFrame frame, ByteBuffer buffer) private ControlFrameBytes(IStream stream, Callback callback, ControlFrame frame, ByteBuffer buffer)
{ {
super(stream,callback); super(stream, callback);
this.frame = frame; this.frame = frame;
this.buffer = buffer; this.buffer = buffer;
} }
@ -1276,7 +1304,7 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
if (size > windowSize) if (size > windowSize)
size = windowSize; size = windowSize;
buffer = generator.data(stream.getId(),size,dataInfo); buffer = generator.data(stream.getId(), size, dataInfo);
return buffer; return buffer;
} }
catch (Throwable x) catch (Throwable x)
@ -1303,7 +1331,7 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
else else
{ {
super.complete(); super.complete();
stream.updateCloseState(dataInfo.isClose(),true); stream.updateCloseState(dataInfo.isClose(), true);
if (stream.isClosed()) if (stream.isClosed())
removeStream(stream); removeStream(stream);
} }
@ -1337,14 +1365,14 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
} }
} }
private static class PingInfoCallback extends PingInfo implements Callback private static class PingInfoCallback extends PingResultInfo implements Callback
{ {
private final Promise<PingInfo> promise; private final Promise<PingResultInfo> promise;
public PingInfoCallback(int pingId, Promise<PingInfo> promise) public PingInfoCallback(int pingId, Promise<PingResultInfo> promise)
{ {
super(pingId); super(pingId);
this.promise=promise; this.promise = promise;
} }
@Override @Override

View File

@ -22,18 +22,18 @@ import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.jetty.spdy.api.DataInfo; import org.eclipse.jetty.spdy.api.DataInfo;
import org.eclipse.jetty.spdy.api.HeadersInfo; import org.eclipse.jetty.spdy.api.HeadersInfo;
import org.eclipse.jetty.spdy.api.PushInfo;
import org.eclipse.jetty.spdy.api.ReplyInfo; import org.eclipse.jetty.spdy.api.ReplyInfo;
import org.eclipse.jetty.spdy.api.RstInfo; import org.eclipse.jetty.spdy.api.RstInfo;
import org.eclipse.jetty.spdy.api.Stream; import org.eclipse.jetty.spdy.api.Stream;
import org.eclipse.jetty.spdy.api.StreamFrameListener; import org.eclipse.jetty.spdy.api.StreamFrameListener;
import org.eclipse.jetty.spdy.api.StreamStatus; import org.eclipse.jetty.spdy.api.StreamStatus;
import org.eclipse.jetty.spdy.api.SynInfo;
import org.eclipse.jetty.spdy.frames.ControlFrame; import org.eclipse.jetty.spdy.frames.ControlFrame;
import org.eclipse.jetty.spdy.frames.HeadersFrame; import org.eclipse.jetty.spdy.frames.HeadersFrame;
import org.eclipse.jetty.spdy.frames.SynReplyFrame; import org.eclipse.jetty.spdy.frames.SynReplyFrame;
@ -133,7 +133,7 @@ public class StandardStream implements IStream
@Override @Override
public void setAttribute(String key, Object value) public void setAttribute(String key, Object value)
{ {
attributes.put(key,value); attributes.put(key, value);
} }
@Override @Override
@ -156,7 +156,7 @@ public class StandardStream implements IStream
@Override @Override
public void updateCloseState(boolean close, boolean local) public void updateCloseState(boolean close, boolean local)
{ {
LOG.debug("{} close={} local={}",this,close,local); LOG.debug("{} close={} local={}", this, close, local);
if (close) if (close)
{ {
switch (closeState) switch (closeState)
@ -184,7 +184,7 @@ public class StandardStream implements IStream
} }
default: default:
{ {
LOG.warn("Already CLOSED! {} local={}",this,local); LOG.warn("Already CLOSED! {} local={}", this, local);
} }
} }
} }
@ -243,8 +243,8 @@ public class StandardStream implements IStream
if (!canReceive()) if (!canReceive())
{ {
LOG.debug("Protocol error receiving {}, resetting" + dataInfo); LOG.debug("Protocol error receiving {}, resetting", dataInfo);
session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR)); session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR), new Adapter());
return; return;
} }
@ -335,15 +335,18 @@ public class StandardStream implements IStream
} }
@Override @Override
public Future<Stream> syn(SynInfo synInfo) public Stream push(PushInfo pushInfo) throws InterruptedException, ExecutionException, TimeoutException
{ {
FuturePromise<Stream> result = new FuturePromise<>(); FuturePromise<Stream> result = new FuturePromise<>();
syn(synInfo,0,TimeUnit.MILLISECONDS,result); push(pushInfo, result);
return result; if (pushInfo.getTimeout() > 0)
return result.get(pushInfo.getTimeout(), pushInfo.getUnit());
else
return result.get();
} }
@Override @Override
public void syn(SynInfo synInfo, long timeout, TimeUnit unit, Promise<Stream> promise) public void push(PushInfo pushInfo, Promise<Stream> promise)
{ {
if (isClosed() || isReset()) if (isClosed() || isReset())
{ {
@ -351,81 +354,90 @@ public class StandardStream implements IStream
"Stream: " + this + " already closed or reset!")); "Stream: " + this + " already closed or reset!"));
return; return;
} }
PushSynInfo pushSynInfo = new PushSynInfo(getId(), synInfo); PushSynInfo pushSynInfo = new PushSynInfo(getId(), pushInfo);
session.syn(pushSynInfo, null, timeout, unit, promise); session.syn(pushSynInfo, null, promise);
} }
@Override @Override
public Future<Void> reply(ReplyInfo replyInfo) public void reply(ReplyInfo replyInfo) throws InterruptedException, ExecutionException, TimeoutException
{ {
FutureCallback result = new FutureCallback(); FutureCallback result = new FutureCallback();
reply(replyInfo, 0, TimeUnit.MILLISECONDS, result); reply(replyInfo, result);
return result; if (replyInfo.getTimeout() > 0)
result.get(replyInfo.getTimeout(), replyInfo.getUnit());
else
result.get();
} }
@Override @Override
public void reply(ReplyInfo replyInfo, long timeout, TimeUnit unit, Callback callback) public void reply(ReplyInfo replyInfo, Callback callback)
{ {
if (isUnidirectional()) if (isUnidirectional())
throw new IllegalStateException("Protocol violation: cannot send SYN_REPLY frames in unidirectional streams"); throw new IllegalStateException("Protocol violation: cannot send SYN_REPLY frames in unidirectional streams");
openState = OpenState.REPLY_SENT; openState = OpenState.REPLY_SENT;
updateCloseState(replyInfo.isClose(), true); updateCloseState(replyInfo.isClose(), true);
SynReplyFrame frame = new SynReplyFrame(session.getVersion(), replyInfo.getFlags(), getId(), replyInfo.getHeaders()); SynReplyFrame frame = new SynReplyFrame(session.getVersion(), replyInfo.getFlags(), getId(), replyInfo.getHeaders());
session.control(this, frame, timeout, unit, callback); session.control(this, frame, replyInfo.getTimeout(), replyInfo.getUnit(), callback);
} }
@Override @Override
public Future<Void> data(DataInfo dataInfo) public void data(DataInfo dataInfo) throws InterruptedException, ExecutionException, TimeoutException
{ {
FutureCallback result = new FutureCallback(); FutureCallback result = new FutureCallback();
data(dataInfo, 0, TimeUnit.MILLISECONDS, result); data(dataInfo, result);
return result; if (dataInfo.getTimeout() > 0)
result.get(dataInfo.getTimeout(), dataInfo.getUnit());
else
result.get();
} }
@Override @Override
public void data(DataInfo dataInfo, long timeout, TimeUnit unit, Callback callback) public void data(DataInfo dataInfo, Callback callback)
{ {
if (!canSend()) if (!canSend())
{ {
session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR)); session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR), new Adapter());
throw new IllegalStateException("Protocol violation: cannot send a DATA frame before a SYN_REPLY frame"); throw new IllegalStateException("Protocol violation: cannot send a DATA frame before a SYN_REPLY frame");
} }
if (isLocallyClosed()) if (isLocallyClosed())
{ {
session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR)); session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR), new Adapter());
throw new IllegalStateException("Protocol violation: cannot send a DATA frame on a closed stream"); throw new IllegalStateException("Protocol violation: cannot send a DATA frame on a closed stream");
} }
// Cannot update the close state here, because the data that we send may // Cannot update the close state here, because the data that we send may
// be flow controlled, so we need the stream to update the window size. // be flow controlled, so we need the stream to update the window size.
session.data(this, dataInfo, timeout, unit, callback); session.data(this, dataInfo, dataInfo.getTimeout(), dataInfo.getUnit(), callback);
} }
@Override @Override
public Future<Void> headers(HeadersInfo headersInfo) public void headers(HeadersInfo headersInfo) throws InterruptedException, ExecutionException, TimeoutException
{ {
FutureCallback result = new FutureCallback(); FutureCallback result = new FutureCallback();
headers(headersInfo, 0, TimeUnit.MILLISECONDS, result); headers(headersInfo, result);
return result; if (headersInfo.getTimeout() > 0)
result.get(headersInfo.getTimeout(), headersInfo.getUnit());
else
result.get();
} }
@Override @Override
public void headers(HeadersInfo headersInfo, long timeout, TimeUnit unit, Callback callback) public void headers(HeadersInfo headersInfo, Callback callback)
{ {
if (!canSend()) if (!canSend())
{ {
session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR)); session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR), new Adapter());
throw new IllegalStateException("Protocol violation: cannot send a HEADERS frame before a SYN_REPLY frame"); throw new IllegalStateException("Protocol violation: cannot send a HEADERS frame before a SYN_REPLY frame");
} }
if (isLocallyClosed()) if (isLocallyClosed())
{ {
session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR)); session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR), new Adapter());
throw new IllegalStateException("Protocol violation: cannot send a HEADERS frame on a closed stream"); throw new IllegalStateException("Protocol violation: cannot send a HEADERS frame on a closed stream");
} }
updateCloseState(headersInfo.isClose(), true); updateCloseState(headersInfo.isClose(), true);
HeadersFrame frame = new HeadersFrame(session.getVersion(), headersInfo.getFlags(), getId(), headersInfo.getHeaders()); HeadersFrame frame = new HeadersFrame(session.getVersion(), headersInfo.getFlags(), getId(), headersInfo.getHeaders());
session.control(this, frame, timeout, unit, callback); session.control(this, frame, headersInfo.getTimeout(), headersInfo.getUnit(), callback);
} }
@Override @Override

View File

@ -19,6 +19,7 @@
package org.eclipse.jetty.spdy.api; package org.eclipse.jetty.spdy.api;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.concurrent.TimeUnit;
/** /**
* <p>Specialized {@link DataInfo} for {@link ByteBuffer} content.</p> * <p>Specialized {@link DataInfo} for {@link ByteBuffer} content.</p>
@ -30,12 +31,12 @@ public class ByteBufferDataInfo extends DataInfo
public ByteBufferDataInfo(ByteBuffer buffer, boolean close) public ByteBufferDataInfo(ByteBuffer buffer, boolean close)
{ {
this(buffer, close, false); this(0, TimeUnit.SECONDS, buffer, close);
} }
public ByteBufferDataInfo(ByteBuffer buffer, boolean close, boolean compress) public ByteBufferDataInfo(long timeout, TimeUnit unit, ByteBuffer buffer, boolean close)
{ {
super(close, compress); super(timeout, unit, close);
this.buffer = buffer; this.buffer = buffer;
this.length = buffer.remaining(); this.length = buffer.remaining();
} }

View File

@ -19,6 +19,7 @@
package org.eclipse.jetty.spdy.api; package org.eclipse.jetty.spdy.api;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.concurrent.TimeUnit;
/** /**
* <p>Specialized {@link DataInfo} for byte array content.</p> * <p>Specialized {@link DataInfo} for byte array content.</p>
@ -32,12 +33,17 @@ public class BytesDataInfo extends DataInfo
public BytesDataInfo(byte[] bytes, boolean close) public BytesDataInfo(byte[] bytes, boolean close)
{ {
this(bytes, 0, bytes.length, close); this(0, TimeUnit.SECONDS, bytes, close);
} }
public BytesDataInfo(byte[] bytes, int offset, int length, boolean close) public BytesDataInfo(long timeout, TimeUnit unit, byte[] bytes, boolean close)
{ {
super(close, false); this(timeout, unit, bytes, 0, bytes.length, close);
}
public BytesDataInfo(long timeout, TimeUnit unit, byte[] bytes, int offset, int length, boolean close)
{
super(timeout, unit, close);
this.bytes = bytes; this.bytes = bytes;
this.offset = offset; this.offset = offset;
this.length = length; this.length = length;

View File

@ -20,6 +20,7 @@ package org.eclipse.jetty.spdy.api;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
/** /**
@ -41,7 +42,7 @@ import java.util.concurrent.atomic.AtomicInteger;
* <p>Consuming the data bytes can be done only via {@link #consumeInto(ByteBuffer)} or by a combination * <p>Consuming the data bytes can be done only via {@link #consumeInto(ByteBuffer)} or by a combination
* of {@link #readInto(ByteBuffer)} and {@link #consume(int)} (possibly at different times).</p> * of {@link #readInto(ByteBuffer)} and {@link #consume(int)} (possibly at different times).</p>
*/ */
public abstract class DataInfo public abstract class DataInfo extends Info
{ {
/** /**
* <p>Flag that indicates that this {@link DataInfo} is the last frame in the stream.</p> * <p>Flag that indicates that this {@link DataInfo} is the last frame in the stream.</p>
@ -50,17 +51,9 @@ public abstract class DataInfo
* @see #getFlags() * @see #getFlags()
*/ */
public final static byte FLAG_CLOSE = 1; public final static byte FLAG_CLOSE = 1;
/**
* <p>Flag that indicates that this {@link DataInfo}'s data is compressed.</p>
*
* @see #isCompress()
* @see #getFlags()
*/
public final static byte FLAG_COMPRESS = 2;
private final AtomicInteger consumed = new AtomicInteger(); private final AtomicInteger consumed = new AtomicInteger();
private boolean close; private boolean close;
private boolean compress;
/** /**
* <p>Creates a new {@link DataInfo} with the given close flag and no compression flag.</p> * <p>Creates a new {@link DataInfo} with the given close flag and no compression flag.</p>
@ -73,33 +66,16 @@ public abstract class DataInfo
} }
/** /**
* <p>Creates a new {@link DataInfo} with the given close flag and given compression flag.</p> * <p>Creates a new {@link DataInfo} with the given close flag and no compression flag.</p>
* *
* @param close the close flag * @param timeout
* @param compress the compress flag * @param unit
* @param close the value of the close flag
*/ */
public DataInfo(boolean close, boolean compress) protected DataInfo(long timeout, TimeUnit unit, boolean close)
{ {
setClose(close); super(timeout, unit);
setCompress(compress); this.close = close;
}
/**
* @return the value of the compress flag
* @see #setCompress(boolean)
*/
public boolean isCompress()
{
return compress;
}
/**
* @param compress the value of the compress flag
* @see #isCompress()
*/
public void setCompress(boolean compress)
{
this.compress = compress;
} }
/** /**
@ -123,13 +99,10 @@ public abstract class DataInfo
/** /**
* @return the close and compress flags as integer * @return the close and compress flags as integer
* @see #FLAG_CLOSE * @see #FLAG_CLOSE
* @see #FLAG_COMPRESS
*/ */
public byte getFlags() public byte getFlags()
{ {
byte flags = isClose() ? FLAG_CLOSE : 0; return isClose() ? FLAG_CLOSE : 0;
flags |= isCompress() ? FLAG_COMPRESS : 0;
return flags;
} }
/** /**
@ -275,6 +248,6 @@ public abstract class DataInfo
@Override @Override
public String toString() public String toString()
{ {
return String.format("DATA @%x available=%d consumed=%d close=%b compress=%b", hashCode(), available(), consumed(), isClose(), isCompress()); return String.format("DATA @%x available=%d consumed=%d close=%b", hashCode(), available(), consumed(), isClose());
} }
} }

View File

@ -18,40 +18,21 @@
package org.eclipse.jetty.spdy.api; package org.eclipse.jetty.spdy.api;
import java.util.concurrent.TimeUnit;
/** /**
* <p>A container for GOAWAY frames metadata: the last good stream id and * A GoAwayInfo container. Currently adding nothing to it's base class, but serves to keep the api unchanged in
* the session status.</p> * future versions when we need to pass more info to the methods having a {@link GoAwayInfo} parameter.
*/ */
public class GoAwayInfo public class GoAwayInfo extends Info
{ {
private final int lastStreamId; public GoAwayInfo(long timeout, TimeUnit unit)
private final SessionStatus sessionStatus;
/**
* <p>Creates a new {@link GoAwayInfo} with the given last good stream id and session status</p>
*
* @param lastStreamId the last good stream id
* @param sessionStatus the session status
*/
public GoAwayInfo(int lastStreamId, SessionStatus sessionStatus)
{ {
this.lastStreamId = lastStreamId; super(timeout, unit);
this.sessionStatus = sessionStatus;
} }
/** public GoAwayInfo()
* @return the last good stream id
*/
public int getLastStreamId()
{ {
return lastStreamId; super();
}
/**
* @return the session status
*/
public SessionStatus getSessionStatus()
{
return sessionStatus;
} }
} }

View File

@ -0,0 +1,57 @@
//
// ========================================================================
// Copyright (c) 1995-2012 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.spdy.api;
/**
* <p>A container for GOAWAY frames metadata: the last good stream id and
* the session status.</p>
*/
public class GoAwayReceivedInfo
{
private final int lastStreamId;
private final SessionStatus sessionStatus;
/**
* <p>Creates a new {@link GoAwayReceivedInfo} with the given last good stream id and session status</p>
*
* @param lastStreamId the last good stream id
* @param sessionStatus the session status
*/
public GoAwayReceivedInfo(int lastStreamId, SessionStatus sessionStatus)
{
this.lastStreamId = lastStreamId;
this.sessionStatus = sessionStatus;
}
/**
* @return the last good stream id
*/
public int getLastStreamId()
{
return lastStreamId;
}
/**
* @return the session status
*/
public SessionStatus getSessionStatus()
{
return sessionStatus;
}
}

View File

@ -18,12 +18,14 @@
package org.eclipse.jetty.spdy.api; package org.eclipse.jetty.spdy.api;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.util.Fields;
/** /**
* <p>A container for HEADERS frame metadata and headers.</p> * <p>A container for HEADERS frame metadata and headers.</p>
*/ */
public class HeadersInfo public class HeadersInfo extends Info
{ {
/** /**
* <p>Flag that indicates that this {@link HeadersInfo} is the last frame in the stream.</p> * <p>Flag that indicates that this {@link HeadersInfo} is the last frame in the stream.</p>
@ -45,8 +47,8 @@ public class HeadersInfo
private final Fields headers; private final Fields headers;
/** /**
* <p>Creates a new {@link HeadersInfo} instance with the given headers, * <p>Creates a new {@link HeadersInfo} instance with the given headers, the given close flag and no reset
* the given close flag and no reset compression flag</p> * compression flag</p>
* *
* @param headers the {@link Fields} * @param headers the {@link Fields}
* @param close the value of the close flag * @param close the value of the close flag
@ -57,8 +59,8 @@ public class HeadersInfo
} }
/** /**
* <p>Creates a new {@link HeadersInfo} instance with the given headers, * <p>Creates a new {@link HeadersInfo} instance with the given headers, the given close flag and the given reset
* the given close flag and the given reset compression flag</p> * compression flag</p>
* *
* @param headers the {@link Fields} * @param headers the {@link Fields}
* @param close the value of the close flag * @param close the value of the close flag
@ -71,6 +73,24 @@ public class HeadersInfo
this.resetCompression = resetCompression; this.resetCompression = resetCompression;
} }
/**
* <p>Creates a new {@link HeadersInfo} instance with the given headers, the given close flag and the given reset
* compression flag</p>
*
* @param timeout the operation's timeout
* @param unit the timeout's unit
* @param headers the {@link Fields}
* @param close the value of the close flag
* @param resetCompression the value of the reset compression flag
*/
public HeadersInfo(long timeout, TimeUnit unit, boolean close, boolean resetCompression, Fields headers)
{
super(timeout, unit);
this.close = close;
this.resetCompression = resetCompression;
this.headers = headers;
}
/** /**
* @return the value of the close flag * @return the value of the close flag
*/ */

View File

@ -0,0 +1,52 @@
//
// ========================================================================
// Copyright (c) 1995-2012 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.spdy.api;
import java.util.concurrent.TimeUnit;
/**
* A base class for all *Info classes providing timeout and unit and api to access them
*/
public class Info
{
private final long timeout;
private final TimeUnit unit;
public Info(long timeout, TimeUnit unit)
{
this.timeout = timeout;
this.unit = unit;
}
public Info()
{
timeout = 0;
unit = TimeUnit.SECONDS;
}
public long getTimeout()
{
return timeout;
}
public TimeUnit getUnit()
{
return unit;
}
}

View File

@ -18,27 +18,21 @@
package org.eclipse.jetty.spdy.api; package org.eclipse.jetty.spdy.api;
/** import java.util.concurrent.TimeUnit;
* <p>A container for PING frames data.</p>
*/
public class PingInfo
{
private final int pingId;
/** /**
* <p>Creates a {@link PingInfo} with the given ping id</p> * A PingInfo container. Currently adding nothing to it's base class, but serves to keep the api unchanged in
* @param pingId the ping id * future versions when we need to pass more info to the methods having a {@link PingInfo} parameter.
*/ */
public PingInfo(int pingId) public class PingInfo extends Info
{
public PingInfo(long timeout, TimeUnit unit)
{ {
this.pingId = pingId; super(timeout, unit);
} }
/** public PingInfo()
* @return the ping id
*/
public int getPingId()
{ {
return pingId; this(0, TimeUnit.SECONDS);
} }
} }

View File

@ -0,0 +1,44 @@
//
// ========================================================================
// Copyright (c) 1995-2012 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.spdy.api;
/**
* <p>A container for PING frames data.</p>
*/
public class PingResultInfo
{
private final int pingId;
/**
* <p>Creates a {@link PingResultInfo} with the given ping id</p>
* @param pingId the ping id
*/
public PingResultInfo(int pingId)
{
this.pingId = pingId;
}
/**
* @return the ping id
*/
public int getPingId()
{
return pingId;
}
}

View File

@ -0,0 +1,101 @@
//
// ========================================================================
// Copyright (c) 1995-2012 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.spdy.api;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.util.Fields;
/**
* <p>A container for PUSH_SYN_STREAM frames metadata and data.</p>
*/
public class PushInfo extends Info
{
/**
* <p>Flag that indicates that this {@link PushInfo} is the last frame in the stream.</p>
*
* @see #isClose()
* @see #getFlags()
*/
public static final byte FLAG_CLOSE = 1;
private final boolean close;
private final Fields headers;
/**
* <p>Creates a {@link PushInfo} instance with the given headers and the given close flag,
* not unidirectional, without associated stream, and with default priority.</p>
*
* @param headers the {@link Fields}
* @param close the value of the close flag
*/
public PushInfo(Fields headers, boolean close)
{
this(0, TimeUnit.SECONDS, headers, close);
// either builder or setters for timeout
}
/**
* <p>
* Creates a {@link PushInfo} instance with the given headers, the given close flag and with the given priority.
* </p>
* @param timeout the timeout value
* @param unit the TimeUnit of the timeout
* @param headers
* the {@link Fields}
* @param close
*/
public PushInfo(long timeout, TimeUnit unit, Fields headers, boolean close)
{
super(timeout, unit);
this.close = close;
this.headers = headers;
}
/**
* @return the value of the close flag
*/
public boolean isClose()
{
return close;
}
/**
* @return the {@link Fields}
*/
public Fields getHeaders()
{
return headers;
}
/**
* @return the close flag as integer
* @see #FLAG_CLOSE
*/
public byte getFlags()
{
return isClose() ? FLAG_CLOSE : 0;
}
@Override
public String toString()
{
return String.format("SYN push close=%b headers=%s", close, headers);
}
}

View File

@ -18,12 +18,14 @@
package org.eclipse.jetty.spdy.api; package org.eclipse.jetty.spdy.api;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.util.Fields;
/** /**
* <p>A container for SYN_REPLY frames metadata and headers.</p> * <p>A container for SYN_REPLY frames metadata and headers.</p>
*/ */
public class ReplyInfo public class ReplyInfo extends Info
{ {
/** /**
* <p>Flag that indicates that this {@link ReplyInfo} is the last frame in the stream.</p> * <p>Flag that indicates that this {@link ReplyInfo} is the last frame in the stream.</p>
@ -54,6 +56,20 @@ public class ReplyInfo
*/ */
public ReplyInfo(Fields headers, boolean close) public ReplyInfo(Fields headers, boolean close)
{ {
this(0, TimeUnit.SECONDS, headers, close);
}
/**
* <p>Creates a {@link ReplyInfo} instance with the given headers and the given close flag.</p>
*
* @param timeout the timeout
* @param unit the time unit for the timeout
* @param headers the {@link Fields}
* @param close the value of the close flag
*/
public ReplyInfo(long timeout, TimeUnit unit, Fields headers, boolean close)
{
super(timeout, unit);
this.headers = headers; this.headers = headers;
this.close = close; this.close = close;
} }

View File

@ -18,10 +18,12 @@
package org.eclipse.jetty.spdy.api; package org.eclipse.jetty.spdy.api;
import java.util.concurrent.TimeUnit;
/** /**
* <p>A container for RST_STREAM frames data: the stream id and the stream status.</p> * <p>A container for RST_STREAM frames data: the stream id and the stream status.</p>
*/ */
public class RstInfo public class RstInfo extends Info
{ {
private final int streamId; private final int streamId;
private final StreamStatus streamStatus; private final StreamStatus streamStatus;
@ -29,15 +31,29 @@ public class RstInfo
/** /**
* <p>Creates a new {@link RstInfo} with the given stream id and stream status</p> * <p>Creates a new {@link RstInfo} with the given stream id and stream status</p>
* *
* @param timeout the operation's timeout
* @param unit the timeout's unit
* @param streamId the stream id * @param streamId the stream id
* @param streamStatus the stream status * @param streamStatus the stream status
*/ */
public RstInfo(int streamId, StreamStatus streamStatus) public RstInfo(long timeout, TimeUnit unit, int streamId, StreamStatus streamStatus)
{ {
super(timeout, unit);
this.streamId = streamId; this.streamId = streamId;
this.streamStatus = streamStatus; this.streamStatus = streamStatus;
} }
/**
* <p>Creates a new {@link RstInfo} with the given stream id and stream status</p>
*
* @param streamId
* @param streamStatus
*/
public RstInfo(int streamId, StreamStatus streamStatus)
{
this(0, TimeUnit.SECONDS, streamId, streamStatus);
}
/** /**
* @return the stream id * @return the stream id
*/ */

View File

@ -21,8 +21,8 @@ package org.eclipse.jetty.spdy.api;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.EventListener; import java.util.EventListener;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Future; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.Promise;
@ -33,7 +33,7 @@ import org.eclipse.jetty.util.Promise;
* <pre> * <pre>
* Session session = ...; * Session session = ...;
* SynInfo synInfo = new SynInfo(true); * SynInfo synInfo = new SynInfo(true);
* session.syn(synInfo, new Stream.FrameListener.Adapter() * session.push(synInfo, new Stream.FrameListener.Adapter()
* { * {
* public void onReply(Stream stream, ReplyInfo replyInfo) * public void onReply(Stream stream, ReplyInfo replyInfo)
* { * {
@ -75,115 +75,118 @@ public interface Session
* <p>Callers may use the returned future to wait for the stream to be created, and * <p>Callers may use the returned future to wait for the stream to be created, and
* use the stream, for example, to send data frames.</p> * use the stream, for example, to send data frames.</p>
* *
*
* @param synInfo the metadata to send on stream creation * @param synInfo the metadata to send on stream creation
* @param listener the listener to invoke when events happen on the stream just created * @param listener the listener to invoke when events happen on the stream just created
* @return a future for the stream that will be created * @return the stream that will be created
* @see #syn(SynInfo, StreamFrameListener, long, TimeUnit, Promise) * @see #syn(SynInfo, StreamFrameListener, Promise
*/ */
public Future<Stream> syn(SynInfo synInfo, StreamFrameListener listener); public Stream syn(SynInfo synInfo, StreamFrameListener listener) throws ExecutionException, InterruptedException, TimeoutException;
/** /**
* <p>Sends asynchronously a SYN_FRAME to create a new {@link Stream SPDY stream}.</p> * <p>Sends asynchronously a SYN_FRAME to create a new {@link Stream SPDY stream}.</p>
* <p>Callers may pass a non-null completion callback to be notified of when the * <p>Callers may pass a non-null completion callback to be notified of when the
* stream has been created and use the stream, for example, to send data frames.</p> * stream has been created and use the stream, for example, to send data frames.</p>
* *
*
* @param synInfo the metadata to send on stream creation * @param synInfo the metadata to send on stream creation
* @param listener the listener to invoke when events happen on the stream just created * @param listener the listener to invoke when events happen on the stream just created
* @param timeout the operation's timeout
* @param unit the timeout's unit
* @param promise the completion callback that gets notified of stream creation * @param promise the completion callback that gets notified of stream creation
* @see #syn(SynInfo, StreamFrameListener) * @see #syn(SynInfo, StreamFrameListener)
*/ */
public void syn(SynInfo synInfo, StreamFrameListener listener, long timeout, TimeUnit unit, Promise<Stream> promise); public void syn(SynInfo synInfo, StreamFrameListener listener, Promise<Stream> promise);
/** /**
* <p>Sends asynchronously a RST_STREAM to abort a stream.</p> * <p>Sends asynchronously a RST_STREAM to abort a stream.</p>
* <p>Callers may use the returned future to wait for the reset to be sent.</p> * <p>Callers may use the returned future to wait for the reset to be sent.</p>
* *
*
* @param rstInfo the metadata to reset the stream * @param rstInfo the metadata to reset the stream
* @return a future to wait for the reset to be sent * @return the RstInfo belonging to the reset to be sent
* @see #rst(RstInfo, long, TimeUnit, Callback) * @see #rst(RstInfo, Callback)
*/ */
public Future<Void> rst(RstInfo rstInfo); public void rst(RstInfo rstInfo) throws InterruptedException, ExecutionException, TimeoutException;
/** /**
* <p>Sends asynchronously a RST_STREAM to abort a stream.</p> * <p>Sends asynchronously a RST_STREAM to abort a stream.</p>
* <p>Callers may pass a non-null completion callback to be notified of when the * <p>Callers may pass a non-null completion callback to be notified of when the
* reset has been actually sent.</p> * reset has been actually sent.</p>
* *
*
* @param rstInfo the metadata to reset the stream * @param rstInfo the metadata to reset the stream
* @param timeout the operation's timeout
* @param unit the timeout's unit
* @param callback the completion callback that gets notified of reset's send * @param callback the completion callback that gets notified of reset's send
* @see #rst(RstInfo) * @see #rst(RstInfo)
*/ */
public void rst(RstInfo rstInfo, long timeout, TimeUnit unit, Callback callback); public void rst(RstInfo rstInfo, Callback callback);
/** /**
* <p>Sends asynchronously a SETTINGS to configure the SPDY connection.</p> * <p>Sends asynchronously a SETTINGS to configure the SPDY connection.</p>
* <p>Callers may use the returned future to wait for the settings to be sent.</p> * <p>Callers may use the returned future to wait for the settings to be sent.</p>
* *
*
* @param settingsInfo the metadata to send * @param settingsInfo the metadata to send
* @return a future to wait for the settings to be sent * @return a future to wait for the settings to be sent
* @see #settings(SettingsInfo, long, TimeUnit, Callback) * @see #settings(SettingsInfo, Callback)
*/ */
public Future<Void> settings(SettingsInfo settingsInfo); public void settings(SettingsInfo settingsInfo) throws ExecutionException, InterruptedException, TimeoutException;
/** /**
* <p>Sends asynchronously a SETTINGS to configure the SPDY connection.</p> * <p>Sends asynchronously a SETTINGS to configure the SPDY connection.</p>
* <p>Callers may pass a non-null completion callback to be notified of when the * <p>Callers may pass a non-null completion callback to be notified of when the
* settings has been actually sent.</p> * settings has been actually sent.</p>
* *
*
* @param settingsInfo the metadata to send * @param settingsInfo the metadata to send
* @param timeout the operation's timeout
* @param unit the timeout's unit
* @param callback the completion callback that gets notified of settings' send * @param callback the completion callback that gets notified of settings' send
* @see #settings(SettingsInfo) * @see #settings(SettingsInfo)
*/ */
public void settings(SettingsInfo settingsInfo, long timeout, TimeUnit unit, Callback callback); public void settings(SettingsInfo settingsInfo, Callback callback);
/** /**
* <p>Sends asynchronously a PING, normally to measure round-trip time.</p> * <p>Sends asynchronously a PING, normally to measure round-trip time.</p>
* <p>Callers may use the returned future to wait for the ping to be sent.</p> * <p>Callers may use the returned future to wait for the ping to be sent.</p>
* *
* @return a future for the metadata sent * @return a future for the metadata sent
* @see #ping(long, TimeUnit, Promise) * @see #ping(PingInfo, Promise
* @param pingInfo
*/ */
public Future<PingInfo> ping(); public PingResultInfo ping(PingInfo pingInfo) throws ExecutionException, InterruptedException, TimeoutException;
/** /**
* <p>Sends asynchronously a PING, normally to measure round-trip time.</p> * <p>Sends asynchronously a PING, normally to measure round-trip time.</p>
* <p>Callers may pass a non-null completion callback to be notified of when the * <p>Callers may pass a non-null completion callback to be notified of when the
* ping has been actually sent.</p> * ping has been actually sent.</p>
* *
* @param timeout the operation's timeout *
* @param unit the timeout's unit *
* @param pingInfo
* @param promise the completion callback that gets notified of ping's send * @param promise the completion callback that gets notified of ping's send
* @see #ping() * @see #ping(PingInfo)
*/ */
public void ping(long timeout, TimeUnit unit, Promise<PingInfo> promise); public void ping(PingInfo pingInfo, Promise<PingResultInfo> promise);
/** /**
* <p>Closes gracefully this session, sending a GO_AWAY frame and then closing the TCP connection.</p> * <p>Closes gracefully this session, sending a GO_AWAY frame and then closing the TCP connection.</p>
* <p>Callers may use the returned future to wait for the go away to be sent.</p> * <p>Callers may use the returned future to wait for the go away to be sent.</p>
* *
* @return a future to wait for the go away to be sent * @return a future to wait for the go away to be sent
* @see #goAway(long, TimeUnit, Callback) * @see #goAway(GoAwayInfo, Callback)
* @param goAwayInfo
*/ */
public Future<Void> goAway(); public void goAway(GoAwayInfo goAwayInfo) throws ExecutionException, InterruptedException, TimeoutException;
/** /**
* <p>Closes gracefully this session, sending a GO_AWAY frame and then closing the TCP connection.</p> * <p>Closes gracefully this session, sending a GO_AWAY frame and then closing the TCP connection.</p>
* <p>Callers may pass a non-null completion callback to be notified of when the * <p>Callers may pass a non-null completion callback to be notified of when the
* go away has been actually sent.</p> * go away has been actually sent.</p>
* *
* @param timeout the operation's timeout *
* @param unit the timeout's unit *
* @param goAwayInfo
* @param callback the completion callback that gets notified of go away's send * @param callback the completion callback that gets notified of go away's send
* @see #goAway() * @see #goAway(GoAwayInfo)
*/ */
public void goAway(long timeout, TimeUnit unit, Callback callback); public void goAway(GoAwayInfo goAwayInfo, Callback callback);
/** /**
* @return a snapshot of the streams currently active in this session * @return a snapshot of the streams currently active in this session

View File

@ -98,17 +98,17 @@ public interface SessionFrameListener extends EventListener
* <p>Callback invoked when a ping request has completed its round-trip.</p> * <p>Callback invoked when a ping request has completed its round-trip.</p>
* *
* @param session the session * @param session the session
* @param pingInfo the metadata received * @param pingResultInfo the metadata received
*/ */
public void onPing(Session session, PingInfo pingInfo); public void onPing(Session session, PingResultInfo pingResultInfo);
/** /**
* <p>Callback invoked when the other peer signals that it is closing the connection.</p> * <p>Callback invoked when the other peer signals that it is closing the connection.</p>
* *
* @param session the session * @param session the session
* @param goAwayInfo the metadata sent * @param goAwayReceivedInfo the metadata sent
*/ */
public void onGoAway(Session session, GoAwayInfo goAwayInfo); public void onGoAway(Session session, GoAwayReceivedInfo goAwayReceivedInfo);
/** /**
* <p>Callback invoked when an exception is thrown during the processing of an event on a * <p>Callback invoked when an exception is thrown during the processing of an event on a
@ -143,12 +143,12 @@ public interface SessionFrameListener extends EventListener
} }
@Override @Override
public void onPing(Session session, PingInfo pingInfo) public void onPing(Session session, PingResultInfo pingResultInfo)
{ {
} }
@Override @Override
public void onGoAway(Session session, GoAwayInfo goAwayInfo) public void onGoAway(Session session, GoAwayReceivedInfo goAwayReceivedInfo)
{ {
} }

View File

@ -18,7 +18,9 @@
package org.eclipse.jetty.spdy.api; package org.eclipse.jetty.spdy.api;
public class SettingsInfo import java.util.concurrent.TimeUnit;
public class SettingsInfo extends Info
{ {
public static final byte CLEAR_PERSISTED = 1; public static final byte CLEAR_PERSISTED = 1;
@ -27,13 +29,19 @@ public class SettingsInfo
public SettingsInfo(Settings settings) public SettingsInfo(Settings settings)
{ {
this(settings, false); this(0, TimeUnit.SECONDS, settings, false);
}
public SettingsInfo(long timeout, TimeUnit unit, Settings settings, boolean clearPersisted)
{
super(timeout, unit);
this.settings = settings;
this.clearPersisted = clearPersisted;
} }
public SettingsInfo(Settings settings, boolean clearPersisted) public SettingsInfo(Settings settings, boolean clearPersisted)
{ {
this.settings = settings; this(0, TimeUnit.SECONDS, settings, clearPersisted);
this.clearPersisted = clearPersisted;
} }
public boolean isClearPersisted() public boolean isClearPersisted()

View File

@ -20,8 +20,8 @@ package org.eclipse.jetty.spdy.api;
import java.nio.channels.WritePendingException; import java.nio.channels.WritePendingException;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Future; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.Promise;
@ -50,7 +50,7 @@ import org.eclipse.jetty.util.Promise;
* stream.data(StringDataInfo("chunk1", false), 5, TimeUnit.SECONDS, new Handler&lt;Void&gt;() { ... }); * stream.data(StringDataInfo("chunk1", false), 5, TimeUnit.SECONDS, new Handler&lt;Void&gt;() { ... });
* stream.data(StringDataInfo("chunk2", true), 1, TimeUnit.SECONDS, new Handler&lt;Void&gt;() { ... }); * stream.data(StringDataInfo("chunk2", true), 1, TimeUnit.SECONDS, new Handler&lt;Void&gt;() { ... });
* </pre> * </pre>
* <p>where the second call to {@link #data(DataInfo, long, TimeUnit, Callback)} has a timeout smaller * <p>where the second call to {@link #data(DataInfo, Callback)} has a timeout smaller
* than the previous call.</p> * than the previous call.</p>
* <p>The behavior of such style of invocations is unspecified (it may even throw an exception - similar * <p>The behavior of such style of invocations is unspecified (it may even throw an exception - similar
* to {@link WritePendingException}).</p> * to {@link WritePendingException}).</p>
@ -95,35 +95,37 @@ public interface Stream
* <p>Initiate a unidirectional spdy pushstream associated to this stream asynchronously<p> * <p>Initiate a unidirectional spdy pushstream associated to this stream asynchronously<p>
* <p>Callers may use the returned future to get the pushstream once it got created</p> * <p>Callers may use the returned future to get the pushstream once it got created</p>
* *
* @param synInfo the metadata to send on stream creation *
*
* @param pushInfo the metadata to send on stream creation
* @return a future containing the stream once it got established * @return a future containing the stream once it got established
* @see #syn(SynInfo, long, TimeUnit, Promise) * @see #push(PushInfo, Promise
*/ */
public Future<Stream> syn(SynInfo synInfo); public Stream push(PushInfo pushInfo) throws InterruptedException, ExecutionException, TimeoutException;
/** /**
* <p>Initiate a unidirectional spdy pushstream associated to this stream asynchronously<p> * <p>Initiate a unidirectional spdy pushstream associated to this stream asynchronously<p>
* <p>Callers may pass a non-null completion callback to be notified of when the * <p>Callers may pass a non-null completion callback to be notified of when the
* pushstream has been established.</p> * pushstream has been established.</p>
* *
* @param synInfo the metadata to send on stream creation *
* @param timeout the operation's timeout * @param pushInfo the metadata to send on stream creation
* @param unit the timeout's unit
* @param callback the completion callback that gets notified once the pushstream is established * @param callback the completion callback that gets notified once the pushstream is established
* @see #syn(SynInfo) * @see #push(PushInfo)
*/ */
public void syn(SynInfo synInfo, long timeout, TimeUnit unit, Promise<Stream> callback); public void push(PushInfo pushInfo, Promise<Stream> callback);
/** /**
* <p>Sends asynchronously a SYN_REPLY frame in response to a SYN_STREAM frame.</p> * <p>Sends asynchronously a SYN_REPLY frame in response to a SYN_STREAM frame.</p>
* <p>Callers may use the returned future to wait for the reply to be actually sent.</p> * <p>Callers may use the returned future to wait for the reply to be actually sent.</p>
* *
*
* @param replyInfo the metadata to send * @param replyInfo the metadata to send
* @return a future to wait for the reply to be sent * @return a future to wait for the reply to be sent
* @see #reply(ReplyInfo, long, TimeUnit, Callback) * @see #reply(ReplyInfo, Callback)
* @see SessionFrameListener#onSyn(Stream, SynInfo) * @see SessionFrameListener#onSyn(Stream, SynInfo)
*/ */
public Future<Void> reply(ReplyInfo replyInfo); public void reply(ReplyInfo replyInfo) throws InterruptedException, ExecutionException, TimeoutException;
/** /**
* <p>Sends asynchronously a SYN_REPLY frame in response to a SYN_STREAM frame.</p> * <p>Sends asynchronously a SYN_REPLY frame in response to a SYN_STREAM frame.</p>
@ -131,24 +133,23 @@ public interface Stream
* reply has been actually sent.</p> * reply has been actually sent.</p>
* *
* @param replyInfo the metadata to send * @param replyInfo the metadata to send
* @param timeout the operation's timeout
* @param unit the timeout's unit
* @param callback the completion callback that gets notified of reply sent * @param callback the completion callback that gets notified of reply sent
* @see #reply(ReplyInfo) * @see #reply(ReplyInfo)
*/ */
public void reply(ReplyInfo replyInfo, long timeout, TimeUnit unit, Callback callback); public void reply(ReplyInfo replyInfo, Callback callback);
/** /**
* <p>Sends asynchronously a DATA frame on this stream.</p> * <p>Sends asynchronously a DATA frame on this stream.</p>
* <p>DATA frames should always be sent after a SYN_REPLY frame.</p> * <p>DATA frames should always be sent after a SYN_REPLY frame.</p>
* <p>Callers may use the returned future to wait for the data to be actually sent.</p> * <p>Callers may use the returned future to wait for the data to be actually sent.</p>
* *
*
* @param dataInfo the metadata to send * @param dataInfo the metadata to send
* @return a future to wait for the data to be sent * @return a future to wait for the data to be sent
* @see #data(DataInfo, long, TimeUnit, Callback) * @see #data(DataInfo, Callback)
* @see #reply(ReplyInfo) * @see #reply(ReplyInfo)
*/ */
public Future<Void> data(DataInfo dataInfo); public void data(DataInfo dataInfo) throws InterruptedException, ExecutionException, TimeoutException;
/** /**
* <p>Sends asynchronously a DATA frame on this stream.</p> * <p>Sends asynchronously a DATA frame on this stream.</p>
@ -157,24 +158,23 @@ public interface Stream
* data has been actually sent.</p> * data has been actually sent.</p>
* *
* @param dataInfo the metadata to send * @param dataInfo the metadata to send
* @param timeout the operation's timeout
* @param unit the timeout's unit
* @param callback the completion callback that gets notified of data sent * @param callback the completion callback that gets notified of data sent
* @see #data(DataInfo) * @see #data(DataInfo)
*/ */
public void data(DataInfo dataInfo, long timeout, TimeUnit unit, Callback callback); public void data(DataInfo dataInfo, Callback callback);
/** /**
* <p>Sends asynchronously a HEADER frame on this stream.</p> * <p>Sends asynchronously a HEADER frame on this stream.</p>
* <p>HEADERS frames should always be sent after a SYN_REPLY frame.</p> * <p>HEADERS frames should always be sent after a SYN_REPLY frame.</p>
* <p>Callers may use the returned future to wait for the headers to be actually sent.</p> * <p>Callers may use the returned future to wait for the headers to be actually sent.</p>
* *
*
* @param headersInfo the metadata to send * @param headersInfo the metadata to send
* @return a future to wait for the headers to be sent * @return a future to wait for the headers to be sent
* @see #headers(HeadersInfo, long, TimeUnit, Callback * @see #headers(HeadersInfo, Callback
* @see #reply(ReplyInfo) * @see #reply(ReplyInfo)
*/ */
public Future<Void> headers(HeadersInfo headersInfo); public void headers(HeadersInfo headersInfo) throws InterruptedException, ExecutionException, TimeoutException;
/** /**
* <p>Sends asynchronously a HEADER frame on this stream.</p> * <p>Sends asynchronously a HEADER frame on this stream.</p>
@ -183,12 +183,10 @@ public interface Stream
* headers have been actually sent.</p> * headers have been actually sent.</p>
* *
* @param headersInfo the metadata to send * @param headersInfo the metadata to send
* @param timeout the operation's timeout
* @param unit the timeout's unit
* @param callback the completion callback that gets notified of headers sent * @param callback the completion callback that gets notified of headers sent
* @see #headers(HeadersInfo) * @see #headers(HeadersInfo)
*/ */
public void headers(HeadersInfo headersInfo, long timeout, TimeUnit unit, Callback callback); public void headers(HeadersInfo headersInfo, Callback callback);
/** /**
* @return whether this stream is unidirectional or not * @return whether this stream is unidirectional or not

View File

@ -19,6 +19,7 @@
package org.eclipse.jetty.spdy.api; package org.eclipse.jetty.spdy.api;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;
/** /**
* <p>Specialized {@link DataInfo} for {@link String} content.</p> * <p>Specialized {@link DataInfo} for {@link String} content.</p>
@ -29,4 +30,9 @@ public class StringDataInfo extends BytesDataInfo
{ {
super(string.getBytes(Charset.forName("UTF-8")), close); super(string.getBytes(Charset.forName("UTF-8")), close);
} }
public StringDataInfo(long timeout, TimeUnit unit, String string, boolean close)
{
super(timeout, unit, string.getBytes(Charset.forName("UTF-8")), close);
}
} }

View File

@ -18,15 +18,17 @@
package org.eclipse.jetty.spdy.api; package org.eclipse.jetty.spdy.api;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.util.Fields;
/** /**
* <p>A container for SYN_STREAM frames metadata and data.</p> * <p>A container for SYN_STREAM frames metadata and data.</p>
*/ */
public class SynInfo public class SynInfo extends Info
{ {
/** /**
* <p>Flag that indicates that this {@link DataInfo} is the last frame in the stream.</p> * <p>Flag that indicates that this {@link SynInfo} is the last frame in the stream.</p>
* *
* @see #isClose() * @see #isClose()
* @see #getFlags() * @see #getFlags()
@ -38,18 +40,7 @@ public class SynInfo
private final Fields headers; private final Fields headers;
/** /**
* <p>Creates a new {@link SynInfo} instance with empty headers and the given close flag, * <p>Creates a {@link SynInfo} instance with the given headers and the given close flag,
* not unidirectional, without associated stream, and with default priority.</p>
*
* @param close the value of the close flag
*/
public SynInfo(boolean close)
{
this(new Fields(), close);
}
/**
* <p>Creates a {@link ReplyInfo} instance with the given headers and the given close flag,
* not unidirectional, without associated stream, and with default priority.</p> * not unidirectional, without associated stream, and with default priority.</p>
* *
* @param headers the {@link Fields} * @param headers the {@link Fields}
@ -57,23 +48,40 @@ public class SynInfo
*/ */
public SynInfo(Fields headers, boolean close) public SynInfo(Fields headers, boolean close)
{ {
this(headers, close, (byte)0); this(0, TimeUnit.SECONDS, headers, close, (byte)0);
// either builder or setters for timeout
} }
/** /**
* <p> * <p>
* Creates a {@link ReplyInfo} instance with the given headers, the given close flag and with the given priority. * Creates a {@link SynInfo} instance with the given headers, the given close flag and with the given priority.
* </p> * </p>
*
* @param headers * @param headers
* the {@link Fields} * the {@link Fields}
* @param close * @param close
* the value of the close flag * the value of the close flag
* @param priority * @param priority
* the priority
*/ */
public SynInfo(Fields headers, boolean close, byte priority) public SynInfo(Fields headers, boolean close, byte priority)
{ {
this(0, TimeUnit.SECONDS, headers, close, priority);
}
/**
* <p>
* Creates a {@link SynInfo} instance with the given headers, the given close flag and with the given priority.
* </p>
* @param timeout the timeout value
* @param unit the TimeUnit of the timeout
* @param headers
* the {@link Fields}
* @param close
* the value of the close flag
* @param priority
*/
public SynInfo(long timeout, TimeUnit unit, Fields headers, boolean close, byte priority)
{
super(timeout, unit);
this.close = close; this.close = close;
this.priority = priority; this.priority = priority;
this.headers = headers; this.headers = headers;

View File

@ -55,14 +55,9 @@ public class DataFrame
return (flags & DataInfo.FLAG_CLOSE) == DataInfo.FLAG_CLOSE; return (flags & DataInfo.FLAG_CLOSE) == DataInfo.FLAG_CLOSE;
} }
public boolean isCompress()
{
return (flags & DataInfo.FLAG_COMPRESS) == DataInfo.FLAG_COMPRESS;
}
@Override @Override
public String toString() public String toString()
{ {
return String.format("DATA frame stream=%d length=%d close=%b compress=%b", getStreamId(), getLength(), isClose(), isCompress()); return String.format("DATA frame stream=%d length=%d close=%b", getStreamId(), getLength(), isClose());
} }
} }

View File

@ -36,6 +36,7 @@ import org.eclipse.jetty.spdy.generator.Generator;
import org.eclipse.jetty.toolchain.test.AdvancedRunner; import org.eclipse.jetty.toolchain.test.AdvancedRunner;
import org.eclipse.jetty.toolchain.test.annotation.Slow; import org.eclipse.jetty.toolchain.test.annotation.Slow;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.thread.Scheduler; import org.eclipse.jetty.util.thread.Scheduler;
import org.eclipse.jetty.util.thread.TimerScheduler; import org.eclipse.jetty.util.thread.TimerScheduler;
@ -77,7 +78,7 @@ public class AsyncTimeoutTest
}; };
final CountDownLatch failedLatch = new CountDownLatch(1); final CountDownLatch failedLatch = new CountDownLatch(1);
session.syn(new SynInfo(true), null, timeout, unit, new Promise.Adapter<Stream>() session.syn(new SynInfo(timeout, unit, new Fields(), true, (byte)0), null, new Promise.Adapter<Stream>()
{ {
@Override @Override
public void failed(Throwable x) public void failed(Throwable x)
@ -121,9 +122,9 @@ public class AsyncTimeoutTest
} }
}; };
Stream stream = session.syn(new SynInfo(false), null).get(5, TimeUnit.SECONDS); Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), null);
final CountDownLatch failedLatch = new CountDownLatch(1); final CountDownLatch failedLatch = new CountDownLatch(1);
stream.data(new StringDataInfo("data", true), timeout, unit, new Callback.Adapter() stream.data(new StringDataInfo(timeout, unit, "data", true), new Callback.Adapter()
{ {
@Override @Override
public void failed(Throwable x) public void failed(Throwable x)

View File

@ -34,6 +34,7 @@ import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.spdy.api.ByteBufferDataInfo; import org.eclipse.jetty.spdy.api.ByteBufferDataInfo;
import org.eclipse.jetty.spdy.api.DataInfo; import org.eclipse.jetty.spdy.api.DataInfo;
import org.eclipse.jetty.spdy.api.HeadersInfo; import org.eclipse.jetty.spdy.api.HeadersInfo;
import org.eclipse.jetty.spdy.api.PushInfo;
import org.eclipse.jetty.spdy.api.RstInfo; import org.eclipse.jetty.spdy.api.RstInfo;
import org.eclipse.jetty.spdy.api.SPDY; import org.eclipse.jetty.spdy.api.SPDY;
import org.eclipse.jetty.spdy.api.Session; import org.eclipse.jetty.spdy.api.Session;
@ -48,6 +49,7 @@ import org.eclipse.jetty.spdy.frames.SynStreamFrame;
import org.eclipse.jetty.spdy.generator.Generator; import org.eclipse.jetty.spdy.generator.Generator;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.FuturePromise;
import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
@ -76,6 +78,7 @@ import static org.mockito.Mockito.verify;
public class StandardSessionTest public class StandardSessionTest
{ {
private static final Logger LOG = Log.getLogger(StandardSessionTest.class); private static final Logger LOG = Log.getLogger(StandardSessionTest.class);
private static final short VERSION = SPDY.V2;
@Mock @Mock
private Controller controller; private Controller controller;
@ -92,7 +95,7 @@ public class StandardSessionTest
threadPool = Executors.newCachedThreadPool(); threadPool = Executors.newCachedThreadPool();
scheduler = new TimerScheduler(); scheduler = new TimerScheduler();
scheduler.start(); scheduler.start();
session = new StandardSession(SPDY.V2, bufferPool, threadPool, scheduler, controller, null, null, 1, null, session = new StandardSession(VERSION, bufferPool, threadPool, scheduler, controller, null, null, 1, null,
generator, new FlowControlStrategy.None()); generator, new FlowControlStrategy.None());
headers = new Fields(); headers = new Fields();
} }
@ -144,7 +147,7 @@ public class StandardSessionTest
IStream stream = createStream(); IStream stream = createStream();
assertThatStreamIsInSession(stream); assertThatStreamIsInSession(stream);
stream.updateCloseState(true, true); stream.updateCloseState(true, true);
session.onControlFrame(new SynReplyFrame(SPDY.V2, SynInfo.FLAG_CLOSE, stream.getId(), null)); session.onControlFrame(new SynReplyFrame(VERSION, SynInfo.FLAG_CLOSE, stream.getId(), null));
assertThatStreamIsClosed(stream); assertThatStreamIsClosed(stream);
assertThatStreamIsNotInSession(stream); assertThatStreamIsNotInSession(stream);
} }
@ -202,7 +205,7 @@ public class StandardSessionTest
assertThatPushStreamIsHalfClosed(pushStream); assertThatPushStreamIsHalfClosed(pushStream);
assertThatPushStreamIsNotClosed(pushStream); assertThatPushStreamIsNotClosed(pushStream);
session.onControlFrame(new SynReplyFrame(SPDY.V2, SynInfo.FLAG_CLOSE, stream.getId(), null)); session.onControlFrame(new SynReplyFrame(VERSION, SynInfo.FLAG_CLOSE, stream.getId(), null));
assertThatStreamIsClosed(stream); assertThatStreamIsClosed(stream);
assertThatPushStreamIsNotClosed(pushStream); assertThatPushStreamIsNotClosed(pushStream);
} }
@ -223,8 +226,8 @@ public class StandardSessionTest
private void createPushStreamAndMakeSureItFails(IStream stream) throws InterruptedException private void createPushStreamAndMakeSureItFails(IStream stream) throws InterruptedException
{ {
final CountDownLatch failedLatch = new CountDownLatch(1); final CountDownLatch failedLatch = new CountDownLatch(1);
SynInfo synInfo = new SynInfo(headers, false, stream.getPriority()); PushInfo pushInfo = new PushInfo(5, TimeUnit.SECONDS, headers, false);
stream.syn(synInfo, 5, TimeUnit.SECONDS, new Promise.Adapter<Stream>() stream.push(pushInfo, new Promise.Adapter<Stream>()
{ {
@Override @Override
public void failed(Throwable x) public void failed(Throwable x)
@ -257,7 +260,7 @@ public class StandardSessionTest
setControllerWriteExpectation(false); setControllerWriteExpectation(false);
IStream stream = createStream(); IStream stream = createStream();
IStream pushStream = (IStream)stream.syn(new SynInfo(false)).get(); IStream pushStream = (IStream)stream.push(new PushInfo(new Fields(), false));
assertThatPushStreamIsInSession(pushStream); assertThatPushStreamIsInSession(pushStream);
session.rst(new RstInfo(pushStream.getId(), StreamStatus.INVALID_STREAM)); session.rst(new RstInfo(pushStream.getId(), StreamStatus.INVALID_STREAM));
assertThatPushStreamIsNotInSession(pushStream); assertThatPushStreamIsNotInSession(pushStream);
@ -271,8 +274,8 @@ public class StandardSessionTest
setControllerWriteExpectation(false); setControllerWriteExpectation(false);
IStream stream = createStream(); IStream stream = createStream();
SynInfo synInfo = new SynInfo(headers, true, stream.getPriority()); PushInfo pushInfo = new PushInfo(5, TimeUnit.SECONDS, headers, true);
IStream pushStream = (IStream)stream.syn(synInfo).get(5, TimeUnit.SECONDS); IStream pushStream = (IStream)stream.push(pushInfo);
assertThatPushStreamIsHalfClosed(pushStream); assertThatPushStreamIsHalfClosed(pushStream);
assertThatPushStreamIsClosed(pushStream); assertThatPushStreamIsClosed(pushStream);
assertThatStreamIsNotAssociatedWithPushStream(stream, pushStream); assertThatStreamIsNotAssociatedWithPushStream(stream, pushStream);
@ -286,8 +289,8 @@ public class StandardSessionTest
setControllerWriteExpectation(false); setControllerWriteExpectation(false);
IStream stream = createStream(); IStream stream = createStream();
SynInfo synInfo = new SynInfo(headers, false, stream.getPriority()); PushInfo pushInfo = new PushInfo(5, TimeUnit.SECONDS, headers, false);
IStream pushStream = (IStream)stream.syn(synInfo).get(5, TimeUnit.SECONDS); IStream pushStream = (IStream)stream.push(pushInfo);
assertThatStreamIsAssociatedWithPushStream(stream, pushStream); assertThatStreamIsAssociatedWithPushStream(stream, pushStream);
assertThatPushStreamIsInSession(pushStream); assertThatPushStreamIsInSession(pushStream);
pushStream.headers(new HeadersInfo(headers, true)); pushStream.headers(new HeadersInfo(headers, true));
@ -306,6 +309,7 @@ public class StandardSessionTest
final CountDownLatch closedListenerCalledLatch = new CountDownLatch(1); final CountDownLatch closedListenerCalledLatch = new CountDownLatch(1);
session.addListener(new TestStreamListener(createdListenerCalledLatch, closedListenerCalledLatch)); session.addListener(new TestStreamListener(createdListenerCalledLatch, closedListenerCalledLatch));
IStream stream = createStream(); IStream stream = createStream();
session.onControlFrame(new SynReplyFrame(VERSION, (byte)0, stream.getId(), new Fields()));
session.onDataFrame(new DataFrame(stream.getId(), SynInfo.FLAG_CLOSE, 128), ByteBuffer.allocate(128)); session.onDataFrame(new DataFrame(stream.getId(), SynInfo.FLAG_CLOSE, 128), ByteBuffer.allocate(128));
stream.data(new StringDataInfo("close", true)); stream.data(new StringDataInfo("close", true));
assertThat("onStreamCreated listener has been called", createdListenerCalledLatch.await(5, TimeUnit.SECONDS), is(true)); assertThat("onStreamCreated listener has been called", createdListenerCalledLatch.await(5, TimeUnit.SECONDS), is(true));
@ -383,11 +387,11 @@ public class StandardSessionTest
@Test @Test
@Ignore("In V3 we need to rst the stream if we receive data on a remotely half closed stream.") @Ignore("In V3 we need to rst the stream if we receive data on a remotely half closed stream.")
public void receiveDataOnRemotelyHalfClosedStreamResetsStreamInV3() throws InterruptedException, ExecutionException public void receiveDataOnRemotelyHalfClosedStreamResetsStreamInV3() throws InterruptedException, ExecutionException, TimeoutException
{ {
setControllerWriteExpectation(false); setControllerWriteExpectation(false);
IStream stream = (IStream)session.syn(new SynInfo(false), new StreamFrameListener.Adapter()).get(); IStream stream = (IStream)session.syn(new SynInfo(new Fields(), false), new StreamFrameListener.Adapter());
stream.updateCloseState(true, false); stream.updateCloseState(true, false);
assertThat("stream is half closed from remote side", stream.isHalfClosed(), is(true)); assertThat("stream is half closed from remote side", stream.isHalfClosed(), is(true));
stream.process(new ByteBufferDataInfo(ByteBuffer.allocate(256), true)); stream.process(new ByteBufferDataInfo(ByteBuffer.allocate(256), true));
@ -399,7 +403,8 @@ public class StandardSessionTest
setControllerWriteExpectation(false); setControllerWriteExpectation(false);
final CountDownLatch onDataCalledLatch = new CountDownLatch(1); final CountDownLatch onDataCalledLatch = new CountDownLatch(1);
Stream stream = session.syn(new SynInfo(false), new StreamFrameListener.Adapter() Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0),
new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onData(Stream stream, DataInfo dataInfo) public void onData(Stream stream, DataInfo dataInfo)
@ -407,8 +412,8 @@ public class StandardSessionTest
onDataCalledLatch.countDown(); onDataCalledLatch.countDown();
super.onData(stream, dataInfo); super.onData(stream, dataInfo);
} }
}).get(5, TimeUnit.SECONDS); });
session.onControlFrame(new SynReplyFrame(SPDY.V2, SynInfo.FLAG_CLOSE, stream.getId(), headers)); session.onControlFrame(new SynReplyFrame(VERSION, SynInfo.FLAG_CLOSE, stream.getId(), headers));
session.onDataFrame(new DataFrame(stream.getId(), (byte)0, 0), ByteBuffer.allocate(128)); session.onDataFrame(new DataFrame(stream.getId(), (byte)0, 0), ByteBuffer.allocate(128));
assertThat("onData is never called", onDataCalledLatch.await(1, TimeUnit.SECONDS), not(true)); assertThat("onData is never called", onDataCalledLatch.await(1, TimeUnit.SECONDS), not(true));
} }
@ -420,7 +425,7 @@ public class StandardSessionTest
setControllerWriteExpectation(true); setControllerWriteExpectation(true);
final CountDownLatch failedCalledLatch = new CountDownLatch(2); final CountDownLatch failedCalledLatch = new CountDownLatch(2);
SynStreamFrame synStreamFrame = new SynStreamFrame(SPDY.V2, SynInfo.FLAG_CLOSE, 1, 0, (byte)0, (short)0, null); SynStreamFrame synStreamFrame = new SynStreamFrame(VERSION, SynInfo.FLAG_CLOSE, 1, 0, (byte)0, (short)0, null);
IStream stream = new StandardStream(synStreamFrame.getStreamId(), synStreamFrame.getPriority(), session, null, null); IStream stream = new StandardStream(synStreamFrame.getStreamId(), synStreamFrame.getPriority(), session, null, null);
stream.updateWindowSize(8192); stream.updateWindowSize(8192);
Callback.Adapter callback = new Callback.Adapter() Callback.Adapter callback = new Callback.Adapter()
@ -433,9 +438,9 @@ public class StandardSessionTest
}; };
// first data frame should fail on controller.write() // first data frame should fail on controller.write()
stream.data(new StringDataInfo("data", false), 5, TimeUnit.SECONDS, callback); stream.data(new StringDataInfo(5, TimeUnit.SECONDS, "data", false), callback);
// second data frame should fail without controller.write() as the connection is expected to be broken after first controller.write() call failed. // second data frame should fail without controller.write() as the connection is expected to be broken after first controller.write() call failed.
stream.data(new StringDataInfo("data", false), 5, TimeUnit.SECONDS, callback); stream.data(new StringDataInfo(5, TimeUnit.SECONDS, "data", false), callback);
verify(controller, times(1)).write(any(ByteBuffer.class), any(Callback.class)); verify(controller, times(1)).write(any(ByteBuffer.class), any(Callback.class));
assertThat("Callback.failed has been called twice", failedCalledLatch.await(5, TimeUnit.SECONDS), is(true)); assertThat("Callback.failed has been called twice", failedCalledLatch.await(5, TimeUnit.SECONDS), is(true));
@ -449,7 +454,7 @@ public class StandardSessionTest
// This is necessary to keep the compression context of Headers valid // This is necessary to keep the compression context of Headers valid
IStream stream = createStream(); IStream stream = createStream();
session.rst(new RstInfo(stream.getId(), StreamStatus.INVALID_STREAM)); session.rst(new RstInfo(stream.getId(), StreamStatus.INVALID_STREAM));
stream.headers(new HeadersInfo(headers,true)); stream.headers(new HeadersInfo(headers, true));
verify(controller, times(3)).write(any(ByteBuffer.class), any(Callback.class)); verify(controller, times(3)).write(any(ByteBuffer.class), any(Callback.class));
@ -471,7 +476,7 @@ public class StandardSessionTest
private void testHeaderFramesAreSentInOrder(final byte priority0, final byte priority1, final byte priority2) throws InterruptedException, ExecutionException private void testHeaderFramesAreSentInOrder(final byte priority0, final byte priority1, final byte priority2) throws InterruptedException, ExecutionException
{ {
final StandardSession testLocalSession = new StandardSession(SPDY.V2, bufferPool, threadPool, scheduler, final StandardSession testLocalSession = new StandardSession(VERSION, bufferPool, threadPool, scheduler,
new ControllerMock(), null, null, 1, null, generator, new FlowControlStrategy.None()); new ControllerMock(), null, null, 1, null, generator, new FlowControlStrategy.None());
HashSet<Future> tasks = new HashSet<>(); HashSet<Future> tasks = new HashSet<>();
@ -492,7 +497,7 @@ public class StandardSessionTest
private void synStream(byte priority) private void synStream(byte priority)
{ {
SynInfo synInfo = new SynInfo(headers, false, priority); SynInfo synInfo = new SynInfo(headers, false, priority);
testLocalSession.syn(synInfo, new StreamFrameListener.Adapter()); testLocalSession.syn(synInfo, new StreamFrameListener.Adapter(), new FuturePromise<Stream>());
} }
})); }));
} }
@ -533,14 +538,14 @@ public class StandardSessionTest
private IStream createStream() throws InterruptedException, ExecutionException, TimeoutException private IStream createStream() throws InterruptedException, ExecutionException, TimeoutException
{ {
SynInfo synInfo = new SynInfo(headers, false, (byte)0); SynInfo synInfo = new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0);
return (IStream)session.syn(synInfo, new StreamFrameListener.Adapter()).get(5, TimeUnit.SECONDS); return (IStream)session.syn(synInfo, new StreamFrameListener.Adapter());
} }
private IStream createPushStream(Stream stream) throws InterruptedException, ExecutionException, TimeoutException private IStream createPushStream(Stream stream) throws InterruptedException, ExecutionException, TimeoutException
{ {
SynInfo synInfo = new SynInfo(headers, false, stream.getPriority()); PushInfo pushInfo = new PushInfo(5, TimeUnit.SECONDS, headers, false);
return (IStream)stream.syn(synInfo).get(5, TimeUnit.SECONDS); return (IStream)stream.push(pushInfo);
} }
private void assertThatStreamIsClosed(IStream stream) private void assertThatStreamIsClosed(IStream stream)

View File

@ -26,6 +26,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import org.eclipse.jetty.spdy.api.DataInfo; import org.eclipse.jetty.spdy.api.DataInfo;
import org.eclipse.jetty.spdy.api.PushInfo;
import org.eclipse.jetty.spdy.api.SPDY; import org.eclipse.jetty.spdy.api.SPDY;
import org.eclipse.jetty.spdy.api.Stream; import org.eclipse.jetty.spdy.api.Stream;
import org.eclipse.jetty.spdy.api.StreamFrameListener; import org.eclipse.jetty.spdy.api.StreamFrameListener;
@ -33,6 +34,7 @@ import org.eclipse.jetty.spdy.api.StringDataInfo;
import org.eclipse.jetty.spdy.api.SynInfo; import org.eclipse.jetty.spdy.api.SynInfo;
import org.eclipse.jetty.spdy.frames.SynStreamFrame; import org.eclipse.jetty.spdy.frames.SynStreamFrame;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.Promise;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -45,7 +47,6 @@ import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.argThat; import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@ -60,7 +61,7 @@ public class StandardStreamTest
private SynStreamFrame synStreamFrame; private SynStreamFrame synStreamFrame;
/** /**
* Test method for {@link org.eclipse.jetty.spdy.StandardStream#syn(org.eclipse.jetty.spdy.api.SynInfo)}. * Test method for {@link Stream#push(org.eclipse.jetty.spdy.api.PushInfo)}.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Test @Test
@ -70,30 +71,29 @@ public class StandardStreamTest
Set<Stream> streams = new HashSet<>(); Set<Stream> streams = new HashSet<>();
streams.add(stream); streams.add(stream);
when(synStreamFrame.isClose()).thenReturn(false); when(synStreamFrame.isClose()).thenReturn(false);
SynInfo synInfo = new SynInfo(false); PushInfo pushInfo = new PushInfo(new Fields(), false);
when(session.getStreams()).thenReturn(streams); when(session.getStreams()).thenReturn(streams);
stream.syn(synInfo); stream.push(pushInfo, new Promise.Adapter<Stream>());
verify(session).syn(argThat(new PushSynInfoMatcher(stream.getId(), synInfo)), any(StreamFrameListener.class), anyLong(), any(TimeUnit.class), any(Promise.class)); verify(session).syn(argThat(new PushSynInfoMatcher(stream.getId(), pushInfo)),
any(StreamFrameListener.class), any(Promise.class));
} }
private class PushSynInfoMatcher extends ArgumentMatcher<PushSynInfo> private class PushSynInfoMatcher extends ArgumentMatcher<PushSynInfo>
{ {
int associatedStreamId; private int associatedStreamId;
SynInfo synInfo; private PushInfo pushInfo;
public PushSynInfoMatcher(int associatedStreamId, SynInfo synInfo) public PushSynInfoMatcher(int associatedStreamId, PushInfo pushInfo)
{ {
this.associatedStreamId = associatedStreamId; this.associatedStreamId = associatedStreamId;
this.synInfo = synInfo; this.pushInfo = pushInfo;
} }
@Override @Override
public boolean matches(Object argument) public boolean matches(Object argument)
{ {
PushSynInfo pushSynInfo = (PushSynInfo)argument; PushSynInfo pushSynInfo = (PushSynInfo)argument;
if (pushSynInfo.getAssociatedStreamId() != associatedStreamId) return pushSynInfo.getAssociatedStreamId() == associatedStreamId && pushSynInfo.isClose() == pushInfo.isClose();
return false;
return pushSynInfo.isClose() == synInfo.isClose();
} }
} }
@ -105,7 +105,7 @@ public class StandardStreamTest
stream.updateCloseState(true, false); stream.updateCloseState(true, false);
assertThat("stream expected to be closed", stream.isClosed(), is(true)); assertThat("stream expected to be closed", stream.isClosed(), is(true));
final CountDownLatch failedLatch = new CountDownLatch(1); final CountDownLatch failedLatch = new CountDownLatch(1);
stream.syn(new SynInfo(false), 1, TimeUnit.SECONDS, new Promise.Adapter<Stream>() stream.push(new PushInfo(1, TimeUnit.SECONDS, new Fields(), false), new Promise.Adapter<Stream>()
{ {
@Override @Override
public void failed(Throwable x) public void failed(Throwable x)

View File

@ -19,9 +19,12 @@
package org.eclipse.jetty.spdy.api; package org.eclipse.jetty.spdy.api;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.eclipse.jetty.spdy.StandardSession; import org.eclipse.jetty.spdy.StandardSession;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.Promise;
import org.junit.Ignore; import org.junit.Ignore;
@ -35,7 +38,7 @@ public class ClientUsageTest
{ {
Session session = new StandardSession(SPDY.V2, null, null, null, null, null, null, 1, null, null, null); Session session = new StandardSession(SPDY.V2, null, null, null, null, null, null, 1, null, null, null);
session.syn(new SynInfo(true), new StreamFrameListener.Adapter() session.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onReply(Stream stream, ReplyInfo replyInfo) public void onReply(Stream stream, ReplyInfo replyInfo)
@ -44,7 +47,14 @@ public class ClientUsageTest
replyInfo.getHeaders().get("host"); replyInfo.getHeaders().get("host");
// Then issue another similar request // Then issue another similar request
stream.getSession().syn(new SynInfo(true), this); try
{
stream.getSession().syn(new SynInfo(new Fields(), true), this);
}
catch (ExecutionException | InterruptedException | TimeoutException e)
{
throw new IllegalStateException(e);
}
} }
}); });
} }
@ -54,7 +64,8 @@ public class ClientUsageTest
{ {
Session session = new StandardSession(SPDY.V2, null, null, null, null, null, null, 1, null, null, null); Session session = new StandardSession(SPDY.V2, null, null, null, null, null, null, 1, null, null, null);
Stream stream = session.syn(new SynInfo(false), new StreamFrameListener.Adapter() Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0),
new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onReply(Stream stream, ReplyInfo replyInfo) public void onReply(Stream stream, ReplyInfo replyInfo)
@ -63,9 +74,16 @@ public class ClientUsageTest
replyInfo.getHeaders().get("host"); replyInfo.getHeaders().get("host");
// Then issue another similar request // Then issue another similar request
stream.getSession().syn(new SynInfo(true), this); try
{
stream.getSession().syn(new SynInfo(new Fields(), true), this);
} }
}).get(5, TimeUnit.SECONDS); catch (ExecutionException | InterruptedException | TimeoutException e)
{
throw new IllegalStateException(e);
}
}
});
// Send-and-forget the data // Send-and-forget the data
stream.data(new StringDataInfo("data", true)); stream.data(new StringDataInfo("data", true));
} }
@ -76,7 +94,7 @@ public class ClientUsageTest
Session session = new StandardSession(SPDY.V2, null, null, null, null, null, null, 1, null, null, null); Session session = new StandardSession(SPDY.V2, null, null, null, null, null, null, 1, null, null, null);
final String context = "context"; final String context = "context";
session.syn(new SynInfo(false), new StreamFrameListener.Adapter() session.syn(new SynInfo(new Fields(), false), new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onReply(Stream stream, ReplyInfo replyInfo) public void onReply(Stream stream, ReplyInfo replyInfo)
@ -85,9 +103,16 @@ public class ClientUsageTest
replyInfo.getHeaders().get("host"); replyInfo.getHeaders().get("host");
// Then issue another similar request // Then issue another similar request
stream.getSession().syn(new SynInfo(true), this); try
{
stream.getSession().syn(new SynInfo(new Fields(), true), this);
} }
}, 0, TimeUnit.MILLISECONDS, new Promise.Adapter<Stream>() catch (ExecutionException | InterruptedException | TimeoutException e)
{
throw new IllegalStateException(e);
}
}
}, new Promise.Adapter<Stream>()
{ {
@Override @Override
public void succeeded(Stream stream) public void succeeded(Stream stream)
@ -100,7 +125,7 @@ public class ClientUsageTest
// The style below is fire-and-forget, since // The style below is fire-and-forget, since
// we do not pass the handler nor we call get() // we do not pass the handler nor we call get()
// to wait for the data to be sent // to wait for the data to be sent
stream.data(new StringDataInfo(context, true)); stream.data(new StringDataInfo(context, true), new Callback.Adapter());
} }
}); });
} }
@ -110,9 +135,9 @@ public class ClientUsageTest
{ {
Session session = new StandardSession(SPDY.V2, null, null, null, null, null, null, 1, null, null, null); Session session = new StandardSession(SPDY.V2, null, null, null, null, null, null, 1, null, null, null);
session.syn(new SynInfo(false), new StreamFrameListener.Adapter() session.syn(new SynInfo(new Fields(), false), new StreamFrameListener.Adapter()
{ {
// The good of passing the listener to syn() is that applications can safely // The good of passing the listener to push() is that applications can safely
// accumulate info from the reply headers to be used in the data callback, // accumulate info from the reply headers to be used in the data callback,
// e.g. content-type, charset, etc. // e.g. content-type, charset, etc.
@ -127,7 +152,14 @@ public class ClientUsageTest
stream.setAttribute("builder", new StringBuilder()); stream.setAttribute("builder", new StringBuilder());
// May issue another similar request while waiting for data // May issue another similar request while waiting for data
stream.getSession().syn(new SynInfo(true), this); try
{
stream.getSession().syn(new SynInfo(new Fields(), true), this);
}
catch (ExecutionException | InterruptedException | TimeoutException e)
{
throw new IllegalStateException(e);
}
} }
@Override @Override
@ -138,18 +170,18 @@ public class ClientUsageTest
if (dataInfo.isClose()) if (dataInfo.isClose())
{ {
int receivedLength = builder.toString().getBytes(Charset.forName("UTF-8")).length; int receivedLength = builder.toString().getBytes(Charset.forName("UTF-8")).length;
assert receivedLength == (Integer)stream.getAttribute("content-length"); assert receivedLength == stream.getAttribute("content-length");
} }
} }
}, 0, TimeUnit.MILLISECONDS, new Promise.Adapter<Stream>() }, new Promise.Adapter<Stream>()
{ {
@Override @Override
public void succeeded(Stream stream) public void succeeded(Stream stream)
{ {
stream.data(new BytesDataInfo("wee".getBytes(Charset.forName("UTF-8")), false)); stream.data(new BytesDataInfo("wee".getBytes(Charset.forName("UTF-8")), false), new Callback.Adapter());
stream.data(new StringDataInfo("foo", false)); stream.data(new StringDataInfo("foo", false), new Callback.Adapter());
stream.data(new ByteBufferDataInfo(Charset.forName("UTF-8").encode("bar"), true)); stream.data(new ByteBufferDataInfo(Charset.forName("UTF-8").encode("bar"), true), new Callback.Adapter());
} }
}); });
} }

View File

@ -18,8 +18,6 @@
package org.eclipse.jetty.spdy.api; package org.eclipse.jetty.spdy.api;
import java.util.concurrent.TimeUnit;
import junit.framework.Assert; import junit.framework.Assert;
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
@ -48,11 +46,11 @@ public class ServerUsageTest
Fields replyHeaders = new Fields(); Fields replyHeaders = new Fields();
replyHeaders.put(synHeaders.get("host")); replyHeaders.put(synHeaders.get("host"));
// Sends a reply // Sends a reply
stream.reply(new ReplyInfo(replyHeaders, false)); stream.reply(new ReplyInfo(replyHeaders, false), new Callback.Adapter());
// Sends data // Sends data
StringDataInfo dataInfo = new StringDataInfo("foo", false); StringDataInfo dataInfo = new StringDataInfo("foo", false);
stream.data(dataInfo); stream.data(dataInfo, new Callback.Adapter());
// Stream is now closed // Stream is now closed
return null; return null;
} }
@ -77,7 +75,7 @@ public class ServerUsageTest
// //
// However, the API may allow to initiate the stream // However, the API may allow to initiate the stream
session.syn(new SynInfo(false), null, 0, TimeUnit.MILLISECONDS, new Promise.Adapter<Stream>() session.syn(new SynInfo(new Fields(), false), null, new Promise.Adapter<Stream>()
{ {
@Override @Override
public void succeeded(Stream stream) public void succeeded(Stream stream)
@ -87,7 +85,7 @@ public class ServerUsageTest
// the client sends a rst frame. // the client sends a rst frame.
// We have to atomically set some flag on the stream to signal it's closed // We have to atomically set some flag on the stream to signal it's closed
// and any operation on it will throw // and any operation on it will throw
stream.headers(new HeadersInfo(new Fields(), true)); stream.headers(new HeadersInfo(new Fields(), true), new Callback.Adapter());
} }
}); });
} }
@ -104,16 +102,16 @@ public class ServerUsageTest
public StreamFrameListener onSyn(Stream stream, SynInfo streamInfo) public StreamFrameListener onSyn(Stream stream, SynInfo streamInfo)
{ {
// Need to send the reply first // Need to send the reply first
stream.reply(new ReplyInfo(false)); stream.reply(new ReplyInfo(false), new Callback.Adapter());
Session session = stream.getSession(); Session session = stream.getSession();
// Since it's unidirectional, no need to pass the listener // Since it's unidirectional, no need to pass the listener
session.syn(new SynInfo(new Fields(), false, (byte)0), null, 0, TimeUnit.MILLISECONDS, new Promise.Adapter<Stream>() session.syn(new SynInfo(new Fields(), false, (byte)0), null, new Promise.Adapter<Stream>()
{ {
@Override @Override
public void succeeded(Stream pushStream) public void succeeded(Stream pushStream)
{ {
pushStream.data(new StringDataInfo("foo", false)); pushStream.data(new StringDataInfo("foo", false), new Callback.Adapter());
} }
}); });
return null; return null;

View File

@ -134,7 +134,7 @@ public class HttpChannelOverSPDY extends HttpChannel<DataInfo>
// will be consumed. When the copy is consumed, we consume also the // will be consumed. When the copy is consumed, we consume also the
// original, so the implementation can send a window update. // original, so the implementation can send a window update.
ByteBuffer copyByteBuffer = dataInfo.asByteBuffer(false); ByteBuffer copyByteBuffer = dataInfo.asByteBuffer(false);
ByteBufferDataInfo copyDataInfo = new ByteBufferDataInfo(copyByteBuffer, dataInfo.isClose(), dataInfo.isCompress()) ByteBufferDataInfo copyDataInfo = new ByteBufferDataInfo(copyByteBuffer, dataInfo.isClose())
{ {
@Override @Override
public void consume(int delta) public void consume(int delta)

View File

@ -37,11 +37,11 @@ import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpTransport; import org.eclipse.jetty.server.HttpTransport;
import org.eclipse.jetty.spdy.StreamException; import org.eclipse.jetty.spdy.StreamException;
import org.eclipse.jetty.spdy.api.ByteBufferDataInfo; import org.eclipse.jetty.spdy.api.ByteBufferDataInfo;
import org.eclipse.jetty.spdy.api.PushInfo;
import org.eclipse.jetty.spdy.api.ReplyInfo; import org.eclipse.jetty.spdy.api.ReplyInfo;
import org.eclipse.jetty.spdy.api.SPDY; import org.eclipse.jetty.spdy.api.SPDY;
import org.eclipse.jetty.spdy.api.Stream; import org.eclipse.jetty.spdy.api.Stream;
import org.eclipse.jetty.spdy.api.StreamStatus; import org.eclipse.jetty.spdy.api.StreamStatus;
import org.eclipse.jetty.spdy.api.SynInfo;
import org.eclipse.jetty.util.BlockingCallback; import org.eclipse.jetty.util.BlockingCallback;
import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;
@ -68,7 +68,7 @@ public class HttpTransportOverSPDY implements HttpTransport
this.connector = connector; this.connector = connector;
this.configuration = configuration; this.configuration = configuration;
this.endPoint = endPoint; this.endPoint = endPoint;
this.pushStrategy = pushStrategy==null?new PushStrategy.None():pushStrategy; this.pushStrategy = pushStrategy == null ? new PushStrategy.None() : pushStrategy;
this.stream = stream; this.stream = stream;
this.requestHeaders = requestHeaders; this.requestHeaders = requestHeaders;
} }
@ -77,7 +77,7 @@ public class HttpTransportOverSPDY implements HttpTransport
public void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback) public void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback)
{ {
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("send {} {} {} {} last={}",this,stream,info,BufferUtil.toDetailString(content),lastContent); LOG.debug("send {} {} {} {} last={}", this, stream, info, BufferUtil.toDetailString(content), lastContent);
if (stream.isClosed() || stream.isReset()) if (stream.isClosed() || stream.isReset())
{ {
@ -98,9 +98,10 @@ public class HttpTransportOverSPDY implements HttpTransport
boolean hasContent = BufferUtil.hasContent(content); boolean hasContent = BufferUtil.hasContent(content);
if (info!=null) if (info != null)
{
if (!committed.compareAndSet(false, true))
{ {
if(!committed.compareAndSet(false, true)){
StreamException exception = new StreamException(stream.getId(), StreamStatus.PROTOCOL_ERROR, StreamException exception = new StreamException(stream.getId(), StreamStatus.PROTOCOL_ERROR,
"Stream already committed!"); "Stream already committed!");
callback.failed(exception); callback.failed(exception);
@ -138,7 +139,7 @@ public class HttpTransportOverSPDY implements HttpTransport
} }
boolean close = !hasContent && lastContent; boolean close = !hasContent && lastContent;
ReplyInfo reply = new ReplyInfo(headers,close); ReplyInfo reply = new ReplyInfo(headers, close);
reply(stream, reply); reply(stream, reply);
} }
@ -146,23 +147,25 @@ public class HttpTransportOverSPDY implements HttpTransport
if (hasContent) if (hasContent)
{ {
// Is the stream still open? // Is the stream still open?
if (stream.isClosed()|| stream.isReset()) if (stream.isClosed() || stream.isReset())
// tell the callback about the EOF // tell the callback about the EOF
callback.failed(new EofException("stream closed")); callback.failed(new EofException("stream closed"));
else else
// send the data and let it call the callback // send the data and let it call the callback
stream.data(new ByteBufferDataInfo(content, lastContent),endPoint.getIdleTimeout(),TimeUnit.MILLISECONDS,callback); stream.data(new ByteBufferDataInfo(endPoint.getIdleTimeout(), TimeUnit.MILLISECONDS, content, lastContent
), callback);
} }
// else do we need to close // else do we need to close
else if (lastContent) else if (lastContent)
{ {
// Are we closed ? // Are we closed ?
if (stream.isClosed()|| stream.isReset()) if (stream.isClosed() || stream.isReset())
// already closed by reply, so just tell callback we are complete // already closed by reply, so just tell callback we are complete
callback.succeeded(); callback.succeeded();
else else
// send empty data to close and let the send call the callback // send empty data to close and let the send call the callback
stream.data(new ByteBufferDataInfo(BufferUtil.EMPTY_BUFFER, lastContent),endPoint.getIdleTimeout(),TimeUnit.MILLISECONDS,callback); stream.data(new ByteBufferDataInfo(endPoint.getIdleTimeout(), TimeUnit.MILLISECONDS,
BufferUtil.EMPTY_BUFFER, lastContent), callback);
} }
else else
// No data and no close so tell callback we are completed // No data and no close so tell callback we are completed
@ -173,7 +176,7 @@ public class HttpTransportOverSPDY implements HttpTransport
@Override @Override
public void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent) throws EofException public void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent) throws EofException
{ {
send(info,content,lastContent,streamBlocker); send(info, content, lastContent, streamBlocker);
try try
{ {
streamBlocker.block(); streamBlocker.block();
@ -194,7 +197,7 @@ public class HttpTransportOverSPDY implements HttpTransport
private void reply(Stream stream, ReplyInfo replyInfo) private void reply(Stream stream, ReplyInfo replyInfo)
{ {
if (!stream.isUnidirectional()) if (!stream.isUnidirectional())
stream.reply(replyInfo); stream.reply(replyInfo, new Callback.Adapter());
Fields responseHeaders = replyInfo.getHeaders(); Fields responseHeaders = replyInfo.getHeaders();
short version = stream.getSession().getVersion(); short version = stream.getSession().getVersion();
@ -212,7 +215,7 @@ public class HttpTransportOverSPDY implements HttpTransport
final Fields pushRequestHeaders = createRequestHeaders(scheme, host, uri, pushResource); final Fields pushRequestHeaders = createRequestHeaders(scheme, host, uri, pushResource);
// TODO: handle the timeout better // TODO: handle the timeout better
stream.syn(new SynInfo(pushHeaders, false), 0, TimeUnit.MILLISECONDS, new Promise.Adapter<Stream>() stream.push(new PushInfo(0, TimeUnit.MILLISECONDS, pushHeaders, false), new Promise.Adapter<Stream>()
{ {
@Override @Override
public void succeeded(Stream pushStream) public void succeeded(Stream pushStream)

View File

@ -23,8 +23,8 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.jetty.spdy.api.GoAwayInfo; import org.eclipse.jetty.spdy.api.GoAwayReceivedInfo;
import org.eclipse.jetty.spdy.api.PingInfo; import org.eclipse.jetty.spdy.api.PingResultInfo;
import org.eclipse.jetty.spdy.api.RstInfo; import org.eclipse.jetty.spdy.api.RstInfo;
import org.eclipse.jetty.spdy.api.Session; import org.eclipse.jetty.spdy.api.Session;
import org.eclipse.jetty.spdy.api.Stream; import org.eclipse.jetty.spdy.api.Stream;
@ -33,14 +33,15 @@ import org.eclipse.jetty.spdy.api.StreamStatus;
import org.eclipse.jetty.spdy.api.SynInfo; import org.eclipse.jetty.spdy.api.SynInfo;
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
import org.eclipse.jetty.spdy.server.http.HTTPSPDYHeader; import org.eclipse.jetty.spdy.server.http.HTTPSPDYHeader;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
/** /**
* <p>{@link ProxyEngineSelector} is the main entry point for syn stream events of a jetty SPDY proxy. It receives the * <p>{@link ProxyEngineSelector} is the main entry point for push stream events of a jetty SPDY proxy. It receives the
* syn stream frames from the clients, checks if there's an appropriate {@link ProxyServerInfo} for the given target * push stream frames from the clients, checks if there's an appropriate {@link ProxyServerInfo} for the given target
* host and forwards the syn to a {@link ProxyEngine} for the protocol defined in {@link ProxyServerInfo}.</p> * host and forwards the push to a {@link ProxyEngine} for the protocol defined in {@link ProxyServerInfo}.</p>
* *
* <p>If no {@link ProxyServerInfo} can be found for the given target host or no {@link ProxyEngine} can be found for * <p>If no {@link ProxyServerInfo} can be found for the given target host or no {@link ProxyEngine} can be found for
* the given protocol, it resets the client stream.</p> * the given protocol, it resets the client stream.</p>
@ -96,14 +97,14 @@ public class ProxyEngineSelector extends ServerSessionFrameListener.Adapter
} }
@Override @Override
public void onPing(Session clientSession, PingInfo pingInfo) public void onPing(Session clientSession, PingResultInfo pingResultInfo)
{ {
// We do not know to which upstream server // We do not know to which upstream server
// to send the PING so we just ignore it // to send the PING so we just ignore it
} }
@Override @Override
public void onGoAway(Session session, GoAwayInfo goAwayInfo) public void onGoAway(Session session, GoAwayReceivedInfo goAwayReceivedInfo)
{ {
// TODO: // TODO:
} }
@ -153,7 +154,7 @@ public class ProxyEngineSelector extends ServerSessionFrameListener.Adapter
private void rst(Stream stream) private void rst(Stream stream)
{ {
RstInfo rstInfo = new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM); RstInfo rstInfo = new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM);
stream.getSession().rst(rstInfo); stream.getSession().rst(rstInfo, new Callback.Adapter());
} }
public static class ProxyServerInfo public static class ProxyServerInfo

View File

@ -20,8 +20,6 @@ package org.eclipse.jetty.spdy.server.proxy;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -44,7 +42,9 @@ import org.eclipse.jetty.spdy.StandardStream;
import org.eclipse.jetty.spdy.api.ByteBufferDataInfo; import org.eclipse.jetty.spdy.api.ByteBufferDataInfo;
import org.eclipse.jetty.spdy.api.DataInfo; import org.eclipse.jetty.spdy.api.DataInfo;
import org.eclipse.jetty.spdy.api.GoAwayInfo; import org.eclipse.jetty.spdy.api.GoAwayInfo;
import org.eclipse.jetty.spdy.api.GoAwayReceivedInfo;
import org.eclipse.jetty.spdy.api.HeadersInfo; import org.eclipse.jetty.spdy.api.HeadersInfo;
import org.eclipse.jetty.spdy.api.PushInfo;
import org.eclipse.jetty.spdy.api.ReplyInfo; import org.eclipse.jetty.spdy.api.ReplyInfo;
import org.eclipse.jetty.spdy.api.RstInfo; import org.eclipse.jetty.spdy.api.RstInfo;
import org.eclipse.jetty.spdy.api.SessionStatus; import org.eclipse.jetty.spdy.api.SessionStatus;
@ -135,7 +135,7 @@ public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParse
{ {
assert content == null; assert content == null;
if (headers.isEmpty()) if (headers.isEmpty())
proxyEngineSelector.onGoAway(session, new GoAwayInfo(0, SessionStatus.OK)); proxyEngineSelector.onGoAway(session, new GoAwayReceivedInfo(0, SessionStatus.OK));
else else
syn(true); syn(true);
} }
@ -184,14 +184,14 @@ public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParse
} }
@Override @Override
public void rst(RstInfo rstInfo, long timeout, TimeUnit unit, Callback handler) public void rst(RstInfo rstInfo, Callback handler)
{ {
// Not much we can do in HTTP land: just close the connection // Not much we can do in HTTP land: just close the connection
goAway(timeout, unit, handler); goAway(new GoAwayInfo(rstInfo.getTimeout(), rstInfo.getUnit()), handler);
} }
@Override @Override
public void goAway(long timeout, TimeUnit unit, Callback handler) public void goAway(GoAwayInfo goAwayInfo, Callback handler)
{ {
getEndPoint().close(); getEndPoint().close();
handler.succeeded(); handler.succeeded();
@ -211,21 +211,21 @@ public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParse
} }
@Override @Override
public void syn(SynInfo synInfo, long timeout, TimeUnit unit, Promise<Stream> handler) public void push(PushInfo pushInfo, Promise<Stream> handler)
{ {
// HTTP does not support pushed streams // HTTP does not support pushed streams
handler.succeeded(new HTTPPushStream(2, getPriority(), getSession(), this)); handler.succeeded(new HTTPPushStream(2, getPriority(), getSession(), this));
} }
@Override @Override
public void headers(HeadersInfo headersInfo, long timeout, TimeUnit unit, Callback handler) public void headers(HeadersInfo headersInfo, Callback handler)
{ {
// TODO // TODO
throw new UnsupportedOperationException("Not Yet Implemented"); throw new UnsupportedOperationException("Not Yet Implemented");
} }
@Override @Override
public void reply(ReplyInfo replyInfo, long timeout, TimeUnit unit, Callback handler) public void reply(ReplyInfo replyInfo, Callback handler)
{ {
try try
{ {
@ -284,7 +284,7 @@ public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParse
} }
@Override @Override
public void data(DataInfo dataInfo, long timeout, TimeUnit unit, Callback handler) public void data(DataInfo dataInfo, Callback handler)
{ {
try try
{ {
@ -313,14 +313,14 @@ public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParse
} }
@Override @Override
public void headers(HeadersInfo headersInfo, long timeout, TimeUnit unit, Callback handler) public void headers(HeadersInfo headersInfo, Callback handler)
{ {
// Ignore pushed headers // Ignore pushed headers
handler.succeeded(); handler.succeeded();
} }
@Override @Override
public void data(DataInfo dataInfo, long timeout, TimeUnit unit, Callback handler) public void data(DataInfo dataInfo, Callback handler)
{ {
// Ignore pushed data // Ignore pushed data
handler.succeeded(); handler.succeeded();

View File

@ -29,7 +29,9 @@ import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.spdy.api.ByteBufferDataInfo; import org.eclipse.jetty.spdy.api.ByteBufferDataInfo;
import org.eclipse.jetty.spdy.api.DataInfo; import org.eclipse.jetty.spdy.api.DataInfo;
import org.eclipse.jetty.spdy.api.GoAwayInfo; import org.eclipse.jetty.spdy.api.GoAwayInfo;
import org.eclipse.jetty.spdy.api.GoAwayReceivedInfo;
import org.eclipse.jetty.spdy.api.HeadersInfo; import org.eclipse.jetty.spdy.api.HeadersInfo;
import org.eclipse.jetty.spdy.api.PushInfo;
import org.eclipse.jetty.spdy.api.ReplyInfo; import org.eclipse.jetty.spdy.api.ReplyInfo;
import org.eclipse.jetty.spdy.api.RstInfo; import org.eclipse.jetty.spdy.api.RstInfo;
import org.eclipse.jetty.spdy.api.SPDY; import org.eclipse.jetty.spdy.api.SPDY;
@ -108,7 +110,7 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
StreamFrameListener listener = new ProxyStreamFrameListener(clientStream); StreamFrameListener listener = new ProxyStreamFrameListener(clientStream);
StreamHandler handler = new StreamHandler(clientStream, serverSynInfo); StreamHandler handler = new StreamHandler(clientStream, serverSynInfo);
clientStream.setAttribute(STREAM_HANDLER_ATTRIBUTE, handler); clientStream.setAttribute(STREAM_HANDLER_ATTRIBUTE, handler);
serverSession.syn(serverSynInfo, listener, timeout, TimeUnit.MILLISECONDS, handler); serverSession.syn(serverSynInfo, listener, handler);
return this; return this;
} }
@ -170,7 +172,7 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
Session existing = serverSessions.putIfAbsent(host, session); Session existing = serverSessions.putIfAbsent(host, session);
if (existing != null) if (existing != null)
{ {
session.goAway(getTimeout(), TimeUnit.MILLISECONDS, new Callback.Adapter()); session.goAway(new GoAwayInfo(), new Callback.Adapter());
session = existing; session = existing;
} }
} }
@ -203,7 +205,7 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
private void rst(Stream stream) private void rst(Stream stream)
{ {
RstInfo rstInfo = new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM); RstInfo rstInfo = new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM);
stream.getSession().rst(rstInfo, getTimeout(), TimeUnit.MILLISECONDS, new Callback.Adapter()); stream.getSession().rst(rstInfo, new Callback.Adapter());
} }
private class ProxyStreamFrameListener extends StreamFrameListener.Adapter private class ProxyStreamFrameListener extends StreamFrameListener.Adapter
@ -259,7 +261,7 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
{ {
final ReplyInfo replyInfo = this.replyInfo; final ReplyInfo replyInfo = this.replyInfo;
this.replyInfo = null; this.replyInfo = null;
clientStream.reply(replyInfo, getTimeout(), TimeUnit.MILLISECONDS, new Callback() clientStream.reply(replyInfo, new Callback()
{ {
@Override @Override
public void succeeded() public void succeeded()
@ -278,7 +280,7 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
private void data(final Stream stream, final DataInfo dataInfo) private void data(final Stream stream, final DataInfo dataInfo)
{ {
clientStream.data(dataInfo, getTimeout(), TimeUnit.MILLISECONDS, new Callback() clientStream.data(dataInfo, new Callback() //TODO: timeout???
{ {
@Override @Override
public void succeeded() public void succeeded()
@ -394,7 +396,7 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
private void flush(Stream serverStream, DataInfoHandler dataInfoHandler) private void flush(Stream serverStream, DataInfoHandler dataInfoHandler)
{ {
logger.debug("P -> S {} on {}", dataInfoHandler.dataInfo, serverStream); logger.debug("P -> S {} on {}", dataInfoHandler.dataInfo, serverStream);
serverStream.data(dataInfoHandler.dataInfo, getTimeout(), TimeUnit.MILLISECONDS,dataInfoHandler); serverStream.data(dataInfoHandler.dataInfo, dataInfoHandler); //TODO: timeout???
} }
private class DataInfoHandler implements Callback private class DataInfoHandler implements Callback
@ -459,8 +461,8 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
StreamHandler handler = new StreamHandler(clientStream, serverSynInfo); StreamHandler handler = new StreamHandler(clientStream, serverSynInfo);
serverStream.setAttribute(STREAM_HANDLER_ATTRIBUTE, handler); serverStream.setAttribute(STREAM_HANDLER_ATTRIBUTE, handler);
clientStream.syn(new SynInfo(headers, serverSynInfo.isClose()), getTimeout(), TimeUnit.MILLISECONDS, handler); clientStream.push(new PushInfo(getTimeout(), TimeUnit.MILLISECONDS, headers, serverSynInfo.isClose()),
handler);
return this; return this;
} }
@ -475,13 +477,13 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
{ {
Session clientSession = clientStream.getSession(); Session clientSession = clientStream.getSession();
RstInfo clientRstInfo = new RstInfo(clientStream.getId(), serverRstInfo.getStreamStatus()); RstInfo clientRstInfo = new RstInfo(clientStream.getId(), serverRstInfo.getStreamStatus());
clientSession.rst(clientRstInfo, getTimeout(), TimeUnit.MILLISECONDS, new Callback.Adapter()); clientSession.rst(clientRstInfo, new Callback.Adapter());
} }
} }
} }
@Override @Override
public void onGoAway(Session serverSession, GoAwayInfo goAwayInfo) public void onGoAway(Session serverSession, GoAwayReceivedInfo goAwayReceivedInfo)
{ {
serverSessions.values().remove(serverSession); serverSessions.values().remove(serverSession);
} }

View File

@ -21,7 +21,6 @@ package org.eclipse.jetty.spdy.server.http;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Random; import java.util.Random;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.http.HttpGenerator; import org.eclipse.jetty.http.HttpGenerator;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;
@ -49,7 +48,6 @@ import org.mockito.runners.MockitoJUnitRunner;
import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ -97,7 +95,7 @@ public class HttpTransportOverSPDYTest
httpTransportOverSPDY.send(null, content, lastContent, callback); httpTransportOverSPDY.send(null, content, lastContent, callback);
ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class); ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class);
verify(stream, times(1)).data(dataInfoCaptor.capture(), anyLong(), any(TimeUnit.class), any(Callback.class)); verify(stream, times(1)).data(dataInfoCaptor.capture(), any(Callback.class));
assertThat("lastContent is true", dataInfoCaptor.getValue().isClose(), is(true)); assertThat("lastContent is true", dataInfoCaptor.getValue().isClose(), is(true));
assertThat("ByteBuffer is empty", dataInfoCaptor.getValue().length(), is(0)); assertThat("ByteBuffer is empty", dataInfoCaptor.getValue().length(), is(0));
} }
@ -109,10 +107,9 @@ public class HttpTransportOverSPDYTest
boolean lastContent = true; boolean lastContent = true;
httpTransportOverSPDY.send(null, content, lastContent, callback); httpTransportOverSPDY.send(null, content, lastContent, callback);
ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class); ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class);
verify(stream, times(1)).data(dataInfoCaptor.capture(), anyLong(), any(TimeUnit.class), any(Callback.class)); verify(stream, times(1)).data(dataInfoCaptor.capture(), any(Callback.class));
assertThat("lastContent is true", dataInfoCaptor.getValue().isClose(), is(true)); assertThat("lastContent is true", dataInfoCaptor.getValue().isClose(), is(true));
assertThat("ByteBuffer length is 4096", dataInfoCaptor.getValue().length(), is(4096)); assertThat("ByteBuffer length is 4096", dataInfoCaptor.getValue().length(), is(4096));
} }
@ -126,7 +123,7 @@ public class HttpTransportOverSPDYTest
httpTransportOverSPDY.send(null, content, lastContent, callback); httpTransportOverSPDY.send(null, content, lastContent, callback);
ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class); ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class);
verify(stream, times(1)).data(dataInfoCaptor.capture(), anyLong(), any(TimeUnit.class), any(Callback.class)); verify(stream, times(1)).data(dataInfoCaptor.capture(), any(Callback.class));
assertThat("lastContent is true", dataInfoCaptor.getValue().isClose(), is(true)); assertThat("lastContent is true", dataInfoCaptor.getValue().isClose(), is(true));
assertThat("ByteBuffer is empty", dataInfoCaptor.getValue().length(), is(0)); assertThat("ByteBuffer is empty", dataInfoCaptor.getValue().length(), is(0));
} }
@ -139,7 +136,7 @@ public class HttpTransportOverSPDYTest
httpTransportOverSPDY.send(null, content, lastContent, callback); httpTransportOverSPDY.send(null, content, lastContent, callback);
verify(stream, times(0)).data(any(ByteBufferDataInfo.class), anyLong(), any(TimeUnit.class), any(Callback.class)); verify(stream, times(0)).data(any(ByteBufferDataInfo.class), any(Callback.class));
} }
@Test @Test
@ -151,7 +148,7 @@ public class HttpTransportOverSPDYTest
httpTransportOverSPDY.send(null, content, lastContent, callback); httpTransportOverSPDY.send(null, content, lastContent, callback);
ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class); ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class);
verify(stream, times(1)).data(dataInfoCaptor.capture(), anyLong(), any(TimeUnit.class), any(Callback.class)); verify(stream, times(1)).data(dataInfoCaptor.capture(), any(Callback.class));
assertThat("lastContent is false", dataInfoCaptor.getValue().isClose(), is(false)); assertThat("lastContent is false", dataInfoCaptor.getValue().isClose(), is(false));
assertThat("ByteBuffer is empty", dataInfoCaptor.getValue().length(), is(4096)); assertThat("ByteBuffer is empty", dataInfoCaptor.getValue().length(), is(4096));
} }
@ -164,7 +161,7 @@ public class HttpTransportOverSPDYTest
httpTransportOverSPDY.send(null, content, lastContent, callback); httpTransportOverSPDY.send(null, content, lastContent, callback);
verify(stream, times(0)).data(any(ByteBufferDataInfo.class), anyLong(), any(TimeUnit.class), any(Callback.class)); verify(stream, times(0)).data(any(ByteBufferDataInfo.class), any(Callback.class));
verify(callback, times(1)).succeeded(); verify(callback, times(1)).succeeded();
} }
@ -179,7 +176,7 @@ public class HttpTransportOverSPDYTest
httpTransportOverSPDY.send(responseInfo, content, lastContent, callback); httpTransportOverSPDY.send(responseInfo, content, lastContent, callback);
ArgumentCaptor<ReplyInfo> replyInfoCaptor = ArgumentCaptor.forClass(ReplyInfo.class); ArgumentCaptor<ReplyInfo> replyInfoCaptor = ArgumentCaptor.forClass(ReplyInfo.class);
verify(stream, times(1)).reply(replyInfoCaptor.capture()); verify(stream, times(1)).reply(replyInfoCaptor.capture(), any(Callback.class));
assertThat("ReplyInfo close is true", replyInfoCaptor.getValue().isClose(), is(true)); assertThat("ReplyInfo close is true", replyInfoCaptor.getValue().isClose(), is(true));
verify(callback, times(1)).succeeded(); verify(callback, times(1)).succeeded();
@ -196,11 +193,11 @@ public class HttpTransportOverSPDYTest
httpTransportOverSPDY.send(responseInfo, content, lastContent, callback); httpTransportOverSPDY.send(responseInfo, content, lastContent, callback);
ArgumentCaptor<ReplyInfo> replyInfoCaptor = ArgumentCaptor.forClass(ReplyInfo.class); ArgumentCaptor<ReplyInfo> replyInfoCaptor = ArgumentCaptor.forClass(ReplyInfo.class);
verify(stream, times(1)).reply(replyInfoCaptor.capture()); verify(stream, times(1)).reply(replyInfoCaptor.capture(), any(Callback.class));
assertThat("ReplyInfo close is false", replyInfoCaptor.getValue().isClose(), is(false)); assertThat("ReplyInfo close is false", replyInfoCaptor.getValue().isClose(), is(false));
ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class); ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class);
verify(stream, times(1)).data(dataInfoCaptor.capture(), anyLong(), any(TimeUnit.class), any(Callback.class)); verify(stream, times(1)).data(dataInfoCaptor.capture(), any(Callback.class));
assertThat("lastContent is true", dataInfoCaptor.getValue().isClose(), is(true)); assertThat("lastContent is true", dataInfoCaptor.getValue().isClose(), is(true));
assertThat("ByteBuffer length is 4096", dataInfoCaptor.getValue().length(), is(4096)); assertThat("ByteBuffer length is 4096", dataInfoCaptor.getValue().length(), is(4096));
} }
@ -214,10 +211,10 @@ public class HttpTransportOverSPDYTest
httpTransportOverSPDY.send(responseInfo, content, lastContent, callback); httpTransportOverSPDY.send(responseInfo, content, lastContent, callback);
ArgumentCaptor<ReplyInfo> replyInfoCaptor = ArgumentCaptor.forClass(ReplyInfo.class); ArgumentCaptor<ReplyInfo> replyInfoCaptor = ArgumentCaptor.forClass(ReplyInfo.class);
verify(stream, times(1)).reply(replyInfoCaptor.capture()); verify(stream, times(1)).reply(replyInfoCaptor.capture(), any(Callback.class));
assertThat("ReplyInfo close is true", replyInfoCaptor.getValue().isClose(), is(false)); assertThat("ReplyInfo close is true", replyInfoCaptor.getValue().isClose(), is(false));
verify(stream, times(0)).data(any(ByteBufferDataInfo.class), anyLong(), any(TimeUnit.class), any(Callback.class)); verify(stream, times(0)).data(any(ByteBufferDataInfo.class), any(Callback.class));
} }
@Test @Test
@ -230,11 +227,11 @@ public class HttpTransportOverSPDYTest
httpTransportOverSPDY.send(responseInfo, content, lastContent, callback); httpTransportOverSPDY.send(responseInfo, content, lastContent, callback);
ArgumentCaptor<ReplyInfo> replyInfoCaptor = ArgumentCaptor.forClass(ReplyInfo.class); ArgumentCaptor<ReplyInfo> replyInfoCaptor = ArgumentCaptor.forClass(ReplyInfo.class);
verify(stream, times(1)).reply(replyInfoCaptor.capture()); verify(stream, times(1)).reply(replyInfoCaptor.capture(), any(Callback.class));
assertThat("ReplyInfo close is false", replyInfoCaptor.getValue().isClose(), is(false)); assertThat("ReplyInfo close is false", replyInfoCaptor.getValue().isClose(), is(false));
ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class); ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class);
verify(stream, times(1)).data(dataInfoCaptor.capture(), anyLong(), any(TimeUnit.class), any(Callback.class)); verify(stream, times(1)).data(dataInfoCaptor.capture(), any(Callback.class));
assertThat("lastContent is false", dataInfoCaptor.getValue().isClose(), is(false)); assertThat("lastContent is false", dataInfoCaptor.getValue().isClose(), is(false));
assertThat("ByteBuffer length is 4096", dataInfoCaptor.getValue().length(), is(4096)); assertThat("ByteBuffer length is 4096", dataInfoCaptor.getValue().length(), is(4096));
} }
@ -248,13 +245,12 @@ public class HttpTransportOverSPDYTest
httpTransportOverSPDY.send(responseInfo,content,lastContent, callback); httpTransportOverSPDY.send(responseInfo,content,lastContent, callback);
ArgumentCaptor<ReplyInfo> replyInfoCaptor = ArgumentCaptor.forClass(ReplyInfo.class); ArgumentCaptor<ReplyInfo> replyInfoCaptor = ArgumentCaptor.forClass(ReplyInfo.class);
verify(stream, times(1)).reply(replyInfoCaptor.capture()); verify(stream, times(1)).reply(replyInfoCaptor.capture(), any(Callback.class));
assertThat("ReplyInfo close is false", replyInfoCaptor.getValue().isClose(), is(false)); assertThat("ReplyInfo close is false", replyInfoCaptor.getValue().isClose(), is(false));
httpTransportOverSPDY.send(HttpGenerator.RESPONSE_500_INFO, null,true); httpTransportOverSPDY.send(HttpGenerator.RESPONSE_500_INFO, null,true);
verify(stream, times(0)).data(any(DataInfo.class)); verify(stream, times(1)).data(any(DataInfo.class), any(Callback.class));
verify(stream, times(1)).data(any(DataInfo.class), anyLong(), any(TimeUnit.class), any(Callback.class));
((StdErrLog)Log.getLogger(HttpTransportOverSPDY.class)).setHideStacks(false); ((StdErrLog)Log.getLogger(HttpTransportOverSPDY.class)).setHideStacks(false);
} }

View File

@ -43,6 +43,7 @@ import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.spdy.api.DataInfo; import org.eclipse.jetty.spdy.api.DataInfo;
import org.eclipse.jetty.spdy.api.GoAwayInfo;
import org.eclipse.jetty.spdy.api.SPDY; import org.eclipse.jetty.spdy.api.SPDY;
import org.eclipse.jetty.spdy.api.Session; import org.eclipse.jetty.spdy.api.Session;
import org.eclipse.jetty.spdy.api.SessionFrameListener; import org.eclipse.jetty.spdy.api.SessionFrameListener;
@ -97,7 +98,7 @@ public class PushStrategyBenchmarkTest extends AbstractHTTPSPDYTest
connector.setDefaultProtocol(factory.getProtocol()); connector.setDefaultProtocol(factory.getProtocol());
Session session = startClient(version, address, new ClientSessionFrameListener()); Session session = startClient(version, address, new ClientSessionFrameListener());
benchmarkSPDY(pushStrategy, session); benchmarkSPDY(pushStrategy, session);
session.goAway().get(5, TimeUnit.SECONDS); session.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
// Second push strategy // Second push strategy
pushStrategy = new ReferrerPushStrategy(); pushStrategy = new ReferrerPushStrategy();
@ -105,7 +106,7 @@ public class PushStrategyBenchmarkTest extends AbstractHTTPSPDYTest
connector.setDefaultProtocol(factory.getProtocol()); connector.setDefaultProtocol(factory.getProtocol());
session = startClient(version, address, new ClientSessionFrameListener()); session = startClient(version, address, new ClientSessionFrameListener());
benchmarkSPDY(pushStrategy, session); benchmarkSPDY(pushStrategy, session);
session.goAway().get(5, TimeUnit.SECONDS); session.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
} }
private void benchmarkHTTP(HttpClient httpClient) throws Exception private void benchmarkHTTP(HttpClient httpClient) throws Exception

View File

@ -43,7 +43,9 @@ import org.eclipse.jetty.spdy.api.StreamFrameListener;
import org.eclipse.jetty.spdy.api.StreamStatus; import org.eclipse.jetty.spdy.api.StreamStatus;
import org.eclipse.jetty.spdy.api.SynInfo; import org.eclipse.jetty.spdy.api.SynInfo;
import org.eclipse.jetty.spdy.server.NPNServerConnectionFactory; import org.eclipse.jetty.spdy.server.NPNServerConnectionFactory;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.Promise;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -117,7 +119,7 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
("" + ("" +
".css"), ".css"),
is(true)); is(true));
stream.getSession().rst(new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM)); stream.getSession().rst(new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM), new Callback.Adapter());
return new StreamFrameListener.Adapter() return new StreamFrameListener.Adapter()
{ {
@ -130,11 +132,11 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
}; };
} }
}); });
// Send main request. That should initiate the push syn's which get reset by the client // Send main request. That should initiate the push push's which get reset by the client
sendRequest(session, mainRequestHeaders); sendRequest(session, mainRequestHeaders);
assertThat("No push data is received", pushDataLatch.await(1, TimeUnit.SECONDS), is(false)); assertThat("No push data is received", pushDataLatch.await(1, TimeUnit.SECONDS), is(false));
assertThat("Push syn headers valid", pushSynHeadersValid.await(5, TimeUnit.SECONDS), is(true)); assertThat("Push push headers valid", pushSynHeadersValid.await(5, TimeUnit.SECONDS), is(true));
sendRequest(session, associatedCSSRequestHeaders); sendRequest(session, associatedCSSRequestHeaders);
} }
@ -224,7 +226,7 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
if (dataInfo.isClose()) if (dataInfo.isClose())
dataReceivedLatch.countDown(); dataReceivedLatch.countDown();
} }
}); }, new Promise.Adapter<Stream>());
Assert.assertTrue(received200OKLatch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(received200OKLatch.await(5, TimeUnit.SECONDS));
Assert.assertTrue(dataReceivedLatch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(dataReceivedLatch.await(5, TimeUnit.SECONDS));
} }
@ -286,7 +288,7 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
else else
assertThat("No push data is received", pushDataLatch.await(1, TimeUnit.SECONDS), is(false)); assertThat("No push data is received", pushDataLatch.await(1, TimeUnit.SECONDS), is(false));
if (validateHeaders) if (validateHeaders)
assertThat("Push syn headers valid", pushSynHeadersValid.await(5, TimeUnit.SECONDS), is(true)); assertThat("Push push headers valid", pushSynHeadersValid.await(5, TimeUnit.SECONDS), is(true));
} }
@Test @Test

View File

@ -202,7 +202,8 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
Fields headers = createHeaders("POST", path); Fields headers = createHeaders("POST", path);
headers.put("content-type", "application/x-www-form-urlencoded"); headers.put("content-type", "application/x-www-form-urlencoded");
final CountDownLatch replyLatch = new CountDownLatch(1); final CountDownLatch replyLatch = new CountDownLatch(1);
Stream stream = session.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter() Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0),
new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onReply(Stream stream, ReplyInfo replyInfo) public void onReply(Stream stream, ReplyInfo replyInfo)
@ -212,7 +213,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).value().contains("200")); Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).value().contains("200"));
replyLatch.countDown(); replyLatch.countDown();
} }
}).get(5, TimeUnit.SECONDS); });
stream.data(new StringDataInfo(data, true)); stream.data(new StringDataInfo(data, true));
Assert.assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(handlerLatch.await(5, TimeUnit.SECONDS));
@ -243,7 +244,8 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
Fields headers = createHeaders("POST", path); Fields headers = createHeaders("POST", path);
headers.put("content-type", "application/x-www-form-urlencoded"); headers.put("content-type", "application/x-www-form-urlencoded");
final CountDownLatch replyLatch = new CountDownLatch(1); final CountDownLatch replyLatch = new CountDownLatch(1);
Stream stream = session.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter() Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0),
new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onReply(Stream stream, ReplyInfo replyInfo) public void onReply(Stream stream, ReplyInfo replyInfo)
@ -253,7 +255,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).value().contains("200")); Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).value().contains("200"));
replyLatch.countDown(); replyLatch.countDown();
} }
}).get(5, TimeUnit.SECONDS); });
// Sleep between the data frames so that they will be read in 2 reads // Sleep between the data frames so that they will be read in 2 reads
stream.data(new StringDataInfo(data1, false)); stream.data(new StringDataInfo(data1, false));
Thread.sleep(1000); Thread.sleep(1000);
@ -287,7 +289,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
Fields headers = createHeaders("POST", path); Fields headers = createHeaders("POST", path);
headers.put("content-type", "application/x-www-form-urlencoded"); headers.put("content-type", "application/x-www-form-urlencoded");
final CountDownLatch replyLatch = new CountDownLatch(1); final CountDownLatch replyLatch = new CountDownLatch(1);
Stream stream = session.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter() Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onReply(Stream stream, ReplyInfo replyInfo) public void onReply(Stream stream, ReplyInfo replyInfo)
@ -297,7 +299,8 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
Assert.assertTrue(replyHeaders.toString(), replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).value().contains("200")); Assert.assertTrue(replyHeaders.toString(), replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).value().contains("200"));
replyLatch.countDown(); replyLatch.countDown();
} }
}).get(5, TimeUnit.SECONDS); });
// Send the data frames consecutively, so the server reads both frames in one read // Send the data frames consecutively, so the server reads both frames in one read
stream.data(new StringDataInfo(data1, false)); stream.data(new StringDataInfo(data1, false));
stream.data(new StringDataInfo(data2, true)); stream.data(new StringDataInfo(data2, true));
@ -1034,7 +1037,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
Fields headers = createHeaders("POST", "/foo"); Fields headers = createHeaders("POST", "/foo");
final CountDownLatch replyLatch = new CountDownLatch(1); final CountDownLatch replyLatch = new CountDownLatch(1);
Stream stream = session.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter() Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onReply(Stream stream, ReplyInfo replyInfo) public void onReply(Stream stream, ReplyInfo replyInfo)
@ -1043,7 +1046,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).value().contains("200")); Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).value().contains("200"));
replyLatch.countDown(); replyLatch.countDown();
} }
}).get(5, TimeUnit.SECONDS); });
stream.data(new BytesDataInfo(data, true)); stream.data(new BytesDataInfo(data, true));
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
@ -1077,7 +1080,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
Fields headers = createHeaders("POST", "/foo"); Fields headers = createHeaders("POST", "/foo");
final CountDownLatch replyLatch = new CountDownLatch(1); final CountDownLatch replyLatch = new CountDownLatch(1);
session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, true, (byte)0), new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onReply(Stream stream, ReplyInfo replyInfo) public void onReply(Stream stream, ReplyInfo replyInfo)
@ -1086,7 +1089,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).value().contains("200")); Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).value().contains("200"));
replyLatch.countDown(); replyLatch.countDown();
} }
}).get(5, TimeUnit.SECONDS); });
Assert.assertTrue("Not dispatched again after expire", dispatchedAgainAfterExpire.await(5, Assert.assertTrue("Not dispatched again after expire", dispatchedAgainAfterExpire.await(5,
TimeUnit.SECONDS)); TimeUnit.SECONDS));
@ -1122,7 +1125,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
Fields headers = createHeaders("POST", "/foo"); Fields headers = createHeaders("POST", "/foo");
final CountDownLatch replyLatch = new CountDownLatch(1); final CountDownLatch replyLatch = new CountDownLatch(1);
Stream stream = session.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter() Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onReply(Stream stream, ReplyInfo replyInfo) public void onReply(Stream stream, ReplyInfo replyInfo)
@ -1131,7 +1134,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).value().contains("200")); Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).value().contains("200"));
replyLatch.countDown(); replyLatch.countDown();
} }
}).get(5, TimeUnit.SECONDS); });
stream.data(new BytesDataInfo(data, true)); stream.data(new BytesDataInfo(data, true));
Assert.assertTrue("Not dispatched again after expire", dispatchedAgainAfterExpire.await(5, Assert.assertTrue("Not dispatched again after expire", dispatchedAgainAfterExpire.await(5,
@ -1190,7 +1193,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
Fields headers = createHeaders("POST", "/foo"); Fields headers = createHeaders("POST", "/foo");
final CountDownLatch replyLatch = new CountDownLatch(1); final CountDownLatch replyLatch = new CountDownLatch(1);
Stream stream = session.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter() Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onReply(Stream stream, ReplyInfo replyInfo) public void onReply(Stream stream, ReplyInfo replyInfo)
@ -1199,7 +1202,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).value().contains("200")); Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).value().contains("200"));
replyLatch.countDown(); replyLatch.countDown();
} }
}).get(5, TimeUnit.SECONDS); });
stream.data(new BytesDataInfo(data, false)); stream.data(new BytesDataInfo(data, false));
stream.data(new BytesDataInfo(data, true)); stream.data(new BytesDataInfo(data, true));
@ -1258,7 +1261,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
Fields headers = createHeaders("POST", "/foo"); Fields headers = createHeaders("POST", "/foo");
final CountDownLatch responseLatch = new CountDownLatch(2); final CountDownLatch responseLatch = new CountDownLatch(2);
Stream stream = session.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter() Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onReply(Stream stream, ReplyInfo replyInfo) public void onReply(Stream stream, ReplyInfo replyInfo)
@ -1274,7 +1277,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
if (dataInfo.isClose()) if (dataInfo.isClose())
responseLatch.countDown(); responseLatch.countDown();
} }
}).get(5, TimeUnit.SECONDS); });
stream.data(new BytesDataInfo(data, true)); stream.data(new BytesDataInfo(data, true));
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
@ -1299,7 +1302,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
Fields headers = createHeaders("POST", "/foo"); Fields headers = createHeaders("POST", "/foo");
final CountDownLatch responseLatch = new CountDownLatch(1); final CountDownLatch responseLatch = new CountDownLatch(1);
Stream stream = session.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter() Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onReply(Stream stream, ReplyInfo replyInfo) public void onReply(Stream stream, ReplyInfo replyInfo)
@ -1308,9 +1311,9 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).value().contains("200")); Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).value().contains("200"));
responseLatch.countDown(); responseLatch.countDown();
} }
}).get(5, TimeUnit.SECONDS); });
stream.data(new BytesDataInfo(data, false)); stream.data(new BytesDataInfo(data, false));
stream.data(new BytesDataInfo(data, true)).get(5, TimeUnit.SECONDS); stream.data(new BytesDataInfo(5, TimeUnit.SECONDS, data, true));
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
Assert.assertTrue(responseLatch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(responseLatch.await(5, TimeUnit.SECONDS));

View File

@ -35,7 +35,10 @@ import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.spdy.api.BytesDataInfo; import org.eclipse.jetty.spdy.api.BytesDataInfo;
import org.eclipse.jetty.spdy.api.DataInfo; import org.eclipse.jetty.spdy.api.DataInfo;
import org.eclipse.jetty.spdy.api.GoAwayInfo; import org.eclipse.jetty.spdy.api.GoAwayInfo;
import org.eclipse.jetty.spdy.api.GoAwayReceivedInfo;
import org.eclipse.jetty.spdy.api.PingInfo; import org.eclipse.jetty.spdy.api.PingInfo;
import org.eclipse.jetty.spdy.api.PingResultInfo;
import org.eclipse.jetty.spdy.api.PushInfo;
import org.eclipse.jetty.spdy.api.ReplyInfo; import org.eclipse.jetty.spdy.api.ReplyInfo;
import org.eclipse.jetty.spdy.api.RstInfo; import org.eclipse.jetty.spdy.api.RstInfo;
import org.eclipse.jetty.spdy.api.SPDY; import org.eclipse.jetty.spdy.api.SPDY;
@ -103,7 +106,7 @@ public class ProxyHTTPSPDYTest
{ {
server = new Server(); server = new Server();
SPDYServerConnector serverConnector = new SPDYServerConnector(server, listener); SPDYServerConnector serverConnector = new SPDYServerConnector(server, listener);
serverConnector.addConnectionFactory(new SPDYServerConnectionFactory(version,listener)); serverConnector.addConnectionFactory(new SPDYServerConnectionFactory(version, listener));
serverConnector.setPort(0); serverConnector.setPort(0);
server.addConnector(serverConnector); server.addConnector(serverConnector);
server.start(); server.start();
@ -159,12 +162,12 @@ public class ProxyHTTPSPDYTest
Fields responseHeaders = new Fields(); Fields responseHeaders = new Fields();
responseHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1"); responseHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
responseHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200 OK"); responseHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200 OK");
stream.reply(new ReplyInfo(responseHeaders, true)); stream.reply(new ReplyInfo(responseHeaders, true), new Callback.Adapter());
return null; return null;
} }
@Override @Override
public void onGoAway(Session session, GoAwayInfo goAwayInfo) public void onGoAway(Session session, GoAwayReceivedInfo goAwayInfo)
{ {
closeLatch.countDown(); closeLatch.countDown();
} }
@ -211,7 +214,7 @@ public class ProxyHTTPSPDYTest
responseHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1"); responseHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
responseHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200 OK"); responseHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200 OK");
ReplyInfo replyInfo = new ReplyInfo(responseHeaders, true); ReplyInfo replyInfo = new ReplyInfo(responseHeaders, true);
stream.reply(replyInfo); stream.reply(replyInfo, new Callback.Adapter());
return null; return null;
} }
})); }));
@ -272,8 +275,8 @@ public class ProxyHTTPSPDYTest
responseHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1"); responseHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
responseHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200 OK"); responseHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200 OK");
ReplyInfo replyInfo = new ReplyInfo(responseHeaders, false); ReplyInfo replyInfo = new ReplyInfo(responseHeaders, false);
stream.reply(replyInfo); stream.reply(replyInfo, new Callback.Adapter());
stream.data(new BytesDataInfo(data, true)); stream.data(new BytesDataInfo(data, true), new Callback.Adapter());
return null; return null;
} }
@ -335,7 +338,7 @@ public class ProxyHTTPSPDYTest
Fields headers = new Fields(); Fields headers = new Fields();
headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1"); headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
headers.put(HTTPSPDYHeader.STATUS.name(version), "303 See Other"); headers.put(HTTPSPDYHeader.STATUS.name(version), "303 See Other");
stream.reply(new ReplyInfo(headers, true)); stream.reply(new ReplyInfo(headers, true), new Callback.Adapter());
} }
} }
}; };
@ -399,8 +402,8 @@ public class ProxyHTTPSPDYTest
responseHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1"); responseHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
responseHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200 OK"); responseHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200 OK");
ReplyInfo replyInfo = new ReplyInfo(responseHeaders, false); ReplyInfo replyInfo = new ReplyInfo(responseHeaders, false);
stream.reply(replyInfo); stream.reply(replyInfo, new Callback.Adapter());
stream.data(new BytesDataInfo(data, true)); stream.data(new BytesDataInfo(data, true), new Callback.Adapter());
} }
} }
}; };
@ -462,7 +465,7 @@ public class ProxyHTTPSPDYTest
Fields responseHeaders = new Fields(); Fields responseHeaders = new Fields();
responseHeaders.put(header, "baz"); responseHeaders.put(header, "baz");
stream.reply(new ReplyInfo(responseHeaders, true)); stream.reply(new ReplyInfo(responseHeaders, true), new Callback.Adapter());
return null; return null;
} }
})); }));
@ -487,7 +490,7 @@ public class ProxyHTTPSPDYTest
Assert.assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
client.goAway().get(5, TimeUnit.SECONDS); client.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
} }
@Test @Test
@ -506,8 +509,8 @@ public class ProxyHTTPSPDYTest
Fields responseHeaders = new Fields(); Fields responseHeaders = new Fields();
responseHeaders.put(header, "baz"); responseHeaders.put(header, "baz");
stream.reply(new ReplyInfo(responseHeaders, false)); stream.reply(new ReplyInfo(responseHeaders, false), new Callback.Adapter());
stream.data(new BytesDataInfo(data, true)); stream.data(new BytesDataInfo(data, true), new Callback.Adapter());
return null; return null;
} }
})); }));
@ -547,7 +550,7 @@ public class ProxyHTTPSPDYTest
Assert.assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
client.goAway().get(5, TimeUnit.SECONDS); client.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
} }
@Test @Test
@ -565,16 +568,16 @@ public class ProxyHTTPSPDYTest
Fields pushHeaders = new Fields(); Fields pushHeaders = new Fields();
pushHeaders.put(HTTPSPDYHeader.URI.name(version), "/push"); pushHeaders.put(HTTPSPDYHeader.URI.name(version), "/push");
stream.syn(new SynInfo(pushHeaders, false), 5, TimeUnit.SECONDS, new Promise.Adapter<Stream>() stream.push(new PushInfo(5, TimeUnit.SECONDS, pushHeaders, false), new Promise.Adapter<Stream>()
{ {
@Override @Override
public void succeeded(Stream pushStream) public void succeeded(Stream pushStream)
{ {
pushStream.data(new BytesDataInfo(data, true)); pushStream.data(new BytesDataInfo(data, true), new Callback.Adapter());
} }
}); });
stream.reply(new ReplyInfo(responseHeaders, true)); stream.reply(new ReplyInfo(responseHeaders, true), new Callback.Adapter());
return null; return null;
} }
})); }));
@ -614,20 +617,20 @@ public class ProxyHTTPSPDYTest
Fields responseHeaders = new Fields(); Fields responseHeaders = new Fields();
responseHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1"); responseHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
responseHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200 OK"); responseHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200 OK");
stream.reply(new ReplyInfo(responseHeaders, false)); stream.reply(new ReplyInfo(responseHeaders, false), new Callback.Adapter());
Fields pushHeaders = new Fields(); Fields pushHeaders = new Fields();
pushHeaders.put(HTTPSPDYHeader.URI.name(version), "/push"); pushHeaders.put(HTTPSPDYHeader.URI.name(version), "/push");
stream.syn(new SynInfo(pushHeaders, false), 5, TimeUnit.SECONDS, new Promise.Adapter<Stream>() stream.push(new PushInfo(5, TimeUnit.SECONDS, pushHeaders, false), new Promise.Adapter<Stream>()
{ {
@Override @Override
public void succeeded(Stream pushStream) public void succeeded(Stream pushStream)
{ {
pushStream.data(new BytesDataInfo(data, true)); pushStream.data(new BytesDataInfo(data, true), new Callback.Adapter());
} }
}); });
stream.data(new BytesDataInfo(data, true)); stream.data(new BytesDataInfo(data, true), new Callback.Adapter());
return null; return null;
} }
@ -681,7 +684,7 @@ public class ProxyHTTPSPDYTest
Assert.assertTrue(pushDataLatch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(pushDataLatch.await(5, TimeUnit.SECONDS));
Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
client.goAway().get(5, TimeUnit.SECONDS); client.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
} }
@Test @Test
@ -697,17 +700,17 @@ public class ProxyHTTPSPDYTest
Session client = factory.newSPDYClient(version).connect(proxyAddress, new SessionFrameListener.Adapter() Session client = factory.newSPDYClient(version).connect(proxyAddress, new SessionFrameListener.Adapter()
{ {
@Override @Override
public void onPing(Session session, PingInfo pingInfo) public void onPing(Session session, PingResultInfo pingInfo)
{ {
pingLatch.countDown(); pingLatch.countDown();
} }
}).get(5, TimeUnit.SECONDS); }).get(5, TimeUnit.SECONDS);
client.ping().get(5, TimeUnit.SECONDS); client.ping(new PingInfo(5, TimeUnit.SECONDS));
Assert.assertTrue(pingLatch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(pingLatch.await(5, TimeUnit.SECONDS));
client.goAway().get(5, TimeUnit.SECONDS); client.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
} }
@Test @Test
@ -722,7 +725,7 @@ public class ProxyHTTPSPDYTest
Fields requestHeaders = synInfo.getHeaders(); Fields requestHeaders = synInfo.getHeaders();
Assert.assertNotNull(requestHeaders.get("via")); Assert.assertNotNull(requestHeaders.get("via"));
stream.getSession().rst(new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM)); stream.getSession().rst(new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM), new Callback.Adapter());
return null; return null;
} }
@ -758,7 +761,7 @@ public class ProxyHTTPSPDYTest
Fields requestHeaders = synInfo.getHeaders(); Fields requestHeaders = synInfo.getHeaders();
Assert.assertNotNull(requestHeaders.get("via")); Assert.assertNotNull(requestHeaders.get("via"));
stream.getSession().rst(new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM)); stream.getSession().rst(new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM), new Callback.Adapter());
return null; return null;
} }
@ -781,6 +784,6 @@ public class ProxyHTTPSPDYTest
Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS));
client.goAway().get(5, TimeUnit.SECONDS); client.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
} }
} }

View File

@ -32,18 +32,24 @@ import org.eclipse.jetty.spdy.CompressionFactory;
import org.eclipse.jetty.spdy.FlowControlStrategy; import org.eclipse.jetty.spdy.FlowControlStrategy;
import org.eclipse.jetty.spdy.StandardCompressionFactory; import org.eclipse.jetty.spdy.StandardCompressionFactory;
import org.eclipse.jetty.spdy.StandardSession; import org.eclipse.jetty.spdy.StandardSession;
import org.eclipse.jetty.spdy.api.GoAwayInfo;
import org.eclipse.jetty.spdy.api.Session; import org.eclipse.jetty.spdy.api.Session;
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
import org.eclipse.jetty.spdy.client.FlowControlStrategyFactory; import org.eclipse.jetty.spdy.client.FlowControlStrategyFactory;
import org.eclipse.jetty.spdy.client.SPDYConnection; import org.eclipse.jetty.spdy.client.SPDYConnection;
import org.eclipse.jetty.spdy.generator.Generator; import org.eclipse.jetty.spdy.generator.Generator;
import org.eclipse.jetty.spdy.parser.Parser; import org.eclipse.jetty.spdy.parser.Parser;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ManagedObject("SPDY Server Connection Factory") @ManagedObject("SPDY Server Connection Factory")
public class SPDYServerConnectionFactory extends AbstractConnectionFactory public class SPDYServerConnectionFactory extends AbstractConnectionFactory
{ {
private static final Logger LOG = Log.getLogger(SPDYServerConnectionFactory.class);
// This method is placed here so as to provide a check for NPN before attempting to load any // This method is placed here so as to provide a check for NPN before attempting to load any
// NPN classes. // NPN classes.
public static void checkNPNAvailable() public static void checkNPNAvailable()
@ -51,12 +57,12 @@ public class SPDYServerConnectionFactory extends AbstractConnectionFactory
try try
{ {
Class<?> npn = ClassLoader.getSystemClassLoader().loadClass("org.eclipse.jetty.npn.NextProtoNego"); Class<?> npn = ClassLoader.getSystemClassLoader().loadClass("org.eclipse.jetty.npn.NextProtoNego");
if (npn.getClassLoader()!=null) if (npn.getClassLoader() != null)
throw new IllegalStateException("NextProtoNego must be on JVM boot path"); throw new IllegalStateException("NextProtoNego must be on JVM boot path");
} }
catch (ClassNotFoundException e) catch (ClassNotFoundException e)
{ {
throw new IllegalStateException("No NextProtoNego on boot path",e); throw new IllegalStateException("No NextProtoNego on boot path", e);
} }
} }
@ -72,7 +78,7 @@ public class SPDYServerConnectionFactory extends AbstractConnectionFactory
public SPDYServerConnectionFactory(int version, ServerSessionFrameListener listener) public SPDYServerConnectionFactory(int version, ServerSessionFrameListener listener)
{ {
super("spdy/"+version); super("spdy/" + version);
this.version = (short)version; this.version = (short)version;
this.listener = listener; this.listener = listener;
setInitialWindowSize(65536); setInitialWindowSize(65536);
@ -96,8 +102,8 @@ public class SPDYServerConnectionFactory extends AbstractConnectionFactory
Parser parser = new Parser(compressionFactory.newDecompressor()); Parser parser = new Parser(compressionFactory.newDecompressor());
Generator generator = new Generator(connector.getByteBufferPool(), compressionFactory.newCompressor()); Generator generator = new Generator(connector.getByteBufferPool(), compressionFactory.newCompressor());
ServerSessionFrameListener listener = provideServerSessionFrameListener(connector,endPoint); ServerSessionFrameListener listener = provideServerSessionFrameListener(connector, endPoint);
SPDYConnection connection = new ServerSPDYConnection(connector,endPoint, parser, listener, getInputBufferSize()); SPDYConnection connection = new ServerSPDYConnection(connector, endPoint, parser, listener, getInputBufferSize());
FlowControlStrategy flowControlStrategy = newFlowControlStrategy(version); FlowControlStrategy flowControlStrategy = newFlowControlStrategy(version);
@ -110,7 +116,7 @@ public class SPDYServerConnectionFactory extends AbstractConnectionFactory
sessionOpened(session); sessionOpened(session);
return configure(connection,connector,endPoint); return configure(connection, connector, endPoint);
} }
protected FlowControlStrategy newFlowControlStrategy(short version) protected FlowControlStrategy newFlowControlStrategy(short version)
@ -150,7 +156,7 @@ public class SPDYServerConnectionFactory extends AbstractConnectionFactory
void closeSessions() void closeSessions()
{ {
for (Session session : sessions) for (Session session : sessions)
session.goAway(); session.goAway(new GoAwayInfo(), new Callback.Adapter());
sessions.clear(); sessions.clear();
} }
@ -171,9 +177,9 @@ public class SPDYServerConnectionFactory extends AbstractConnectionFactory
private final ServerSessionFrameListener listener; private final ServerSessionFrameListener listener;
private final AtomicBoolean connected = new AtomicBoolean(); private final AtomicBoolean connected = new AtomicBoolean();
private ServerSPDYConnection(Connector connector,EndPoint endPoint, Parser parser, ServerSessionFrameListener listener, int bufferSize) private ServerSPDYConnection(Connector connector, EndPoint endPoint, Parser parser, ServerSessionFrameListener listener, int bufferSize)
{ {
super(endPoint, connector.getByteBufferPool(), parser, connector.getExecutor(),bufferSize); super(endPoint, connector.getByteBufferPool(), parser, connector.getExecutor(), bufferSize);
this.listener = listener; this.listener = listener;
} }

View File

@ -31,6 +31,7 @@ import org.eclipse.jetty.spdy.StandardCompressionFactory;
import org.eclipse.jetty.spdy.api.BytesDataInfo; import org.eclipse.jetty.spdy.api.BytesDataInfo;
import org.eclipse.jetty.spdy.api.DataInfo; import org.eclipse.jetty.spdy.api.DataInfo;
import org.eclipse.jetty.spdy.api.GoAwayInfo; import org.eclipse.jetty.spdy.api.GoAwayInfo;
import org.eclipse.jetty.spdy.api.GoAwayReceivedInfo;
import org.eclipse.jetty.spdy.api.ReplyInfo; import org.eclipse.jetty.spdy.api.ReplyInfo;
import org.eclipse.jetty.spdy.api.SPDY; import org.eclipse.jetty.spdy.api.SPDY;
import org.eclipse.jetty.spdy.api.Session; import org.eclipse.jetty.spdy.api.Session;
@ -48,6 +49,7 @@ import org.eclipse.jetty.spdy.frames.SynStreamFrame;
import org.eclipse.jetty.spdy.generator.Generator; import org.eclipse.jetty.spdy.generator.Generator;
import org.eclipse.jetty.spdy.parser.Parser; import org.eclipse.jetty.spdy.parser.Parser;
import org.eclipse.jetty.spdy.parser.Parser.Listener; import org.eclipse.jetty.spdy.parser.Parser.Listener;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.util.Fields;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Ignore; import org.junit.Ignore;
@ -69,7 +71,7 @@ public class ClosedStreamTest extends AbstractTest
Session session = startClient(new InetSocketAddress("localhost", server.socket().getLocalPort()), null); Session session = startClient(new InetSocketAddress("localhost", server.socket().getLocalPort()), null);
final CountDownLatch dataLatch = new CountDownLatch(2); final CountDownLatch dataLatch = new CountDownLatch(2);
session.syn(new SynInfo(true), new StreamFrameListener.Adapter() session.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onData(Stream stream, DataInfo dataInfo) public void onData(Stream stream, DataInfo dataInfo)
@ -102,7 +104,7 @@ public class ClosedStreamTest extends AbstractTest
Assert.assertFalse(dataLatch.await(1, TimeUnit.SECONDS)); Assert.assertFalse(dataLatch.await(1, TimeUnit.SECONDS));
session.goAway().get(5, TimeUnit.SECONDS); session.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
server.close(); server.close();
} }
@ -119,7 +121,7 @@ public class ClosedStreamTest extends AbstractTest
@Override @Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{ {
stream.reply(new ReplyInfo(true)); stream.reply(new ReplyInfo(true), new Callback.Adapter());
try try
{ {
replyReceivedLatch.await(5,TimeUnit.SECONDS); replyReceivedLatch.await(5,TimeUnit.SECONDS);
@ -130,7 +132,7 @@ public class ClosedStreamTest extends AbstractTest
} }
try try
{ {
stream.data(new StringDataInfo("data send after half closed",false)); stream.data(new StringDataInfo("data send after half closed",false), new Callback.Adapter());
} }
catch (RuntimeException e) catch (RuntimeException e)
{ {
@ -142,7 +144,7 @@ public class ClosedStreamTest extends AbstractTest
} }
}),null); }),null);
Stream stream = clientSession.syn(new SynInfo(false),new StreamFrameListener.Adapter() Stream stream = clientSession.syn(new SynInfo(new Fields(), false),new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onReply(Stream stream, ReplyInfo replyInfo) public void onReply(Stream stream, ReplyInfo replyInfo)
@ -155,7 +157,7 @@ public class ClosedStreamTest extends AbstractTest
{ {
clientReceivedDataLatch.countDown(); clientReceivedDataLatch.countDown();
} }
}).get(); });
assertThat("reply has been received by client",replyReceivedLatch.await(5,TimeUnit.SECONDS),is(true)); assertThat("reply has been received by client",replyReceivedLatch.await(5,TimeUnit.SECONDS),is(true));
assertThat("stream is half closed from server",stream.isHalfClosed(),is(true)); assertThat("stream is half closed from server",stream.isHalfClosed(),is(true));
assertThat("client has not received any data sent after stream was half closed by server", assertThat("client has not received any data sent after stream was half closed by server",
@ -189,7 +191,7 @@ public class ClosedStreamTest extends AbstractTest
@Override @Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{ {
stream.reply(new ReplyInfo(false)); stream.reply(new ReplyInfo(false), new Callback.Adapter());
serverReplySentLatch.countDown(); serverReplySentLatch.countDown();
try try
{ {
@ -209,7 +211,7 @@ public class ClosedStreamTest extends AbstractTest
}; };
} }
@Override @Override
public void onGoAway(Session session, GoAwayInfo goAwayInfo) public void onGoAway(Session session, GoAwayReceivedInfo goAwayInfo)
{ {
goAwayReceivedLatch.countDown(); goAwayReceivedLatch.countDown();
} }
@ -223,7 +225,7 @@ public class ClosedStreamTest extends AbstractTest
socketChannel.write(synData); socketChannel.write(synData);
assertThat("synData is fully written", synData.hasRemaining(), is(false)); assertThat("synData is fully written", synData.hasRemaining(), is(false));
assertThat("server: syn reply is sent",serverReplySentLatch.await(5,TimeUnit.SECONDS),is(true)); assertThat("server: push reply is sent",serverReplySentLatch.await(5,TimeUnit.SECONDS),is(true));
Parser parser = new Parser(new StandardCompressionFactory.StandardDecompressor()); Parser parser = new Parser(new StandardCompressionFactory.StandardDecompressor());
parser.addListener(new Listener.Adapter() parser.addListener(new Listener.Adapter()

View File

@ -42,6 +42,9 @@ import org.eclipse.jetty.spdy.api.Stream;
import org.eclipse.jetty.spdy.api.StreamFrameListener; import org.eclipse.jetty.spdy.api.StreamFrameListener;
import org.eclipse.jetty.spdy.api.SynInfo; import org.eclipse.jetty.spdy.api.SynInfo;
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.FutureCallback;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@ -66,7 +69,7 @@ public class FlowControlTest extends AbstractTest
@Override @Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{ {
stream.reply(new ReplyInfo(true)); stream.reply(new ReplyInfo(true), new Callback.Adapter());
return new StreamFrameListener.Adapter() return new StreamFrameListener.Adapter()
{ {
private final AtomicInteger dataFrames = new AtomicInteger(); private final AtomicInteger dataFrames = new AtomicInteger();
@ -80,7 +83,7 @@ public class FlowControlTest extends AbstractTest
dataInfoRef.set(dataInfo); dataInfoRef.set(dataInfo);
Settings settings = new Settings(); Settings settings = new Settings();
settings.put(new Settings.Setting(Settings.ID.INITIAL_WINDOW_SIZE, size)); settings.put(new Settings.Setting(Settings.ID.INITIAL_WINDOW_SIZE, size));
stream.getSession().settings(new SettingsInfo(settings)); stream.getSession().settings(new SettingsInfo(settings), new FutureCallback());
} }
else if (dataFrameCount > 1) else if (dataFrameCount > 1)
{ {
@ -99,12 +102,12 @@ public class FlowControlTest extends AbstractTest
} }
}); });
Stream stream = session.syn(new SynInfo(false), null).get(5, TimeUnit.SECONDS); Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), null);
stream.data(new BytesDataInfo(new byte[size * 2], false)); stream.data(new BytesDataInfo(new byte[size * 2], false));
settingsLatch.await(5, TimeUnit.SECONDS); settingsLatch.await(5, TimeUnit.SECONDS);
// Send the second chunk of data, must not arrive since we're flow control stalled now // Send the second chunk of data, must not arrive since we're flow control stalled now
stream.data(new BytesDataInfo(new byte[size * 2], true)); stream.data(new BytesDataInfo(new byte[size * 2], true), new Callback.Adapter());
Assert.assertFalse(dataLatch.await(1, TimeUnit.SECONDS)); Assert.assertFalse(dataLatch.await(1, TimeUnit.SECONDS));
// Consume the data arrived to server, this will resume flow control // Consume the data arrived to server, this will resume flow control
@ -131,8 +134,8 @@ public class FlowControlTest extends AbstractTest
@Override @Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{ {
stream.reply(new ReplyInfo(false)); stream.reply(new ReplyInfo(false), new Callback.Adapter());
stream.data(new BytesDataInfo(new byte[length], true)); stream.data(new BytesDataInfo(new byte[length], true), new Callback.Adapter());
return null; return null;
} }
}), null); }), null);
@ -144,7 +147,7 @@ public class FlowControlTest extends AbstractTest
Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS));
final Exchanger<DataInfo> exchanger = new Exchanger<>(); final Exchanger<DataInfo> exchanger = new Exchanger<>();
session.syn(new SynInfo(true), new StreamFrameListener.Adapter() session.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter()
{ {
private AtomicInteger dataFrames = new AtomicInteger(); private AtomicInteger dataFrames = new AtomicInteger();
@ -230,13 +233,13 @@ public class FlowControlTest extends AbstractTest
{ {
Settings settings = new Settings(); Settings settings = new Settings();
settings.put(new Settings.Setting(Settings.ID.INITIAL_WINDOW_SIZE, windowSize)); settings.put(new Settings.Setting(Settings.ID.INITIAL_WINDOW_SIZE, windowSize));
session.settings(new SettingsInfo(settings)); session.settings(new SettingsInfo(settings), new FutureCallback());
} }
@Override @Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{ {
stream.reply(new ReplyInfo(false)); stream.reply(new ReplyInfo(false), new Callback.Adapter());
return new StreamFrameListener.Adapter() return new StreamFrameListener.Adapter()
{ {
private AtomicInteger dataFrames = new AtomicInteger(); private AtomicInteger dataFrames = new AtomicInteger();
@ -294,9 +297,9 @@ public class FlowControlTest extends AbstractTest
Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS));
Stream stream = session.syn(new SynInfo(false), null).get(5, TimeUnit.SECONDS); Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), null);
final int length = 5 * windowSize; final int length = 5 * windowSize;
stream.data(new BytesDataInfo(new byte[length], true)); stream.data(new BytesDataInfo(new byte[length], true), new Callback.Adapter());
DataInfo dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); DataInfo dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS);
checkThatWeAreFlowControlStalled(exchanger); checkThatWeAreFlowControlStalled(exchanger);
@ -341,8 +344,8 @@ public class FlowControlTest extends AbstractTest
@Override @Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{ {
stream.reply(new ReplyInfo(false)); stream.reply(new ReplyInfo(false), new Callback.Adapter());
stream.data(new BytesDataInfo(new byte[windowSize * 2], true)); stream.data(new BytesDataInfo(new byte[windowSize * 2], true), new Callback.Adapter());
return null; return null;
} }
}), null); }), null);
@ -355,7 +358,7 @@ public class FlowControlTest extends AbstractTest
final CountDownLatch latch = new CountDownLatch(3); final CountDownLatch latch = new CountDownLatch(3);
final AtomicReference<DataInfo> dataInfoRef1 = new AtomicReference<>(); final AtomicReference<DataInfo> dataInfoRef1 = new AtomicReference<>();
final AtomicReference<DataInfo> dataInfoRef2 = new AtomicReference<>(); final AtomicReference<DataInfo> dataInfoRef2 = new AtomicReference<>();
session.syn(new SynInfo(true), new StreamFrameListener.Adapter() session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), new StreamFrameListener.Adapter()
{ {
private final AtomicInteger dataFrames = new AtomicInteger(); private final AtomicInteger dataFrames = new AtomicInteger();
@ -375,8 +378,8 @@ public class FlowControlTest extends AbstractTest
latch.countDown(); latch.countDown();
} }
} }
}).get(5, TimeUnit.SECONDS); });
session.syn(new SynInfo(true), new StreamFrameListener.Adapter() session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), new StreamFrameListener.Adapter()
{ {
private final AtomicInteger dataFrames = new AtomicInteger(); private final AtomicInteger dataFrames = new AtomicInteger();
@ -396,8 +399,8 @@ public class FlowControlTest extends AbstractTest
latch.countDown(); latch.countDown();
} }
} }
}).get(5, TimeUnit.SECONDS); });
session.syn(new SynInfo(true), new StreamFrameListener.Adapter() session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onData(Stream stream, DataInfo dataInfo) public void onData(Stream stream, DataInfo dataInfo)
@ -412,7 +415,7 @@ public class FlowControlTest extends AbstractTest
if (dataInfo.isClose()) if (dataInfo.isClose())
latch.countDown(); latch.countDown();
} }
}).get(5, TimeUnit.SECONDS); });
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
} }
@ -440,13 +443,13 @@ public class FlowControlTest extends AbstractTest
@Override @Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{ {
stream.reply(new ReplyInfo(false)); stream.reply(new ReplyInfo(false), new Callback.Adapter());
stream.data(bigByteBufferDataInfo); stream.data(bigByteBufferDataInfo, new Callback.Adapter());
return null; return null;
} }
}),new SessionFrameListener.Adapter()); }),new SessionFrameListener.Adapter());
session.syn(new SynInfo(false),new StreamFrameListener.Adapter() session.syn(new SynInfo(new Fields(), false),new StreamFrameListener.Adapter()
{ {
private int dataBytesReceived; private int dataBytesReceived;

View File

@ -18,16 +18,17 @@
package org.eclipse.jetty.spdy.server; package org.eclipse.jetty.spdy.server;
import java.nio.channels.ClosedChannelException;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.spdy.api.DataInfo; import org.eclipse.jetty.spdy.api.DataInfo;
import org.eclipse.jetty.spdy.api.GoAwayInfo; import org.eclipse.jetty.spdy.api.GoAwayInfo;
import org.eclipse.jetty.spdy.api.GoAwayReceivedInfo;
import org.eclipse.jetty.spdy.api.ReplyInfo; import org.eclipse.jetty.spdy.api.ReplyInfo;
import org.eclipse.jetty.spdy.api.SPDYException;
import org.eclipse.jetty.spdy.api.Session; import org.eclipse.jetty.spdy.api.Session;
import org.eclipse.jetty.spdy.api.SessionFrameListener; import org.eclipse.jetty.spdy.api.SessionFrameListener;
import org.eclipse.jetty.spdy.api.SessionStatus; import org.eclipse.jetty.spdy.api.SessionStatus;
@ -36,6 +37,10 @@ import org.eclipse.jetty.spdy.api.StreamFrameListener;
import org.eclipse.jetty.spdy.api.StringDataInfo; import org.eclipse.jetty.spdy.api.StringDataInfo;
import org.eclipse.jetty.spdy.api.SynInfo; import org.eclipse.jetty.spdy.api.SynInfo;
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.FutureCallback;
import org.eclipse.jetty.util.FuturePromise;
import org.hamcrest.CoreMatchers; import org.hamcrest.CoreMatchers;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@ -51,12 +56,12 @@ public class GoAwayTest extends AbstractTest
@Override @Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{ {
stream.reply(new ReplyInfo(true)); stream.reply(new ReplyInfo(true), new Callback.Adapter());
return null; return null;
} }
@Override @Override
public void onGoAway(Session session, GoAwayInfo goAwayInfo) public void onGoAway(Session session, GoAwayReceivedInfo goAwayInfo)
{ {
Assert.assertEquals(0, goAwayInfo.getLastStreamId()); Assert.assertEquals(0, goAwayInfo.getLastStreamId());
Assert.assertSame(SessionStatus.OK, goAwayInfo.getSessionStatus()); Assert.assertSame(SessionStatus.OK, goAwayInfo.getSessionStatus());
@ -65,9 +70,9 @@ public class GoAwayTest extends AbstractTest
}; };
Session session = startClient(startServer(serverSessionFrameListener), null); Session session = startClient(startServer(serverSessionFrameListener), null);
session.syn(new SynInfo(true), null); session.syn(new SynInfo(new Fields(), true), null);
session.goAway(); session.goAway(new GoAwayInfo());
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
} }
@ -80,17 +85,17 @@ public class GoAwayTest extends AbstractTest
@Override @Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{ {
stream.reply(new ReplyInfo(true)); stream.reply(new ReplyInfo(true), new Callback.Adapter());
stream.getSession().goAway(); stream.getSession().goAway(new GoAwayInfo(), new FutureCallback());
return null; return null;
} }
}; };
final AtomicReference<GoAwayInfo> ref = new AtomicReference<>(); final AtomicReference<GoAwayReceivedInfo> ref = new AtomicReference<>();
final CountDownLatch latch = new CountDownLatch(1); final CountDownLatch latch = new CountDownLatch(1);
SessionFrameListener clientSessionFrameListener = new SessionFrameListener.Adapter() SessionFrameListener clientSessionFrameListener = new SessionFrameListener.Adapter()
{ {
@Override @Override
public void onGoAway(Session session, GoAwayInfo goAwayInfo) public void onGoAway(Session session, GoAwayReceivedInfo goAwayInfo)
{ {
ref.set(goAwayInfo); ref.set(goAwayInfo);
latch.countDown(); latch.countDown();
@ -98,13 +103,13 @@ public class GoAwayTest extends AbstractTest
}; };
Session session = startClient(startServer(serverSessionFrameListener), clientSessionFrameListener); Session session = startClient(startServer(serverSessionFrameListener), clientSessionFrameListener);
Stream stream1 = session.syn(new SynInfo(true), null).get(5, TimeUnit.SECONDS); Stream stream1 = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), null);
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
GoAwayInfo goAwayInfo = ref.get(); GoAwayReceivedInfo goAwayReceivedInfo = ref.get();
Assert.assertNotNull(goAwayInfo); Assert.assertNotNull(goAwayReceivedInfo);
Assert.assertEquals(stream1.getId(), goAwayInfo.getLastStreamId()); Assert.assertEquals(stream1.getId(), goAwayReceivedInfo.getLastStreamId());
Assert.assertSame(SessionStatus.OK, goAwayInfo.getSessionStatus()); Assert.assertSame(SessionStatus.OK, goAwayReceivedInfo.getSessionStatus());
} }
@Test @Test
@ -121,8 +126,8 @@ public class GoAwayTest extends AbstractTest
int synCount = syns.incrementAndGet(); int synCount = syns.incrementAndGet();
if (synCount == 1) if (synCount == 1)
{ {
stream.reply(new ReplyInfo(true)); stream.reply(new ReplyInfo(true), new Callback.Adapter());
stream.getSession().goAway(); stream.getSession().goAway(new GoAwayInfo(), new FutureCallback());
} }
else else
{ {
@ -134,14 +139,14 @@ public class GoAwayTest extends AbstractTest
SessionFrameListener clientSessionFrameListener = new SessionFrameListener.Adapter() SessionFrameListener clientSessionFrameListener = new SessionFrameListener.Adapter()
{ {
@Override @Override
public void onGoAway(Session session, GoAwayInfo goAwayInfo) public void onGoAway(Session session, GoAwayReceivedInfo goAwayInfo)
{ {
session.syn(new SynInfo(true), null); session.syn(new SynInfo(new Fields(), true), null, new FuturePromise<Stream>());
} }
}; };
Session session = startClient(startServer(serverSessionFrameListener), clientSessionFrameListener); Session session = startClient(startServer(serverSessionFrameListener), clientSessionFrameListener);
session.syn(new SynInfo(true), null); session.syn(new SynInfo(new Fields(), true), null);
Assert.assertFalse(latch.await(1, TimeUnit.SECONDS)); Assert.assertFalse(latch.await(1, TimeUnit.SECONDS));
} }
@ -158,7 +163,7 @@ public class GoAwayTest extends AbstractTest
@Override @Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{ {
stream.reply(new ReplyInfo(true)); stream.reply(new ReplyInfo(true), new Callback.Adapter());
int synCount = syns.incrementAndGet(); int synCount = syns.incrementAndGet();
if (synCount == 1) if (synCount == 1)
{ {
@ -166,7 +171,7 @@ public class GoAwayTest extends AbstractTest
} }
else else
{ {
stream.getSession().goAway(); stream.getSession().goAway(new GoAwayInfo(), new FutureCallback());
closeLatch.countDown(); closeLatch.countDown();
return new StreamFrameListener.Adapter() return new StreamFrameListener.Adapter()
{ {
@ -179,12 +184,12 @@ public class GoAwayTest extends AbstractTest
} }
} }
}; };
final AtomicReference<GoAwayInfo> goAwayRef = new AtomicReference<>(); final AtomicReference<GoAwayReceivedInfo> goAwayRef = new AtomicReference<>();
final CountDownLatch goAwayLatch = new CountDownLatch(1); final CountDownLatch goAwayLatch = new CountDownLatch(1);
SessionFrameListener clientSessionFrameListener = new SessionFrameListener.Adapter() SessionFrameListener clientSessionFrameListener = new SessionFrameListener.Adapter()
{ {
@Override @Override
public void onGoAway(Session session, GoAwayInfo goAwayInfo) public void onGoAway(Session session, GoAwayReceivedInfo goAwayInfo)
{ {
goAwayRef.set(goAwayInfo); goAwayRef.set(goAwayInfo);
goAwayLatch.countDown(); goAwayLatch.countDown();
@ -194,18 +199,18 @@ public class GoAwayTest extends AbstractTest
// First stream is processed ok // First stream is processed ok
final CountDownLatch reply1Latch = new CountDownLatch(1); final CountDownLatch reply1Latch = new CountDownLatch(1);
Stream stream1 = session.syn(new SynInfo(true), new StreamFrameListener.Adapter() session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onReply(Stream stream, ReplyInfo replyInfo) public void onReply(Stream stream, ReplyInfo replyInfo)
{ {
reply1Latch.countDown(); reply1Latch.countDown();
} }
}).get(5, TimeUnit.SECONDS); });
Assert.assertTrue(reply1Latch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(reply1Latch.await(5, TimeUnit.SECONDS));
// Second stream is closed in the middle // Second stream is closed in the middle
Stream stream2 = session.syn(new SynInfo(false), null).get(5, TimeUnit.SECONDS); Stream stream2 = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), null);
Assert.assertTrue(closeLatch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(closeLatch.await(5, TimeUnit.SECONDS));
// There is a race between the data we want to send, and the client // There is a race between the data we want to send, and the client
@ -216,14 +221,14 @@ public class GoAwayTest extends AbstractTest
stream2.data(new StringDataInfo("foo", true)); stream2.data(new StringDataInfo("foo", true));
Assert.assertFalse(dataLatch.await(1, TimeUnit.SECONDS)); Assert.assertFalse(dataLatch.await(1, TimeUnit.SECONDS));
} }
catch (SPDYException x) catch (ExecutionException x)
{ {
Assert.assertThat(x.getCause(), CoreMatchers.instanceOf(ClosedChannelException.class)); Assert.assertThat(x.getCause(), CoreMatchers.instanceOf(EofException.class));
} }
// The last good stream is the second, because it was received by the server // The last good stream is the second, because it was received by the server
Assert.assertTrue(goAwayLatch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(goAwayLatch.await(5, TimeUnit.SECONDS));
GoAwayInfo goAway = goAwayRef.get(); GoAwayReceivedInfo goAway = goAwayRef.get();
Assert.assertNotNull(goAway); Assert.assertNotNull(goAway);
Assert.assertEquals(stream2.getId(), goAway.getLastStreamId()); Assert.assertEquals(stream2.getId(), goAway.getLastStreamId());
} }

View File

@ -29,6 +29,7 @@ import org.eclipse.jetty.spdy.api.Stream;
import org.eclipse.jetty.spdy.api.StreamFrameListener; import org.eclipse.jetty.spdy.api.StreamFrameListener;
import org.eclipse.jetty.spdy.api.SynInfo; import org.eclipse.jetty.spdy.api.SynInfo;
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.util.Fields;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@ -43,14 +44,14 @@ public class HeadersTest extends AbstractTest
@Override @Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{ {
stream.reply(new ReplyInfo(false)); stream.reply(new ReplyInfo(false), new Callback.Adapter());
return new StreamFrameListener.Adapter() return new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onHeaders(Stream stream, HeadersInfo headersInfo) public void onHeaders(Stream stream, HeadersInfo headersInfo)
{ {
Assert.assertTrue(stream.isHalfClosed()); Assert.assertTrue(stream.isHalfClosed());
stream.headers(new HeadersInfo(new Fields(), true)); stream.headers(new HeadersInfo(new Fields(), true), new Callback.Adapter());
Assert.assertTrue(stream.isClosed()); Assert.assertTrue(stream.isClosed());
} }
}; };
@ -60,7 +61,7 @@ public class HeadersTest extends AbstractTest
Session session = startClient(startServer(serverSessionFrameListener), null); Session session = startClient(startServer(serverSessionFrameListener), null);
final CountDownLatch latch = new CountDownLatch(1); final CountDownLatch latch = new CountDownLatch(1);
session.syn(new SynInfo(false), new StreamFrameListener.Adapter() session.syn(new SynInfo(new Fields(), false), new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onReply(Stream stream, ReplyInfo replyInfo) public void onReply(Stream stream, ReplyInfo replyInfo)
@ -68,7 +69,7 @@ public class HeadersTest extends AbstractTest
Fields headers = new Fields(); Fields headers = new Fields();
headers.put("foo", "bar"); headers.put("foo", "bar");
headers.put("baz", "woo"); headers.put("baz", "woo");
stream.headers(new HeadersInfo(headers, true)); stream.headers(new HeadersInfo(headers, true), new Callback.Adapter());
Assert.assertTrue(stream.isHalfClosed()); Assert.assertTrue(stream.isHalfClosed());
} }

View File

@ -23,7 +23,7 @@ import java.net.InetSocketAddress;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.spdy.api.GoAwayInfo; import org.eclipse.jetty.spdy.api.GoAwayReceivedInfo;
import org.eclipse.jetty.spdy.api.ReplyInfo; import org.eclipse.jetty.spdy.api.ReplyInfo;
import org.eclipse.jetty.spdy.api.SPDY; import org.eclipse.jetty.spdy.api.SPDY;
import org.eclipse.jetty.spdy.api.Session; import org.eclipse.jetty.spdy.api.Session;
@ -33,6 +33,8 @@ import org.eclipse.jetty.spdy.api.StreamFrameListener;
import org.eclipse.jetty.spdy.api.SynInfo; import org.eclipse.jetty.spdy.api.SynInfo;
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
import org.eclipse.jetty.spdy.client.SPDYClient; import org.eclipse.jetty.spdy.client.SPDYClient;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@ -51,7 +53,7 @@ public class IdleTimeoutTest extends AbstractTest
@Override @Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{ {
stream.reply(new ReplyInfo(true)); stream.reply(new ReplyInfo(true), new Callback.Adapter());
return null; return null;
} }
}); });
@ -61,13 +63,13 @@ public class IdleTimeoutTest extends AbstractTest
Session session = startClient(startServer(null), new SessionFrameListener.Adapter() Session session = startClient(startServer(null), new SessionFrameListener.Adapter()
{ {
@Override @Override
public void onGoAway(Session session, GoAwayInfo goAwayInfo) public void onGoAway(Session session, GoAwayReceivedInfo goAwayInfo)
{ {
latch.countDown(); latch.countDown();
} }
}); });
session.syn(new SynInfo(true), null); session.syn(new SynInfo(new Fields(), true), null);
Assert.assertTrue(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); Assert.assertTrue(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS));
} }
@ -83,14 +85,14 @@ public class IdleTimeoutTest extends AbstractTest
Session session = startClient(startServer(null), new SessionFrameListener.Adapter() Session session = startClient(startServer(null), new SessionFrameListener.Adapter()
{ {
@Override @Override
public void onGoAway(Session session, GoAwayInfo goAwayInfo) public void onGoAway(Session session, GoAwayReceivedInfo goAwayInfo)
{ {
latch.countDown(); latch.countDown();
} }
}); });
// The SYN is not replied, and the server should idle timeout // The SYN is not replied, and the server should idle timeout
session.syn(new SynInfo(true), null); session.syn(new SynInfo(new Fields(), true), null);
Assert.assertTrue(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); Assert.assertTrue(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS));
} }
@ -107,7 +109,7 @@ public class IdleTimeoutTest extends AbstractTest
try try
{ {
Thread.sleep(2 * idleTimeout); Thread.sleep(2 * idleTimeout);
stream.reply(new ReplyInfo(true)); stream.reply(new ReplyInfo(true), new Callback.Adapter());
return null; return null;
} }
catch (InterruptedException x) catch (InterruptedException x)
@ -123,14 +125,14 @@ public class IdleTimeoutTest extends AbstractTest
Session session = startClient(startServer(null), new SessionFrameListener.Adapter() Session session = startClient(startServer(null), new SessionFrameListener.Adapter()
{ {
@Override @Override
public void onGoAway(Session session, GoAwayInfo goAwayInfo) public void onGoAway(Session session, GoAwayReceivedInfo goAwayInfo)
{ {
goAwayLatch.countDown(); goAwayLatch.countDown();
} }
}); });
final CountDownLatch replyLatch = new CountDownLatch(1); final CountDownLatch replyLatch = new CountDownLatch(1);
session.syn(new SynInfo(true), new StreamFrameListener.Adapter() session.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onReply(Stream stream, ReplyInfo replyInfo) public void onReply(Stream stream, ReplyInfo replyInfo)
@ -154,12 +156,12 @@ public class IdleTimeoutTest extends AbstractTest
@Override @Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{ {
stream.reply(new ReplyInfo(true)); stream.reply(new ReplyInfo(true), new Callback.Adapter());
return null; return null;
} }
@Override @Override
public void onGoAway(Session session, GoAwayInfo goAwayInfo) public void onGoAway(Session session, GoAwayReceivedInfo goAwayInfo)
{ {
latch.countDown(); latch.countDown();
} }
@ -173,7 +175,7 @@ public class IdleTimeoutTest extends AbstractTest
client.setIdleTimeout(idleTimeout); client.setIdleTimeout(idleTimeout);
Session session = client.connect(address, null).get(5, TimeUnit.SECONDS); Session session = client.connect(address, null).get(5, TimeUnit.SECONDS);
session.syn(new SynInfo(true), null); session.syn(new SynInfo(new Fields(), true), null);
Assert.assertTrue(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); Assert.assertTrue(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS));
} }
@ -185,7 +187,7 @@ public class IdleTimeoutTest extends AbstractTest
InetSocketAddress address = startServer(new ServerSessionFrameListener.Adapter() InetSocketAddress address = startServer(new ServerSessionFrameListener.Adapter()
{ {
@Override @Override
public void onGoAway(Session session, GoAwayInfo goAwayInfo) public void onGoAway(Session session, GoAwayReceivedInfo goAwayInfo)
{ {
latch.countDown(); latch.countDown();
} }
@ -199,7 +201,7 @@ public class IdleTimeoutTest extends AbstractTest
client.setIdleTimeout(idleTimeout); client.setIdleTimeout(idleTimeout);
Session session = client.connect(address, null).get(5, TimeUnit.SECONDS); Session session = client.connect(address, null).get(5, TimeUnit.SECONDS);
session.syn(new SynInfo(true), null); session.syn(new SynInfo(new Fields(), true), null);
Assert.assertTrue(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); Assert.assertTrue(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS));
} }
@ -213,12 +215,12 @@ public class IdleTimeoutTest extends AbstractTest
@Override @Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{ {
stream.reply(new ReplyInfo(true)); stream.reply(new ReplyInfo(true), new Callback.Adapter());
return null; return null;
} }
@Override @Override
public void onGoAway(Session session, GoAwayInfo goAwayInfo) public void onGoAway(Session session, GoAwayReceivedInfo goAwayInfo)
{ {
latch.countDown(); latch.countDown();
} }
@ -233,7 +235,7 @@ public class IdleTimeoutTest extends AbstractTest
Session session = client.connect(address, null).get(5, TimeUnit.SECONDS); Session session = client.connect(address, null).get(5, TimeUnit.SECONDS);
final CountDownLatch replyLatch = new CountDownLatch(1); final CountDownLatch replyLatch = new CountDownLatch(1);
session.syn(new SynInfo(true), new StreamFrameListener.Adapter() session.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onReply(Stream stream, ReplyInfo replyInfo) public void onReply(Stream stream, ReplyInfo replyInfo)

View File

@ -24,10 +24,10 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.jetty.spdy.api.PingInfo; import org.eclipse.jetty.spdy.api.PingInfo;
import org.eclipse.jetty.spdy.api.PingResultInfo;
import org.eclipse.jetty.spdy.api.Session; import org.eclipse.jetty.spdy.api.Session;
import org.eclipse.jetty.spdy.api.SessionFrameListener; import org.eclipse.jetty.spdy.api.SessionFrameListener;
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.Promise;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@ -37,25 +37,25 @@ public class PingTest extends AbstractTest
@Test @Test
public void testPingPong() throws Exception public void testPingPong() throws Exception
{ {
final AtomicReference<PingInfo> ref = new AtomicReference<>(); final AtomicReference<PingResultInfo> ref = new AtomicReference<>();
final CountDownLatch latch = new CountDownLatch(1); final CountDownLatch latch = new CountDownLatch(1);
SessionFrameListener clientSessionFrameListener = new SessionFrameListener.Adapter() SessionFrameListener clientSessionFrameListener = new SessionFrameListener.Adapter()
{ {
@Override @Override
public void onPing(Session session, PingInfo pingInfo) public void onPing(Session session, PingResultInfo pingInfo)
{ {
ref.set(pingInfo); ref.set(pingInfo);
latch.countDown(); latch.countDown();
} }
}; };
Session session = startClient(startServer(null), clientSessionFrameListener); Session session = startClient(startServer(null), clientSessionFrameListener);
PingInfo pingInfo = session.ping().get(5, TimeUnit.SECONDS); PingResultInfo pingResultInfo = session.ping(new PingInfo(5, TimeUnit.SECONDS));
Assert.assertEquals(1, pingInfo.getPingId() % 2); Assert.assertEquals(1, pingResultInfo.getPingId() % 2);
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
PingInfo pongInfo = ref.get(); PingResultInfo pongInfo = ref.get();
Assert.assertNotNull(pongInfo); Assert.assertNotNull(pongInfo);
Assert.assertEquals(pingInfo.getPingId(), pongInfo.getPingId()); Assert.assertEquals(pingResultInfo.getPingId(), pongInfo.getPingId());
} }
@Test @Test
@ -69,10 +69,10 @@ public class PingTest extends AbstractTest
@Override @Override
public void onConnect(Session session) public void onConnect(Session session)
{ {
session.ping(0, TimeUnit.MILLISECONDS, new Promise.Adapter<PingInfo>() session.ping(new PingInfo(), new Promise.Adapter<PingResultInfo>()
{ {
@Override @Override
public void succeeded(PingInfo pingInfo) public void succeeded(PingResultInfo pingInfo)
{ {
pingId = pingInfo.getPingId(); pingId = pingInfo.getPingId();
} }
@ -80,7 +80,7 @@ public class PingTest extends AbstractTest
} }
@Override @Override
public void onPing(Session session, PingInfo pingInfo) public void onPing(Session session, PingResultInfo pingInfo)
{ {
Assert.assertEquals(0, pingInfo.getPingId() % 2); Assert.assertEquals(0, pingInfo.getPingId() % 2);
Assert.assertEquals(pingId, pingInfo.getPingId()); Assert.assertEquals(pingId, pingInfo.getPingId());

View File

@ -29,6 +29,7 @@ import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.spdy.StandardCompressionFactory; import org.eclipse.jetty.spdy.StandardCompressionFactory;
import org.eclipse.jetty.spdy.api.BytesDataInfo; import org.eclipse.jetty.spdy.api.BytesDataInfo;
import org.eclipse.jetty.spdy.api.DataInfo; import org.eclipse.jetty.spdy.api.DataInfo;
import org.eclipse.jetty.spdy.api.GoAwayInfo;
import org.eclipse.jetty.spdy.api.HeadersInfo; import org.eclipse.jetty.spdy.api.HeadersInfo;
import org.eclipse.jetty.spdy.api.RstInfo; import org.eclipse.jetty.spdy.api.RstInfo;
import org.eclipse.jetty.spdy.api.SPDY; import org.eclipse.jetty.spdy.api.SPDY;
@ -43,6 +44,7 @@ import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
import org.eclipse.jetty.spdy.frames.ControlFrameType; import org.eclipse.jetty.spdy.frames.ControlFrameType;
import org.eclipse.jetty.spdy.frames.SynReplyFrame; import org.eclipse.jetty.spdy.frames.SynReplyFrame;
import org.eclipse.jetty.spdy.generator.Generator; import org.eclipse.jetty.spdy.generator.Generator;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.util.Fields;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@ -64,7 +66,7 @@ public class ProtocolViolationsTest extends AbstractTest
{ {
try try
{ {
stream.data(new StringDataInfo("failure", true)); stream.data(new StringDataInfo("failure", true), new Callback.Adapter());
return null; return null;
} }
catch (IllegalStateException x) catch (IllegalStateException x)
@ -82,7 +84,7 @@ public class ProtocolViolationsTest extends AbstractTest
resetLatch.countDown(); resetLatch.countDown();
} }
}); });
session.syn(new SynInfo(true), null); session.syn(new SynInfo(new Fields(), true), null);
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS));
} }
@ -94,7 +96,7 @@ public class ProtocolViolationsTest extends AbstractTest
server.bind(new InetSocketAddress("localhost", 0)); server.bind(new InetSocketAddress("localhost", 0));
Session session = startClient(new InetSocketAddress("localhost", server.socket().getLocalPort()), null); Session session = startClient(new InetSocketAddress("localhost", server.socket().getLocalPort()), null);
session.syn(new SynInfo(true), null); session.syn(new SynInfo(new Fields(), true), null);
SocketChannel channel = server.accept(); SocketChannel channel = server.accept();
ByteBuffer readBuffer = ByteBuffer.allocate(1024); ByteBuffer readBuffer = ByteBuffer.allocate(1024);
@ -114,7 +116,7 @@ public class ProtocolViolationsTest extends AbstractTest
Assert.assertEquals(ControlFrameType.RST_STREAM.getCode(), readBuffer.getShort(2)); Assert.assertEquals(ControlFrameType.RST_STREAM.getCode(), readBuffer.getShort(2));
Assert.assertEquals(streamId, readBuffer.getInt(8)); Assert.assertEquals(streamId, readBuffer.getInt(8));
session.goAway().get(5,TimeUnit.SECONDS); session.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
server.close(); server.close();
} }
@ -123,7 +125,7 @@ public class ProtocolViolationsTest extends AbstractTest
public void testSendDataAfterCloseIsIllegal() throws Exception public void testSendDataAfterCloseIsIllegal() throws Exception
{ {
Session session = startClient(startServer(null), null); Session session = startClient(startServer(null), null);
Stream stream = session.syn(new SynInfo(true), null).get(5, TimeUnit.SECONDS); Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), null);
stream.data(new StringDataInfo("test", true)); stream.data(new StringDataInfo("test", true));
} }
@ -131,7 +133,7 @@ public class ProtocolViolationsTest extends AbstractTest
public void testSendHeadersAfterCloseIsIllegal() throws Exception public void testSendHeadersAfterCloseIsIllegal() throws Exception
{ {
Session session = startClient(startServer(null), null); Session session = startClient(startServer(null), null);
Stream stream = session.syn(new SynInfo(true), null).get(5, TimeUnit.SECONDS); Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), null);
stream.headers(new HeadersInfo(new Fields(), true)); stream.headers(new HeadersInfo(new Fields(), true));
} }
@ -143,7 +145,7 @@ public class ProtocolViolationsTest extends AbstractTest
Session session = startClient(new InetSocketAddress("localhost", server.socket().getLocalPort()), null); Session session = startClient(new InetSocketAddress("localhost", server.socket().getLocalPort()), null);
final CountDownLatch dataLatch = new CountDownLatch(2); final CountDownLatch dataLatch = new CountDownLatch(2);
session.syn(new SynInfo(false), new StreamFrameListener.Adapter() session.syn(new SynInfo(new Fields(), false), new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onData(Stream stream, DataInfo dataInfo) public void onData(Stream stream, DataInfo dataInfo)
@ -176,7 +178,7 @@ public class ProtocolViolationsTest extends AbstractTest
Assert.assertFalse(dataLatch.await(1, TimeUnit.SECONDS)); Assert.assertFalse(dataLatch.await(1, TimeUnit.SECONDS));
session.goAway().get(5,TimeUnit.SECONDS); session.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
server.close(); server.close();
} }

View File

@ -30,6 +30,7 @@ import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.Exchanger; import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
@ -37,7 +38,8 @@ import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.spdy.StandardCompressionFactory; import org.eclipse.jetty.spdy.StandardCompressionFactory;
import org.eclipse.jetty.spdy.api.BytesDataInfo; import org.eclipse.jetty.spdy.api.BytesDataInfo;
import org.eclipse.jetty.spdy.api.DataInfo; import org.eclipse.jetty.spdy.api.DataInfo;
import org.eclipse.jetty.spdy.api.GoAwayInfo; import org.eclipse.jetty.spdy.api.GoAwayReceivedInfo;
import org.eclipse.jetty.spdy.api.PushInfo;
import org.eclipse.jetty.spdy.api.ReplyInfo; import org.eclipse.jetty.spdy.api.ReplyInfo;
import org.eclipse.jetty.spdy.api.RstInfo; import org.eclipse.jetty.spdy.api.RstInfo;
import org.eclipse.jetty.spdy.api.SPDY; import org.eclipse.jetty.spdy.api.SPDY;
@ -62,6 +64,8 @@ import org.eclipse.jetty.spdy.parser.Parser.Listener;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@ -73,6 +77,8 @@ import static org.junit.Assert.fail;
public class PushStreamTest extends AbstractTest public class PushStreamTest extends AbstractTest
{ {
private static final Logger LOG = Log.getLogger(PushStreamTest.class);
@Test @Test
public void testSynPushStream() throws Exception public void testSynPushStream() throws Exception
{ {
@ -84,8 +90,8 @@ public class PushStreamTest extends AbstractTest
@Override @Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{ {
stream.reply(new ReplyInfo(false)); stream.reply(new ReplyInfo(false), new Callback.Adapter());
stream.syn(new SynInfo(true)); stream.push(new PushInfo(new Fields(), true), new Promise.Adapter<Stream>());
return null; return null;
} }
}), new SessionFrameListener.Adapter() }), new SessionFrameListener.Adapter()
@ -93,13 +99,13 @@ public class PushStreamTest extends AbstractTest
@Override @Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{ {
assertThat("streamId is even",stream.getId() % 2,is(0)); assertThat("streamId is even", stream.getId() % 2, is(0));
assertThat("stream is unidirectional",stream.isUnidirectional(),is(true)); assertThat("stream is unidirectional", stream.isUnidirectional(), is(true));
assertThat("stream is closed",stream.isClosed(),is(true)); assertThat("stream is closed", stream.isClosed(), is(true));
assertThat("stream has associated stream",stream.getAssociatedStream(),notNullValue()); assertThat("stream has associated stream", stream.getAssociatedStream(), notNullValue());
try try
{ {
stream.reply(new ReplyInfo(false)); stream.reply(new ReplyInfo(false), new Callback.Adapter());
fail("Cannot reply to push streams"); fail("Cannot reply to push streams");
} }
catch (IllegalStateException x) catch (IllegalStateException x)
@ -112,10 +118,10 @@ public class PushStreamTest extends AbstractTest
} }
}); });
Stream stream = clientSession.syn(new SynInfo(true),null).get(); Stream stream = clientSession.syn(new SynInfo(new Fields(), true), null);
assertThat("onSyn has been called",pushStreamLatch.await(5,TimeUnit.SECONDS),is(true)); assertThat("onSyn has been called", pushStreamLatch.await(5, TimeUnit.SECONDS), is(true));
Stream pushStream = pushStreamRef.get(); Stream pushStream = pushStreamRef.get();
assertThat("main stream and associated stream are the same",stream,sameInstance(pushStream.getAssociatedStream())); assertThat("main stream and associated stream are the same", stream, sameInstance(pushStream.getAssociatedStream()));
} }
@Test @Test
@ -134,10 +140,10 @@ public class PushStreamTest extends AbstractTest
@Override @Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{ {
stream.reply(new ReplyInfo(false)); stream.reply(new ReplyInfo(false), new Callback.Adapter());
try try
{ {
replyBarrier.await(5,TimeUnit.SECONDS); replyBarrier.await(5, TimeUnit.SECONDS);
return new StreamFrameListener.Adapter() return new StreamFrameListener.Adapter()
{ {
@Override @Override
@ -147,14 +153,14 @@ public class PushStreamTest extends AbstractTest
{ {
if (dataInfo.isClose()) if (dataInfo.isClose())
{ {
stream.data(new StringDataInfo("close stream",true)); stream.data(new StringDataInfo("close stream", true));
closeBarrier.await(5,TimeUnit.SECONDS); closeBarrier.await(5, TimeUnit.SECONDS);
} }
streamDataSent.countDown(); streamDataSent.countDown();
if (pushStreamDataReceived.getCount() == 2) if (pushStreamDataReceived.getCount() == 2)
{ {
Stream pushStream = stream.syn(new SynInfo(false)).get(); Stream pushStream = stream.push(new PushInfo(new Fields(), false));
streamExchanger.exchange(pushStream,5,TimeUnit.SECONDS); streamExchanger.exchange(pushStream, 5, TimeUnit.SECONDS);
} }
} }
catch (Exception e) catch (Exception e)
@ -171,7 +177,7 @@ public class PushStreamTest extends AbstractTest
} }
} }
}),new SessionFrameListener.Adapter() }), new SessionFrameListener.Adapter()
{ {
@Override @Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
@ -183,20 +189,20 @@ public class PushStreamTest extends AbstractTest
public void onData(Stream stream, DataInfo dataInfo) public void onData(Stream stream, DataInfo dataInfo)
{ {
pushStreamDataReceived.countDown(); pushStreamDataReceived.countDown();
super.onData(stream,dataInfo); super.onData(stream, dataInfo);
} }
}; };
} }
}); });
Stream stream = clientSession.syn(new SynInfo(false),new StreamFrameListener.Adapter() Stream stream = clientSession.syn(new SynInfo(new Fields(), false), new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onReply(Stream stream, ReplyInfo replyInfo) public void onReply(Stream stream, ReplyInfo replyInfo)
{ {
try try
{ {
replyBarrier.await(5,TimeUnit.SECONDS); replyBarrier.await(5, TimeUnit.SECONDS);
} }
catch (Exception e) catch (Exception e)
{ {
@ -209,29 +215,29 @@ public class PushStreamTest extends AbstractTest
{ {
try try
{ {
closeBarrier.await(5,TimeUnit.SECONDS); closeBarrier.await(5, TimeUnit.SECONDS);
} }
catch (Exception e) catch (Exception e)
{ {
exceptionCountDownLatch.countDown(); exceptionCountDownLatch.countDown();
} }
} }
}).get(); });
replyBarrier.await(5,TimeUnit.SECONDS); replyBarrier.await(5, TimeUnit.SECONDS);
stream.data(new StringDataInfo("client data",false)); stream.data(new StringDataInfo("client data", false));
Stream pushStream = streamExchanger.exchange(null,5,TimeUnit.SECONDS); Stream pushStream = streamExchanger.exchange(null, 5, TimeUnit.SECONDS);
pushStream.data(new StringDataInfo("first push data frame",false)); pushStream.data(new StringDataInfo("first push data frame", false));
// nasty, but less complex than using another cyclicBarrier for example // nasty, but less complex than using another cyclicBarrier for example
while (pushStreamDataReceived.getCount() != 1) while (pushStreamDataReceived.getCount() != 1)
Thread.sleep(1); Thread.sleep(1);
stream.data(new StringDataInfo("client close",true)); stream.data(new StringDataInfo("client close", true));
closeBarrier.await(5,TimeUnit.SECONDS); closeBarrier.await(5, TimeUnit.SECONDS);
assertThat("stream is closed",stream.isClosed(),is(true)); assertThat("stream is closed", stream.isClosed(), is(true));
pushStream.data(new StringDataInfo("second push data frame while associated stream has been closed already",false)); pushStream.data(new StringDataInfo("second push data frame while associated stream has been closed already", false));
assertThat("2 pushStream data frames have been received.",pushStreamDataReceived.await(5,TimeUnit.SECONDS),is(true)); assertThat("2 pushStream data frames have been received.", pushStreamDataReceived.await(5, TimeUnit.SECONDS), is(true));
assertThat("2 data frames have been sent",streamDataSent.await(5,TimeUnit.SECONDS),is(true)); assertThat("2 data frames have been sent", streamDataSent.await(5, TimeUnit.SECONDS), is(true));
assertThatNoExceptionOccured(exceptionCountDownLatch); assertThatNoExceptionOccurred(exceptionCountDownLatch);
} }
@Test @Test
@ -244,8 +250,9 @@ public class PushStreamTest extends AbstractTest
@Override @Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{ {
stream.reply(new ReplyInfo(true)); stream.reply(new ReplyInfo(true), new Callback.Adapter());
stream.syn(new SynInfo(false),1,TimeUnit.SECONDS,new Promise.Adapter<Stream>() stream.push(new PushInfo(1, TimeUnit.SECONDS, new Fields(), false),
new Promise.Adapter<Stream>()
{ {
@Override @Override
public void failed(Throwable x) public void failed(Throwable x)
@ -253,12 +260,12 @@ public class PushStreamTest extends AbstractTest
pushStreamFailedLatch.countDown(); pushStreamFailedLatch.countDown();
} }
}); });
return super.onSyn(stream,synInfo); return super.onSyn(stream, synInfo);
} }
}),new SessionFrameListener.Adapter()); }), new SessionFrameListener.Adapter());
clientSession.syn(new SynInfo(true),null); clientSession.syn(new SynInfo(new Fields(), true), null);
assertThat("pushStream syn has failed",pushStreamFailedLatch.await(5,TimeUnit.SECONDS),is(true)); assertThat("pushStream push has failed", pushStreamFailedLatch.await(5, TimeUnit.SECONDS), is(true));
} }
@Test @Test
@ -278,11 +285,11 @@ public class PushStreamTest extends AbstractTest
{ {
try try
{ {
Stream pushStream = stream.syn(new SynInfo(false)).get(); Stream pushStream = stream.push(new PushInfo(new Fields(), false));
stream.reply(new ReplyInfo(true)); stream.reply(new ReplyInfo(true));
// wait until stream is closed // wait until stream is closed
streamClosedLatch.await(5,TimeUnit.SECONDS); streamClosedLatch.await(5, TimeUnit.SECONDS);
pushStream.data(new BytesDataInfo(transferBytes,true)); pushStream.data(new BytesDataInfo(transferBytes, true), new Callback.Adapter());
return null; return null;
} }
catch (Exception e) catch (Exception e)
@ -291,7 +298,7 @@ public class PushStreamTest extends AbstractTest
throw new IllegalStateException(e); throw new IllegalStateException(e);
} }
} }
}),new SessionFrameListener.Adapter() }), new SessionFrameListener.Adapter()
{ {
@Override @Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
@ -310,7 +317,7 @@ public class PushStreamTest extends AbstractTest
try try
{ {
receivedBytes.flip(); receivedBytes.flip();
exchanger.exchange(receivedBytes.slice(),5,TimeUnit.SECONDS); exchanger.exchange(receivedBytes.slice(), 5, TimeUnit.SECONDS);
} }
catch (Exception e) catch (Exception e)
{ {
@ -322,23 +329,23 @@ public class PushStreamTest extends AbstractTest
} }
}); });
Stream stream = clientSession.syn(new SynInfo(true),new StreamFrameListener.Adapter() Stream stream = clientSession.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onReply(Stream stream, ReplyInfo replyInfo) public void onReply(Stream stream, ReplyInfo replyInfo)
{ {
streamClosedLatch.countDown(); streamClosedLatch.countDown();
super.onReply(stream,replyInfo); super.onReply(stream, replyInfo);
} }
}).get(); });
ByteBuffer receivedBytes = exchanger.exchange(null,5,TimeUnit.SECONDS); ByteBuffer receivedBytes = exchanger.exchange(null, 5, TimeUnit.SECONDS);
assertThat("received byte array is the same as transferred byte array",Arrays.equals(transferBytes,receivedBytes.array()),is(true)); assertThat("received byte array is the same as transferred byte array", Arrays.equals(transferBytes, receivedBytes.array()), is(true));
assertThat("onReply has been called to close the stream",streamClosedLatch.await(5,TimeUnit.SECONDS),is(true)); assertThat("onReply has been called to close the stream", streamClosedLatch.await(5, TimeUnit.SECONDS), is(true));
assertThat("stream is closed",stream.isClosed(),is(true)); assertThat("stream is closed", stream.isClosed(), is(true));
assertThat("all data has been received",allDataReceived.await(20,TimeUnit.SECONDS),is(true)); assertThat("all data has been received", allDataReceived.await(20, TimeUnit.SECONDS), is(true));
assertThatNoExceptionOccured(exceptionCountDownLatch); assertThatNoExceptionOccurred(exceptionCountDownLatch);
} }
private byte[] createHugeByteArray(int sizeInBytes) private byte[] createHugeByteArray(int sizeInBytes)
@ -364,10 +371,11 @@ public class PushStreamTest extends AbstractTest
} }
private volatile boolean read = true; private volatile boolean read = true;
private void testNoMoreFramesAreSentOnPushStreamAfterClientResetsThePushStream(final boolean flowControl) throws Exception, IOException, InterruptedException
private void testNoMoreFramesAreSentOnPushStreamAfterClientResetsThePushStream(final boolean flowControl) throws Exception
{ {
final short version = SPDY.V3; final short version = SPDY.V3;
final AtomicBoolean unexpectedExceptionOccured = new AtomicBoolean(false); final AtomicBoolean unexpectedExceptionOccurred = new AtomicBoolean(false);
final CountDownLatch resetReceivedLatch = new CountDownLatch(1); final CountDownLatch resetReceivedLatch = new CountDownLatch(1);
final CountDownLatch allDataFramesReceivedLatch = new CountDownLatch(1); final CountDownLatch allDataFramesReceivedLatch = new CountDownLatch(1);
final CountDownLatch goAwayReceivedLatch = new CountDownLatch(1); final CountDownLatch goAwayReceivedLatch = new CountDownLatch(1);
@ -385,20 +393,28 @@ public class PushStreamTest extends AbstractTest
@Override @Override
public void run() public void run()
{ {
Stream pushStream=null; Stream pushStream = null;
try try
{ {
stream.reply(new ReplyInfo(false)); stream.reply(new ReplyInfo(false), new Callback.Adapter());
pushStream = stream.syn(new SynInfo(false)).get(); pushStream = stream.push(new PushInfo(new Fields(), false));
resetReceivedLatch.await(5,TimeUnit.SECONDS); resetReceivedLatch.await(5, TimeUnit.SECONDS);
} }
catch (InterruptedException | ExecutionException e) catch (InterruptedException | ExecutionException | TimeoutException e)
{ {
e.printStackTrace(); e.printStackTrace();
unexpectedExceptionOccured.set(true); unexpectedExceptionOccurred.set(true);
}
assert pushStream != null;
try
{
pushStream.data(new BytesDataInfo(transferBytes, true));
stream.data(new StringDataInfo("close", true));
}
catch (InterruptedException | ExecutionException | TimeoutException e)
{
LOG.debug(e.getMessage());
} }
pushStream.data(new BytesDataInfo(transferBytes,true));
stream.data(new StringDataInfo("close",true));
} }
}).start(); }).start();
return null; return null;
@ -411,7 +427,7 @@ public class PushStreamTest extends AbstractTest
} }
@Override @Override
public void onGoAway(Session session, GoAwayInfo goAwayInfo) public void onGoAway(Session session, GoAwayReceivedInfo goAwayInfo)
{ {
goAwayReceivedLatch.countDown(); goAwayReceivedLatch.countDown();
} }
@ -420,9 +436,9 @@ public class PushStreamTest extends AbstractTest
final SocketChannel channel = SocketChannel.open(serverAddress); final SocketChannel channel = SocketChannel.open(serverAddress);
final Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory.StandardCompressor()); final Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory.StandardCompressor());
int streamId = 1; int streamId = 1;
ByteBuffer writeBuffer = generator.control(new SynStreamFrame(version,(byte)0,streamId,0,(byte)0,(short)0,new Fields())); ByteBuffer writeBuffer = generator.control(new SynStreamFrame(version, (byte)0, streamId, 0, (byte)0, (short)0, new Fields()));
channel.write(writeBuffer); channel.write(writeBuffer);
assertThat("writeBuffer is fully written",writeBuffer.hasRemaining(), is(false)); assertThat("writeBuffer is fully written", writeBuffer.hasRemaining(), is(false));
final Parser parser = new Parser(new StandardCompressionFactory.StandardDecompressor()); final Parser parser = new Parser(new StandardCompressionFactory.StandardDecompressor());
parser.addListener(new Listener.Adapter() parser.addListener(new Listener.Adapter()
@ -432,9 +448,10 @@ public class PushStreamTest extends AbstractTest
@Override @Override
public void onControlFrame(ControlFrame frame) public void onControlFrame(ControlFrame frame)
{ {
if(frame instanceof SynStreamFrame){ if (frame instanceof SynStreamFrame)
{
int pushStreamId = ((SynStreamFrame)frame).getStreamId(); int pushStreamId = ((SynStreamFrame)frame).getStreamId();
ByteBuffer writeBuffer = generator.control(new RstStreamFrame(version,pushStreamId,StreamStatus.CANCEL_STREAM.getCode(version))); ByteBuffer writeBuffer = generator.control(new RstStreamFrame(version, pushStreamId, StreamStatus.CANCEL_STREAM.getCode(version)));
try try
{ {
channel.write(writeBuffer); channel.write(writeBuffer);
@ -442,7 +459,7 @@ public class PushStreamTest extends AbstractTest
catch (IOException e) catch (IOException e)
{ {
e.printStackTrace(); e.printStackTrace();
unexpectedExceptionOccured.set(true); unexpectedExceptionOccurred.set(true);
} }
} }
} }
@ -450,15 +467,16 @@ public class PushStreamTest extends AbstractTest
@Override @Override
public void onDataFrame(DataFrame frame, ByteBuffer data) public void onDataFrame(DataFrame frame, ByteBuffer data)
{ {
if(frame.getStreamId() == 2) if (frame.getStreamId() == 2)
bytesRead = bytesRead + frame.getLength(); bytesRead = bytesRead + frame.getLength();
if(bytesRead == dataSizeInBytes){ if (bytesRead == dataSizeInBytes)
{
allDataFramesReceivedLatch.countDown(); allDataFramesReceivedLatch.countDown();
return; return;
} }
if (flowControl) if (flowControl)
{ {
ByteBuffer writeBuffer = generator.control(new WindowUpdateFrame(version,frame.getStreamId(),frame.getLength())); ByteBuffer writeBuffer = generator.control(new WindowUpdateFrame(version, frame.getStreamId(), frame.getLength()));
try try
{ {
channel.write(writeBuffer); channel.write(writeBuffer);
@ -466,7 +484,7 @@ public class PushStreamTest extends AbstractTest
catch (IOException e) catch (IOException e)
{ {
e.printStackTrace(); e.printStackTrace();
unexpectedExceptionOccured.set(true); unexpectedExceptionOccurred.set(true);
} }
} }
} }
@ -477,7 +495,7 @@ public class PushStreamTest extends AbstractTest
@Override @Override
public void run() public void run()
{ {
ByteBuffer readBuffer = ByteBuffer.allocate(dataSizeInBytes*2); ByteBuffer readBuffer = ByteBuffer.allocate(dataSizeInBytes * 2);
while (read) while (read)
{ {
try try
@ -487,7 +505,7 @@ public class PushStreamTest extends AbstractTest
catch (IOException e) catch (IOException e)
{ {
e.printStackTrace(); e.printStackTrace();
unexpectedExceptionOccured.set(true); unexpectedExceptionOccurred.set(true);
} }
readBuffer.flip(); readBuffer.flip();
parser.parse(readBuffer); parser.parse(readBuffer);
@ -499,15 +517,15 @@ public class PushStreamTest extends AbstractTest
reader.start(); reader.start();
read = false; read = false;
assertThat("no unexpected exceptions occured", unexpectedExceptionOccured.get(), is(false)); assertThat("no unexpected exceptions occurred", unexpectedExceptionOccurred.get(), is(false));
assertThat("not all dataframes have been received as the pushstream has been reset by the client.",allDataFramesReceivedLatch.await(streamId,TimeUnit.SECONDS),is(false)); assertThat("not all dataframes have been received as the pushstream has been reset by the client.", allDataFramesReceivedLatch.await(streamId, TimeUnit.SECONDS), is(false));
ByteBuffer buffer = generator.control(new GoAwayFrame(version, streamId, SessionStatus.OK.getCode())); ByteBuffer buffer = generator.control(new GoAwayFrame(version, streamId, SessionStatus.OK.getCode()));
channel.write(buffer); channel.write(buffer);
Assert.assertThat(buffer.hasRemaining(), is(false)); Assert.assertThat(buffer.hasRemaining(), is(false));
assertThat("GoAway frame is received by server", goAwayReceivedLatch.await(5,TimeUnit.SECONDS), is(true)); assertThat("GoAway frame is received by server", goAwayReceivedLatch.await(5, TimeUnit.SECONDS), is(true));
channel.shutdownOutput(); channel.shutdownOutput();
channel.close(); channel.close();
} }
@ -522,42 +540,42 @@ public class PushStreamTest extends AbstractTest
@Override @Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{ {
stream.syn(new SynInfo(false)); stream.push(new PushInfo(new Fields(), false), new Promise.Adapter<Stream>());
return null; return null;
} }
}),new SessionFrameListener.Adapter() }), new SessionFrameListener.Adapter()
{ {
@Override @Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{ {
assertStreamIdIsEven(stream); assertStreamIdIsEven(stream);
pushStreamIdIsEvenLatch.countDown(); pushStreamIdIsEvenLatch.countDown();
return super.onSyn(stream,synInfo); return super.onSyn(stream, synInfo);
} }
}); });
Stream stream = clientSession.syn(new SynInfo(false),null).get(); Stream stream = clientSession.syn(new SynInfo(new Fields(), false), null);
Stream stream2 = clientSession.syn(new SynInfo(false),null).get(); Stream stream2 = clientSession.syn(new SynInfo(new Fields(), false), null);
Stream stream3 = clientSession.syn(new SynInfo(false),null).get(); Stream stream3 = clientSession.syn(new SynInfo(new Fields(), false), null);
assertStreamIdIsOdd(stream); assertStreamIdIsOdd(stream);
assertStreamIdIsOdd(stream2); assertStreamIdIsOdd(stream2);
assertStreamIdIsOdd(stream3); assertStreamIdIsOdd(stream3);
assertThat("all pushStreams had even ids",pushStreamIdIsEvenLatch.await(5,TimeUnit.SECONDS),is(true)); assertThat("all pushStreams had even ids", pushStreamIdIsEvenLatch.await(5, TimeUnit.SECONDS), is(true));
} }
private void assertStreamIdIsEven(Stream stream) private void assertStreamIdIsEven(Stream stream)
{ {
assertThat("streamId is odd",stream.getId() % 2,is(0)); assertThat("streamId is odd", stream.getId() % 2, is(0));
} }
private void assertStreamIdIsOdd(Stream stream) private void assertStreamIdIsOdd(Stream stream)
{ {
assertThat("streamId is odd",stream.getId() % 2,is(1)); assertThat("streamId is odd", stream.getId() % 2, is(1));
} }
private void assertThatNoExceptionOccured(final CountDownLatch exceptionCountDownLatch) throws InterruptedException private void assertThatNoExceptionOccurred(final CountDownLatch exceptionCountDownLatch) throws InterruptedException
{ {
assertThat("No exception occured",exceptionCountDownLatch.await(1,TimeUnit.SECONDS),is(false)); assertThat("No exception occurred", exceptionCountDownLatch.await(1, TimeUnit.SECONDS), is(false));
} }
} }

View File

@ -33,6 +33,8 @@ import org.eclipse.jetty.spdy.api.StringDataInfo;
import org.eclipse.jetty.spdy.api.SynInfo; import org.eclipse.jetty.spdy.api.SynInfo;
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.FutureCallback;
import org.junit.Test; import org.junit.Test;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
@ -46,12 +48,12 @@ public class ResetStreamTest extends AbstractTest
@Test @Test
public void testResetStreamIsRemoved() throws Exception public void testResetStreamIsRemoved() throws Exception
{ {
Session session = startClient(startServer(new ServerSessionFrameListener.Adapter()/*TODO, true*/),null); Session session = startClient(startServer(new ServerSessionFrameListener.Adapter()/*TODO, true*/), null);
Stream stream = session.syn(new SynInfo(false),null).get(5,TimeUnit.SECONDS); Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), null);
session.rst(new RstInfo(stream.getId(),StreamStatus.CANCEL_STREAM)).get(5,TimeUnit.SECONDS); session.rst(new RstInfo(5, TimeUnit.SECONDS, stream.getId(), StreamStatus.CANCEL_STREAM));
assertEquals("session expected to contain 0 streams",0,session.getStreams().size()); assertEquals("session expected to contain 0 streams", 0, session.getStreams().size());
} }
@Test @Test
@ -67,11 +69,11 @@ public class ResetStreamTest extends AbstractTest
{ {
Session serverSession = stream.getSession(); Session serverSession = stream.getSession();
serverSessionRef.set(serverSession); serverSessionRef.set(serverSession);
serverSession.rst(new RstInfo(stream.getId(),StreamStatus.REFUSED_STREAM)); serverSession.rst(new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM), new FutureCallback());
synLatch.countDown(); synLatch.countDown();
return null; return null;
} }
}),new SessionFrameListener.Adapter() }), new SessionFrameListener.Adapter()
{ {
@Override @Override
public void onRst(Session session, RstInfo rstInfo) public void onRst(Session session, RstInfo rstInfo)
@ -80,17 +82,17 @@ public class ResetStreamTest extends AbstractTest
} }
}); });
Stream stream = clientSession.syn(new SynInfo(false),null).get(5,TimeUnit.SECONDS); Stream stream = clientSession.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), null);
assertTrue("syncLatch didn't count down",synLatch.await(5,TimeUnit.SECONDS)); assertTrue("syncLatch didn't count down", synLatch.await(5, TimeUnit.SECONDS));
Session serverSession = serverSessionRef.get(); Session serverSession = serverSessionRef.get();
assertEquals("serverSession expected to contain 0 streams",0,serverSession.getStreams().size()); assertEquals("serverSession expected to contain 0 streams", 0, serverSession.getStreams().size());
assertTrue("rstLatch didn't count down",rstLatch.await(5,TimeUnit.SECONDS)); assertTrue("rstLatch didn't count down", rstLatch.await(5, TimeUnit.SECONDS));
// Need to sleep a while to give the chance to the implementation to remove the stream // Need to sleep a while to give the chance to the implementation to remove the stream
TimeUnit.SECONDS.sleep(1); TimeUnit.SECONDS.sleep(1);
assertTrue("stream is expected to be reset",stream.isReset()); assertTrue("stream is expected to be reset", stream.isReset());
assertEquals("clientSession expected to contain 0 streams",0,clientSession.getStreams().size()); assertEquals("clientSession expected to contain 0 streams", 0, clientSession.getStreams().size());
} }
@Test @Test
@ -107,8 +109,8 @@ public class ResetStreamTest extends AbstractTest
try try
{ {
// Refuse the stream, we must ignore data frames // Refuse the stream, we must ignore data frames
assertTrue(synLatch.await(5,TimeUnit.SECONDS)); assertTrue(synLatch.await(5, TimeUnit.SECONDS));
stream.getSession().rst(new RstInfo(stream.getId(),StreamStatus.REFUSED_STREAM)); stream.getSession().rst(new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM), new FutureCallback());
return new StreamFrameListener.Adapter() return new StreamFrameListener.Adapter()
{ {
@Override @Override
@ -124,7 +126,7 @@ public class ResetStreamTest extends AbstractTest
return null; return null;
} }
} }
}),new SessionFrameListener.Adapter() }), new SessionFrameListener.Adapter()
{ {
@Override @Override
public void onRst(Session session, RstInfo rstInfo) public void onRst(Session session, RstInfo rstInfo)
@ -133,8 +135,8 @@ public class ResetStreamTest extends AbstractTest
} }
}); });
Stream stream = session.syn(new SynInfo(false),null).get(5,TimeUnit.SECONDS); Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), null);
stream.data(new StringDataInfo("data",true),5,TimeUnit.SECONDS,new Callback.Adapter() stream.data(new StringDataInfo(5, TimeUnit.SECONDS, "data", true), new Callback.Adapter()
{ {
@Override @Override
public void succeeded() public void succeeded()
@ -143,9 +145,9 @@ public class ResetStreamTest extends AbstractTest
} }
}); });
assertTrue("rstLatch didn't count down",rstLatch.await(5,TimeUnit.SECONDS)); assertTrue("rstLatch didn't count down", rstLatch.await(5, TimeUnit.SECONDS));
assertTrue("stream is expected to be reset",stream.isReset()); assertTrue("stream is expected to be reset", stream.isReset());
assertFalse("dataLatch shouln't be count down",dataLatch.await(1,TimeUnit.SECONDS)); assertFalse("dataLatch shouldn't be count down", dataLatch.await(1, TimeUnit.SECONDS));
} }
@Test @Test
@ -167,11 +169,11 @@ public class ResetStreamTest extends AbstractTest
public void onData(Stream stream, DataInfo dataInfo) public void onData(Stream stream, DataInfo dataInfo)
{ {
dataLatch.countDown(); dataLatch.countDown();
stream.getSession().rst(new RstInfo(stream.getId(),StreamStatus.REFUSED_STREAM)); stream.getSession().rst(new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM), new FutureCallback());
} }
}; };
} }
}),new SessionFrameListener.Adapter() }), new SessionFrameListener.Adapter()
{ {
@Override @Override
public void onRst(Session session, RstInfo rstInfo) public void onRst(Session session, RstInfo rstInfo)
@ -180,11 +182,11 @@ public class ResetStreamTest extends AbstractTest
} }
}); });
Stream stream = session.syn(new SynInfo(false),null).get(5,TimeUnit.SECONDS); Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), null);
assertThat("syn is received by server", synLatch.await(5,TimeUnit.SECONDS),is(true)); assertThat("push is received by server", synLatch.await(5, TimeUnit.SECONDS), is(true));
stream.data(new StringDataInfo("data",false),5,TimeUnit.SECONDS,new Callback.Adapter()); stream.data(new StringDataInfo(5, TimeUnit.SECONDS, "data", false), new Callback.Adapter());
assertThat("stream is reset",rstLatch.await(5,TimeUnit.SECONDS),is(true)); assertThat("stream is reset", rstLatch.await(5, TimeUnit.SECONDS), is(true));
stream.data(new StringDataInfo("2nd dataframe",false),5L,TimeUnit.SECONDS,new Callback.Adapter() stream.data(new StringDataInfo(5, TimeUnit.SECONDS, "2nd dataframe", false), new Callback.Adapter()
{ {
@Override @Override
public void failed(Throwable x) public void failed(Throwable x)
@ -193,8 +195,8 @@ public class ResetStreamTest extends AbstractTest
} }
}); });
assertThat("2nd data call failed",failLatch.await(5,TimeUnit.SECONDS),is(true)); assertThat("2nd data call failed", failLatch.await(5, TimeUnit.SECONDS), is(true));
assertThat("stream is reset",stream.isReset(),is(true)); assertThat("stream is reset", stream.isReset(), is(true));
} }
// TODO: If server already received 2nd dataframe after it rst, it should ignore it. Not easy to do. // TODO: If server already received 2nd dataframe after it rst, it should ignore it. Not easy to do.

View File

@ -23,6 +23,7 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.spdy.api.GoAwayInfo; import org.eclipse.jetty.spdy.api.GoAwayInfo;
import org.eclipse.jetty.spdy.api.GoAwayReceivedInfo;
import org.eclipse.jetty.spdy.api.Session; import org.eclipse.jetty.spdy.api.Session;
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
import org.junit.Assert; import org.junit.Assert;
@ -37,7 +38,7 @@ public class SPDYClientFactoryTest extends AbstractTest
startClient(startServer(new ServerSessionFrameListener.Adapter() startClient(startServer(new ServerSessionFrameListener.Adapter()
{ {
@Override @Override
public void onGoAway(Session session, GoAwayInfo goAwayInfo) public void onGoAway(Session session, GoAwayReceivedInfo goAwayReceivedInfo)
{ {
latch.countDown(); latch.countDown();
} }
@ -58,7 +59,7 @@ public class SPDYClientFactoryTest extends AbstractTest
{ {
Session session = startClient(startServer(null), null); Session session = startClient(startServer(null), null);
session.goAway().get(5, TimeUnit.SECONDS); session.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
// Sleep a while to allow the factory to remove the session // Sleep a while to allow the factory to remove the session
// since it is done asynchronously by the selector thread // since it is done asynchronously by the selector thread

View File

@ -23,6 +23,7 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.spdy.api.GoAwayInfo; import org.eclipse.jetty.spdy.api.GoAwayInfo;
import org.eclipse.jetty.spdy.api.GoAwayReceivedInfo;
import org.eclipse.jetty.spdy.api.Session; import org.eclipse.jetty.spdy.api.Session;
import org.eclipse.jetty.spdy.api.SessionFrameListener; import org.eclipse.jetty.spdy.api.SessionFrameListener;
import org.junit.Assert; import org.junit.Assert;
@ -37,7 +38,7 @@ public class SPDYServerConnectorTest extends AbstractTest
startClient(startServer(null), new SessionFrameListener.Adapter() startClient(startServer(null), new SessionFrameListener.Adapter()
{ {
@Override @Override
public void onGoAway(Session session, GoAwayInfo goAwayInfo) public void onGoAway(Session session, GoAwayReceivedInfo goAwayReceivedInfo)
{ {
latch.countDown(); latch.countDown();
} }
@ -58,7 +59,7 @@ public class SPDYServerConnectorTest extends AbstractTest
{ {
Session session = startClient(startServer(null), null); Session session = startClient(startServer(null), null);
session.goAway().get(5, TimeUnit.SECONDS); session.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
// Sleep a while to allow the connector to remove the session // Sleep a while to allow the connector to remove the session
// since it is done asynchronously by the selector thread // since it is done asynchronously by the selector thread

View File

@ -25,6 +25,7 @@ import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.npn.NextProtoNego; import org.eclipse.jetty.npn.NextProtoNego;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.spdy.api.GoAwayInfo;
import org.eclipse.jetty.spdy.api.Session; import org.eclipse.jetty.spdy.api.Session;
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
import org.eclipse.jetty.spdy.client.SPDYClient; import org.eclipse.jetty.spdy.client.SPDYClient;
@ -83,6 +84,6 @@ public class SSLEngineLeakTest extends AbstractTest
private void avoidStackLocalVariables() throws Exception private void avoidStackLocalVariables() throws Exception
{ {
Session session = startClient(startServer(null), null); Session session = startClient(startServer(null), null);
session.goAway().get(5, TimeUnit.SECONDS); session.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
} }
} }

View File

@ -31,6 +31,7 @@ import org.eclipse.jetty.spdy.api.SessionFrameListener;
import org.eclipse.jetty.spdy.api.Settings; import org.eclipse.jetty.spdy.api.Settings;
import org.eclipse.jetty.spdy.api.SettingsInfo; import org.eclipse.jetty.spdy.api.SettingsInfo;
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
import org.eclipse.jetty.util.FutureCallback;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@ -106,7 +107,7 @@ public class SettingsTest extends AbstractTest
@Override @Override
public void onConnect(Session session) public void onConnect(Session session)
{ {
session.settings(serverSettingsInfo); session.settings(serverSettingsInfo, new FutureCallback());
} }
}; };

View File

@ -57,14 +57,14 @@ public class SynDataReplyDataLoadTest extends AbstractTest
@Override @Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{ {
stream.reply(new ReplyInfo(synInfo.getHeaders(), false)); stream.reply(new ReplyInfo(synInfo.getHeaders(), false), new Callback.Adapter());
return new StreamFrameListener.Adapter() return new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onData(Stream stream, DataInfo dataInfo) public void onData(Stream stream, DataInfo dataInfo)
{ {
ByteBuffer buffer = dataInfo.asByteBuffer(true); ByteBuffer buffer = dataInfo.asByteBuffer(true);
stream.data(new ByteBufferDataInfo(buffer, dataInfo.isClose())); stream.data(new ByteBufferDataInfo(buffer, dataInfo.isClose()), new Callback.Adapter());
} }
}; };
} }
@ -173,12 +173,13 @@ public class SynDataReplyDataLoadTest extends AbstractTest
latch.countDown(); latch.countDown();
} }
} }
}, 0, TimeUnit.SECONDS, new Promise.Adapter<Stream>() }, new Promise.Adapter<Stream>()
{ {
@Override @Override
public void succeeded(Stream stream) public void succeeded(Stream stream)
{ {
stream.data(new StringDataInfo("data_" + stream.getId(), true), 0, TimeUnit.SECONDS, new Callback.Adapter()); stream.data(new StringDataInfo("data_" + stream.getId(), true),
new Callback.Adapter());
} }
}); });
} }
@ -195,7 +196,8 @@ public class SynDataReplyDataLoadTest extends AbstractTest
final AtomicInteger count = new AtomicInteger(2); final AtomicInteger count = new AtomicInteger(2);
final int index = i; final int index = i;
counter.put(index, index); counter.put(index, index);
Stream stream = session.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter() Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0),
new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onReply(Stream stream, ReplyInfo replyInfo) public void onReply(Stream stream, ReplyInfo replyInfo)
@ -216,8 +218,8 @@ public class SynDataReplyDataLoadTest extends AbstractTest
latch.countDown(); latch.countDown();
} }
} }
}).get(5, TimeUnit.SECONDS); });
stream.data(new StringDataInfo("data_" + stream.getId(), true)).get(5, TimeUnit.SECONDS); stream.data(new StringDataInfo(5, TimeUnit.SECONDS, "data_" + stream.getId(), true));
} }
Assert.assertTrue(latch.await(iterations, TimeUnit.SECONDS)); Assert.assertTrue(latch.await(iterations, TimeUnit.SECONDS));
Assert.assertTrue(counter.toString(), counter.isEmpty()); Assert.assertTrue(counter.toString(), counter.isEmpty());

View File

@ -64,7 +64,7 @@ public class SynReplyTest extends AbstractTest
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{ {
Assert.assertTrue(stream.isHalfClosed()); Assert.assertTrue(stream.isHalfClosed());
stream.reply(new ReplyInfo(new Fields(), true)); stream.reply(new ReplyInfo(new Fields(), true), new Callback.Adapter());
synLatch.countDown(); synLatch.countDown();
return null; return null;
} }
@ -94,7 +94,8 @@ public class SynReplyTest extends AbstractTest
}); });
final CountDownLatch replyLatch = new CountDownLatch(1); final CountDownLatch replyLatch = new CountDownLatch(1);
Stream stream = session.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter() Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0),
new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onReply(Stream stream, ReplyInfo replyInfo) public void onReply(Stream stream, ReplyInfo replyInfo)
@ -102,7 +103,7 @@ public class SynReplyTest extends AbstractTest
Assert.assertTrue(stream.isClosed()); Assert.assertTrue(stream.isClosed());
replyLatch.countDown(); replyLatch.countDown();
} }
}).get(5, TimeUnit.SECONDS); });
Assert.assertTrue(synLatch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(synLatch.await(5, TimeUnit.SECONDS));
@ -147,7 +148,7 @@ public class SynReplyTest extends AbstractTest
Assert.assertTrue(stream.isHalfClosed()); Assert.assertTrue(stream.isHalfClosed());
Assert.assertFalse(stream.isClosed()); Assert.assertFalse(stream.isClosed());
stream.reply(new ReplyInfo(true)); stream.reply(new ReplyInfo(true), new Callback.Adapter());
Assert.assertTrue(stream.isClosed()); Assert.assertTrue(stream.isClosed());
dataLatch.countDown(); dataLatch.countDown();
} }
@ -168,14 +169,15 @@ public class SynReplyTest extends AbstractTest
}); });
final CountDownLatch replyLatch = new CountDownLatch(1); final CountDownLatch replyLatch = new CountDownLatch(1);
Stream stream = session.syn(new SynInfo(false), new StreamFrameListener.Adapter() Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0),
new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onReply(Stream stream, ReplyInfo replyInfo) public void onReply(Stream stream, ReplyInfo replyInfo)
{ {
replyLatch.countDown(); replyLatch.countDown();
} }
}).get(5, TimeUnit.SECONDS); });
stream.data(new BytesDataInfo(dataBytes, true)); stream.data(new BytesDataInfo(dataBytes, true));
Assert.assertTrue(synLatch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(synLatch.await(5, TimeUnit.SECONDS));
@ -199,13 +201,13 @@ public class SynReplyTest extends AbstractTest
{ {
Assert.assertTrue(stream.isHalfClosed()); Assert.assertTrue(stream.isHalfClosed());
stream.reply(new ReplyInfo(false)); stream.reply(new ReplyInfo(false), new Callback.Adapter());
stream.data(new StringDataInfo(data1, false), 5, TimeUnit.SECONDS, new Callback.Adapter() stream.data(new StringDataInfo(5, TimeUnit.SECONDS, data1, false), new Callback.Adapter()
{ {
@Override @Override
public void succeeded() public void succeeded()
{ {
stream.data(new StringDataInfo(data2, true)); stream.data(new StringDataInfo(data2, true), new Adapter());
} }
}); });
@ -216,7 +218,7 @@ public class SynReplyTest extends AbstractTest
final CountDownLatch replyLatch = new CountDownLatch(1); final CountDownLatch replyLatch = new CountDownLatch(1);
final CountDownLatch dataLatch1 = new CountDownLatch(1); final CountDownLatch dataLatch1 = new CountDownLatch(1);
final CountDownLatch dataLatch2 = new CountDownLatch(1); final CountDownLatch dataLatch2 = new CountDownLatch(1);
session.syn(new SynInfo(true), new StreamFrameListener.Adapter() session.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter()
{ {
private AtomicInteger dataCount = new AtomicInteger(); private AtomicInteger dataCount = new AtomicInteger();
@ -264,7 +266,7 @@ public class SynReplyTest extends AbstractTest
@Override @Override
public void onConnect(Session session) public void onConnect(Session session)
{ {
session.syn(new SynInfo(false), new StreamFrameListener.Adapter() session.syn(new SynInfo(new Fields(), false), new StreamFrameListener.Adapter()
{ {
@Override @Override
public void onReply(Stream stream, ReplyInfo replyInfo) public void onReply(Stream stream, ReplyInfo replyInfo)
@ -279,12 +281,12 @@ public class SynReplyTest extends AbstractTest
Assert.assertEquals(clientData, data); Assert.assertEquals(clientData, data);
clientDataLatch.countDown(); clientDataLatch.countDown();
} }
}, 0, TimeUnit.MILLISECONDS, new Promise.Adapter<Stream>() }, new Promise.Adapter<Stream>()
{ {
@Override @Override
public void succeeded(Stream stream) public void succeeded(Stream stream)
{ {
stream.data(new StringDataInfo(serverData, true)); stream.data(new StringDataInfo(serverData, true), new Callback.Adapter());
} }
}); });
} }
@ -299,8 +301,8 @@ public class SynReplyTest extends AbstractTest
{ {
Assert.assertEquals(0, stream.getId() % 2); Assert.assertEquals(0, stream.getId() % 2);
stream.reply(new ReplyInfo(false)); stream.reply(new ReplyInfo(false), new Callback.Adapter());
stream.data(new StringDataInfo(clientData, true)); stream.data(new StringDataInfo(clientData, true), new Callback.Adapter());
synLatch.countDown(); synLatch.countDown();
return new StreamFrameListener.Adapter() return new StreamFrameListener.Adapter()
@ -336,8 +338,8 @@ public class SynReplyTest extends AbstractTest
{ {
Assert.assertTrue(stream.isHalfClosed()); Assert.assertTrue(stream.isHalfClosed());
stream.reply(new ReplyInfo(false)); stream.reply(new ReplyInfo(false), new Callback.Adapter());
stream.data(new StringDataInfo(data, true)); stream.data(new StringDataInfo(data, true), new Callback.Adapter());
return null; return null;
} }
@ -364,8 +366,8 @@ public class SynReplyTest extends AbstractTest
dataLatch.countDown(); dataLatch.countDown();
} }
}; };
session.syn(new SynInfo(true), clientStreamFrameListener); session.syn(new SynInfo(new Fields(), true), clientStreamFrameListener);
session.syn(new SynInfo(true), clientStreamFrameListener); session.syn(new SynInfo(new Fields(), true), clientStreamFrameListener);
Assert.assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));

View File

@ -18,71 +18,68 @@
package org.eclipse.jetty.util; package org.eclipse.jetty.util;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.HashSet; import java.util.HashSet;
import java.util.ListIterator;
import java.util.Random; import java.util.Random;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CyclicBarrier; import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.jetty.toolchain.test.AdvancedRunner; import org.eclipse.jetty.toolchain.test.AdvancedRunner;
import org.eclipse.jetty.toolchain.test.annotation.Slow; import org.eclipse.jetty.toolchain.test.annotation.Slow;
import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@RunWith(AdvancedRunner.class) @RunWith(AdvancedRunner.class)
public class BlockingArrayQueueTest public class BlockingArrayQueueTest
{ {
@Test @Test
public void testWrap() throws Exception public void testWrap() throws Exception
{ {
BlockingArrayQueue<String> queue = new BlockingArrayQueue<String>(3); BlockingArrayQueue<String> queue = new BlockingArrayQueue<>(3);
assertEquals(0,queue.size()); Assert.assertEquals(0, queue.size());
for (int i=0;i<3;i++) for (int i=0;i<queue.getMaxCapacity();i++)
{ {
queue.offer("one"); queue.offer("one");
assertEquals(1,queue.size()); Assert.assertEquals(1, queue.size());
queue.offer("two"); queue.offer("two");
assertEquals(2,queue.size()); Assert.assertEquals(2, queue.size());
queue.offer("three"); queue.offer("three");
assertEquals(3,queue.size()); Assert.assertEquals(3, queue.size());
assertEquals("one",queue.get(0)); Assert.assertEquals("one", queue.get(0));
assertEquals("two",queue.get(1)); Assert.assertEquals("two", queue.get(1));
assertEquals("three",queue.get(2)); Assert.assertEquals("three", queue.get(2));
assertEquals("[one, two, three]",queue.toString()); Assert.assertEquals("[one, two, three]", queue.toString());
assertEquals("one",queue.poll()); Assert.assertEquals("one", queue.poll());
assertEquals(2,queue.size()); Assert.assertEquals(2, queue.size());
assertEquals("two",queue.poll()); Assert.assertEquals("two", queue.poll());
assertEquals(1,queue.size()); Assert.assertEquals(1, queue.size());
assertEquals("three",queue.poll()); Assert.assertEquals("three", queue.poll());
assertEquals(0,queue.size()); Assert.assertEquals(0, queue.size());
queue.offer("xxx"); queue.offer("xxx");
assertEquals(1,queue.size()); Assert.assertEquals(1, queue.size());
assertEquals("xxx",queue.poll()); Assert.assertEquals("xxx", queue.poll());
assertEquals(0,queue.size()); Assert.assertEquals(0, queue.size());
} }
} }
@Test @Test
public void testRemove() throws Exception public void testRemove() throws Exception
{ {
BlockingArrayQueue<String> queue = new BlockingArrayQueue<String>(3,3); BlockingArrayQueue<String> queue = new BlockingArrayQueue<>(3,3);
queue.add("0"); queue.add("0");
queue.add("x"); queue.add("x");
@ -96,23 +93,36 @@ public class BlockingArrayQueueTest
} }
for (int i=0;i<99;i++) for (int i=0;i<99;i++)
assertEquals(i+"!",queue.get(i)); Assert.assertEquals(i + "!", queue.get(i));
}
@Test
public void testLimit() throws Exception
{
BlockingArrayQueue<String> queue = new BlockingArrayQueue<>(1,0,1);
String element = "0";
Assert.assertTrue(queue.add(element));
Assert.assertFalse(queue.offer("1"));
Assert.assertEquals(element, queue.poll());
Assert.assertTrue(queue.add(element));
} }
@Test @Test
public void testGrow() throws Exception public void testGrow() throws Exception
{ {
BlockingArrayQueue<String> queue = new BlockingArrayQueue<String>(3,2); BlockingArrayQueue<String> queue = new BlockingArrayQueue<>(3,2);
assertEquals(3,queue.getCapacity()); Assert.assertEquals(3, queue.getCapacity());
queue.add("a"); queue.add("a");
queue.add("a"); queue.add("a");
assertEquals(2,queue.size()); Assert.assertEquals(2, queue.size());
assertEquals(3,queue.getCapacity()); Assert.assertEquals(3, queue.getCapacity());
queue.add("a"); queue.add("a");
queue.add("a"); queue.add("a");
assertEquals(4,queue.size()); Assert.assertEquals(4, queue.size());
assertEquals(5,queue.getCapacity()); Assert.assertEquals(5, queue.getCapacity());
int s=5; int s=5;
int c=5; int c=5;
@ -120,25 +130,25 @@ public class BlockingArrayQueueTest
for (int t=0;t<100;t++) for (int t=0;t<100;t++)
{ {
assertEquals(s,queue.size()); Assert.assertEquals(s, queue.size());
assertEquals(c,queue.getCapacity()); Assert.assertEquals(c, queue.getCapacity());
for (int i=queue.size();i-->0;) for (int i=queue.size();i-->0;)
queue.poll(); queue.poll();
assertEquals(0,queue.size()); Assert.assertEquals(0, queue.size());
assertEquals(c,queue.getCapacity()); Assert.assertEquals(c, queue.getCapacity());
for (int i=queue.getCapacity();i-->0;) for (int i=queue.getCapacity();i-->0;)
queue.add("a"); queue.add("a");
queue.add("a"); queue.add("a");
assertEquals(s+1,queue.size()); Assert.assertEquals(s + 1, queue.size());
assertEquals(c+2,queue.getCapacity()); Assert.assertEquals(c + 2, queue.getCapacity());
queue.poll(); queue.poll();
queue.add("a"); queue.add("a");
queue.add("a"); queue.add("a");
assertEquals(s+2,queue.size()); Assert.assertEquals(s + 2, queue.size());
assertEquals(c+2,queue.getCapacity()); Assert.assertEquals(c + 2, queue.getCapacity());
s+=2; s+=2;
c+=2; c+=2;
@ -151,7 +161,7 @@ public class BlockingArrayQueueTest
{ {
final String[] data=new String[4]; final String[] data=new String[4];
final BlockingArrayQueue<String> queue = new BlockingArrayQueue<String>(); final BlockingArrayQueue<String> queue = new BlockingArrayQueue<>();
Thread thread = new Thread() Thread thread = new Thread()
{ {
@ -168,8 +178,8 @@ public class BlockingArrayQueueTest
} }
catch(Exception e) catch(Exception e)
{ {
assertTrue(false);
e.printStackTrace(); e.printStackTrace();
Assert.fail();
} }
} }
}; };
@ -183,15 +193,12 @@ public class BlockingArrayQueueTest
queue.offer("two"); queue.offer("two");
thread.join(); thread.join();
assertEquals("zero",data[0]); Assert.assertEquals("zero", data[0]);
assertEquals("one",data[1]); Assert.assertEquals("one", data[1]);
assertEquals("two",data[2]); Assert.assertEquals("two", data[2]);
assertEquals(null,data[3]); Assert.assertEquals(null, data[3]);
} }
volatile boolean _running;
@Test @Test
@Slow @Slow
public void testConcurrentAccess() throws Exception public void testConcurrentAccess() throws Exception
@ -199,19 +206,17 @@ public class BlockingArrayQueueTest
final int THREADS=50; final int THREADS=50;
final int LOOPS=1000; final int LOOPS=1000;
final BlockingArrayQueue<Integer> queue = new BlockingArrayQueue<Integer>(1+THREADS*LOOPS); final BlockingArrayQueue<Integer> queue = new BlockingArrayQueue<>(1+THREADS*LOOPS);
final ConcurrentLinkedQueue<Integer> produced=new ConcurrentLinkedQueue<Integer>(); final ConcurrentLinkedQueue<Integer> produced=new ConcurrentLinkedQueue<>();
final ConcurrentLinkedQueue<Integer> consumed=new ConcurrentLinkedQueue<Integer>(); final ConcurrentLinkedQueue<Integer> consumed=new ConcurrentLinkedQueue<>();
final AtomicBoolean running = new AtomicBoolean(true);
_running=true;
// start consumers // start consumers
final CyclicBarrier barrier0 = new CyclicBarrier(THREADS+1); final CyclicBarrier barrier0 = new CyclicBarrier(THREADS+1);
for (int i=0;i<THREADS;i++) for (int i=0;i<THREADS;i++)
{ {
final Integer id = new Integer(i);
new Thread() new Thread()
{ {
@Override @Override
@ -222,7 +227,7 @@ public class BlockingArrayQueueTest
setPriority(getPriority()-1); setPriority(getPriority()-1);
try try
{ {
while(_running) while(running.get())
{ {
int r=1+random.nextInt(10); int r=1+random.nextInt(10);
if (r%2==0) if (r%2==0)
@ -267,7 +272,7 @@ public class BlockingArrayQueueTest
final CyclicBarrier barrier1 = new CyclicBarrier(THREADS+1); final CyclicBarrier barrier1 = new CyclicBarrier(THREADS+1);
for (int i=0;i<THREADS;i++) for (int i=0;i<THREADS;i++)
{ {
final Integer id = new Integer(i); final int id = i;
new Thread() new Thread()
{ {
@Override @Override
@ -278,7 +283,7 @@ public class BlockingArrayQueueTest
{ {
for (int j=0;j<LOOPS;j++) for (int j=0;j<LOOPS;j++)
{ {
Integer msg = new Integer(random.nextInt()); Integer msg = random.nextInt();
produced.add(msg); produced.add(msg);
if (!queue.offer(msg)) if (!queue.offer(msg))
throw new Exception(id+" FULL! "+queue.size()); throw new Exception(id+" FULL! "+queue.size());
@ -313,12 +318,178 @@ public class BlockingArrayQueueTest
Thread.sleep(500); Thread.sleep(500);
size=queue.size(); size=queue.size();
} }
_running=false; running.set(false);
barrier0.await(); barrier0.await();
HashSet<Integer> prodSet = new HashSet<Integer>(produced); HashSet<Integer> prodSet = new HashSet<>(produced);
HashSet<Integer> consSet = new HashSet<Integer>(consumed); HashSet<Integer> consSet = new HashSet<>(consumed);
assertEquals(prodSet,consSet); Assert.assertEquals(prodSet, consSet);
}
@Test
public void testRemoveObjectFromEmptyQueue()
{
BlockingArrayQueue<String> queue = new BlockingArrayQueue<>(4,0,4);
Assert.assertFalse(queue.remove("SOMETHING"));
}
@Test
public void testRemoveObjectWithWrappedTail() throws Exception
{
BlockingArrayQueue<String> queue = new BlockingArrayQueue<>(6);
// Wrap the tail
for (int i = 0; i < queue.getMaxCapacity(); ++i)
queue.offer("" + i);
// Advance the head
queue.poll();
// Remove from the middle
Assert.assertTrue(queue.remove("2"));
// Advance the tail
Assert.assertTrue(queue.offer("A"));
Assert.assertTrue(queue.offer("B"));
queue.poll();
// Remove from the middle
Assert.assertTrue(queue.remove("3"));
}
@Test
public void testRemoveObject() throws Exception
{
BlockingArrayQueue<String> queue = new BlockingArrayQueue<>(4,0,4);
String element1 = "A";
Assert.assertTrue(queue.offer(element1));
Assert.assertTrue(queue.remove(element1));
for (int i = 0; i < queue.getMaxCapacity() - 1; ++i)
{
queue.offer("" + i);
queue.poll();
}
String element2 = "B";
Assert.assertTrue(queue.offer(element2));
Assert.assertTrue(queue.offer(element1));
Assert.assertTrue(queue.remove(element1));
Assert.assertFalse(queue.remove("NOT_PRESENT"));
Assert.assertTrue(queue.remove(element2));
Assert.assertFalse(queue.remove("NOT_PRESENT"));
queue.clear();
for (int i = 0; i < queue.getMaxCapacity(); ++i)
queue.offer("" + i);
Assert.assertTrue(queue.remove("" + (queue.getMaxCapacity() - 1)));
}
@Test
public void testRemoveWithMaxCapacityOne() throws Exception
{
BlockingArrayQueue<String> queue = new BlockingArrayQueue<>(1);
String element = "A";
Assert.assertTrue(queue.offer(element));
Assert.assertTrue(queue.remove(element));
Assert.assertTrue(queue.offer(element));
Assert.assertEquals(element, queue.remove(0));
}
@Test
public void testIteratorWithModification() throws Exception
{
BlockingArrayQueue<String> queue = new BlockingArrayQueue<>(4,0,4);
int count = queue.getMaxCapacity() - 1;
for (int i = 0; i < count; ++i)
queue.offer("" + i);
int sum = 0;
for (String element : queue)
{
++sum;
// Concurrent modification, must not change the iterator
queue.remove(element);
}
Assert.assertEquals(count, sum);
Assert.assertTrue(queue.isEmpty());
}
@Test
public void testListIterator() throws Exception
{
BlockingArrayQueue<String> queue = new BlockingArrayQueue<>(4,0,4);
String element1 = "A";
String element2 = "B";
queue.offer(element1);
queue.offer(element2);
ListIterator<String> iterator = queue.listIterator();
Assert.assertTrue(iterator.hasNext());
Assert.assertFalse(iterator.hasPrevious());
String element = iterator.next();
Assert.assertEquals(element1, element);
Assert.assertTrue(iterator.hasNext());
Assert.assertTrue(iterator.hasPrevious());
element = iterator.next();
Assert.assertEquals(element2, element);
Assert.assertFalse(iterator.hasNext());
Assert.assertTrue(iterator.hasPrevious());
element = iterator.previous();
Assert.assertEquals(element2, element);
Assert.assertTrue(iterator.hasNext());
Assert.assertTrue(iterator.hasPrevious());
element = iterator.previous();
Assert.assertEquals(element1, element);
Assert.assertTrue(iterator.hasNext());
Assert.assertFalse(iterator.hasPrevious());
}
@Test
public void testListIteratorWithWrappedHead() throws Exception
{
BlockingArrayQueue<String> queue = new BlockingArrayQueue<>(4,0,4);
// This sequence of offers and polls wraps the head around the array
queue.offer("0");
queue.offer("1");
queue.offer("2");
queue.offer("3");
queue.poll();
queue.poll();
String element1 = queue.get(0);
String element2 = queue.get(1);
ListIterator<String> iterator = queue.listIterator();
Assert.assertTrue(iterator.hasNext());
Assert.assertFalse(iterator.hasPrevious());
String element = iterator.next();
Assert.assertEquals(element1, element);
Assert.assertTrue(iterator.hasNext());
Assert.assertTrue(iterator.hasPrevious());
element = iterator.next();
Assert.assertEquals(element2, element);
Assert.assertFalse(iterator.hasNext());
Assert.assertTrue(iterator.hasPrevious());
element = iterator.previous();
Assert.assertEquals(element2, element);
Assert.assertTrue(iterator.hasNext());
Assert.assertTrue(iterator.hasPrevious());
element = iterator.previous();
Assert.assertEquals(element1, element);
Assert.assertTrue(iterator.hasNext());
Assert.assertFalse(iterator.hasPrevious());
} }
} }

View File

@ -41,6 +41,7 @@ public class LocalWebSocketConnection implements WebSocketConnection, LogicalCon
private WebSocketPolicy policy = WebSocketPolicy.newServerPolicy(); private WebSocketPolicy policy = WebSocketPolicy.newServerPolicy();
private boolean open = false; private boolean open = false;
private IncomingFrames incoming; private IncomingFrames incoming;
private IOState ioState = new IOState();
public LocalWebSocketConnection() public LocalWebSocketConnection()
{ {
@ -83,8 +84,7 @@ public class LocalWebSocketConnection implements WebSocketConnection, LogicalCon
@Override @Override
public IOState getIOState() public IOState getIOState()
{ {
// TODO Auto-generated method stub return ioState;
return null;
} }
@Override @Override

View File

@ -25,13 +25,16 @@ import java.nio.ByteBuffer;
import java.util.Arrays; import java.util.Arrays;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.toolchain.test.AdvancedRunner;
import org.eclipse.jetty.util.Utf8Appendable.NotUtf8Exception; import org.eclipse.jetty.util.Utf8Appendable.NotUtf8Exception;
import org.eclipse.jetty.util.Utf8StringBuilder; import org.eclipse.jetty.util.Utf8StringBuilder;
import org.eclipse.jetty.util.log.StdErrLog;
import org.eclipse.jetty.websocket.api.StatusCode; import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.api.extensions.Frame; import org.eclipse.jetty.websocket.api.extensions.Frame;
import org.eclipse.jetty.websocket.common.CloseInfo; import org.eclipse.jetty.websocket.common.CloseInfo;
import org.eclipse.jetty.websocket.common.Generator; import org.eclipse.jetty.websocket.common.Generator;
import org.eclipse.jetty.websocket.common.OpCode; 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.WebSocketFrame;
import org.eclipse.jetty.websocket.server.blockhead.BlockheadClient; import org.eclipse.jetty.websocket.server.blockhead.BlockheadClient;
import org.eclipse.jetty.websocket.server.helper.IncomingFramesCapture; import org.eclipse.jetty.websocket.server.helper.IncomingFramesCapture;
@ -42,12 +45,14 @@ import org.junit.Assert;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith;
/** /**
* Test various <a href="http://tools.ietf.org/html/rfc6455">RFC 6455</a> specified requirements placed on {@link WebSocketServlet} * Test various <a href="http://tools.ietf.org/html/rfc6455">RFC 6455</a> specified requirements placed on {@link WebSocketServlet}
* <p> * <p>
* This test serves a different purpose than than the {@link WebSocketMessageRFC6455Test}, and {@link WebSocketParserRFC6455Test} tests. * This test serves a different purpose than than the {@link WebSocketMessageRFC6455Test}, and {@link WebSocketParserRFC6455Test} tests.
*/ */
@RunWith(AdvancedRunner.class)
public class WebSocketServletRFCTest public class WebSocketServletRFCTest
{ {
private static Generator generator = new UnitGenerator(); private static Generator generator = new UnitGenerator();
@ -66,6 +71,12 @@ public class WebSocketServletRFCTest
server.stop(); server.stop();
} }
private void enableStacks(Class<?> clazz, boolean enabled)
{
StdErrLog log = StdErrLog.getLogger(clazz);
log.setHideStacks(!enabled);
}
/** /**
* Test that aggregation of binary frames into a single message occurs * Test that aggregation of binary frames into a single message occurs
*/ */
@ -324,6 +335,9 @@ public class WebSocketServletRFCTest
@Test @Test
public void testTextNotUTF8() throws Exception public void testTextNotUTF8() throws Exception
{ {
// Disable Long Stacks from Parser (we know this test will throw an exception)
enableStacks(Parser.class,false);
BlockheadClient client = new BlockheadClient(server.getServerUri()); BlockheadClient client = new BlockheadClient(server.getServerUri());
client.setProtocols("other"); client.setProtocols("other");
try try
@ -347,8 +361,9 @@ public class WebSocketServletRFCTest
} }
finally finally
{ {
// Reenable Long Stacks from Parser
enableStacks(Parser.class,true);
client.close(); client.close();
} }
} }
} }

View File

@ -23,6 +23,7 @@ import java.nio.ByteBuffer;
import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.StdErrLog;
import org.eclipse.jetty.websocket.api.WebSocketPolicy; import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.common.Generator; import org.eclipse.jetty.websocket.common.Generator;
import org.eclipse.jetty.websocket.server.SimpleServletServer; import org.eclipse.jetty.websocket.server.SimpleServletServer;
@ -88,6 +89,12 @@ public abstract class AbstractABCase
@Rule @Rule
public TestName testname = new TestName(); public TestName testname = new TestName();
protected void enableStacks(Class<?> clazz, boolean enabled)
{
StdErrLog log = StdErrLog.getLogger(clazz);
log.setHideStacks(!enabled);
}
public Generator getLaxGenerator() public Generator getLaxGenerator()
{ {
return laxGenerator; return laxGenerator;

View File

@ -190,6 +190,7 @@ public class Fuzzer
// we expect that the close handshake to have occurred and the server should have closed the connection // we expect that the close handshake to have occurred and the server should have closed the connection
try try
{ {
@SuppressWarnings("unused")
int val = client.read(); int val = client.read();
Assert.fail("Server has not closed socket"); Assert.fail("Server has not closed socket");

View File

@ -22,13 +22,17 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import org.eclipse.jetty.toolchain.test.AdvancedRunner;
import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.websocket.api.StatusCode; import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.common.CloseInfo; import org.eclipse.jetty.websocket.common.CloseInfo;
import org.eclipse.jetty.websocket.common.OpCode; 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.WebSocketFrame;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AdvancedRunner.class)
public class TestABCase2 extends AbstractABCase public class TestABCase2 extends AbstractABCase
{ {
/** /**
@ -232,6 +236,9 @@ public class TestABCase2 extends AbstractABCase
@Test @Test
public void testCase2_5() throws Exception public void testCase2_5() throws Exception
{ {
// Disable Long Stacks from Parser (we know this test will throw an exception)
enableStacks(Parser.class,false);
byte payload[] = new byte[126]; // intentionally too big byte payload[] = new byte[126]; // intentionally too big
Arrays.fill(payload,(byte)'5'); Arrays.fill(payload,(byte)'5');
@ -253,6 +260,7 @@ public class TestABCase2 extends AbstractABCase
} }
finally finally
{ {
enableStacks(Parser.class,true);
fuzzer.close(); fuzzer.close();
} }
} }

View File

@ -22,13 +22,34 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import org.eclipse.jetty.toolchain.test.AdvancedRunner;
import org.eclipse.jetty.websocket.api.StatusCode; import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.common.CloseInfo; import org.eclipse.jetty.websocket.common.CloseInfo;
import org.eclipse.jetty.websocket.common.Parser;
import org.eclipse.jetty.websocket.common.WebSocketFrame; import org.eclipse.jetty.websocket.common.WebSocketFrame;
import org.junit.After;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith;
/**
* Test various RSV violations
*/
@RunWith(AdvancedRunner.class)
public class TestABCase3 extends AbstractABCase public class TestABCase3 extends AbstractABCase
{ {
@After
public void enableParserStacks()
{
enableStacks(Parser.class,true);
}
@Before
public void quietParserStacks()
{
enableStacks(Parser.class,false);
}
/** /**
* Send small text frame, with RSV1 == true, with no extensions defined. * Send small text frame, with RSV1 == true, with no extensions defined.
*/ */

View File

@ -21,12 +21,21 @@ package org.eclipse.jetty.websocket.server.ab;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.eclipse.jetty.toolchain.test.AdvancedRunner;
import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.websocket.api.StatusCode; import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.common.CloseInfo; import org.eclipse.jetty.websocket.common.CloseInfo;
import org.eclipse.jetty.websocket.common.Parser;
import org.eclipse.jetty.websocket.common.WebSocketFrame; import org.eclipse.jetty.websocket.common.WebSocketFrame;
import org.junit.After;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith;
/**
* Test various bad / forbidden opcodes (per spec)
*/
@RunWith(AdvancedRunner.class)
public class TestABCase4 extends AbstractABCase public class TestABCase4 extends AbstractABCase
{ {
// Allow Fuzzer / Generator to create bad frames for testing frame validation // Allow Fuzzer / Generator to create bad frames for testing frame validation
@ -40,6 +49,18 @@ public class TestABCase4 extends AbstractABCase
} }
} }
@After
public void enableParserStacks()
{
enableStacks(Parser.class,true);
}
@Before
public void quietParserStacks()
{
enableStacks(Parser.class,false);
}
/** /**
* Send opcode 3 (reserved) * Send opcode 3 (reserved)
*/ */

View File

@ -27,6 +27,7 @@ import org.eclipse.jetty.toolchain.test.annotation.Slow;
import org.eclipse.jetty.websocket.api.StatusCode; import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.common.CloseInfo; import org.eclipse.jetty.websocket.common.CloseInfo;
import org.eclipse.jetty.websocket.common.OpCode; 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.WebSocketFrame;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -43,6 +44,9 @@ public class TestABCase5 extends AbstractABCase
@Test @Test
public void testCase5_1() throws Exception public void testCase5_1() throws Exception
{ {
// Disable Long Stacks from Parser (we know this test will throw an exception)
enableStacks(Parser.class,false);
List<WebSocketFrame> send = new ArrayList<>(); List<WebSocketFrame> send = new ArrayList<>();
send.add(new WebSocketFrame(OpCode.PING).setPayload("hello, ").setFin(false)); send.add(new WebSocketFrame(OpCode.PING).setPayload("hello, ").setFin(false));
send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("world")); send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("world"));
@ -62,6 +66,7 @@ public class TestABCase5 extends AbstractABCase
finally finally
{ {
fuzzer.close(); fuzzer.close();
enableStacks(Parser.class,true);
} }
} }
@ -71,6 +76,9 @@ public class TestABCase5 extends AbstractABCase
@Test @Test
public void testCase5_10() throws Exception public void testCase5_10() throws Exception
{ {
// Disable Long Stacks from Parser (we know this test will throw an exception)
enableStacks(Parser.class,false);
List<WebSocketFrame> send = new ArrayList<>(); List<WebSocketFrame> send = new ArrayList<>();
send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("sorry").setFin(true)); send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("sorry").setFin(true));
send.add(new WebSocketFrame(OpCode.TEXT).setPayload("hello, world")); send.add(new WebSocketFrame(OpCode.TEXT).setPayload("hello, world"));
@ -89,6 +97,7 @@ public class TestABCase5 extends AbstractABCase
} }
finally finally
{ {
enableStacks(Parser.class,true);
fuzzer.close(); fuzzer.close();
} }
} }
@ -99,6 +108,9 @@ public class TestABCase5 extends AbstractABCase
@Test @Test
public void testCase5_11() throws Exception public void testCase5_11() throws Exception
{ {
// Disable Long Stacks from Parser (we know this test will throw an exception)
enableStacks(Parser.class,false);
List<WebSocketFrame> send = new ArrayList<>(); List<WebSocketFrame> send = new ArrayList<>();
send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("sorry").setFin(true)); send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("sorry").setFin(true));
send.add(new WebSocketFrame(OpCode.TEXT).setPayload("hello, world")); send.add(new WebSocketFrame(OpCode.TEXT).setPayload("hello, world"));
@ -118,6 +130,7 @@ public class TestABCase5 extends AbstractABCase
} }
finally finally
{ {
enableStacks(Parser.class,true);
fuzzer.close(); fuzzer.close();
} }
} }
@ -128,6 +141,9 @@ public class TestABCase5 extends AbstractABCase
@Test @Test
public void testCase5_12() throws Exception public void testCase5_12() throws Exception
{ {
// Disable Long Stacks from Parser (we know this test will throw an exception)
enableStacks(Parser.class,false);
List<WebSocketFrame> send = new ArrayList<>(); List<WebSocketFrame> send = new ArrayList<>();
send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("sorry").setFin(false)); send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("sorry").setFin(false));
send.add(new WebSocketFrame(OpCode.TEXT).setPayload("hello, world")); send.add(new WebSocketFrame(OpCode.TEXT).setPayload("hello, world"));
@ -146,6 +162,7 @@ public class TestABCase5 extends AbstractABCase
} }
finally finally
{ {
enableStacks(Parser.class,true);
fuzzer.close(); fuzzer.close();
} }
} }
@ -156,6 +173,8 @@ public class TestABCase5 extends AbstractABCase
@Test @Test
public void testCase5_13() throws Exception public void testCase5_13() throws Exception
{ {
// Disable Long Stacks from Parser (we know this test will throw an exception)
enableStacks(Parser.class,false);
List<WebSocketFrame> send = new ArrayList<>(); List<WebSocketFrame> send = new ArrayList<>();
send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("sorry").setFin(false)); send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("sorry").setFin(false));
send.add(new WebSocketFrame(OpCode.TEXT).setPayload("hello, world")); send.add(new WebSocketFrame(OpCode.TEXT).setPayload("hello, world"));
@ -174,6 +193,7 @@ public class TestABCase5 extends AbstractABCase
} }
finally finally
{ {
enableStacks(Parser.class,true);
fuzzer.close(); fuzzer.close();
} }
} }
@ -184,6 +204,9 @@ public class TestABCase5 extends AbstractABCase
@Test @Test
public void testCase5_14() throws Exception public void testCase5_14() throws Exception
{ {
// Disable Long Stacks from Parser (we know this test will throw an exception)
enableStacks(Parser.class,false);
List<WebSocketFrame> send = new ArrayList<>(); List<WebSocketFrame> send = new ArrayList<>();
send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("sorry").setFin(false)); send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("sorry").setFin(false));
send.add(new WebSocketFrame(OpCode.TEXT).setPayload("hello, world")); send.add(new WebSocketFrame(OpCode.TEXT).setPayload("hello, world"));
@ -203,6 +226,7 @@ public class TestABCase5 extends AbstractABCase
} }
finally finally
{ {
enableStacks(Parser.class,false);
fuzzer.close(); fuzzer.close();
} }
} }
@ -213,6 +237,9 @@ public class TestABCase5 extends AbstractABCase
@Test @Test
public void testCase5_15() throws Exception public void testCase5_15() throws Exception
{ {
// Disable Long Stacks from Parser (we know this test will throw an exception)
enableStacks(Parser.class,false);
List<WebSocketFrame> send = new ArrayList<>(); List<WebSocketFrame> send = new ArrayList<>();
send.add(new WebSocketFrame(OpCode.TEXT).setPayload("fragment1").setFin(false)); send.add(new WebSocketFrame(OpCode.TEXT).setPayload("fragment1").setFin(false));
send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("fragment2").setFin(true)); send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("fragment2").setFin(true));
@ -234,6 +261,7 @@ public class TestABCase5 extends AbstractABCase
} }
finally finally
{ {
enableStacks(Parser.class,true);
fuzzer.close(); fuzzer.close();
} }
} }
@ -244,6 +272,9 @@ public class TestABCase5 extends AbstractABCase
@Test @Test
public void testCase5_16() throws Exception public void testCase5_16() throws Exception
{ {
// Disable Long Stacks from Parser (we know this test will throw an exception)
enableStacks(Parser.class,false);
List<WebSocketFrame> send = new ArrayList<>(); List<WebSocketFrame> send = new ArrayList<>();
send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("fragment1").setFin(false)); // bad frame send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("fragment1").setFin(false)); // bad frame
send.add(new WebSocketFrame(OpCode.TEXT).setPayload("fragment2").setFin(false)); send.add(new WebSocketFrame(OpCode.TEXT).setPayload("fragment2").setFin(false));
@ -266,6 +297,7 @@ public class TestABCase5 extends AbstractABCase
} }
finally finally
{ {
enableStacks(Parser.class,true);
fuzzer.close(); fuzzer.close();
} }
} }
@ -276,6 +308,9 @@ public class TestABCase5 extends AbstractABCase
@Test @Test
public void testCase5_17() throws Exception public void testCase5_17() throws Exception
{ {
// Disable Long Stacks from Parser (we know this test will throw an exception)
enableStacks(Parser.class,false);
List<WebSocketFrame> send = new ArrayList<>(); List<WebSocketFrame> send = new ArrayList<>();
send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("fragment1").setFin(true)); // nothing to continue send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("fragment1").setFin(true)); // nothing to continue
send.add(new WebSocketFrame(OpCode.TEXT).setPayload("fragment2").setFin(false)); send.add(new WebSocketFrame(OpCode.TEXT).setPayload("fragment2").setFin(false));
@ -298,6 +333,7 @@ public class TestABCase5 extends AbstractABCase
} }
finally finally
{ {
enableStacks(Parser.class,true);
fuzzer.close(); fuzzer.close();
} }
} }
@ -308,6 +344,9 @@ public class TestABCase5 extends AbstractABCase
@Test @Test
public void testCase5_18() throws Exception public void testCase5_18() throws Exception
{ {
// Disable Long Stacks from Parser (we know this test will throw an exception)
enableStacks(Parser.class,false);
List<WebSocketFrame> send = new ArrayList<>(); List<WebSocketFrame> send = new ArrayList<>();
send.add(new WebSocketFrame(OpCode.TEXT).setPayload("fragment1").setFin(false)); send.add(new WebSocketFrame(OpCode.TEXT).setPayload("fragment1").setFin(false));
send.add(new WebSocketFrame(OpCode.TEXT).setPayload("fragment2").setFin(true)); // bad frame, must be continuation send.add(new WebSocketFrame(OpCode.TEXT).setPayload("fragment2").setFin(true)); // bad frame, must be continuation
@ -326,6 +365,7 @@ public class TestABCase5 extends AbstractABCase
} }
finally finally
{ {
enableStacks(Parser.class,true);
fuzzer.close(); fuzzer.close();
} }
} }
@ -388,6 +428,9 @@ public class TestABCase5 extends AbstractABCase
@Test @Test
public void testCase5_2() throws Exception public void testCase5_2() throws Exception
{ {
// Disable Long Stacks from Parser (we know this test will throw an exception)
enableStacks(Parser.class,false);
List<WebSocketFrame> send = new ArrayList<>(); List<WebSocketFrame> send = new ArrayList<>();
send.add(new WebSocketFrame(OpCode.PONG).setPayload("hello, ").setFin(false)); send.add(new WebSocketFrame(OpCode.PONG).setPayload("hello, ").setFin(false));
send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("world")); send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("world"));
@ -406,6 +449,7 @@ public class TestABCase5 extends AbstractABCase
} }
finally finally
{ {
enableStacks(Parser.class,true);
fuzzer.close(); fuzzer.close();
} }
} }
@ -691,6 +735,9 @@ public class TestABCase5 extends AbstractABCase
@Test @Test
public void testCase5_9() throws Exception public void testCase5_9() throws Exception
{ {
// Disable Long Stacks from Parser (we know this test will throw an exception)
enableStacks(Parser.class,false);
List<WebSocketFrame> send = new ArrayList<>(); List<WebSocketFrame> send = new ArrayList<>();
send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("sorry").setFin(true)); send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("sorry").setFin(true));
send.add(new WebSocketFrame(OpCode.TEXT).setPayload("hello, world")); send.add(new WebSocketFrame(OpCode.TEXT).setPayload("hello, world"));
@ -709,6 +756,7 @@ public class TestABCase5 extends AbstractABCase
} }
finally finally
{ {
enableStacks(Parser.class,true);
fuzzer.close(); fuzzer.close();
} }
} }

View File

@ -31,6 +31,7 @@ import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.websocket.api.StatusCode; import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.common.CloseInfo; import org.eclipse.jetty.websocket.common.CloseInfo;
import org.eclipse.jetty.websocket.common.OpCode; 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.WebSocketFrame;
import org.eclipse.jetty.websocket.server.helper.Hex; import org.eclipse.jetty.websocket.server.helper.Hex;
import org.junit.Test; import org.junit.Test;
@ -356,6 +357,9 @@ public class TestABCase6 extends AbstractABCase
@Slow @Slow
public void testCase6_4_3() throws Exception public void testCase6_4_3() throws Exception
{ {
// Disable Long Stacks from Parser (we know this test will throw an exception)
enableStacks(Parser.class,false);
ByteBuffer payload = ByteBuffer.allocate(64); ByteBuffer payload = ByteBuffer.allocate(64);
BufferUtil.clearToFill(payload); BufferUtil.clearToFill(payload);
payload.put(TypeUtil.fromHexString("cebae1bdb9cf83cebcceb5")); // good payload.put(TypeUtil.fromHexString("cebae1bdb9cf83cebcceb5")); // good
@ -400,6 +404,7 @@ public class TestABCase6 extends AbstractABCase
} }
finally finally
{ {
enableStacks(Parser.class,true);
fuzzer.close(); fuzzer.close();
} }
} }
@ -411,6 +416,9 @@ public class TestABCase6 extends AbstractABCase
@Slow @Slow
public void testCase6_4_4() throws Exception public void testCase6_4_4() throws Exception
{ {
// Disable Long Stacks from Parser (we know this test will throw an exception)
enableStacks(Parser.class,false);
byte invalid[] = Hex.asByteArray("CEBAE1BDB9CF83CEBCCEB5F49080808080656469746564"); byte invalid[] = Hex.asByteArray("CEBAE1BDB9CF83CEBCCEB5F49080808080656469746564");
List<WebSocketFrame> send = new ArrayList<>(); List<WebSocketFrame> send = new ArrayList<>();
@ -437,6 +445,7 @@ public class TestABCase6 extends AbstractABCase
} }
finally finally
{ {
enableStacks(Parser.class,true);
fuzzer.close(); fuzzer.close();
} }
} }

View File

@ -24,7 +24,6 @@ import java.util.List;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.log.StdErrLog;
import org.eclipse.jetty.websocket.api.StatusCode; import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.common.CloseInfo; import org.eclipse.jetty.websocket.common.CloseInfo;
import org.eclipse.jetty.websocket.common.OpCode; import org.eclipse.jetty.websocket.common.OpCode;
@ -177,10 +176,4 @@ public class TestABCase6_BadUTF extends AbstractABCase
enableStacks(Parser.class,true); enableStacks(Parser.class,true);
} }
} }
private void enableStacks(Class<?> clazz, boolean enabled)
{
StdErrLog log = StdErrLog.getLogger(clazz);
log.setHideStacks(!enabled);
}
} }

View File

@ -26,7 +26,6 @@ import java.util.List;
import org.eclipse.jetty.toolchain.test.TestTracker; import org.eclipse.jetty.toolchain.test.TestTracker;
import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.StdErrLog;
import org.eclipse.jetty.websocket.api.StatusCode; import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.common.CloseInfo; import org.eclipse.jetty.websocket.common.CloseInfo;
import org.eclipse.jetty.websocket.common.OpCode; import org.eclipse.jetty.websocket.common.OpCode;
@ -41,12 +40,6 @@ import org.junit.Test;
*/ */
public class TestABCase7 extends AbstractABCase public class TestABCase7 extends AbstractABCase
{ {
private static void enableStacks(Class<?> clazz, boolean enabled)
{
StdErrLog log = StdErrLog.getLogger(clazz);
log.setHideStacks(!enabled);
}
@Rule @Rule
public TestTracker tt = new TestTracker(); public TestTracker tt = new TestTracker();

View File

@ -1,8 +1,8 @@
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
# org.eclipse.jetty.LEVEL=WARN org.eclipse.jetty.LEVEL=WARN
# org.eclipse.jetty.websocket.LEVEL=DEBUG # org.eclipse.jetty.websocket.LEVEL=DEBUG
org.eclipse.jetty.websocket.LEVEL=WARN # org.eclipse.jetty.websocket.LEVEL=WARN
# org.eclipse.jetty.websocket.common.io.LEVEL=DEBUG # org.eclipse.jetty.websocket.common.io.LEVEL=DEBUG
# org.eclipse.jetty.websocket.server.ab.LEVEL=DEBUG # org.eclipse.jetty.websocket.server.ab.LEVEL=DEBUG
# org.eclipse.jetty.websocket.common.io.LEVEL=DEBUG # org.eclipse.jetty.websocket.common.io.LEVEL=DEBUG