diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultFullHttpRequest.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultFullHttpRequest.java index c2a1843066..2073824715 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultFullHttpRequest.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultFullHttpRequest.java @@ -23,18 +23,24 @@ import io.netty.buffer.Unpooled; */ public class DefaultFullHttpRequest extends DefaultHttpRequest implements FullHttpRequest { private final ByteBuf content; - private final HttpHeaders trailingHeader = new DefaultHttpHeaders(); + private final HttpHeaders trailingHeader; public DefaultFullHttpRequest(HttpVersion httpVersion, HttpMethod method, String uri) { this(httpVersion, method, uri, Unpooled.buffer(0)); } public DefaultFullHttpRequest(HttpVersion httpVersion, HttpMethod method, String uri, ByteBuf content) { - super(httpVersion, method, uri); + this(httpVersion, method, uri, content, true); + } + + public DefaultFullHttpRequest(HttpVersion httpVersion, HttpMethod method, String uri, + ByteBuf content, boolean validateHeaders) { + super(httpVersion, method, uri, validateHeaders); if (content == null) { throw new NullPointerException("content"); } this.content = content; + trailingHeader = new DefaultHttpHeaders(validateHeaders); } @Override diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultFullHttpResponse.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultFullHttpResponse.java index fe12c234e2..1b13df96ce 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultFullHttpResponse.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultFullHttpResponse.java @@ -25,18 +25,24 @@ import io.netty.buffer.Unpooled; public class DefaultFullHttpResponse extends DefaultHttpResponse implements FullHttpResponse { private final ByteBuf content; - private final HttpHeaders trailingHeaders = new DefaultHttpHeaders(); + private final HttpHeaders trailingHeaders; public DefaultFullHttpResponse(HttpVersion version, HttpResponseStatus status) { this(version, status, Unpooled.buffer(0)); } public DefaultFullHttpResponse(HttpVersion version, HttpResponseStatus status, ByteBuf content) { - super(version, status); + this(version, status, content, true); + } + + public DefaultFullHttpResponse(HttpVersion version, HttpResponseStatus status, + ByteBuf content, boolean validateHeaders) { + super(version, status, validateHeaders); if (content == null) { throw new NullPointerException("content"); } this.content = content; + trailingHeaders = new DefaultHttpHeaders(validateHeaders); } @Override diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpHeaders.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpHeaders.java index 14c05a1d33..72cacfe32a 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpHeaders.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpHeaders.java @@ -80,8 +80,14 @@ public class DefaultHttpHeaders extends HttpHeaders { private final HeaderEntry[] entries = new HeaderEntry[BUCKET_SIZE]; private final HeaderEntry head = new HeaderEntry(-1, null, null); + protected final boolean validate; public DefaultHttpHeaders() { + this(true); + } + + public DefaultHttpHeaders(boolean validate) { + this.validate = validate; head.before = head.after = head; } @@ -91,9 +97,14 @@ public class DefaultHttpHeaders extends HttpHeaders { @Override public HttpHeaders add(final String name, final Object value) { - validateHeaderName0(name); - String strVal = toString(value); - validateHeaderValue(strVal); + String strVal; + if (validate) { + validateHeaderName0(name); + strVal = toString(value); + validateHeaderValue(strVal); + } else { + strVal = toString(value); + } int h = hash(name); int i = index(h); add0(h, i, name, strVal); @@ -102,12 +113,16 @@ public class DefaultHttpHeaders extends HttpHeaders { @Override public HttpHeaders add(String name, Iterable values) { - validateHeaderName0(name); + if (validate) { + validateHeaderName0(name); + } int h = hash(name); int i = index(h); for (Object v: values) { String vstr = toString(v); - validateHeaderValue(vstr); + if (validate) { + validateHeaderValue(vstr); + } add0(h, i, name, vstr); } return this; @@ -173,9 +188,14 @@ public class DefaultHttpHeaders extends HttpHeaders { @Override public HttpHeaders set(final String name, final Object value) { - validateHeaderName0(name); - String strVal = toString(value); - validateHeaderValue(strVal); + String strVal; + if (validate) { + validateHeaderName0(name); + strVal = toString(value); + validateHeaderValue(strVal); + } else { + strVal = toString(value); + } int h = hash(name); int i = index(h); remove0(h, i, name); @@ -188,8 +208,9 @@ public class DefaultHttpHeaders extends HttpHeaders { if (values == null) { throw new NullPointerException("values"); } - - validateHeaderName0(name); + if (validate) { + validateHeaderName0(name); + } int h = hash(name); int i = index(h); @@ -200,7 +221,9 @@ public class DefaultHttpHeaders extends HttpHeaders { break; } String strVal = toString(v); - validateHeaderValue(strVal); + if (validate) { + validateHeaderValue(strVal); + } add0(h, i, name, strVal); } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpMessage.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpMessage.java index 8f66cb345d..b6e0889414 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpMessage.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpMessage.java @@ -25,16 +25,21 @@ import java.util.Map; public abstract class DefaultHttpMessage extends DefaultHttpObject implements HttpMessage { private HttpVersion version; - private final HttpHeaders headers = new DefaultHttpHeaders(); + private final HttpHeaders headers; /** * Creates a new instance. */ protected DefaultHttpMessage(final HttpVersion version) { + this(version, true); + } + + protected DefaultHttpMessage(final HttpVersion version, boolean validate) { if (version == null) { throw new NullPointerException("version"); } this.version = version; + headers = new DefaultHttpHeaders(validate); } @Override diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpRequest.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpRequest.java index e2f3463955..6212371136 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpRequest.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpRequest.java @@ -33,7 +33,19 @@ public class DefaultHttpRequest extends DefaultHttpMessage implements HttpReques * @param uri the URI or path of the request */ public DefaultHttpRequest(HttpVersion httpVersion, HttpMethod method, String uri) { - super(httpVersion); + this(httpVersion, method, uri, true); + } + + /** + * Creates a new instance. + * + * @param httpVersion the HTTP version of the request + * @param method the HTTP getMethod of the request + * @param uri the URI or path of the request + * @param validateHeaders validate the headers when adding them + */ + public DefaultHttpRequest(HttpVersion httpVersion, HttpMethod method, String uri, boolean validateHeaders) { + super(httpVersion, validateHeaders); if (method == null) { throw new NullPointerException("method"); } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpResponse.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpResponse.java index 3eb95cf7e1..057839c0dd 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpResponse.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpResponse.java @@ -31,7 +31,18 @@ public class DefaultHttpResponse extends DefaultHttpMessage implements HttpRespo * @param status the getStatus of this response */ public DefaultHttpResponse(HttpVersion version, HttpResponseStatus status) { - super(version); + this(version, status, true); + } + + /** + * Creates a new instance. + * + * @param version the HTTP version of this response + * @param status the getStatus of this response + * @param validateHeaders validate the headers when adding them + */ + public DefaultHttpResponse(HttpVersion version, HttpResponseStatus status, boolean validateHeaders) { + super(version, validateHeaders); if (status == null) { throw new NullPointerException("status"); } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultLastHttpContent.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultLastHttpContent.java index fbc47f6a12..7967801527 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultLastHttpContent.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultLastHttpContent.java @@ -26,25 +26,19 @@ import java.util.Map; */ public class DefaultLastHttpContent extends DefaultHttpContent implements LastHttpContent { - private final HttpHeaders trailingHeaders = new DefaultHttpHeaders() { - @Override - void validateHeaderName0(String name) { - super.validateHeaderName0(name); - if (name.equalsIgnoreCase(HttpHeaders.Names.CONTENT_LENGTH) || - name.equalsIgnoreCase(HttpHeaders.Names.TRANSFER_ENCODING) || - name.equalsIgnoreCase(HttpHeaders.Names.TRAILER)) { - throw new IllegalArgumentException( - "prohibited trailing header: " + name); - } - } - }; + private final HttpHeaders trailingHeaders; public DefaultLastHttpContent() { this(Unpooled.buffer(0)); } public DefaultLastHttpContent(ByteBuf content) { + this(content, true); + } + + public DefaultLastHttpContent(ByteBuf content, boolean validateHeaders) { super(content); + trailingHeaders = new TrailingHeaders(validateHeaders); } @Override @@ -97,4 +91,21 @@ public class DefaultLastHttpContent extends DefaultHttpContent implements LastHt buf.append(StringUtil.NEWLINE); } } + + private static final class TrailingHeaders extends DefaultHttpHeaders { + TrailingHeaders(boolean validate) { + super(validate); + } + + @Override + void validateHeaderName0(String name) { + super.validateHeaderName0(name); + if (name.equalsIgnoreCase(HttpHeaders.Names.CONTENT_LENGTH) || + name.equalsIgnoreCase(HttpHeaders.Names.TRANSFER_ENCODING) || + name.equalsIgnoreCase(HttpHeaders.Names.TRAILER)) { + throw new IllegalArgumentException( + "prohibited trailing header: " + name); + } + } + } } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpObjectDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpObjectDecoder.java index 7a54a435e8..2afc1f91dd 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpObjectDecoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpObjectDecoder.java @@ -118,6 +118,7 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder 0) { - LastHttpContent trailer = new DefaultLastHttpContent(Unpooled.EMPTY_BUFFER); + LastHttpContent trailer = new DefaultLastHttpContent(Unpooled.EMPTY_BUFFER, validateHeaders); do { char firstChar = line.charAt(0); if (lastHeader != null && (firstChar == ' ' || firstChar == '\t')) { diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpRequestDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpRequestDecoder.java index 37bd1f3353..a1d073ec35 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpRequestDecoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpRequestDecoder.java @@ -70,15 +70,21 @@ public class HttpRequestDecoder extends HttpObjectDecoder { super(maxInitialLineLength, maxHeaderSize, maxChunkSize, true); } + public HttpRequestDecoder( + int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean validateHeaders) { + super(maxInitialLineLength, maxHeaderSize, maxChunkSize, true, validateHeaders); + } + @Override protected HttpMessage createMessage(String[] initialLine) throws Exception { return new DefaultHttpRequest( - HttpVersion.valueOf(initialLine[2]), HttpMethod.valueOf(initialLine[0]), initialLine[1]); + HttpVersion.valueOf(initialLine[2]), + HttpMethod.valueOf(initialLine[0]), initialLine[1], validateHeaders); } @Override protected HttpMessage createInvalidMessage() { - return new DefaultHttpRequest(HttpVersion.HTTP_1_0, HttpMethod.GET, "/bad-request"); + return new DefaultHttpRequest(HttpVersion.HTTP_1_0, HttpMethod.GET, "/bad-request", validateHeaders); } @Override diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpResponseDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpResponseDecoder.java index 7f30dea9f9..2d9d90af79 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpResponseDecoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpResponseDecoder.java @@ -101,16 +101,21 @@ public class HttpResponseDecoder extends HttpObjectDecoder { super(maxInitialLineLength, maxHeaderSize, maxChunkSize, true); } + public HttpResponseDecoder( + int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean validateHeaders) { + super(maxInitialLineLength, maxHeaderSize, maxChunkSize, true, validateHeaders); + } + @Override protected HttpMessage createMessage(String[] initialLine) { return new DefaultHttpResponse( HttpVersion.valueOf(initialLine[0]), - new HttpResponseStatus(Integer.valueOf(initialLine[1]), initialLine[2])); + new HttpResponseStatus(Integer.valueOf(initialLine[1]), initialLine[2]), validateHeaders); } @Override protected HttpMessage createInvalidMessage() { - return new DefaultHttpResponse(HttpVersion.HTTP_1_0, UNKNOWN_STATUS); + return new DefaultHttpResponse(HttpVersion.HTTP_1_0, UNKNOWN_STATUS, validateHeaders); } @Override diff --git a/codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspObjectDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspObjectDecoder.java index 441017f272..7023569e22 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspObjectDecoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspObjectDecoder.java @@ -66,6 +66,11 @@ public abstract class RtspObjectDecoder extends HttpObjectDecoder { super(maxInitialLineLength, maxHeaderSize, maxContentLength * 2, false); } + protected RtspObjectDecoder( + int maxInitialLineLength, int maxHeaderSize, int maxContentLength, boolean validateHeaders) { + super(maxInitialLineLength, maxHeaderSize, maxContentLength * 2, false, validateHeaders); + } + @Override protected boolean isContentAlwaysEmpty(HttpMessage msg) { // Unlike HTTP, RTSP always assumes zero-length body if Content-Length diff --git a/codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspRequestDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspRequestDecoder.java index 3cb47a58af..2222ee91c5 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspRequestDecoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspRequestDecoder.java @@ -65,15 +65,20 @@ public class RtspRequestDecoder extends RtspObjectDecoder { super(maxInitialLineLength, maxHeaderSize, maxContentLength); } + public RtspRequestDecoder( + int maxInitialLineLength, int maxHeaderSize, int maxContentLength, boolean validateHeaders) { + super(maxInitialLineLength, maxHeaderSize, maxContentLength, validateHeaders); + } + @Override protected HttpMessage createMessage(String[] initialLine) throws Exception { return new DefaultHttpRequest(RtspVersions.valueOf(initialLine[2]), - RtspMethods.valueOf(initialLine[0]), initialLine[1]); + RtspMethods.valueOf(initialLine[0]), initialLine[1], validateHeaders); } @Override protected HttpMessage createInvalidMessage() { - return new DefaultHttpRequest(RtspVersions.RTSP_1_0, RtspMethods.OPTIONS, "/bad-request"); + return new DefaultHttpRequest(RtspVersions.RTSP_1_0, RtspMethods.OPTIONS, "/bad-request", validateHeaders); } @Override diff --git a/codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspResponseDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspResponseDecoder.java index 6de6b060ae..0137157567 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspResponseDecoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspResponseDecoder.java @@ -69,16 +69,21 @@ public class RtspResponseDecoder extends RtspObjectDecoder { super(maxInitialLineLength, maxHeaderSize, maxContentLength); } + public RtspResponseDecoder(int maxInitialLineLength, int maxHeaderSize, + int maxContentLength, boolean validateHeaders) { + super(maxInitialLineLength, maxHeaderSize, maxContentLength, validateHeaders); + } + @Override protected HttpMessage createMessage(String[] initialLine) throws Exception { return new DefaultHttpResponse( RtspVersions.valueOf(initialLine[0]), - new HttpResponseStatus(Integer.valueOf(initialLine[1]), initialLine[2])); + new HttpResponseStatus(Integer.valueOf(initialLine[1]), initialLine[2]), validateHeaders); } @Override protected HttpMessage createInvalidMessage() { - return new DefaultHttpResponse(RtspVersions.RTSP_1_0, UNKNOWN_STATUS); + return new DefaultHttpResponse(RtspVersions.RTSP_1_0, UNKNOWN_STATUS, validateHeaders); } @Override