Allow to disable validation of HTTP headers which shows a 5k perf improvement here when disabled
This commit is contained in:
parent
b65b4199dc
commit
c4130e0cf7
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -118,6 +118,7 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
|
||||
private final int maxHeaderSize;
|
||||
private final int maxChunkSize;
|
||||
private final boolean chunkedSupported;
|
||||
protected final boolean validateHeaders;
|
||||
|
||||
private ByteBuf content;
|
||||
private HttpMessage message;
|
||||
@ -159,13 +160,22 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
|
||||
*/
|
||||
protected HttpObjectDecoder(
|
||||
int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean chunkedSupported) {
|
||||
this(maxInitialLineLength, maxHeaderSize, maxChunkSize, chunkedSupported, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance with the specified parameters.
|
||||
*/
|
||||
protected HttpObjectDecoder(
|
||||
int maxInitialLineLength, int maxHeaderSize, int maxChunkSize,
|
||||
boolean chunkedSupported, boolean validateHeaders) {
|
||||
|
||||
super(State.SKIP_CONTROL_CHARS);
|
||||
|
||||
if (maxInitialLineLength <= 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"maxInitialLineLength must be a positive integer: " +
|
||||
maxInitialLineLength);
|
||||
maxInitialLineLength);
|
||||
}
|
||||
if (maxHeaderSize <= 0) {
|
||||
throw new IllegalArgumentException(
|
||||
@ -181,6 +191,7 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
|
||||
this.maxHeaderSize = maxHeaderSize;
|
||||
this.maxChunkSize = maxChunkSize;
|
||||
this.chunkedSupported = chunkedSupported;
|
||||
this.validateHeaders = validateHeaders;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -279,7 +290,7 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
|
||||
ByteBuf content = readBytes(ctx.alloc(), buffer, toRead);
|
||||
if (!buffer.isReadable()) {
|
||||
reset();
|
||||
out.add(new DefaultLastHttpContent(content));
|
||||
out.add(new DefaultLastHttpContent(content, validateHeaders));
|
||||
return;
|
||||
}
|
||||
out.add(new DefaultHttpContent(content));
|
||||
@ -321,7 +332,7 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
|
||||
if (chunkSize == 0) {
|
||||
// Read all content.
|
||||
reset();
|
||||
out.add(new DefaultLastHttpContent(content));
|
||||
out.add(new DefaultLastHttpContent(content, validateHeaders));
|
||||
return;
|
||||
}
|
||||
out.add(new DefaultHttpContent(content));
|
||||
@ -468,7 +479,7 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
|
||||
if (actualContentLength == 0) {
|
||||
out.add(LastHttpContent.EMPTY_LAST_CONTENT);
|
||||
} else {
|
||||
out.add(new DefaultLastHttpContent(content));
|
||||
out.add(new DefaultLastHttpContent(content, validateHeaders));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -513,7 +524,7 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
|
||||
if (content == null || !content.isReadable()) {
|
||||
httpContent = LastHttpContent.EMPTY_LAST_CONTENT;
|
||||
} else {
|
||||
httpContent = new DefaultLastHttpContent(content);
|
||||
httpContent = new DefaultLastHttpContent(content, validateHeaders);
|
||||
}
|
||||
|
||||
out.add(message);
|
||||
@ -629,7 +640,7 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
|
||||
StringBuilder line = readHeader(buffer);
|
||||
String lastHeader = null;
|
||||
if (line.length() > 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')) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user