[#2650] Allow to disable http header validation in SpdyHttpDecoder and SpdyHttpCodec

Motivation:

HTTP header validation can be expensive so we should allow to disable it like we do in HttpObjectDecoder.

Modification:

Add constructor argument to disable validation.

Result:
Performance improvement
This commit is contained in:
Norman Maurer 2014-07-11 08:31:39 +02:00
parent d9d906c54e
commit 8f0d03998c
2 changed files with 46 additions and 6 deletions

View File

@ -28,4 +28,11 @@ public final class SpdyHttpCodec
public SpdyHttpCodec(SpdyVersion version, int maxContentLength) { public SpdyHttpCodec(SpdyVersion version, int maxContentLength) {
super(new SpdyHttpDecoder(version, maxContentLength), new SpdyHttpEncoder(version)); super(new SpdyHttpDecoder(version, maxContentLength), new SpdyHttpEncoder(version));
} }
/**
* Creates a new instance with the specified decoder options.
*/
public SpdyHttpCodec(SpdyVersion version, int maxContentLength, boolean validateHttpHeaders) {
super(new SpdyHttpDecoder(version, maxContentLength, validateHttpHeaders), new SpdyHttpEncoder(version));
}
} }

View File

@ -39,6 +39,7 @@ import java.util.Map;
*/ */
public class SpdyHttpDecoder extends MessageToMessageDecoder<SpdyFrame> { public class SpdyHttpDecoder extends MessageToMessageDecoder<SpdyFrame> {
private final boolean validateHeaders;
private final int spdyVersion; private final int spdyVersion;
private final int maxContentLength; private final int maxContentLength;
private final Map<Integer, FullHttpMessage> messageMap; private final Map<Integer, FullHttpMessage> messageMap;
@ -52,7 +53,20 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<SpdyFrame> {
* a {@link TooLongFrameException} will be raised. * a {@link TooLongFrameException} will be raised.
*/ */
public SpdyHttpDecoder(SpdyVersion version, int maxContentLength) { public SpdyHttpDecoder(SpdyVersion version, int maxContentLength) {
this(version, maxContentLength, new HashMap<Integer, FullHttpMessage>()); this(version, maxContentLength, new HashMap<Integer, FullHttpMessage>(), true);
}
/**
* Creates a new instance.
*
* @param version the protocol version
* @param maxContentLength the maximum length of the message content.
* If the length of the message content exceeds this value,
* a {@link TooLongFrameException} will be raised.
* @param validateHeaders {@code true} if http headers should be validated
*/
public SpdyHttpDecoder(SpdyVersion version, int maxContentLength, boolean validateHeaders) {
this(version, maxContentLength, new HashMap<Integer, FullHttpMessage>(), validateHeaders);
} }
/** /**
@ -65,6 +79,21 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<SpdyFrame> {
* @param messageMap the {@link Map} used to hold partially received messages. * @param messageMap the {@link Map} used to hold partially received messages.
*/ */
protected SpdyHttpDecoder(SpdyVersion version, int maxContentLength, Map<Integer, FullHttpMessage> messageMap) { protected SpdyHttpDecoder(SpdyVersion version, int maxContentLength, Map<Integer, FullHttpMessage> messageMap) {
this(version, maxContentLength, messageMap, true);
}
/**
* Creates a new instance with the specified parameters.
*
* @param version the protocol version
* @param maxContentLength the maximum length of the message content.
* If the length of the message content exceeds this value,
* a {@link TooLongFrameException} will be raised.
* @param messageMap the {@link Map} used to hold partially received messages.
* @param validateHeaders {@code true} if http headers should be validated
*/
protected SpdyHttpDecoder(SpdyVersion version, int maxContentLength, Map<Integer,
FullHttpMessage> messageMap, boolean validateHeaders) {
if (version == null) { if (version == null) {
throw new NullPointerException("version"); throw new NullPointerException("version");
} }
@ -75,6 +104,7 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<SpdyFrame> {
spdyVersion = version.getVersion(); spdyVersion = version.getVersion();
this.maxContentLength = maxContentLength; this.maxContentLength = maxContentLength;
this.messageMap = messageMap; this.messageMap = messageMap;
this.validateHeaders = validateHeaders;
} }
protected FullHttpMessage putMessage(int streamId, FullHttpMessage message) { protected FullHttpMessage putMessage(int streamId, FullHttpMessage message) {
@ -133,7 +163,7 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<SpdyFrame> {
try { try {
FullHttpResponse httpResponseWithEntity = FullHttpResponse httpResponseWithEntity =
createHttpResponse(spdyVersion, spdySynStreamFrame); createHttpResponse(ctx, spdyVersion, spdySynStreamFrame, validateHeaders);
// Set the Stream-ID, Associated-To-Stream-ID, Priority, and URL as headers // Set the Stream-ID, Associated-To-Stream-ID, Priority, and URL as headers
SpdyHttpHeaders.setStreamId(httpResponseWithEntity, streamId); SpdyHttpHeaders.setStreamId(httpResponseWithEntity, streamId);
@ -208,7 +238,8 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<SpdyFrame> {
} }
try { try {
FullHttpResponse httpResponseWithEntity = createHttpResponse(spdyVersion, spdySynReplyFrame); FullHttpResponse httpResponseWithEntity =
createHttpResponse(ctx, spdyVersion, spdySynReplyFrame, validateHeaders);
// Set the Stream-ID as a header // Set the Stream-ID as a header
SpdyHttpHeaders.setStreamId(httpResponseWithEntity, streamId); SpdyHttpHeaders.setStreamId(httpResponseWithEntity, streamId);
@ -323,15 +354,17 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<SpdyFrame> {
return req; return req;
} }
private static FullHttpResponse createHttpResponse(int spdyVersion, SpdyHeadersFrame responseFrame) private static FullHttpResponse createHttpResponse(ChannelHandlerContext ctx, int spdyVersion,
throws Exception { SpdyHeadersFrame responseFrame,
boolean validateHeaders) throws Exception {
// Create the first line of the response from the name/value pairs // Create the first line of the response from the name/value pairs
HttpResponseStatus status = SpdyHeaders.getStatus(spdyVersion, responseFrame); HttpResponseStatus status = SpdyHeaders.getStatus(spdyVersion, responseFrame);
HttpVersion version = SpdyHeaders.getVersion(spdyVersion, responseFrame); HttpVersion version = SpdyHeaders.getVersion(spdyVersion, responseFrame);
SpdyHeaders.removeStatus(spdyVersion, responseFrame); SpdyHeaders.removeStatus(spdyVersion, responseFrame);
SpdyHeaders.removeVersion(spdyVersion, responseFrame); SpdyHeaders.removeVersion(spdyVersion, responseFrame);
FullHttpResponse res = new DefaultFullHttpResponse(version, status); FullHttpResponse res = new DefaultFullHttpResponse(version, status, ctx.alloc().buffer(), validateHeaders);
for (Map.Entry<String, String> e: responseFrame.headers()) { for (Map.Entry<String, String> e: responseFrame.headers()) {
res.headers().add(e.getKey(), e.getValue()); res.headers().add(e.getKey(), e.getValue());
} }