HTTP/2 Header Name Validation
Motivation: The HTTP/2 header name validation was removed, and does not currently exist. Modifications: - Header name validation for HTTP/2 should be restored and set to the default mode of operation. Result: HTTP/2 header names are validated according to https://tools.ietf.org/html/rfc7540
This commit is contained in:
parent
c449ceac3a
commit
4f204009de
@ -64,8 +64,22 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize
|
|||||||
private HeadersContinuation headersContinuation;
|
private HeadersContinuation headersContinuation;
|
||||||
private int maxFrameSize;
|
private int maxFrameSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance.
|
||||||
|
* <p>
|
||||||
|
* Header names will be validated.
|
||||||
|
*/
|
||||||
public DefaultHttp2FrameReader() {
|
public DefaultHttp2FrameReader() {
|
||||||
this(new DefaultHttp2HeadersDecoder());
|
this(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance.
|
||||||
|
* @param validateHeaders {@code true} to validate headers. {@code false} to not validate headers.
|
||||||
|
* @see #DefaultHttp2HeadersDecoder(boolean)
|
||||||
|
*/
|
||||||
|
public DefaultHttp2FrameReader(boolean validateHeaders) {
|
||||||
|
this(new DefaultHttp2HeadersDecoder(validateHeaders));
|
||||||
}
|
}
|
||||||
|
|
||||||
public DefaultHttp2FrameReader(Http2HeadersDecoder headersDecoder) {
|
public DefaultHttp2FrameReader(Http2HeadersDecoder headersDecoder) {
|
||||||
|
@ -17,13 +17,50 @@ package io.netty.handler.codec.http2;
|
|||||||
import io.netty.handler.codec.ByteStringValueConverter;
|
import io.netty.handler.codec.ByteStringValueConverter;
|
||||||
import io.netty.handler.codec.DefaultHeaders;
|
import io.netty.handler.codec.DefaultHeaders;
|
||||||
import io.netty.handler.codec.Headers;
|
import io.netty.handler.codec.Headers;
|
||||||
|
import io.netty.util.ByteProcessor;
|
||||||
import io.netty.util.ByteString;
|
import io.netty.util.ByteString;
|
||||||
|
import io.netty.util.internal.PlatformDependent;
|
||||||
|
|
||||||
public class DefaultHttp2Headers extends DefaultHeaders<ByteString> implements Http2Headers {
|
public class DefaultHttp2Headers extends DefaultHeaders<ByteString> implements Http2Headers {
|
||||||
|
private static final ByteProcessor HTTP2_NAME_VALIDATOR_PROCESSOR = new ByteProcessor() {
|
||||||
|
@Override
|
||||||
|
public boolean process(byte value) throws Exception {
|
||||||
|
if (value >= 'A' && value <= 'Z') {
|
||||||
|
throw new IllegalArgumentException("name must be all lower case but found: " + (char) value);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private static final NameValidator<ByteString> HTTP2_NAME_VALIDATOR = new NameValidator<ByteString>() {
|
||||||
|
@Override
|
||||||
|
public void validateName(ByteString name) {
|
||||||
|
try {
|
||||||
|
name.forEachByte(HTTP2_NAME_VALIDATOR_PROCESSOR);
|
||||||
|
} catch (Exception e) {
|
||||||
|
PlatformDependent.throwException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
private HeaderEntry<ByteString> firstNonPseudo = head;
|
private HeaderEntry<ByteString> firstNonPseudo = head;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance.
|
||||||
|
* <p>
|
||||||
|
* Header names will be validated according to
|
||||||
|
* <a href="https://tools.ietf.org/html/rfc7540">rfc7540</a>.
|
||||||
|
*/
|
||||||
public DefaultHttp2Headers() {
|
public DefaultHttp2Headers() {
|
||||||
super(ByteStringValueConverter.INSTANCE);
|
this(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance.
|
||||||
|
* @param validate {@code true} to validate header names according to
|
||||||
|
* <a href="https://tools.ietf.org/html/rfc7540">rfc7540</a>. {@code false} to not validate header names.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public DefaultHttp2Headers(boolean validate) {
|
||||||
|
super(ByteStringValueConverter.INSTANCE, validate ? HTTP2_NAME_VALIDATOR : NameValidator.NOT_NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -36,18 +36,28 @@ public class DefaultHttp2HeadersDecoder implements Http2HeadersDecoder, Http2Hea
|
|||||||
private final int maxHeaderSize;
|
private final int maxHeaderSize;
|
||||||
private final Decoder decoder;
|
private final Decoder decoder;
|
||||||
private final Http2HeaderTable headerTable;
|
private final Http2HeaderTable headerTable;
|
||||||
|
private final boolean validateHeaders;
|
||||||
|
|
||||||
public DefaultHttp2HeadersDecoder() {
|
public DefaultHttp2HeadersDecoder() {
|
||||||
this(DEFAULT_MAX_HEADER_SIZE, DEFAULT_HEADER_TABLE_SIZE);
|
this(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DefaultHttp2HeadersDecoder(boolean validateHeaders) {
|
||||||
|
this(DEFAULT_MAX_HEADER_SIZE, DEFAULT_HEADER_TABLE_SIZE, validateHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DefaultHttp2HeadersDecoder(int maxHeaderSize, int maxHeaderTableSize) {
|
public DefaultHttp2HeadersDecoder(int maxHeaderSize, int maxHeaderTableSize) {
|
||||||
|
this(maxHeaderSize, maxHeaderTableSize, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DefaultHttp2HeadersDecoder(int maxHeaderSize, int maxHeaderTableSize, boolean validateHeaders) {
|
||||||
if (maxHeaderSize <= 0) {
|
if (maxHeaderSize <= 0) {
|
||||||
throw new IllegalArgumentException("maxHeaderSize must be positive: " + maxHeaderSize);
|
throw new IllegalArgumentException("maxHeaderSize must be positive: " + maxHeaderSize);
|
||||||
}
|
}
|
||||||
decoder = new Decoder(maxHeaderSize, maxHeaderTableSize);
|
decoder = new Decoder(maxHeaderSize, maxHeaderTableSize);
|
||||||
headerTable = new Http2HeaderTableDecoder();
|
headerTable = new Http2HeaderTableDecoder();
|
||||||
this.maxHeaderSize = maxHeaderSize;
|
this.maxHeaderSize = maxHeaderSize;
|
||||||
|
this.validateHeaders = validateHeaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -77,7 +87,7 @@ public class DefaultHttp2HeadersDecoder implements Http2HeadersDecoder, Http2Hea
|
|||||||
public Http2Headers decodeHeaders(ByteBuf headerBlock) throws Http2Exception {
|
public Http2Headers decodeHeaders(ByteBuf headerBlock) throws Http2Exception {
|
||||||
InputStream in = new ByteBufInputStream(headerBlock);
|
InputStream in = new ByteBufInputStream(headerBlock);
|
||||||
try {
|
try {
|
||||||
final Http2Headers headers = new DefaultHttp2Headers();
|
final Http2Headers headers = new DefaultHttp2Headers(validateHeaders);
|
||||||
HeaderListener listener = new HeaderListener() {
|
HeaderListener listener = new HeaderListener() {
|
||||||
@Override
|
@Override
|
||||||
public void addHeader(byte[] key, byte[] value, boolean sensitive) {
|
public void addHeader(byte[] key, byte[] value, boolean sensitive) {
|
||||||
|
@ -69,11 +69,19 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
|
|||||||
private long gracefulShutdownTimeoutMillis = DEFAULT_GRACEFUL_SHUTDOWN_TIMEOUT_MILLIS;
|
private long gracefulShutdownTimeoutMillis = DEFAULT_GRACEFUL_SHUTDOWN_TIMEOUT_MILLIS;
|
||||||
|
|
||||||
public Http2ConnectionHandler(boolean server, Http2FrameListener listener) {
|
public Http2ConnectionHandler(boolean server, Http2FrameListener listener) {
|
||||||
this(new DefaultHttp2Connection(server), listener);
|
this(server, listener, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Http2ConnectionHandler(boolean server, Http2FrameListener listener, boolean validateHeaders) {
|
||||||
|
this(new DefaultHttp2Connection(server), listener, validateHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Http2ConnectionHandler(Http2Connection connection, Http2FrameListener listener) {
|
public Http2ConnectionHandler(Http2Connection connection, Http2FrameListener listener) {
|
||||||
this(connection, new DefaultHttp2FrameReader(), new DefaultHttp2FrameWriter(), listener);
|
this(connection, listener, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Http2ConnectionHandler(Http2Connection connection, Http2FrameListener listener, boolean validateHeaders) {
|
||||||
|
this(connection, new DefaultHttp2FrameReader(validateHeaders), new DefaultHttp2FrameWriter(), listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Http2ConnectionHandler(Http2Connection connection, Http2FrameReader frameReader,
|
public Http2ConnectionHandler(Http2Connection connection, Http2FrameReader frameReader,
|
||||||
|
@ -279,8 +279,8 @@ public final class HttpConversionUtil {
|
|||||||
* </ul>
|
* </ul>
|
||||||
* {@link ExtensionHeaderNames#PATH} is ignored and instead extracted from the {@code Request-Line}.
|
* {@link ExtensionHeaderNames#PATH} is ignored and instead extracted from the {@code Request-Line}.
|
||||||
*/
|
*/
|
||||||
public static Http2Headers toHttp2Headers(HttpMessage in) throws Exception {
|
public static Http2Headers toHttp2Headers(HttpMessage in, boolean validateHeaders) throws Exception {
|
||||||
final Http2Headers out = new DefaultHttp2Headers();
|
final Http2Headers out = new DefaultHttp2Headers(validateHeaders);
|
||||||
HttpHeaders inHeaders = in.headers();
|
HttpHeaders inHeaders = in.headers();
|
||||||
if (in instanceof HttpRequest) {
|
if (in instanceof HttpRequest) {
|
||||||
HttpRequest request = (HttpRequest) in;
|
HttpRequest request = (HttpRequest) in;
|
||||||
@ -304,15 +304,15 @@ public final class HttpConversionUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add the HTTP headers which have not been consumed above
|
// Add the HTTP headers which have not been consumed above
|
||||||
return out.add(toHttp2Headers(inHeaders));
|
return out.add(toHttp2Headers(inHeaders, validateHeaders));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Http2Headers toHttp2Headers(HttpHeaders inHeaders) throws Exception {
|
public static Http2Headers toHttp2Headers(HttpHeaders inHeaders, boolean validateHeaders) throws Exception {
|
||||||
if (inHeaders.isEmpty()) {
|
if (inHeaders.isEmpty()) {
|
||||||
return EmptyHttp2Headers.INSTANCE;
|
return EmptyHttp2Headers.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Http2Headers out = new DefaultHttp2Headers();
|
final Http2Headers out = new DefaultHttp2Headers(validateHeaders);
|
||||||
|
|
||||||
for (Entry<CharSequence, CharSequence> entry : inHeaders) {
|
for (Entry<CharSequence, CharSequence> entry : inHeaders) {
|
||||||
final AsciiString aName = AsciiString.of(entry.getKey()).toLowerCase();
|
final AsciiString aName = AsciiString.of(entry.getKey()).toLowerCase();
|
||||||
|
@ -33,24 +33,48 @@ import io.netty.util.ReferenceCountUtil;
|
|||||||
*/
|
*/
|
||||||
public class HttpToHttp2ConnectionHandler extends Http2ConnectionHandler {
|
public class HttpToHttp2ConnectionHandler extends Http2ConnectionHandler {
|
||||||
|
|
||||||
|
private final boolean validateHeaders;
|
||||||
private int currentStreamId;
|
private int currentStreamId;
|
||||||
|
|
||||||
public HttpToHttp2ConnectionHandler(boolean server, Http2FrameListener listener) {
|
public HttpToHttp2ConnectionHandler(boolean server, Http2FrameListener listener) {
|
||||||
|
this(server, listener, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpToHttp2ConnectionHandler(boolean server, Http2FrameListener listener, boolean validateHeaders) {
|
||||||
super(server, listener);
|
super(server, listener);
|
||||||
|
this.validateHeaders = validateHeaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpToHttp2ConnectionHandler(Http2Connection connection, Http2FrameListener listener) {
|
public HttpToHttp2ConnectionHandler(Http2Connection connection, Http2FrameListener listener) {
|
||||||
|
this(connection, listener, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpToHttp2ConnectionHandler(Http2Connection connection, Http2FrameListener listener,
|
||||||
|
boolean validateHeaders) {
|
||||||
super(connection, listener);
|
super(connection, listener);
|
||||||
|
this.validateHeaders = validateHeaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpToHttp2ConnectionHandler(Http2Connection connection, Http2FrameReader frameReader,
|
public HttpToHttp2ConnectionHandler(Http2Connection connection, Http2FrameReader frameReader,
|
||||||
Http2FrameWriter frameWriter, Http2FrameListener listener) {
|
Http2FrameWriter frameWriter, Http2FrameListener listener) {
|
||||||
|
this(connection, frameReader, frameWriter, listener, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpToHttp2ConnectionHandler(Http2Connection connection, Http2FrameReader frameReader,
|
||||||
|
Http2FrameWriter frameWriter, Http2FrameListener listener, boolean validateHeaders) {
|
||||||
super(connection, frameReader, frameWriter, listener);
|
super(connection, frameReader, frameWriter, listener);
|
||||||
|
this.validateHeaders = validateHeaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpToHttp2ConnectionHandler(Http2ConnectionDecoder decoder,
|
public HttpToHttp2ConnectionHandler(Http2ConnectionDecoder decoder,
|
||||||
Http2ConnectionEncoder encoder) {
|
Http2ConnectionEncoder encoder) {
|
||||||
|
this(decoder, encoder, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpToHttp2ConnectionHandler(Http2ConnectionDecoder decoder,
|
||||||
|
Http2ConnectionEncoder encoder, boolean validateHeaders) {
|
||||||
super(decoder, encoder);
|
super(decoder, encoder);
|
||||||
|
this.validateHeaders = validateHeaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -89,7 +113,7 @@ public class HttpToHttp2ConnectionHandler extends Http2ConnectionHandler {
|
|||||||
currentStreamId = getStreamId(httpMsg.headers());
|
currentStreamId = getStreamId(httpMsg.headers());
|
||||||
|
|
||||||
// Convert and write the headers.
|
// Convert and write the headers.
|
||||||
Http2Headers http2Headers = HttpConversionUtil.toHttp2Headers(httpMsg);
|
Http2Headers http2Headers = HttpConversionUtil.toHttp2Headers(httpMsg, validateHeaders);
|
||||||
endStream = msg instanceof FullHttpMessage && !((FullHttpMessage) msg).content().isReadable();
|
endStream = msg instanceof FullHttpMessage && !((FullHttpMessage) msg).content().isReadable();
|
||||||
encoder.writeHeaders(ctx, currentStreamId, http2Headers, 0, endStream, promiseAggregator.newPromise());
|
encoder.writeHeaders(ctx, currentStreamId, http2Headers, 0, endStream, promiseAggregator.newPromise());
|
||||||
}
|
}
|
||||||
@ -102,7 +126,7 @@ public class HttpToHttp2ConnectionHandler extends Http2ConnectionHandler {
|
|||||||
|
|
||||||
// Convert any trailing headers.
|
// Convert any trailing headers.
|
||||||
final LastHttpContent lastContent = (LastHttpContent) msg;
|
final LastHttpContent lastContent = (LastHttpContent) msg;
|
||||||
trailers = HttpConversionUtil.toHttp2Headers(lastContent.trailingHeaders());
|
trailers = HttpConversionUtil.toHttp2Headers(lastContent.trailingHeaders(), validateHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the data
|
// Write the data
|
||||||
|
@ -121,7 +121,7 @@ public class DefaultHttp2FrameIOTest {
|
|||||||
}
|
}
|
||||||
}).when(ctx).write(any(), any(ChannelPromise.class));
|
}).when(ctx).write(any(), any(ChannelPromise.class));
|
||||||
|
|
||||||
reader = new DefaultHttp2FrameReader();
|
reader = new DefaultHttp2FrameReader(false);
|
||||||
writer = new DefaultHttp2FrameWriter();
|
writer = new DefaultHttp2FrameWriter();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,7 +357,7 @@ public class DefaultHttp2FrameIOTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Http2Headers dummyBinaryHeaders() {
|
private static Http2Headers dummyBinaryHeaders() {
|
||||||
DefaultHttp2Headers headers = new DefaultHttp2Headers();
|
DefaultHttp2Headers headers = new DefaultHttp2Headers(false);
|
||||||
for (int ix = 0; ix < 10; ++ix) {
|
for (int ix = 0; ix < 10; ++ix) {
|
||||||
headers.add(randomString(), randomString());
|
headers.add(randomString(), randomString());
|
||||||
}
|
}
|
||||||
@ -365,13 +365,13 @@ public class DefaultHttp2FrameIOTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Http2Headers dummyHeaders() {
|
private static Http2Headers dummyHeaders() {
|
||||||
return new DefaultHttp2Headers().method(new AsciiString("GET")).scheme(new AsciiString("https"))
|
return new DefaultHttp2Headers(false).method(new AsciiString("GET")).scheme(new AsciiString("https"))
|
||||||
.authority(new AsciiString("example.org")).path(new AsciiString("/some/path"))
|
.authority(new AsciiString("example.org")).path(new AsciiString("/some/path"))
|
||||||
.add(new AsciiString("accept"), new AsciiString("*/*"));
|
.add(new AsciiString("accept"), new AsciiString("*/*"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Http2Headers largeHeaders() {
|
private static Http2Headers largeHeaders() {
|
||||||
DefaultHttp2Headers headers = new DefaultHttp2Headers();
|
DefaultHttp2Headers headers = new DefaultHttp2Headers(false);
|
||||||
for (int i = 0; i < 100; ++i) {
|
for (int i = 0; i < 100; ++i) {
|
||||||
String key = "this-is-a-test-header-key-" + i;
|
String key = "this-is-a-test-header-key-" + i;
|
||||||
String value = "this-is-a-test-header-value-" + i;
|
String value = "this-is-a-test-header-value-" + i;
|
||||||
@ -382,7 +382,7 @@ public class DefaultHttp2FrameIOTest {
|
|||||||
|
|
||||||
private Http2Headers headersOfSize(final int minSize) {
|
private Http2Headers headersOfSize(final int minSize) {
|
||||||
final ByteString singleByte = new ByteString(new byte[]{0});
|
final ByteString singleByte = new ByteString(new byte[]{0});
|
||||||
DefaultHttp2Headers headers = new DefaultHttp2Headers();
|
DefaultHttp2Headers headers = new DefaultHttp2Headers(false);
|
||||||
for (int size = 0; size < minSize; size += 2) {
|
for (int size = 0; size < minSize; size += 2) {
|
||||||
headers.add(singleByte, singleByte);
|
headers.add(singleByte, singleByte);
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ public class DefaultHttp2HeadersDecoderTest {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
decoder = new DefaultHttp2HeadersDecoder();
|
decoder = new DefaultHttp2HeadersDecoder(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -65,6 +65,13 @@ public class DefaultHttp2HeadersTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testHeaderNameValidation() {
|
||||||
|
Http2Headers headers = newHeaders();
|
||||||
|
|
||||||
|
headers.add(fromAscii("Foo"), fromAscii("foo"));
|
||||||
|
}
|
||||||
|
|
||||||
private static void verifyAllPseudoHeadersPresent(Http2Headers headers) {
|
private static void verifyAllPseudoHeadersPresent(Http2Headers headers) {
|
||||||
for (PseudoHeaderName pseudoName : PseudoHeaderName.values()) {
|
for (PseudoHeaderName pseudoName : PseudoHeaderName.values()) {
|
||||||
assertNotNull(headers.get(pseudoName.value()));
|
assertNotNull(headers.get(pseudoName.value()));
|
||||||
|
@ -482,7 +482,7 @@ public class Http2ConnectionRoundtripTest {
|
|||||||
serverFrameCountDown =
|
serverFrameCountDown =
|
||||||
new FrameCountDown(serverListener, serverSettingsAckLatch,
|
new FrameCountDown(serverListener, serverSettingsAckLatch,
|
||||||
requestLatch, dataLatch, trailersLatch, goAwayLatch);
|
requestLatch, dataLatch, trailersLatch, goAwayLatch);
|
||||||
p.addLast(new Http2ConnectionHandler(true, serverFrameCountDown));
|
p.addLast(new Http2ConnectionHandler(true, serverFrameCountDown, false));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -492,7 +492,7 @@ public class Http2ConnectionRoundtripTest {
|
|||||||
@Override
|
@Override
|
||||||
protected void initChannel(Channel ch) throws Exception {
|
protected void initChannel(Channel ch) throws Exception {
|
||||||
ChannelPipeline p = ch.pipeline();
|
ChannelPipeline p = ch.pipeline();
|
||||||
p.addLast(new Http2ConnectionHandler(false, clientListener));
|
p.addLast(new Http2ConnectionHandler(false, clientListener, false));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -513,7 +513,7 @@ public class Http2ConnectionRoundtripTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Http2Headers dummyHeaders() {
|
private static Http2Headers dummyHeaders() {
|
||||||
return new DefaultHttp2Headers().method(new AsciiString("GET")).scheme(new AsciiString("https"))
|
return new DefaultHttp2Headers(false).method(new AsciiString("GET")).scheme(new AsciiString("https"))
|
||||||
.authority(new AsciiString("example.org")).path(new AsciiString("/some/path/resource2"))
|
.authority(new AsciiString("example.org")).path(new AsciiString("/some/path/resource2"))
|
||||||
.add(randomString(), randomString());
|
.add(randomString(), randomString());
|
||||||
}
|
}
|
||||||
|
@ -398,7 +398,7 @@ public class Http2FrameRoundtripTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Http2Headers headers() {
|
private static Http2Headers headers() {
|
||||||
return new DefaultHttp2Headers().method(new AsciiString("GET")).scheme(new AsciiString("https"))
|
return new DefaultHttp2Headers(false).method(new AsciiString("GET")).scheme(new AsciiString("https"))
|
||||||
.authority(new AsciiString("example.org")).path(new AsciiString("/some/path/resource2"))
|
.authority(new AsciiString("example.org")).path(new AsciiString("/some/path/resource2"))
|
||||||
.add(randomString(), randomString());
|
.add(randomString(), randomString());
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ public class Http2HeaderBlockIOTest {
|
|||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
encoder = new DefaultHttp2HeadersEncoder();
|
encoder = new DefaultHttp2HeadersEncoder();
|
||||||
decoder = new DefaultHttp2HeadersDecoder();
|
decoder = new DefaultHttp2HeadersDecoder(false);
|
||||||
buffer = Unpooled.buffer();
|
buffer = Unpooled.buffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,21 +54,18 @@ public class Http2HeaderBlockIOTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void successiveCallsShouldSucceed() throws Http2Exception {
|
public void successiveCallsShouldSucceed() throws Http2Exception {
|
||||||
Http2Headers in =
|
Http2Headers in = new DefaultHttp2Headers().method(new AsciiString("GET")).scheme(new AsciiString("https"))
|
||||||
new DefaultHttp2Headers().method(new AsciiString("GET")).scheme(new AsciiString("https"))
|
|
||||||
.authority(new AsciiString("example.org")).path(new AsciiString("/some/path"))
|
.authority(new AsciiString("example.org")).path(new AsciiString("/some/path"))
|
||||||
.add(new AsciiString("accept"), new AsciiString("*/*"));
|
.add(new AsciiString("accept"), new AsciiString("*/*"));
|
||||||
assertRoundtripSuccessful(in);
|
assertRoundtripSuccessful(in);
|
||||||
|
|
||||||
in =
|
in = new DefaultHttp2Headers().method(new AsciiString("GET")).scheme(new AsciiString("https"))
|
||||||
new DefaultHttp2Headers().method(new AsciiString("GET")).scheme(new AsciiString("https"))
|
|
||||||
.authority(new AsciiString("example.org")).path(new AsciiString("/some/path/resource1"))
|
.authority(new AsciiString("example.org")).path(new AsciiString("/some/path/resource1"))
|
||||||
.add(new AsciiString("accept"), new AsciiString("image/jpeg"))
|
.add(new AsciiString("accept"), new AsciiString("image/jpeg"))
|
||||||
.add(new AsciiString("cache-control"), new AsciiString("no-cache"));
|
.add(new AsciiString("cache-control"), new AsciiString("no-cache"));
|
||||||
assertRoundtripSuccessful(in);
|
assertRoundtripSuccessful(in);
|
||||||
|
|
||||||
in =
|
in = new DefaultHttp2Headers().method(new AsciiString("GET")).scheme(new AsciiString("https"))
|
||||||
new DefaultHttp2Headers().method(new AsciiString("GET")).scheme(new AsciiString("https"))
|
|
||||||
.authority(new AsciiString("example.org")).path(new AsciiString("/some/path/resource2"))
|
.authority(new AsciiString("example.org")).path(new AsciiString("/some/path/resource2"))
|
||||||
.add(new AsciiString("accept"), new AsciiString("image/png"))
|
.add(new AsciiString("accept"), new AsciiString("image/png"))
|
||||||
.add(new AsciiString("cache-control"), new AsciiString("no-cache"));
|
.add(new AsciiString("cache-control"), new AsciiString("no-cache"));
|
||||||
@ -91,7 +88,7 @@ public class Http2HeaderBlockIOTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Http2Headers headers() {
|
private static Http2Headers headers() {
|
||||||
return new DefaultHttp2Headers().method(new AsciiString("GET")).scheme(new AsciiString("https"))
|
return new DefaultHttp2Headers(false).method(new AsciiString("GET")).scheme(new AsciiString("https"))
|
||||||
.authority(new AsciiString("example.org")).path(new AsciiString("/some/path/resource2"))
|
.authority(new AsciiString("example.org")).path(new AsciiString("/some/path/resource2"))
|
||||||
.add(new AsciiString("accept"), new AsciiString("image/png"))
|
.add(new AsciiString("accept"), new AsciiString("image/png"))
|
||||||
.add(new AsciiString("cache-control"), new AsciiString("no-cache"))
|
.add(new AsciiString("cache-control"), new AsciiString("no-cache"))
|
||||||
|
@ -89,7 +89,7 @@ final class Http2TestUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FrameAdapter(Http2Connection connection, Http2FrameListener listener, CountDownLatch latch) {
|
FrameAdapter(Http2Connection connection, Http2FrameListener listener, CountDownLatch latch) {
|
||||||
this(connection, new DefaultHttp2FrameReader(), listener, latch);
|
this(connection, new DefaultHttp2FrameReader(false), listener, latch);
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameAdapter(Http2Connection connection, DefaultHttp2FrameReader reader, Http2FrameListener listener,
|
FrameAdapter(Http2Connection connection, DefaultHttp2FrameReader reader, Http2FrameListener listener,
|
||||||
|
@ -66,6 +66,11 @@ public class DefaultHeaders<T> implements Headers<T> {
|
|||||||
int size;
|
int size;
|
||||||
|
|
||||||
public interface NameValidator<T> {
|
public interface NameValidator<T> {
|
||||||
|
/**
|
||||||
|
* Verify that {@code name} is valid.
|
||||||
|
* @param name The name to validate.
|
||||||
|
* @throws RuntimeException if {@code name} is not valid.
|
||||||
|
*/
|
||||||
void validateName(T name);
|
void validateName(T name);
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
@ -79,7 +84,12 @@ public class DefaultHeaders<T> implements Headers<T> {
|
|||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public DefaultHeaders(ValueConverter<T> valueConverter) {
|
public DefaultHeaders(ValueConverter<T> valueConverter) {
|
||||||
this(JAVA_HASHER, valueConverter, NameValidator.NOT_NULL);
|
this(valueConverter, NameValidator.NOT_NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public DefaultHeaders(ValueConverter<T> valueConverter, NameValidator<T> nameValidator) {
|
||||||
|
this(JAVA_HASHER, valueConverter, nameValidator);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DefaultHeaders(HashingStrategy<T> nameHashingStrategy,
|
public DefaultHeaders(HashingStrategy<T> nameHashingStrategy,
|
||||||
|
Loading…
Reference in New Issue
Block a user