Merge pull request #1929 from wgallagher/netty3spdybuf
avoid holding onto temporary buffers in SpdyFrameCodec
This commit is contained in:
commit
f739579339
@ -20,6 +20,7 @@ import static org.jboss.netty.handler.codec.spdy.SpdyCodecUtil.*;
|
||||
import org.jboss.netty.buffer.ChannelBuffer;
|
||||
import org.jboss.netty.channel.Channel;
|
||||
import org.jboss.netty.channel.ChannelHandlerContext;
|
||||
import org.jboss.netty.channel.ChannelStateEvent;
|
||||
import org.jboss.netty.channel.Channels;
|
||||
import org.jboss.netty.handler.codec.frame.FrameDecoder;
|
||||
|
||||
@ -89,17 +90,6 @@ public class SpdyFrameDecoder extends FrameDecoder {
|
||||
state = State.READ_COMMON_HEADER;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object decodeLast(
|
||||
ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer)
|
||||
throws Exception {
|
||||
try {
|
||||
return decode(ctx, channel, buffer);
|
||||
} finally {
|
||||
headerBlockDecoder.end();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object decode(
|
||||
ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer)
|
||||
@ -521,6 +511,15 @@ public class SpdyFrameDecoder extends FrameDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cleanup(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
|
||||
try {
|
||||
super.cleanup(ctx, e);
|
||||
} finally {
|
||||
headerBlockDecoder.end();
|
||||
}
|
||||
}
|
||||
|
||||
private static void fireInvalidFrameException(ChannelHandlerContext ctx) {
|
||||
Channels.fireExceptionCaught(ctx, INVALID_FRAME);
|
||||
}
|
||||
|
@ -16,19 +16,19 @@
|
||||
package org.jboss.netty.handler.codec.spdy;
|
||||
|
||||
import org.jboss.netty.buffer.ChannelBuffer;
|
||||
import org.jboss.netty.handler.codec.frame.TooLongFrameException;
|
||||
|
||||
import static org.jboss.netty.handler.codec.spdy.SpdyCodecUtil.*;
|
||||
|
||||
public class SpdyHeaderBlockRawDecoder extends SpdyHeaderBlockDecoder {
|
||||
|
||||
private static final int LENGTH_FIELD_SIZE = 4;
|
||||
|
||||
private final int version;
|
||||
private final int maxHeaderSize;
|
||||
private final int lengthFieldSize;
|
||||
|
||||
// Header block decoding fields
|
||||
private int headerSize;
|
||||
private int numHeaders;
|
||||
private int numHeaders = -1;
|
||||
|
||||
public SpdyHeaderBlockRawDecoder(SpdyVersion spdyVersion, int maxHeaderSize) {
|
||||
if (spdyVersion == null) {
|
||||
@ -37,19 +37,11 @@ public class SpdyHeaderBlockRawDecoder extends SpdyHeaderBlockDecoder {
|
||||
|
||||
this.version = spdyVersion.getVersion();
|
||||
this.maxHeaderSize = maxHeaderSize;
|
||||
lengthFieldSize = version < 3 ? 2 : 4;
|
||||
reset();
|
||||
}
|
||||
|
||||
private int readLengthField(ChannelBuffer buffer) {
|
||||
int length;
|
||||
if (version < 3) {
|
||||
length = getUnsignedShort(buffer, buffer.readerIndex());
|
||||
buffer.skipBytes(2);
|
||||
} else {
|
||||
length = getSignedInt(buffer, buffer.readerIndex());
|
||||
buffer.skipBytes(4);
|
||||
}
|
||||
int length = getSignedInt(buffer, buffer.readerIndex());
|
||||
buffer.skipBytes(LENGTH_FIELD_SIZE);
|
||||
return length;
|
||||
}
|
||||
|
||||
@ -64,7 +56,7 @@ public class SpdyHeaderBlockRawDecoder extends SpdyHeaderBlockDecoder {
|
||||
|
||||
if (numHeaders == -1) {
|
||||
// Read number of Name/Value pairs
|
||||
if (encoded.readableBytes() < lengthFieldSize) {
|
||||
if (encoded.readableBytes() < LENGTH_FIELD_SIZE) {
|
||||
return;
|
||||
}
|
||||
numHeaders = readLengthField(encoded);
|
||||
@ -79,7 +71,7 @@ public class SpdyHeaderBlockRawDecoder extends SpdyHeaderBlockDecoder {
|
||||
encoded.markReaderIndex();
|
||||
|
||||
// Try to read length of name
|
||||
if (encoded.readableBytes() < lengthFieldSize) {
|
||||
if (encoded.readableBytes() < LENGTH_FIELD_SIZE) {
|
||||
encoded.resetReaderIndex();
|
||||
return;
|
||||
}
|
||||
@ -112,7 +104,7 @@ public class SpdyHeaderBlockRawDecoder extends SpdyHeaderBlockDecoder {
|
||||
}
|
||||
|
||||
// Try to read length of value
|
||||
if (encoded.readableBytes() < lengthFieldSize) {
|
||||
if (encoded.readableBytes() < LENGTH_FIELD_SIZE) {
|
||||
encoded.resetReaderIndex();
|
||||
return;
|
||||
}
|
||||
@ -126,15 +118,10 @@ public class SpdyHeaderBlockRawDecoder extends SpdyHeaderBlockDecoder {
|
||||
|
||||
// SPDY/3 allows zero-length (empty) header values
|
||||
if (valueLength == 0) {
|
||||
if (version < 3) {
|
||||
frame.setInvalid();
|
||||
return;
|
||||
} else {
|
||||
frame.addHeader(name, "");
|
||||
numHeaders --;
|
||||
this.headerSize = headerSize;
|
||||
continue;
|
||||
}
|
||||
frame.addHeader(name, "");
|
||||
numHeaders --;
|
||||
this.headerSize = headerSize;
|
||||
continue;
|
||||
}
|
||||
|
||||
headerSize += valueLength;
|
||||
|
@ -23,12 +23,11 @@ import java.util.zip.Inflater;
|
||||
import org.jboss.netty.buffer.ChannelBuffer;
|
||||
import org.jboss.netty.buffer.ChannelBuffers;
|
||||
|
||||
class SpdyHeaderBlockZlibDecoder extends SpdyHeaderBlockRawDecoder {
|
||||
final class SpdyHeaderBlockZlibDecoder extends SpdyHeaderBlockRawDecoder {
|
||||
|
||||
private final byte[] out = new byte[8192];
|
||||
private final Inflater decompressor = new Inflater();
|
||||
|
||||
private ChannelBuffer decompressed;
|
||||
private final ChannelBuffer decompressed = ChannelBuffers.buffer(4096);
|
||||
|
||||
public SpdyHeaderBlockZlibDecoder(SpdyVersion spdyVersion, int maxHeaderSize) {
|
||||
super(spdyVersion, maxHeaderSize);
|
||||
@ -36,52 +35,64 @@ class SpdyHeaderBlockZlibDecoder extends SpdyHeaderBlockRawDecoder {
|
||||
|
||||
@Override
|
||||
void decode(ChannelBuffer encoded, SpdyHeadersFrame frame) throws Exception {
|
||||
setInput(encoded);
|
||||
int len = setInput(encoded);
|
||||
|
||||
int numBytes;
|
||||
do {
|
||||
numBytes = decompress(frame);
|
||||
} while (!decompressed.readable() && numBytes > 0);
|
||||
|
||||
if (decompressor.getRemaining() != 0) {
|
||||
throw new SpdyProtocolException("client sent extra data beyond headers");
|
||||
}
|
||||
|
||||
encoded.skipBytes(len);
|
||||
}
|
||||
|
||||
private void setInput(ChannelBuffer compressed) {
|
||||
byte[] in = new byte[compressed.readableBytes()];
|
||||
compressed.readBytes(in);
|
||||
decompressor.setInput(in);
|
||||
private int setInput(ChannelBuffer compressed) {
|
||||
int len = compressed.readableBytes();
|
||||
|
||||
if (compressed.hasArray()) {
|
||||
decompressor.setInput(compressed.array(), compressed.arrayOffset() + compressed.readerIndex(), len);
|
||||
} else {
|
||||
byte[] in = new byte[len];
|
||||
compressed.getBytes(compressed.readerIndex(), in);
|
||||
decompressor.setInput(in, 0, in.length);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
private int decompress(SpdyHeadersFrame frame) throws Exception {
|
||||
if (decompressed == null) {
|
||||
decompressed = ChannelBuffers.dynamicBuffer(8192);
|
||||
}
|
||||
|
||||
byte[] out = decompressed.array();
|
||||
int off = decompressed.arrayOffset() + decompressed.writerIndex();
|
||||
try {
|
||||
int numBytes = decompressor.inflate(out);
|
||||
int numBytes = decompressor.inflate(out, off, decompressed.writableBytes());
|
||||
if (numBytes == 0 && decompressor.needsDictionary()) {
|
||||
decompressor.setDictionary(SPDY_DICT);
|
||||
numBytes = decompressor.inflate(out);
|
||||
numBytes = decompressor.inflate(out, off, decompressed.writableBytes());
|
||||
}
|
||||
if (frame != null) {
|
||||
decompressed.writeBytes(out, 0, numBytes);
|
||||
decompressed.writerIndex(decompressed.writerIndex() + numBytes);
|
||||
super.decode(decompressed, frame);
|
||||
decompressed.discardReadBytes();
|
||||
}
|
||||
|
||||
return numBytes;
|
||||
} catch (DataFormatException e) {
|
||||
throw new SpdyProtocolException(
|
||||
"Received invalid header block", e);
|
||||
throw new SpdyProtocolException("Received invalid header block", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void reset() {
|
||||
decompressed = null;
|
||||
decompressed.clear();
|
||||
super.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end() {
|
||||
decompressed = null;
|
||||
decompressed.clear();
|
||||
decompressor.end();
|
||||
super.end();
|
||||
}
|
||||
|
@ -24,7 +24,6 @@ import org.jboss.netty.buffer.ChannelBuffers;
|
||||
|
||||
class SpdyHeaderBlockZlibEncoder extends SpdyHeaderBlockRawEncoder {
|
||||
|
||||
private final byte[] out = new byte[8192];
|
||||
private final Deflater compressor;
|
||||
|
||||
private boolean finished;
|
||||
@ -39,20 +38,36 @@ class SpdyHeaderBlockZlibEncoder extends SpdyHeaderBlockRawEncoder {
|
||||
compressor.setDictionary(SPDY_DICT);
|
||||
}
|
||||
|
||||
private void setInput(ChannelBuffer decompressed) {
|
||||
byte[] in = new byte[decompressed.readableBytes()];
|
||||
decompressed.readBytes(in);
|
||||
compressor.setInput(in);
|
||||
private int setInput(ChannelBuffer decompressed) {
|
||||
int len = decompressed.readableBytes();
|
||||
|
||||
if (decompressed.hasArray()) {
|
||||
compressor.setInput(decompressed.array(), decompressed.arrayOffset() + decompressed.readerIndex(), len);
|
||||
} else {
|
||||
byte[] in = new byte[len];
|
||||
decompressed.getBytes(decompressed.readerIndex(), in);
|
||||
compressor.setInput(in, 0, in.length);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
private void encode(ChannelBuffer compressed) {
|
||||
int numBytes = out.length;
|
||||
while (numBytes == out.length) {
|
||||
numBytes = compressor.deflate(out, 0, out.length, Deflater.SYNC_FLUSH);
|
||||
compressed.writeBytes(out, 0, numBytes);
|
||||
while (compressInto(compressed)) {
|
||||
// Although unlikely, it's possible that the compressed size is larger than the decompressed size
|
||||
compressed.ensureWritableBytes(compressed.capacity() << 1);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean compressInto(ChannelBuffer compressed) {
|
||||
byte[] out = compressed.array();
|
||||
int off = compressed.arrayOffset() + compressed.writerIndex();
|
||||
int toWrite = compressed.writableBytes();
|
||||
int numBytes = compressor.deflate(out, off, toWrite, Deflater.SYNC_FLUSH);
|
||||
compressed.writerIndex(compressed.writerIndex() + numBytes);
|
||||
return numBytes == toWrite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized ChannelBuffer encode(SpdyHeadersFrame frame) throws Exception {
|
||||
if (frame == null) {
|
||||
@ -68,9 +83,11 @@ class SpdyHeaderBlockZlibEncoder extends SpdyHeaderBlockRawEncoder {
|
||||
return ChannelBuffers.EMPTY_BUFFER;
|
||||
}
|
||||
|
||||
ChannelBuffer compressed = ChannelBuffers.dynamicBuffer();
|
||||
setInput(decompressed);
|
||||
ChannelBuffer compressed = ChannelBuffers.dynamicBuffer(decompressed.readableBytes());
|
||||
int len = setInput(decompressed);
|
||||
encode(compressed);
|
||||
decompressed.skipBytes(len);
|
||||
|
||||
return compressed;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user