SPDY: make MAX_CONCURRENT_STREAMS unidirectional
This commit is contained in:
parent
5a44162c52
commit
dcced96bee
@ -29,42 +29,65 @@ final class SpdySession {
|
|||||||
|
|
||||||
private static final SpdyProtocolException STREAM_CLOSED = new SpdyProtocolException("Stream closed");
|
private static final SpdyProtocolException STREAM_CLOSED = new SpdyProtocolException("Stream closed");
|
||||||
|
|
||||||
|
private final AtomicInteger activeLocalStreams = new AtomicInteger();
|
||||||
|
private final AtomicInteger activeRemoteStreams = new AtomicInteger();
|
||||||
private final Map<Integer, StreamState> activeStreams =
|
private final Map<Integer, StreamState> activeStreams =
|
||||||
new ConcurrentHashMap<Integer, StreamState>();
|
new ConcurrentHashMap<Integer, StreamState>();
|
||||||
|
|
||||||
int numActiveStreams() {
|
int numActiveStreams(boolean remote) {
|
||||||
return activeStreams.size();
|
if (remote) {
|
||||||
|
return activeRemoteStreams.get();
|
||||||
|
} else {
|
||||||
|
return activeLocalStreams.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean noActiveStreams() {
|
boolean noActiveStreams() {
|
||||||
return activeStreams.isEmpty();
|
return activeStreams.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isActiveStream(int streamID) {
|
boolean isActiveStream(int streamId) {
|
||||||
return activeStreams.containsKey(streamID);
|
return activeStreams.containsKey(streamId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stream-IDs should be iterated in priority order
|
// Stream-IDs should be iterated in priority order
|
||||||
Set<Integer> getActiveStreams() {
|
Set<Integer> getActiveStreams() {
|
||||||
TreeSet<Integer> StreamIDs = new TreeSet<Integer>(new PriorityComparator());
|
TreeSet<Integer> StreamIds = new TreeSet<Integer>(new PriorityComparator());
|
||||||
StreamIDs.addAll(activeStreams.keySet());
|
StreamIds.addAll(activeStreams.keySet());
|
||||||
return StreamIDs;
|
return StreamIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
void acceptStream(
|
void acceptStream(
|
||||||
int streamID, byte priority, boolean remoteSideClosed, boolean localSideClosed,
|
int streamId, byte priority, boolean remoteSideClosed, boolean localSideClosed,
|
||||||
int sendWindowSize, int receiveWindowSize) {
|
int sendWindowSize, int receiveWindowSize, boolean remote) {
|
||||||
if (!remoteSideClosed || !localSideClosed) {
|
if (!remoteSideClosed || !localSideClosed) {
|
||||||
activeStreams.put(
|
StreamState state = activeStreams.put(
|
||||||
streamID,
|
streamId,
|
||||||
new StreamState(priority, remoteSideClosed, localSideClosed, sendWindowSize, receiveWindowSize));
|
new StreamState(priority, remoteSideClosed, localSideClosed, sendWindowSize, receiveWindowSize));
|
||||||
|
if (state == null) {
|
||||||
|
if (remote) {
|
||||||
|
activeRemoteStreams.incrementAndGet();
|
||||||
|
} else {
|
||||||
|
activeLocalStreams.incrementAndGet();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeStream(int streamID) {
|
private StreamState removeActiveStream(int streamId, boolean remote) {
|
||||||
Integer StreamID = streamID;
|
StreamState state = activeStreams.remove(streamId);
|
||||||
StreamState state = activeStreams.get(StreamID);
|
if (state != null) {
|
||||||
activeStreams.remove(StreamID);
|
if (remote) {
|
||||||
|
activeRemoteStreams.decrementAndGet();
|
||||||
|
} else {
|
||||||
|
activeLocalStreams.decrementAndGet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeStream(int streamId, boolean remote) {
|
||||||
|
StreamState state = removeActiveStream(streamId, remote);
|
||||||
if (state != null) {
|
if (state != null) {
|
||||||
MessageEvent e = state.removePendingWrite();
|
MessageEvent e = state.removePendingWrite();
|
||||||
while (e != null) {
|
while (e != null) {
|
||||||
@ -74,34 +97,32 @@ final class SpdySession {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isRemoteSideClosed(int streamID) {
|
boolean isRemoteSideClosed(int streamId) {
|
||||||
StreamState state = activeStreams.get(streamID);
|
StreamState state = activeStreams.get(streamId);
|
||||||
return state == null || state.isRemoteSideClosed();
|
return state == null || state.isRemoteSideClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void closeRemoteSide(int streamID) {
|
void closeRemoteSide(int streamId, boolean remote) {
|
||||||
Integer StreamID = streamID;
|
StreamState state = activeStreams.get(streamId);
|
||||||
StreamState state = activeStreams.get(StreamID);
|
|
||||||
if (state != null) {
|
if (state != null) {
|
||||||
state.closeRemoteSide();
|
state.closeRemoteSide();
|
||||||
if (state.isLocalSideClosed()) {
|
if (state.isLocalSideClosed()) {
|
||||||
activeStreams.remove(StreamID);
|
removeActiveStream(streamId, remote);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isLocalSideClosed(int streamID) {
|
boolean isLocalSideClosed(int streamId) {
|
||||||
StreamState state = activeStreams.get(streamID);
|
StreamState state = activeStreams.get(streamId);
|
||||||
return state == null || state.isLocalSideClosed();
|
return state == null || state.isLocalSideClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void closeLocalSide(int streamID) {
|
void closeLocalSide(int streamId, boolean remote) {
|
||||||
Integer StreamID = streamID;
|
StreamState state = activeStreams.get(streamId);
|
||||||
StreamState state = activeStreams.get(StreamID);
|
|
||||||
if (state != null) {
|
if (state != null) {
|
||||||
state.closeLocalSide();
|
state.closeLocalSide();
|
||||||
if (state.isRemoteSideClosed()) {
|
if (state.isRemoteSideClosed()) {
|
||||||
activeStreams.remove(StreamID);
|
removeActiveStream(streamId, remote);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -111,38 +132,38 @@ final class SpdySession {
|
|||||||
* no need to synchronize access to the StreamState
|
* no need to synchronize access to the StreamState
|
||||||
*/
|
*/
|
||||||
|
|
||||||
boolean hasReceivedReply(int streamID) {
|
boolean hasReceivedReply(int streamId) {
|
||||||
StreamState state = activeStreams.get(streamID);
|
StreamState state = activeStreams.get(streamId);
|
||||||
return state != null && state.hasReceivedReply();
|
return state != null && state.hasReceivedReply();
|
||||||
}
|
}
|
||||||
|
|
||||||
void receivedReply(int streamID) {
|
void receivedReply(int streamId) {
|
||||||
StreamState state = activeStreams.get(streamID);
|
StreamState state = activeStreams.get(streamId);
|
||||||
if (state != null) {
|
if (state != null) {
|
||||||
state.receivedReply();
|
state.receivedReply();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int getSendWindowSize(int streamID) {
|
int getSendWindowSize(int streamId) {
|
||||||
StreamState state = activeStreams.get(streamID);
|
StreamState state = activeStreams.get(streamId);
|
||||||
return state != null ? state.getSendWindowSize() : -1;
|
return state != null ? state.getSendWindowSize() : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int updateSendWindowSize(int streamID, int deltaWindowSize) {
|
int updateSendWindowSize(int streamId, int deltaWindowSize) {
|
||||||
StreamState state = activeStreams.get(streamID);
|
StreamState state = activeStreams.get(streamId);
|
||||||
return state != null ? state.updateSendWindowSize(deltaWindowSize) : -1;
|
return state != null ? state.updateSendWindowSize(deltaWindowSize) : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int updateReceiveWindowSize(int streamID, int deltaWindowSize) {
|
int updateReceiveWindowSize(int streamId, int deltaWindowSize) {
|
||||||
StreamState state = activeStreams.get(streamID);
|
StreamState state = activeStreams.get(streamId);
|
||||||
if (deltaWindowSize > 0) {
|
if (deltaWindowSize > 0) {
|
||||||
state.setReceiveWindowSizeLowerBound(0);
|
state.setReceiveWindowSizeLowerBound(0);
|
||||||
}
|
}
|
||||||
return state != null ? state.updateReceiveWindowSize(deltaWindowSize) : -1;
|
return state != null ? state.updateReceiveWindowSize(deltaWindowSize) : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getReceiveWindowSizeLowerBound(int streamID) {
|
int getReceiveWindowSizeLowerBound(int streamId) {
|
||||||
StreamState state = activeStreams.get(streamID);
|
StreamState state = activeStreams.get(streamId);
|
||||||
return state != null ? state.getReceiveWindowSizeLowerBound() : 0;
|
return state != null ? state.getReceiveWindowSizeLowerBound() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,18 +176,18 @@ final class SpdySession {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean putPendingWrite(int streamID, MessageEvent evt) {
|
boolean putPendingWrite(int streamId, MessageEvent evt) {
|
||||||
StreamState state = activeStreams.get(streamID);
|
StreamState state = activeStreams.get(streamId);
|
||||||
return state != null && state.putPendingWrite(evt);
|
return state != null && state.putPendingWrite(evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageEvent getPendingWrite(int streamID) {
|
MessageEvent getPendingWrite(int streamId) {
|
||||||
StreamState state = activeStreams.get(streamID);
|
StreamState state = activeStreams.get(streamId);
|
||||||
return state != null ? state.getPendingWrite() : null;
|
return state != null ? state.getPendingWrite() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageEvent removePendingWrite(int streamID) {
|
MessageEvent removePendingWrite(int streamId) {
|
||||||
StreamState state = activeStreams.get(streamID);
|
StreamState state = activeStreams.get(streamId);
|
||||||
return state != null ? state.removePendingWrite() : null;
|
return state != null ? state.removePendingWrite() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,6 @@ public class SpdySessionHandler extends SimpleChannelUpstreamHandler
|
|||||||
private static final int DEFAULT_MAX_CONCURRENT_STREAMS = Integer.MAX_VALUE;
|
private static final int DEFAULT_MAX_CONCURRENT_STREAMS = Integer.MAX_VALUE;
|
||||||
private volatile int remoteConcurrentStreams = DEFAULT_MAX_CONCURRENT_STREAMS;
|
private volatile int remoteConcurrentStreams = DEFAULT_MAX_CONCURRENT_STREAMS;
|
||||||
private volatile int localConcurrentStreams = DEFAULT_MAX_CONCURRENT_STREAMS;
|
private volatile int localConcurrentStreams = DEFAULT_MAX_CONCURRENT_STREAMS;
|
||||||
private volatile int maxConcurrentStreams = DEFAULT_MAX_CONCURRENT_STREAMS;
|
|
||||||
|
|
||||||
private static final int DEFAULT_WINDOW_SIZE = 64 * 1024; // 64 KB default initial window size
|
private static final int DEFAULT_WINDOW_SIZE = 64 * 1024; // 64 KB default initial window size
|
||||||
private volatile int initialSendWindowSize = DEFAULT_WINDOW_SIZE;
|
private volatile int initialSendWindowSize = DEFAULT_WINDOW_SIZE;
|
||||||
@ -133,7 +132,7 @@ public class SpdySessionHandler extends SimpleChannelUpstreamHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if we received a data frame before receiving a SYN_REPLY
|
// Check if we received a data frame before receiving a SYN_REPLY
|
||||||
if (!isRemoteInitiatedID(streamId) && !spdySession.hasReceivedReply(streamId)) {
|
if (!isRemoteInitiatedId(streamId) && !spdySession.hasReceivedReply(streamId)) {
|
||||||
issueStreamError(ctx, e.getRemoteAddress(), streamId, SpdyStreamStatus.PROTOCOL_ERROR);
|
issueStreamError(ctx, e.getRemoteAddress(), streamId, SpdyStreamStatus.PROTOCOL_ERROR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -206,7 +205,7 @@ public class SpdySessionHandler extends SimpleChannelUpstreamHandler
|
|||||||
|
|
||||||
// Check if we received a valid SYN_STREAM frame
|
// Check if we received a valid SYN_STREAM frame
|
||||||
if (spdySynStreamFrame.isInvalid() ||
|
if (spdySynStreamFrame.isInvalid() ||
|
||||||
!isRemoteInitiatedID(streamId) ||
|
!isRemoteInitiatedId(streamId) ||
|
||||||
spdySession.isActiveStream(streamId)) {
|
spdySession.isActiveStream(streamId)) {
|
||||||
issueStreamError(ctx, e.getRemoteAddress(), streamId, SpdyStreamStatus.PROTOCOL_ERROR);
|
issueStreamError(ctx, e.getRemoteAddress(), streamId, SpdyStreamStatus.PROTOCOL_ERROR);
|
||||||
return;
|
return;
|
||||||
@ -241,7 +240,7 @@ public class SpdySessionHandler extends SimpleChannelUpstreamHandler
|
|||||||
|
|
||||||
// Check if we received a valid SYN_REPLY frame
|
// Check if we received a valid SYN_REPLY frame
|
||||||
if (spdySynReplyFrame.isInvalid() ||
|
if (spdySynReplyFrame.isInvalid() ||
|
||||||
isRemoteInitiatedID(streamId) ||
|
isRemoteInitiatedId(streamId) ||
|
||||||
spdySession.isRemoteSideClosed(streamId)) {
|
spdySession.isRemoteSideClosed(streamId)) {
|
||||||
issueStreamError(ctx, e.getRemoteAddress(), streamId, SpdyStreamStatus.INVALID_STREAM);
|
issueStreamError(ctx, e.getRemoteAddress(), streamId, SpdyStreamStatus.INVALID_STREAM);
|
||||||
return;
|
return;
|
||||||
@ -281,7 +280,7 @@ public class SpdySessionHandler extends SimpleChannelUpstreamHandler
|
|||||||
int newConcurrentStreams =
|
int newConcurrentStreams =
|
||||||
spdySettingsFrame.getValue(SpdySettingsFrame.SETTINGS_MAX_CONCURRENT_STREAMS);
|
spdySettingsFrame.getValue(SpdySettingsFrame.SETTINGS_MAX_CONCURRENT_STREAMS);
|
||||||
if (newConcurrentStreams >= 0) {
|
if (newConcurrentStreams >= 0) {
|
||||||
updateConcurrentStreams(newConcurrentStreams, true);
|
remoteConcurrentStreams = newConcurrentStreams;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Persistence flag are inconsistent with the use of SETTINGS to communicate
|
// Persistence flag are inconsistent with the use of SETTINGS to communicate
|
||||||
@ -313,7 +312,7 @@ public class SpdySessionHandler extends SimpleChannelUpstreamHandler
|
|||||||
|
|
||||||
SpdyPingFrame spdyPingFrame = (SpdyPingFrame) msg;
|
SpdyPingFrame spdyPingFrame = (SpdyPingFrame) msg;
|
||||||
|
|
||||||
if (isRemoteInitiatedID(spdyPingFrame.getId())) {
|
if (isRemoteInitiatedId(spdyPingFrame.getId())) {
|
||||||
Channels.write(ctx, Channels.future(e.getChannel()), spdyPingFrame, e.getRemoteAddress());
|
Channels.write(ctx, Channels.future(e.getChannel()), spdyPingFrame, e.getRemoteAddress());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -517,7 +516,7 @@ public class SpdySessionHandler extends SimpleChannelUpstreamHandler
|
|||||||
SpdySynStreamFrame spdySynStreamFrame = (SpdySynStreamFrame) msg;
|
SpdySynStreamFrame spdySynStreamFrame = (SpdySynStreamFrame) msg;
|
||||||
int streamId = spdySynStreamFrame.getStreamId();
|
int streamId = spdySynStreamFrame.getStreamId();
|
||||||
|
|
||||||
if (isRemoteInitiatedID(streamId)) {
|
if (isRemoteInitiatedId(streamId)) {
|
||||||
e.getFuture().setFailure(PROTOCOL_EXCEPTION);
|
e.getFuture().setFailure(PROTOCOL_EXCEPTION);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -536,7 +535,7 @@ public class SpdySessionHandler extends SimpleChannelUpstreamHandler
|
|||||||
int streamId = spdySynReplyFrame.getStreamId();
|
int streamId = spdySynReplyFrame.getStreamId();
|
||||||
|
|
||||||
// Frames must not be sent on half-closed streams
|
// Frames must not be sent on half-closed streams
|
||||||
if (!isRemoteInitiatedID(streamId) || spdySession.isLocalSideClosed(streamId)) {
|
if (!isRemoteInitiatedId(streamId) || spdySession.isLocalSideClosed(streamId)) {
|
||||||
e.getFuture().setFailure(PROTOCOL_EXCEPTION);
|
e.getFuture().setFailure(PROTOCOL_EXCEPTION);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -558,7 +557,7 @@ public class SpdySessionHandler extends SimpleChannelUpstreamHandler
|
|||||||
int newConcurrentStreams =
|
int newConcurrentStreams =
|
||||||
spdySettingsFrame.getValue(SpdySettingsFrame.SETTINGS_MAX_CONCURRENT_STREAMS);
|
spdySettingsFrame.getValue(SpdySettingsFrame.SETTINGS_MAX_CONCURRENT_STREAMS);
|
||||||
if (newConcurrentStreams >= 0) {
|
if (newConcurrentStreams >= 0) {
|
||||||
updateConcurrentStreams(newConcurrentStreams, false);
|
localConcurrentStreams = newConcurrentStreams;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Persistence flag are inconsistent with the use of SETTINGS to communicate
|
// Persistence flag are inconsistent with the use of SETTINGS to communicate
|
||||||
@ -580,7 +579,7 @@ public class SpdySessionHandler extends SimpleChannelUpstreamHandler
|
|||||||
} else if (msg instanceof SpdyPingFrame) {
|
} else if (msg instanceof SpdyPingFrame) {
|
||||||
|
|
||||||
SpdyPingFrame spdyPingFrame = (SpdyPingFrame) msg;
|
SpdyPingFrame spdyPingFrame = (SpdyPingFrame) msg;
|
||||||
if (isRemoteInitiatedID(spdyPingFrame.getId())) {
|
if (isRemoteInitiatedId(spdyPingFrame.getId())) {
|
||||||
e.getFuture().setFailure(new IllegalArgumentException(
|
e.getFuture().setFailure(new IllegalArgumentException(
|
||||||
"invalid PING ID: " + spdyPingFrame.getId()));
|
"invalid PING ID: " + spdyPingFrame.getId()));
|
||||||
return;
|
return;
|
||||||
@ -665,18 +664,9 @@ public class SpdySessionHandler extends SimpleChannelUpstreamHandler
|
|||||||
* Helper functions
|
* Helper functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private boolean isRemoteInitiatedID(int id) {
|
private boolean isRemoteInitiatedId(int id) {
|
||||||
boolean serverID = isServerId(id);
|
boolean serverId = isServerId(id);
|
||||||
return server && !serverID || !server && serverID;
|
return server && !serverId || !server && serverId;
|
||||||
}
|
|
||||||
|
|
||||||
private void updateConcurrentStreams(int newConcurrentStreams, boolean remote) {
|
|
||||||
if (remote) {
|
|
||||||
remoteConcurrentStreams = newConcurrentStreams;
|
|
||||||
} else {
|
|
||||||
localConcurrentStreams = newConcurrentStreams;
|
|
||||||
}
|
|
||||||
maxConcurrentStreams = Math.min(localConcurrentStreams, remoteConcurrentStreams);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// need to synchronize to prevent new streams from being created while updating active streams
|
// need to synchronize to prevent new streams from being created while updating active streams
|
||||||
@ -703,14 +693,15 @@ public class SpdySessionHandler extends SimpleChannelUpstreamHandler
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int maxConcurrentStreams = this.maxConcurrentStreams; // read volatile once
|
boolean remote = isRemoteInitiatedId(streamId);
|
||||||
if (spdySession.numActiveStreams() >= maxConcurrentStreams) {
|
int maxConcurrentStreams = remote ? localConcurrentStreams : remoteConcurrentStreams;
|
||||||
|
if (spdySession.numActiveStreams(remote) >= maxConcurrentStreams) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
spdySession.acceptStream(
|
spdySession.acceptStream(
|
||||||
streamId, priority, remoteSideClosed, localSideClosed,
|
streamId, priority, remoteSideClosed, localSideClosed,
|
||||||
initialSendWindowSize, initialReceiveWindowSize);
|
initialSendWindowSize, initialReceiveWindowSize, remote);
|
||||||
if (isRemoteInitiatedID(streamId)) {
|
if (remote) {
|
||||||
lastGoodStreamId = streamId;
|
lastGoodStreamId = streamId;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -718,9 +709,9 @@ public class SpdySessionHandler extends SimpleChannelUpstreamHandler
|
|||||||
|
|
||||||
private void halfCloseStream(int streamId, boolean remote, ChannelFuture future) {
|
private void halfCloseStream(int streamId, boolean remote, ChannelFuture future) {
|
||||||
if (remote) {
|
if (remote) {
|
||||||
spdySession.closeRemoteSide(streamId);
|
spdySession.closeRemoteSide(streamId, isRemoteInitiatedId(streamId));
|
||||||
} else {
|
} else {
|
||||||
spdySession.closeLocalSide(streamId);
|
spdySession.closeLocalSide(streamId, isRemoteInitiatedId(streamId));
|
||||||
}
|
}
|
||||||
if (closeSessionFutureListener != null && spdySession.noActiveStreams()) {
|
if (closeSessionFutureListener != null && spdySession.noActiveStreams()) {
|
||||||
future.addListener(closeSessionFutureListener);
|
future.addListener(closeSessionFutureListener);
|
||||||
@ -728,7 +719,7 @@ public class SpdySessionHandler extends SimpleChannelUpstreamHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void removeStream(int streamId, ChannelFuture future) {
|
private void removeStream(int streamId, ChannelFuture future) {
|
||||||
spdySession.removeStream(streamId);
|
spdySession.removeStream(streamId, isRemoteInitiatedId(streamId));
|
||||||
if (closeSessionFutureListener != null && spdySession.noActiveStreams()) {
|
if (closeSessionFutureListener != null && spdySession.noActiveStreams()) {
|
||||||
future.addListener(closeSessionFutureListener);
|
future.addListener(closeSessionFutureListener);
|
||||||
}
|
}
|
||||||
|
@ -100,9 +100,6 @@ public class SpdySessionHandlerTest {
|
|||||||
int localStreamId = server ? 1 : 2;
|
int localStreamId = server ? 1 : 2;
|
||||||
int remoteStreamId = server ? 2 : 1;
|
int remoteStreamId = server ? 2 : 1;
|
||||||
|
|
||||||
SpdyPingFrame localPingFrame = new DefaultSpdyPingFrame(localStreamId);
|
|
||||||
SpdyPingFrame remotePingFrame = new DefaultSpdyPingFrame(remoteStreamId);
|
|
||||||
|
|
||||||
SpdySynStreamFrame spdySynStreamFrame = new DefaultSpdySynStreamFrame(localStreamId, 0, (byte) 0);
|
SpdySynStreamFrame spdySynStreamFrame = new DefaultSpdySynStreamFrame(localStreamId, 0, (byte) 0);
|
||||||
spdySynStreamFrame.setHeader("Compression", "test");
|
spdySynStreamFrame.setHeader("Compression", "test");
|
||||||
|
|
||||||
@ -122,24 +119,11 @@ public class SpdySessionHandlerTest {
|
|||||||
assertNull(sessionHandler.peek());
|
assertNull(sessionHandler.peek());
|
||||||
remoteStreamId += 2;
|
remoteStreamId += 2;
|
||||||
|
|
||||||
// Check if session handler correctly limits the number of
|
|
||||||
// concurrent streams in the SETTINGS frame
|
|
||||||
SpdySettingsFrame spdySettingsFrame = new DefaultSpdySettingsFrame();
|
|
||||||
spdySettingsFrame.setValue(SpdySettingsFrame.SETTINGS_MAX_CONCURRENT_STREAMS, 0);
|
|
||||||
sessionHandler.offer(spdySettingsFrame);
|
|
||||||
assertNull(sessionHandler.peek());
|
|
||||||
sessionHandler.offer(spdySynStreamFrame);
|
|
||||||
assertRstStream(sessionHandler.poll(), localStreamId, SpdyStreamStatus.REFUSED_STREAM);
|
|
||||||
assertNull(sessionHandler.peek());
|
|
||||||
spdySettingsFrame.setValue(SpdySettingsFrame.SETTINGS_MAX_CONCURRENT_STREAMS, 100);
|
|
||||||
sessionHandler.offer(spdySettingsFrame);
|
|
||||||
assertNull(sessionHandler.peek());
|
|
||||||
sessionHandler.offer(new DefaultSpdySynReplyFrame(remoteStreamId));
|
|
||||||
assertNull(sessionHandler.peek());
|
|
||||||
|
|
||||||
// Check if session handler returns PROTOCOL_ERROR if it receives
|
// Check if session handler returns PROTOCOL_ERROR if it receives
|
||||||
// multiple SYN_REPLY frames for the same active Stream-ID
|
// multiple SYN_REPLY frames for the same active Stream-ID
|
||||||
sessionHandler.offer(new DefaultSpdySynReplyFrame(remoteStreamId));
|
sessionHandler.offer(new DefaultSpdySynReplyFrame(remoteStreamId));
|
||||||
|
assertNull(sessionHandler.peek());
|
||||||
|
sessionHandler.offer(new DefaultSpdySynReplyFrame(remoteStreamId));
|
||||||
assertRstStream(sessionHandler.poll(), remoteStreamId, SpdyStreamStatus.STREAM_IN_USE);
|
assertRstStream(sessionHandler.poll(), remoteStreamId, SpdyStreamStatus.STREAM_IN_USE);
|
||||||
assertNull(sessionHandler.peek());
|
assertNull(sessionHandler.peek());
|
||||||
remoteStreamId += 2;
|
remoteStreamId += 2;
|
||||||
@ -166,6 +150,16 @@ public class SpdySessionHandlerTest {
|
|||||||
assertRstStream(sessionHandler.poll(), localStreamId, SpdyStreamStatus.REFUSED_STREAM);
|
assertRstStream(sessionHandler.poll(), localStreamId, SpdyStreamStatus.REFUSED_STREAM);
|
||||||
assertNull(sessionHandler.peek());
|
assertNull(sessionHandler.peek());
|
||||||
|
|
||||||
|
// Check if session handler rejects HEADERS for closed streams
|
||||||
|
int testStreamId = spdyDataFrame.getStreamId();
|
||||||
|
sessionHandler.offer(spdyDataFrame);
|
||||||
|
assertDataFrame(sessionHandler.poll(), testStreamId, spdyDataFrame.isLast());
|
||||||
|
assertNull(sessionHandler.peek());
|
||||||
|
spdyHeadersFrame.setStreamId(testStreamId);
|
||||||
|
sessionHandler.offer(spdyHeadersFrame);
|
||||||
|
assertRstStream(sessionHandler.poll(), testStreamId, SpdyStreamStatus.INVALID_STREAM);
|
||||||
|
assertNull(sessionHandler.peek());
|
||||||
|
|
||||||
// Check if session handler drops active streams if it receives
|
// Check if session handler drops active streams if it receives
|
||||||
// a RST_STREAM frame for that Stream-ID
|
// a RST_STREAM frame for that Stream-ID
|
||||||
sessionHandler.offer(new DefaultSpdyRstStreamFrame(remoteStreamId, 3));
|
sessionHandler.offer(new DefaultSpdyRstStreamFrame(remoteStreamId, 3));
|
||||||
@ -193,31 +187,6 @@ public class SpdySessionHandlerTest {
|
|||||||
assertNull(sessionHandler.peek());
|
assertNull(sessionHandler.peek());
|
||||||
spdySynStreamFrame.setStreamId(localStreamId);
|
spdySynStreamFrame.setStreamId(localStreamId);
|
||||||
|
|
||||||
// Check if session handler correctly handles updates to the max
|
|
||||||
// concurrent streams in the SETTINGS frame
|
|
||||||
spdySettingsFrame.setValue(SpdySettingsFrame.SETTINGS_MAX_CONCURRENT_STREAMS, 2);
|
|
||||||
sessionHandler.offer(spdySettingsFrame);
|
|
||||||
assertNull(sessionHandler.peek());
|
|
||||||
sessionHandler.offer(spdySynStreamFrame);
|
|
||||||
assertRstStream(sessionHandler.poll(), localStreamId, SpdyStreamStatus.REFUSED_STREAM);
|
|
||||||
assertNull(sessionHandler.peek());
|
|
||||||
spdySettingsFrame.setValue(SpdySettingsFrame.SETTINGS_MAX_CONCURRENT_STREAMS, 4);
|
|
||||||
sessionHandler.offer(spdySettingsFrame);
|
|
||||||
assertNull(sessionHandler.peek());
|
|
||||||
sessionHandler.offer(spdySynStreamFrame);
|
|
||||||
assertSynReply(sessionHandler.poll(), localStreamId, false, spdySynStreamFrame);
|
|
||||||
assertNull(sessionHandler.peek());
|
|
||||||
|
|
||||||
// Check if session handler rejects HEADERS for closed streams
|
|
||||||
int testStreamId = spdyDataFrame.getStreamId();
|
|
||||||
sessionHandler.offer(spdyDataFrame);
|
|
||||||
assertDataFrame(sessionHandler.poll(), testStreamId, spdyDataFrame.isLast());
|
|
||||||
assertNull(sessionHandler.peek());
|
|
||||||
spdyHeadersFrame.setStreamId(testStreamId);
|
|
||||||
sessionHandler.offer(spdyHeadersFrame);
|
|
||||||
assertRstStream(sessionHandler.poll(), testStreamId, SpdyStreamStatus.INVALID_STREAM);
|
|
||||||
assertNull(sessionHandler.peek());
|
|
||||||
|
|
||||||
// Check if session handler returns PROTOCOL_ERROR if it receives
|
// Check if session handler returns PROTOCOL_ERROR if it receives
|
||||||
// an invalid HEADERS frame
|
// an invalid HEADERS frame
|
||||||
spdyHeadersFrame.setStreamId(localStreamId);
|
spdyHeadersFrame.setStreamId(localStreamId);
|
||||||
@ -226,6 +195,63 @@ public class SpdySessionHandlerTest {
|
|||||||
assertRstStream(sessionHandler.poll(), localStreamId, SpdyStreamStatus.PROTOCOL_ERROR);
|
assertRstStream(sessionHandler.poll(), localStreamId, SpdyStreamStatus.PROTOCOL_ERROR);
|
||||||
assertNull(sessionHandler.peek());
|
assertNull(sessionHandler.peek());
|
||||||
|
|
||||||
|
sessionHandler.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSpdyClientSessionHandler() {
|
||||||
|
for (int version = SPDY_MIN_VERSION; version <= SPDY_MAX_VERSION; version ++) {
|
||||||
|
testSpdySessionHandler(version, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSpdyClientSessionHandlerPing() {
|
||||||
|
for (int version = SPDY_MIN_VERSION; version <= SPDY_MAX_VERSION; version ++) {
|
||||||
|
testSpdySessionHandlerPing(version, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSpdyClientSessionHandlerGoAway() {
|
||||||
|
for (int version = SPDY_MIN_VERSION; version <= SPDY_MAX_VERSION; version ++) {
|
||||||
|
testSpdySessionHandlerGoAway(version, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSpdyServerSessionHandler() {
|
||||||
|
for (int version = SPDY_MIN_VERSION; version <= SPDY_MAX_VERSION; version ++) {
|
||||||
|
testSpdySessionHandler(version, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSpdyServerSessionHandlerPing() {
|
||||||
|
for (int version = SPDY_MIN_VERSION; version <= SPDY_MAX_VERSION; version ++) {
|
||||||
|
testSpdySessionHandlerPing(version, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSpdyServerSessionHandlerGoAway() {
|
||||||
|
for (int version = SPDY_MIN_VERSION; version <= SPDY_MAX_VERSION; version ++) {
|
||||||
|
testSpdySessionHandlerGoAway(version, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testSpdySessionHandlerPing(int version, boolean server) {
|
||||||
|
DecoderEmbedder<Object> sessionHandler =
|
||||||
|
new DecoderEmbedder<Object>(
|
||||||
|
new SpdySessionHandler(version, server), new EchoHandler(closeSignal, server));
|
||||||
|
sessionHandler.pollAll();
|
||||||
|
|
||||||
|
int localStreamId = server ? 1 : 2;
|
||||||
|
int remoteStreamId = server ? 2 : 1;
|
||||||
|
|
||||||
|
SpdyPingFrame localPingFrame = new DefaultSpdyPingFrame(localStreamId);
|
||||||
|
SpdyPingFrame remotePingFrame = new DefaultSpdyPingFrame(remoteStreamId);
|
||||||
|
|
||||||
// Check if session handler returns identical local PINGs
|
// Check if session handler returns identical local PINGs
|
||||||
sessionHandler.offer(localPingFrame);
|
sessionHandler.offer(localPingFrame);
|
||||||
assertPing(sessionHandler.poll(), localPingFrame.getId());
|
assertPing(sessionHandler.poll(), localPingFrame.getId());
|
||||||
@ -235,6 +261,32 @@ public class SpdySessionHandlerTest {
|
|||||||
sessionHandler.offer(remotePingFrame);
|
sessionHandler.offer(remotePingFrame);
|
||||||
assertNull(sessionHandler.peek());
|
assertNull(sessionHandler.peek());
|
||||||
|
|
||||||
|
sessionHandler.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testSpdySessionHandlerGoAway(int version, boolean server) {
|
||||||
|
DecoderEmbedder<Object> sessionHandler =
|
||||||
|
new DecoderEmbedder<Object>(
|
||||||
|
new SpdySessionHandler(version, server), new EchoHandler(closeSignal, server));
|
||||||
|
sessionHandler.pollAll();
|
||||||
|
|
||||||
|
int localStreamId = server ? 1 : 2;
|
||||||
|
int remoteStreamId = server ? 2 : 1;
|
||||||
|
|
||||||
|
SpdySynStreamFrame spdySynStreamFrame = new DefaultSpdySynStreamFrame(localStreamId, 0, (byte) 0);
|
||||||
|
spdySynStreamFrame.setHeader("Compression", "test");
|
||||||
|
|
||||||
|
SpdyDataFrame spdyDataFrame = new DefaultSpdyDataFrame(localStreamId);
|
||||||
|
spdyDataFrame.setLast(true);
|
||||||
|
|
||||||
|
// Send an initial request
|
||||||
|
sessionHandler.offer(spdySynStreamFrame);
|
||||||
|
assertSynReply(sessionHandler.poll(), localStreamId, false, spdySynStreamFrame);
|
||||||
|
assertNull(sessionHandler.peek());
|
||||||
|
sessionHandler.offer(spdyDataFrame);
|
||||||
|
assertDataFrame(sessionHandler.poll(), localStreamId, true);
|
||||||
|
assertNull(sessionHandler.peek());
|
||||||
|
|
||||||
// Check if session handler sends a GOAWAY frame when closing
|
// Check if session handler sends a GOAWAY frame when closing
|
||||||
sessionHandler.offer(closeMessage);
|
sessionHandler.offer(closeMessage);
|
||||||
assertGoAway(sessionHandler.poll(), localStreamId);
|
assertGoAway(sessionHandler.poll(), localStreamId);
|
||||||
@ -257,20 +309,6 @@ public class SpdySessionHandlerTest {
|
|||||||
sessionHandler.finish();
|
sessionHandler.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSpdyClientSessionHandler() {
|
|
||||||
for (int version = SPDY_MIN_VERSION; version <= SPDY_MAX_VERSION; version ++) {
|
|
||||||
testSpdySessionHandler(version, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSpdyServerSessionHandler() {
|
|
||||||
for (int version = SPDY_MIN_VERSION; version <= SPDY_MAX_VERSION; version ++) {
|
|
||||||
testSpdySessionHandler(version, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Echo Handler opens 4 half-closed streams on session connection
|
// Echo Handler opens 4 half-closed streams on session connection
|
||||||
// and then sets the number of concurrent streams to 3
|
// and then sets the number of concurrent streams to 3
|
||||||
private static class EchoHandler extends SimpleChannelUpstreamHandler {
|
private static class EchoHandler extends SimpleChannelUpstreamHandler {
|
||||||
@ -297,9 +335,9 @@ public class SpdySessionHandlerTest {
|
|||||||
spdySynStreamFrame.setStreamId(spdySynStreamFrame.getStreamId() + 2);
|
spdySynStreamFrame.setStreamId(spdySynStreamFrame.getStreamId() + 2);
|
||||||
Channels.write(e.getChannel(), spdySynStreamFrame);
|
Channels.write(e.getChannel(), spdySynStreamFrame);
|
||||||
|
|
||||||
// Limit the number of concurrent streams to 3
|
// Limit the number of concurrent streams to 1
|
||||||
SpdySettingsFrame spdySettingsFrame = new DefaultSpdySettingsFrame();
|
SpdySettingsFrame spdySettingsFrame = new DefaultSpdySettingsFrame();
|
||||||
spdySettingsFrame.setValue(SpdySettingsFrame.SETTINGS_MAX_CONCURRENT_STREAMS, 3);
|
spdySettingsFrame.setValue(SpdySettingsFrame.SETTINGS_MAX_CONCURRENT_STREAMS, 1);
|
||||||
Channels.write(e.getChannel(), spdySettingsFrame);
|
Channels.write(e.getChannel(), spdySettingsFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user