SPDY: fix for mozilla firefox bug 754766

This commit is contained in:
Jeff Pinner 2012-05-23 08:53:29 -07:00
parent 69d5be4225
commit f60997686d
5 changed files with 181 additions and 8 deletions

View File

@ -0,0 +1,76 @@
/*
* Copyright 2012 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
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.codec.spdy;
import io.netty.util.internal.StringUtil;
/**
* The default {@link SpdyWindowUpdateFrame} implementation.
*/
public class DefaultSpdyWindowUpdateFrame implements SpdyWindowUpdateFrame {
private int streamID;
private int deltaWindowSize;
/**
* Creates a new instance.
*
* @param streamID the Stream-ID of this frame
* @param deltaWindowSize the Delta-Window-Size of this frame
*/
public DefaultSpdyWindowUpdateFrame(int streamID, int deltaWindowSize) {
setStreamID(streamID);
setDeltaWindowSize(deltaWindowSize);
}
public int getStreamID() {
return streamID;
}
public void setStreamID(int streamID) {
if (streamID <= 0) {
throw new IllegalArgumentException(
"Stream-ID must be positive: " + streamID);
}
this.streamID = streamID;
}
public int getDeltaWindowSize() {
return deltaWindowSize;
}
public void setDeltaWindowSize(int deltaWindowSize) {
if (deltaWindowSize <= 0) {
throw new IllegalArgumentException(
"Delta-Window-Size must be positive: " +
deltaWindowSize);
}
this.deltaWindowSize = deltaWindowSize;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append(getClass().getSimpleName());
buf.append(StringUtil.NEWLINE);
buf.append("--> Stream-ID = ");
buf.append(streamID);
buf.append(StringUtil.NEWLINE);
buf.append("--> Delta-Window-Size = ");
buf.append(deltaWindowSize);
return buf.toString();
}
}

View File

@ -115,6 +115,26 @@ public class SpdyFrameDecoder extends FrameDecoder {
fireInvalidControlFrameException(ctx);
}
}
// FrameDecoders must consume data when producing frames
// All length 0 frames must be generated now
if (length == 0) {
if (state == State.READ_DATA_FRAME) {
if (streamID == 0) {
state = State.FRAME_ERROR;
fireProtocolException(ctx, "Received invalid data frame");
return null;
}
SpdyDataFrame spdyDataFrame = new DefaultSpdyDataFrame(streamID);
spdyDataFrame.setLast((flags & SPDY_DATA_FLAG_FIN) != 0);
state = State.READ_COMMON_HEADER;
return spdyDataFrame;
}
// There are no length 0 control frames
state = State.READ_COMMON_HEADER;
}
return null;
case READ_CONTROL_FRAME:
@ -343,13 +363,14 @@ public class SpdyFrameDecoder extends FrameDecoder {
}
private Object readControlFrame(ChannelBuffer buffer) {
int streamID;
switch (type) {
case SPDY_RST_STREAM_FRAME:
if (buffer.readableBytes() < 8) {
return null;
}
int streamID = getUnsignedInt(buffer, buffer.readerIndex());
streamID = getUnsignedInt(buffer, buffer.readerIndex());
int statusCode = getSignedInt(buffer, buffer.readerIndex() + 4);
buffer.skipBytes(8);
@ -375,6 +396,17 @@ public class SpdyFrameDecoder extends FrameDecoder {
return new DefaultSpdyGoAwayFrame(lastGoodStreamID);
case SPDY_WINDOW_UPDATE_FRAME:
if (buffer.readableBytes() < 8) {
return null;
}
streamID = getUnsignedInt(buffer, buffer.readerIndex());
int deltaWindowSize = getUnsignedInt(buffer, buffer.readerIndex() + 4);
buffer.skipBytes(8);
return new DefaultSpdyWindowUpdateFrame(streamID, deltaWindowSize);
default:
throw new Error("Shouldn't reach here.");
}
@ -622,6 +654,8 @@ public class SpdyFrameDecoder extends FrameDecoder {
return length == 4 || length >= 8;
case SPDY_WINDOW_UPDATE_FRAME:
return length == 8;
default:
return true;
}
@ -636,10 +670,10 @@ public class SpdyFrameDecoder extends FrameDecoder {
case SPDY_PING_FRAME:
case SPDY_GOAWAY_FRAME:
case SPDY_HEADERS_FRAME:
case SPDY_WINDOW_UPDATE_FRAME:
return true;
case SPDY_NOOP_FRAME:
case SPDY_WINDOW_UPDATE_FRAME:
default:
return false;
}

View File

@ -231,6 +231,18 @@ public class SpdyFrameEncoder extends OneToOneEncoder {
frame.writeShort(0);
}
return ChannelBuffers.wrappedBuffer(frame, data);
} else if (msg instanceof SpdyWindowUpdateFrame) {
SpdyWindowUpdateFrame spdyWindowUpdateFrame = (SpdyWindowUpdateFrame) msg;
ChannelBuffer frame = ChannelBuffers.buffer(
ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE + 8);
frame.writeShort(SPDY_VERSION | 0x8000);
frame.writeShort(SPDY_WINDOW_UPDATE_FRAME);
frame.writeInt(8);
frame.writeInt(spdyWindowUpdateFrame.getStreamID());
frame.writeInt(spdyWindowUpdateFrame.getDeltaWindowSize());
return frame;
}
// Unknown message type

View File

@ -0,0 +1,43 @@
/*
* Copyright 2012 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
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.handler.codec.spdy;
/**
* A SPDY Protocol WINDOW_UPDATE Control Frame
*/
public interface SpdyWindowUpdateFrame {
/**
* Returns the Stream-ID of this frame.
*/
int getStreamID();
/**
* Sets the Stream-ID of this frame. The Stream-ID must be positive.
*/
void setStreamID(int streamID);
/**
* Returns the Delta-Window-Size of this frame.
*/
int getDeltaWindowSize();
/**
* Sets the Delta-Window-Size of this frame.
* The Delta-Window-Size must be positive.
*/
void setDeltaWindowSize(int deltaWindowSize);
}

View File

@ -47,7 +47,7 @@ import org.junit.Test;
public abstract class AbstractSocketSpdyEchoTest {
private static final Random random = new Random();
static final ChannelBuffer frames = ChannelBuffers.buffer(1160);
static final ChannelBuffer frames = ChannelBuffers.buffer(1176);
static final int ignoredBytes = 20;
private static ExecutorService executor;
@ -68,7 +68,7 @@ public abstract class AbstractSocketSpdyEchoTest {
frames.writeInt(0);
// SPDY Data Frame
frames.writeInt(random.nextInt() & 0x7FFFFFFF);
frames.writeInt(random.nextInt() & 0x7FFFFFFF | 0x01);
frames.writeByte(0x01);
frames.writeMedium(1024);
for (int i = 0; i < 256; i ++) {
@ -81,7 +81,7 @@ public abstract class AbstractSocketSpdyEchoTest {
frames.writeShort(1);
frames.writeByte(0x03);
frames.writeMedium(12);
frames.writeInt(random.nextInt() & 0x7FFFFFFF);
frames.writeInt(random.nextInt() & 0x7FFFFFFF | 0x01);
frames.writeInt(random.nextInt() & 0x7FFFFFFF);
frames.writeShort(0x8000);
frames.writeShort(0);
@ -92,7 +92,7 @@ public abstract class AbstractSocketSpdyEchoTest {
frames.writeShort(2);
frames.writeByte(0x01);
frames.writeMedium(8);
frames.writeInt(random.nextInt() & 0x7FFFFFFF);
frames.writeInt(random.nextInt() & 0x7FFFFFFF | 0x01);
frames.writeInt(0);
// SPDY RST_STREAM Frame
@ -100,7 +100,7 @@ public abstract class AbstractSocketSpdyEchoTest {
frames.writeByte(2);
frames.writeShort(3);
frames.writeInt(8);
frames.writeInt(random.nextInt() & 0x7FFFFFFF);
frames.writeInt(random.nextInt() & 0x7FFFFFFF | 0x01);
frames.writeInt(random.nextInt() | 0x01);
// SPDY SETTINGS Frame
@ -133,7 +133,15 @@ public abstract class AbstractSocketSpdyEchoTest {
frames.writeByte(2);
frames.writeShort(8);
frames.writeInt(4);
frames.writeInt(random.nextInt() & 0x7FFFFFFF);
frames.writeInt(random.nextInt() & 0x7FFFFFFF | 0x01);
// SPDY WINDOW_UPDATE Frame
frames.writeByte(0x80);
frames.writeByte(2);
frames.writeShort(9);
frames.writeInt(8);
frames.writeInt(random.nextInt() & 0x7FFFFFFF | 0x01);
frames.writeInt(random.nextInt() & 0x7FFFFFFF | 0x01);
}
@BeforeClass