SPDY: remove SPDY/2 support

This commit is contained in:
Jeff Pinner 2013-10-14 07:27:50 -07:00
parent 1f1a627a22
commit 949a6968ee
8 changed files with 139 additions and 329 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012 The Netty Project
* Copyright 2013 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
@ -186,23 +186,10 @@ public class SpdyFrameDecoder extends ByteToMessageDecoder {
int readableEntries = Math.min(buffer.readableBytes() >> 3, length >> 3);
for (int i = 0; i < readableEntries; i ++) {
int ID;
byte ID_flags;
if (version < 3) {
// Chromium Issue 79156
// SPDY setting ids are not written in network byte order
// Read id assuming the architecture is little endian
ID = buffer.readByte() & 0xFF |
(buffer.readByte() & 0xFF) << 8 |
(buffer.readByte() & 0xFF) << 16;
ID_flags = buffer.readByte();
} else {
ID_flags = buffer.readByte();
ID = getUnsignedMedium(buffer, buffer.readerIndex());
buffer.skipBytes(3);
}
int value = getSignedInt(buffer, buffer.readerIndex());
buffer.skipBytes(4);
byte ID_flags = buffer.getByte(buffer.readerIndex());
int ID = getUnsignedMedium(buffer, buffer.readerIndex() + 1);
int value = getSignedInt(buffer, buffer.readerIndex() + 4);
buffer.skipBytes(8);
// Check for invalid ID -- avoid IllegalArgumentException in setValue
if (ID == 0) {
@ -427,20 +414,13 @@ public class SpdyFrameDecoder extends ByteToMessageDecoder {
return new DefaultSpdyPingFrame(ID);
case SPDY_GOAWAY_FRAME:
int minLength = version < 3 ? 4 : 8;
if (buffer.readableBytes() < minLength) {
if (buffer.readableBytes() < 8) {
return null;
}
int lastGoodStreamId = getUnsignedInt(buffer, buffer.readerIndex());
buffer.skipBytes(4);
if (version < 3) {
return new DefaultSpdyGoAwayFrame(lastGoodStreamId);
}
statusCode = getSignedInt(buffer, buffer.readerIndex());
buffer.skipBytes(4);
statusCode = getSignedInt(buffer, buffer.readerIndex() + 4);
buffer.skipBytes(8);
return new DefaultSpdyGoAwayFrame(lastGoodStreamId, statusCode);
@ -461,12 +441,10 @@ public class SpdyFrameDecoder extends ByteToMessageDecoder {
}
private SpdyHeadersFrame readHeaderBlockFrame(ByteBuf buffer) {
int minLength;
int streamId;
switch (type) {
case SPDY_SYN_STREAM_FRAME:
minLength = version < 3 ? 12 : 10;
if (buffer.readableBytes() < minLength) {
if (buffer.readableBytes() < 10) {
return null;
}
@ -474,18 +452,9 @@ public class SpdyFrameDecoder extends ByteToMessageDecoder {
streamId = getUnsignedInt(buffer, offset);
int associatedToStreamId = getUnsignedInt(buffer, offset + 4);
byte priority = (byte) (buffer.getByte(offset + 8) >> 5 & 0x07);
if (version < 3) {
priority >>= 1;
}
buffer.skipBytes(10);
length -= 10;
// SPDY/2 requires 16-bits of padding for empty header blocks
if (version < 3 && length == 2 && buffer.getShort(buffer.readerIndex()) == 0) {
buffer.skipBytes(2);
length = 0;
}
SpdySynStreamFrame spdySynStreamFrame =
new DefaultSpdySynStreamFrame(streamId, associatedToStreamId, priority);
spdySynStreamFrame.setLast((flags & SPDY_FLAG_FIN) != 0);
@ -494,8 +463,7 @@ public class SpdyFrameDecoder extends ByteToMessageDecoder {
return spdySynStreamFrame;
case SPDY_SYN_REPLY_FRAME:
minLength = version < 3 ? 8 : 4;
if (buffer.readableBytes() < minLength) {
if (buffer.readableBytes() < 4) {
return null;
}
@ -503,18 +471,6 @@ public class SpdyFrameDecoder extends ByteToMessageDecoder {
buffer.skipBytes(4);
length -= 4;
// SPDY/2 has 16-bits of unused space
if (version < 3) {
buffer.skipBytes(2);
length -= 2;
}
// SPDY/2 requires 16-bits of padding for empty header blocks
if (version < 3 && length == 2 && buffer.getShort(buffer.readerIndex()) == 0) {
buffer.skipBytes(2);
length = 0;
}
SpdySynReplyFrame spdySynReplyFrame = new DefaultSpdySynReplyFrame(streamId);
spdySynReplyFrame.setLast((flags & SPDY_FLAG_FIN) != 0);
@ -525,27 +481,10 @@ public class SpdyFrameDecoder extends ByteToMessageDecoder {
return null;
}
// SPDY/2 allows length 4 frame when there are no name/value pairs
if (version < 3 && length > 4 && buffer.readableBytes() < 8) {
return null;
}
streamId = getUnsignedInt(buffer, buffer.readerIndex());
buffer.skipBytes(4);
length -= 4;
// SPDY/2 has 16-bits of unused space
if (version < 3 && length != 0) {
buffer.skipBytes(2);
length -= 2;
}
// SPDY/2 requires 16-bits of padding for empty header blocks
if (version < 3 && length == 2 && buffer.getShort(buffer.readerIndex()) == 0) {
buffer.skipBytes(2);
length = 0;
}
SpdyHeadersFrame spdyHeadersFrame = new DefaultSpdyHeadersFrame(streamId);
spdyHeadersFrame.setLast((flags & SPDY_FLAG_FIN) != 0);
@ -562,10 +501,10 @@ public class SpdyFrameDecoder extends ByteToMessageDecoder {
return streamId != 0;
case SPDY_SYN_STREAM_FRAME:
return version < 3 ? length >= 12 : length >= 10;
return length >= 10;
case SPDY_SYN_REPLY_FRAME:
return version < 3 ? length >= 8 : length >= 4;
return length >= 4;
case SPDY_RST_STREAM_FRAME:
return flags == 0 && length == 8;
@ -577,14 +516,10 @@ public class SpdyFrameDecoder extends ByteToMessageDecoder {
return length == 4;
case SPDY_GOAWAY_FRAME:
return version < 3 ? length == 4 : length == 8;
return length == 8;
case SPDY_HEADERS_FRAME:
if (version < 3) {
return length == 4 || length >= 8;
} else {
return length >= 4;
}
case SPDY_WINDOW_UPDATE_FRAME:
return length == 8;

View File

@ -92,12 +92,7 @@ public class SpdyFrameEncoder extends MessageToByteEncoder<SpdyFrame> {
flags |= SPDY_FLAG_UNIDIRECTIONAL;
}
int headerBlockLength = data.readableBytes();
int length;
if (version < 3) {
length = headerBlockLength == 0 ? 12 : 10 + headerBlockLength;
} else {
length = 10 + headerBlockLength;
}
int length = 10 + headerBlockLength;
out.ensureWritable(SPDY_HEADER_SIZE + length);
out.writeShort(version | 0x8000);
out.writeShort(SPDY_SYN_STREAM_FRAME);
@ -105,19 +100,7 @@ public class SpdyFrameEncoder extends MessageToByteEncoder<SpdyFrame> {
out.writeMedium(length);
out.writeInt(spdySynStreamFrame.getStreamId());
out.writeInt(spdySynStreamFrame.getAssociatedToStreamId());
if (version < 3) {
// Restrict priorities for SPDY/2 to between 0 and 3
byte priority = spdySynStreamFrame.getPriority();
if (priority > 3) {
priority = 3;
}
out.writeShort((priority & 0xFF) << 14);
} else {
out.writeShort((spdySynStreamFrame.getPriority() & 0xFF) << 13);
}
if (version < 3 && data.readableBytes() == 0) {
out.writeShort(0);
}
out.writeBytes(data, data.readerIndex(), headerBlockLength);
} finally {
data.release();
@ -130,25 +113,13 @@ public class SpdyFrameEncoder extends MessageToByteEncoder<SpdyFrame> {
try {
byte flags = spdySynReplyFrame.isLast() ? SPDY_FLAG_FIN : 0;
int headerBlockLength = data.readableBytes();
int length;
if (version < 3) {
length = headerBlockLength == 0 ? 8 : 6 + headerBlockLength;
} else {
length = 4 + headerBlockLength;
}
int length = 4 + headerBlockLength;
out.ensureWritable(SPDY_HEADER_SIZE + length);
out.writeShort(version | 0x8000);
out.writeShort(SPDY_SYN_REPLY_FRAME);
out.writeByte(flags);
out.writeMedium(length);
out.writeInt(spdySynReplyFrame.getStreamId());
if (version < 3) {
if (headerBlockLength == 0) {
out.writeInt(0);
} else {
out.writeShort(0);
}
}
out.writeBytes(data, data.readerIndex(), headerBlockLength);
} finally {
data.release();
@ -178,8 +149,7 @@ public class SpdyFrameEncoder extends MessageToByteEncoder<SpdyFrame> {
out.writeByte(flags);
out.writeMedium(length);
out.writeInt(numEntries);
for (Integer ID: IDs) {
int id = ID.intValue();
for (Integer id: IDs) {
byte ID_flags = 0;
if (spdySettingsFrame.isPersistValue(id)) {
ID_flags |= SPDY_SETTINGS_PERSIST_VALUE;
@ -187,18 +157,8 @@ public class SpdyFrameEncoder extends MessageToByteEncoder<SpdyFrame> {
if (spdySettingsFrame.isPersisted(id)) {
ID_flags |= SPDY_SETTINGS_PERSISTED;
}
if (version < 3) {
// Chromium Issue 79156
// SPDY setting ids are not written in network byte order
// Write id assuming the architecture is little endian
out.writeByte(id & 0xFF);
out.writeByte(id >> 8 & 0xFF);
out.writeByte(id >> 16 & 0xFF);
out.writeByte(ID_flags);
} else {
out.writeByte(ID_flags);
out.writeMedium(id);
}
out.writeInt(spdySettingsFrame.getValue(id));
}
@ -214,15 +174,12 @@ public class SpdyFrameEncoder extends MessageToByteEncoder<SpdyFrame> {
} else if (msg instanceof SpdyGoAwayFrame) {
SpdyGoAwayFrame spdyGoAwayFrame = (SpdyGoAwayFrame) msg;
int length = version < 3 ? 4 : 8;
out.ensureWritable(SPDY_HEADER_SIZE + length);
out.ensureWritable(SPDY_HEADER_SIZE + 8);
out.writeShort(version | 0x8000);
out.writeShort(SPDY_GOAWAY_FRAME);
out.writeInt(length);
out.writeInt(8);
out.writeInt(spdyGoAwayFrame.getLastGoodStreamId());
if (version >= 3) {
out.writeInt(spdyGoAwayFrame.getStatus().getCode());
}
} else if (msg instanceof SpdyHeadersFrame) {
@ -231,21 +188,13 @@ public class SpdyFrameEncoder extends MessageToByteEncoder<SpdyFrame> {
try {
byte flags = spdyHeadersFrame.isLast() ? SPDY_FLAG_FIN : 0;
int headerBlockLength = data.readableBytes();
int length;
if (version < 3) {
length = headerBlockLength == 0 ? 4 : 6 + headerBlockLength;
} else {
length = 4 + headerBlockLength;
}
int length = 4 + headerBlockLength;
out.ensureWritable(SPDY_HEADER_SIZE + length);
out.writeShort(version | 0x8000);
out.writeShort(SPDY_HEADERS_FRAME);
out.writeByte(flags);
out.writeMedium(length);
out.writeInt(spdyHeadersFrame.getStreamId());
if (version < 3 && headerBlockLength != 0) {
out.writeShort(0);
}
out.writeBytes(data, data.readerIndex(), headerBlockLength);
} finally {
data.release();

View File

@ -39,7 +39,6 @@ public abstract class SpdyOrHttpChooser extends ByteToMessageDecoder {
// TODO: Replace with generic NPN handler
public enum SelectedProtocol {
SPDY_2,
SPDY_3,
SPDY_3_1,
HTTP_1_1,
@ -84,9 +83,6 @@ public abstract class SpdyOrHttpChooser extends ByteToMessageDecoder {
case UNKNOWN:
// Not done with choosing the protocol, so just return here for now,
return false;
case SPDY_2:
addSpdyHandlers(ctx, SpdyVersion.SPDY_2);
break;
case SPDY_3:
addSpdyHandlers(ctx, SpdyVersion.SPDY_3);
break;
@ -137,8 +133,8 @@ public abstract class SpdyOrHttpChooser extends ByteToMessageDecoder {
/**
* Create the {@link ChannelInboundHandler} that is responsible for handling the http responses
* when the {@link SelectedProtocol} was {@link SelectedProtocol#SPDY_2} or
* {@link SelectedProtocol#SPDY_3}.
* when the {@link SelectedProtocol} was {@link SelectedProtocol#SPDY_3} or
* {@link SelectedProtocol#SPDY_3_1}.
*
* By default this getMethod will just delecate to {@link #createHttpRequestHandlerForHttp()}, but
* sub-classes may override this to change the behaviour.

View File

@ -61,7 +61,6 @@ public class SpdySessionHandler
private ChannelFutureListener closeSessionFutureListener;
private final boolean server;
private final boolean flowControl;
private final boolean sessionFlowControl;
/**
@ -78,7 +77,6 @@ public class SpdySessionHandler
throw new NullPointerException("version");
}
this.server = server;
flowControl = version.useFlowControl();
sessionFlowControl = version.useSessionFlowControl();
}
@ -165,7 +163,6 @@ public class SpdySessionHandler
* Recipient should not send a WINDOW_UPDATE frame as it consumes the last data frame.
*/
if (flowControl) {
// Update receive window size
int deltaWindowSize = -1 * spdyDataFrame.content().readableBytes();
int newWindowSize = spdySession.updateReceiveWindowSize(streamId, deltaWindowSize);
@ -199,7 +196,6 @@ public class SpdySessionHandler
new DefaultSpdyWindowUpdateFrame(streamId, deltaWindowSize);
ctx.writeAndFlush(spdyWindowUpdateFrame);
}
}
// Close the remote side of the stream if this is the last frame
if (spdyDataFrame.isLast()) {
@ -313,13 +309,11 @@ public class SpdySessionHandler
}
spdySettingsFrame.setPersistValue(SpdySettingsFrame.SETTINGS_INITIAL_WINDOW_SIZE, false);
if (flowControl) {
int newInitialWindowSize =
spdySettingsFrame.getValue(SpdySettingsFrame.SETTINGS_INITIAL_WINDOW_SIZE);
if (newInitialWindowSize >= 0) {
updateInitialSendWindowSize(newInitialWindowSize);
}
}
} else if (msg instanceof SpdyPingFrame) {
@ -382,7 +376,6 @@ public class SpdySessionHandler
* after sending the last frame for the stream.
*/
if (flowControl) {
SpdyWindowUpdateFrame spdyWindowUpdateFrame = (SpdyWindowUpdateFrame) msg;
int streamId = spdyWindowUpdateFrame.getStreamId();
int deltaWindowSize = spdyWindowUpdateFrame.getDeltaWindowSize();
@ -404,7 +397,6 @@ public class SpdySessionHandler
updateSendWindowSize(ctx, streamId, deltaWindowSize);
}
}
ctx.fireChannelRead(msg);
}
@ -475,7 +467,6 @@ public class SpdySessionHandler
* sender must pause transmitting data frames.
*/
if (flowControl) {
synchronized (flowControlLock) {
int dataLength = spdyDataFrame.content().readableBytes();
int sendWindowSize = spdySession.getSendWindowSize(streamId);
@ -535,7 +526,6 @@ public class SpdySessionHandler
});
}
}
}
// Close the local side of the stream if this is the last frame
if (spdyDataFrame.isLast()) {
@ -599,13 +589,11 @@ public class SpdySessionHandler
}
spdySettingsFrame.setPersistValue(SpdySettingsFrame.SETTINGS_INITIAL_WINDOW_SIZE, false);
if (flowControl) {
int newInitialWindowSize =
spdySettingsFrame.getValue(SpdySettingsFrame.SETTINGS_INITIAL_WINDOW_SIZE);
if (newInitialWindowSize >= 0) {
updateInitialReceiveWindowSize(newInitialWindowSize);
}
}
} else if (msg instanceof SpdyPingFrame) {

View File

@ -16,28 +16,14 @@
package io.netty.handler.codec.spdy;
public enum SpdyVersion {
SPDY_2 (2, false, false),
SPDY_3 (3, true, false),
SPDY_3_1 (3, true, true);
static SpdyVersion valueOf(int version) {
if (version == 2) {
return SPDY_2;
}
if (version == 3) {
return SPDY_3;
}
throw new IllegalArgumentException(
"unsupported version: " + version);
}
SPDY_3 (3, false),
SPDY_3_1 (3, true);
private final int version;
private final boolean flowControl;
private final boolean sessionFlowControl;
private SpdyVersion(int version, boolean flowControl, boolean sessionFlowControl) {
private SpdyVersion(int version, boolean sessionFlowControl) {
this.version = version;
this.flowControl = flowControl;
this.sessionFlowControl = sessionFlowControl;
}
@ -45,10 +31,6 @@ public enum SpdyVersion {
return version;
}
boolean useFlowControl() {
return flowControl;
}
boolean useSessionFlowControl() {
return sessionFlowControl;
}

View File

@ -47,7 +47,6 @@ public class SpdyFrameDecoderTest {
@Test
public void testTooLargeHeaderNameOnSynStreamRequest() throws Exception {
testTooLargeHeaderNameOnSynStreamRequest(SpdyVersion.SPDY_2);
testTooLargeHeaderNameOnSynStreamRequest(SpdyVersion.SPDY_3);
testTooLargeHeaderNameOnSynStreamRequest(SpdyVersion.SPDY_3_1);
}

View File

@ -282,8 +282,6 @@ public class SpdySessionHandlerTest {
@Test
public void testSpdyClientSessionHandler() {
logger.info("Running: testSpdyClientSessionHandler v2");
testSpdySessionHandler(SpdyVersion.SPDY_2, false);
logger.info("Running: testSpdyClientSessionHandler v3");
testSpdySessionHandler(SpdyVersion.SPDY_3, false);
logger.info("Running: testSpdyClientSessionHandler v3.1");
@ -292,8 +290,6 @@ public class SpdySessionHandlerTest {
@Test
public void testSpdyClientSessionHandlerPing() {
logger.info("Running: testSpdyClientSessionHandlerPing v2");
testSpdySessionHandlerPing(SpdyVersion.SPDY_2, false);
logger.info("Running: testSpdyClientSessionHandlerPing v3");
testSpdySessionHandlerPing(SpdyVersion.SPDY_3, false);
logger.info("Running: testSpdyClientSessionHandlerPing v3.1");
@ -302,8 +298,6 @@ public class SpdySessionHandlerTest {
@Test
public void testSpdyClientSessionHandlerGoAway() {
logger.info("Running: testSpdyClientSessionHandlerGoAway v2");
testSpdySessionHandlerGoAway(SpdyVersion.SPDY_2, false);
logger.info("Running: testSpdyClientSessionHandlerGoAway v3");
testSpdySessionHandlerGoAway(SpdyVersion.SPDY_3, false);
logger.info("Running: testSpdyClientSessionHandlerGoAway v3.1");
@ -312,8 +306,6 @@ public class SpdySessionHandlerTest {
@Test
public void testSpdyServerSessionHandler() {
logger.info("Running: testSpdyServerSessionHandler v2");
testSpdySessionHandler(SpdyVersion.SPDY_2, true);
logger.info("Running: testSpdyServerSessionHandler v3");
testSpdySessionHandler(SpdyVersion.SPDY_3, true);
logger.info("Running: testSpdyServerSessionHandler v3.1");
@ -322,8 +314,6 @@ public class SpdySessionHandlerTest {
@Test
public void testSpdyServerSessionHandlerPing() {
logger.info("Running: testSpdyServerSessionHandlerPing v2");
testSpdySessionHandlerPing(SpdyVersion.SPDY_2, true);
logger.info("Running: testSpdyServerSessionHandlerPing v3");
testSpdySessionHandlerPing(SpdyVersion.SPDY_3, true);
logger.info("Running: testSpdyServerSessionHandlerPing v3.1");
@ -332,8 +322,6 @@ public class SpdySessionHandlerTest {
@Test
public void testSpdyServerSessionHandlerGoAway() {
logger.info("Running: testSpdyServerSessionHandlerGoAway v2");
testSpdySessionHandlerGoAway(SpdyVersion.SPDY_2, true);
logger.info("Running: testSpdyServerSessionHandlerGoAway v3");
testSpdySessionHandlerGoAway(SpdyVersion.SPDY_3, true);
logger.info("Running: testSpdyServerSessionHandlerGoAway v3.1");

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012 The Netty Project
* Copyright 2013 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
@ -44,8 +44,7 @@ public class SocketSpdyEchoTest extends AbstractSocketTest {
static final int ignoredBytes = 20;
private static ByteBuf createFrames(int version) {
int length = version < 3 ? 1176 : 1174;
ByteBuf frames = Unpooled.buffer(length);
ByteBuf frames = Unpooled.buffer(1174);
// SPDY UNKNOWN Frame
frames.writeByte(0x80);
@ -74,11 +73,7 @@ public class SocketSpdyEchoTest extends AbstractSocketTest {
frames.writeByte(version);
frames.writeShort(1);
frames.writeByte(0x03);
if (version < 3) {
frames.writeMedium(12);
} else {
frames.writeMedium(10);
}
frames.writeInt(random.nextInt() & 0x7FFFFFFF | 0x01);
frames.writeInt(random.nextInt() & 0x7FFFFFFF);
frames.writeShort(0x8000);
@ -91,11 +86,7 @@ public class SocketSpdyEchoTest extends AbstractSocketTest {
frames.writeByte(version);
frames.writeShort(2);
frames.writeByte(0x01);
if (version < 3) {
frames.writeMedium(8);
} else {
frames.writeMedium(4);
}
frames.writeInt(random.nextInt() & 0x7FFFFFFF | 0x01);
if (version < 3) {
frames.writeInt(0);
@ -116,13 +107,8 @@ public class SocketSpdyEchoTest extends AbstractSocketTest {
frames.writeByte(0x01);
frames.writeMedium(12);
frames.writeInt(1);
if (version < 3) {
frames.writeMedium(random.nextInt());
frames.writeByte(0x03);
} else {
frames.writeByte(0x03);
frames.writeMedium(random.nextInt());
}
frames.writeInt(random.nextInt());
// SPDY PING Frame
@ -136,15 +122,9 @@ public class SocketSpdyEchoTest extends AbstractSocketTest {
frames.writeByte(0x80);
frames.writeByte(version);
frames.writeShort(7);
if (version < 3) {
frames.writeInt(4);
} else {
frames.writeInt(8);
}
frames.writeInt(random.nextInt() & 0x7FFFFFFF);
if (version >= 3) {
frames.writeInt(random.nextInt() | 0x01);
}
// SPDY HEADERS Frame
frames.writeByte(0x80);
@ -169,10 +149,6 @@ public class SocketSpdyEchoTest extends AbstractSocketTest {
@Test(timeout = 15000)
public void testSpdyEcho() throws Throwable {
version = SpdyVersion.SPDY_2;
logger.info("Testing against SPDY v2");
run();
version = SpdyVersion.SPDY_3;
logger.info("Testing against SPDY v3");
run();
@ -186,9 +162,6 @@ public class SocketSpdyEchoTest extends AbstractSocketTest {
ByteBuf frames;
switch (version) {
case SPDY_2:
frames = createFrames(2);
break;
case SPDY_3:
case SPDY_3_1:
frames = createFrames(3);