HTTP to HTTP/2 translation errors (round 2)
Motivation:
Commit 0d8ce23c83
failed to fix the Host header processing. Host is not a URI but is instead defined in https://tools.ietf.org/html/rfc3986#section-3.2.2 as host = IP-literal / IPv4address / reg-name
Modifications:
- Host should not be treated as a URI.
- We should be more explicit about required fields, and unexpected input by throwing exceptions.
Result:
Translation from HTTP/1.x to HTTP/2 is more correct.
This commit is contained in:
parent
0d8ce23c83
commit
48ee962d08
@ -38,7 +38,6 @@ import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpScheme.HTTP;
|
||||
import static io.netty.handler.codec.http.HttpScheme.HTTPS;
|
||||
@ -288,24 +287,15 @@ public final class HttpUtil {
|
||||
URI requestTargetUri = URI.create(request.uri());
|
||||
out.path(toHttp2Path(requestTargetUri));
|
||||
out.method(request.method().asciiName());
|
||||
setHttp2Scheme(inHeaders, requestTargetUri, out);
|
||||
|
||||
// Attempt to take from HOST header before taking from the request-line
|
||||
String host = inHeaders.getAsString(HttpHeaderNames.HOST);
|
||||
boolean shouldSetAuthroity = !isOriginForm(requestTargetUri) && !isAsteriskForm(requestTargetUri);
|
||||
if (host == null) {
|
||||
if (shouldSetAuthroity) {
|
||||
setHttp2Authority(inHeaders, requestTargetUri, out);
|
||||
}
|
||||
setHttp2Scheme(inHeaders, requestTargetUri, true, out);
|
||||
} else {
|
||||
URI hostUri = URI.create(host);
|
||||
if (shouldSetAuthroity) {
|
||||
setHttp2Authority(inHeaders, hostUri, out);
|
||||
}
|
||||
if (!setHttp2Scheme(inHeaders, hostUri, false, out)) {
|
||||
/** :scheme must be present as defined by
|
||||
<a href="https://tools.ietf.org/html/rfc7540#section-8.1.2.3">rfc7540, 8.1.2.3</a>. */
|
||||
setHttp2Scheme(inHeaders, requestTargetUri, true, out);
|
||||
if (!isOriginForm(requestTargetUri) && !isAsteriskForm(requestTargetUri)) {
|
||||
// Attempt to take from HOST header before taking from the request-line
|
||||
String host = inHeaders.getAsString(HttpHeaderNames.HOST);
|
||||
if (host == null || host.isEmpty()) {
|
||||
setHttp2Authority(inHeaders, requestTargetUri.getAuthority(), out);
|
||||
} else {
|
||||
setHttp2Authority(inHeaders, host, out);
|
||||
}
|
||||
}
|
||||
} else if (in instanceof HttpResponse) {
|
||||
@ -361,15 +351,16 @@ public final class HttpUtil {
|
||||
return path.isEmpty() ? EMPTY_REQUEST_PATH : new AsciiString(path);
|
||||
}
|
||||
|
||||
private static void setHttp2Authority(HttpHeaders in, URI uri, Http2Headers out) {
|
||||
private static void setHttp2Authority(HttpHeaders in, String autority, Http2Headers out) {
|
||||
// The authority MUST NOT include the deprecated "userinfo" subcomponent
|
||||
String value = uri.getAuthority();
|
||||
if (value != null) {
|
||||
int endOfUserInfo = value.indexOf('@');
|
||||
if (autority != null) {
|
||||
int endOfUserInfo = autority.indexOf('@');
|
||||
if (endOfUserInfo < 0) {
|
||||
out.authority(new AsciiString(value));
|
||||
} else if (endOfUserInfo + 1 < value.length()) {
|
||||
out.authority(new AsciiString(value.substring(endOfUserInfo + 1)));
|
||||
out.authority(new AsciiString(autority));
|
||||
} else if (endOfUserInfo + 1 < autority.length()) {
|
||||
out.authority(new AsciiString(autority.substring(endOfUserInfo + 1)));
|
||||
} else {
|
||||
throw new IllegalArgumentException("autority: " + autority);
|
||||
}
|
||||
} else {
|
||||
// Consume the Authority extension header if present
|
||||
@ -381,23 +372,28 @@ public final class HttpUtil {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean setHttp2Scheme(HttpHeaders in, URI uri, boolean mustSet, Http2Headers out) {
|
||||
private static void setHttp2Scheme(HttpHeaders in, URI uri, Http2Headers out) {
|
||||
String value = uri.getScheme();
|
||||
if (value != null) {
|
||||
out.scheme(new AsciiString(value));
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Consume the Scheme extension header if present
|
||||
CharSequence cValue = in.get(ExtensionHeaderNames.SCHEME.text());
|
||||
if (cValue != null) {
|
||||
out.scheme(AsciiString.of(cValue));
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
if (uri.getPort() >= 0 || mustSet) {
|
||||
out.scheme(uri.getPort() == HTTPS.port() ? HTTPS.name() : HTTP.name());
|
||||
return true;
|
||||
|
||||
if (uri.getPort() == HTTPS.port()) {
|
||||
out.scheme(HTTPS.name());
|
||||
} else if (uri.getPort() == HTTP.port()) {
|
||||
out.scheme(HTTP.name());
|
||||
} else {
|
||||
throw new IllegalArgumentException(":scheme must be specified. " +
|
||||
"see https://tools.ietf.org/html/rfc7540#section-8.1.2.3");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -118,13 +118,14 @@ public class HttpToHttp2ConnectionHandlerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJustHeadersRequest() throws Exception {
|
||||
public void testHeadersOnlyRequest() throws Exception {
|
||||
bootstrapEnv(2, 1, 0);
|
||||
final FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, GET, "/example");
|
||||
final FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, GET,
|
||||
"http://my-user_name@www.example.org:5555/example");
|
||||
final HttpHeaders httpHeaders = request.headers();
|
||||
httpHeaders.setInt(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 5);
|
||||
httpHeaders.set(HttpHeaderNames.HOST,
|
||||
"http://my-user_name@www.example.org:5555/example");
|
||||
"my-user_name@www.example.org:5555");
|
||||
httpHeaders.set(HttpUtil.ExtensionHeaderNames.AUTHORITY.text(), "www.example.org:5555");
|
||||
httpHeaders.set(HttpUtil.ExtensionHeaderNames.SCHEME.text(), "http");
|
||||
httpHeaders.add("foo", "goo");
|
||||
@ -136,18 +137,9 @@ public class HttpToHttp2ConnectionHandlerTest {
|
||||
.add(new AsciiString("foo"), new AsciiString("goo"))
|
||||
.add(new AsciiString("foo"), new AsciiString("goo2"))
|
||||
.add(new AsciiString("foo2"), new AsciiString("goo2"));
|
||||
ChannelPromise writePromise = newPromise();
|
||||
ChannelFuture writeFuture = clientChannel.writeAndFlush(request, writePromise);
|
||||
|
||||
assertTrue(writePromise.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
|
||||
assertTrue(writePromise.isSuccess());
|
||||
assertTrue(writeFuture.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
|
||||
assertTrue(writeFuture.isSuccess());
|
||||
awaitRequests();
|
||||
verify(serverListener).onHeadersRead(any(ChannelHandlerContext.class), eq(5),
|
||||
eq(http2Headers), eq(0), anyShort(), anyBoolean(), eq(0), eq(true));
|
||||
verify(serverListener, never()).onDataRead(any(ChannelHandlerContext.class), anyInt(),
|
||||
any(ByteBuf.class), anyInt(), anyBoolean());
|
||||
ChannelPromise writePromise = newPromise();
|
||||
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -156,22 +148,14 @@ public class HttpToHttp2ConnectionHandlerTest {
|
||||
final FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, GET, "/where?q=now&f=then#section1");
|
||||
final HttpHeaders httpHeaders = request.headers();
|
||||
httpHeaders.setInt(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 5);
|
||||
httpHeaders.set(HttpUtil.ExtensionHeaderNames.SCHEME.text(), "http");
|
||||
final Http2Headers http2Headers =
|
||||
new DefaultHttp2Headers().method(new AsciiString("GET"))
|
||||
.path(new AsciiString("/where?q=now&f=then#section1"))
|
||||
.scheme(new AsciiString("http"));
|
||||
ChannelPromise writePromise = newPromise();
|
||||
ChannelFuture writeFuture = clientChannel.writeAndFlush(request, writePromise);
|
||||
|
||||
assertTrue(writePromise.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
|
||||
assertTrue(writePromise.isSuccess());
|
||||
assertTrue(writeFuture.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
|
||||
assertTrue(writeFuture.isSuccess());
|
||||
awaitRequests();
|
||||
verify(serverListener).onHeadersRead(any(ChannelHandlerContext.class), eq(5),
|
||||
eq(http2Headers), eq(0), anyShort(), anyBoolean(), eq(0), eq(true));
|
||||
verify(serverListener, never()).onDataRead(any(ChannelHandlerContext.class), anyInt(),
|
||||
any(ByteBuf.class), anyInt(), anyBoolean());
|
||||
ChannelPromise writePromise = newPromise();
|
||||
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -181,26 +165,17 @@ public class HttpToHttp2ConnectionHandlerTest {
|
||||
final HttpHeaders httpHeaders = request.headers();
|
||||
httpHeaders.setInt(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 5);
|
||||
httpHeaders.set(HttpHeaderNames.HOST,
|
||||
"https://foouser@www.example.org:5555/ignored_host");
|
||||
"foouser@www.example.org:5555");
|
||||
httpHeaders.set(HttpUtil.ExtensionHeaderNames.PATH.text(), "ignored_path");
|
||||
httpHeaders.set(HttpUtil.ExtensionHeaderNames.AUTHORITY.text(), "ignored_authority");
|
||||
httpHeaders.set(HttpUtil.ExtensionHeaderNames.SCHEME.text(), "ignored_scheme");
|
||||
httpHeaders.set(HttpUtil.ExtensionHeaderNames.SCHEME.text(), "https");
|
||||
final Http2Headers http2Headers =
|
||||
new DefaultHttp2Headers().method(new AsciiString("GET"))
|
||||
.path(new AsciiString("/pub/WWW/TheProject.html"))
|
||||
.authority(new AsciiString("www.example.org:5555")).scheme(new AsciiString("https"));
|
||||
ChannelPromise writePromise = newPromise();
|
||||
ChannelFuture writeFuture = clientChannel.writeAndFlush(request, writePromise);
|
||||
|
||||
assertTrue(writePromise.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
|
||||
assertTrue(writePromise.isSuccess());
|
||||
assertTrue(writeFuture.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
|
||||
assertTrue(writeFuture.isSuccess());
|
||||
awaitRequests();
|
||||
verify(serverListener).onHeadersRead(any(ChannelHandlerContext.class), eq(5),
|
||||
eq(http2Headers), eq(0), anyShort(), anyBoolean(), eq(0), eq(true));
|
||||
verify(serverListener, never()).onDataRead(any(ChannelHandlerContext.class), anyInt(),
|
||||
any(ByteBuf.class), anyInt(), anyBoolean());
|
||||
ChannelPromise writePromise = newPromise();
|
||||
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -216,18 +191,9 @@ public class HttpToHttp2ConnectionHandlerTest {
|
||||
new DefaultHttp2Headers().method(new AsciiString("GET"))
|
||||
.path(new AsciiString("/pub/WWW/TheProject.html"))
|
||||
.authority(new AsciiString("www.example.org:5555")).scheme(new AsciiString("https"));
|
||||
ChannelPromise writePromise = newPromise();
|
||||
ChannelFuture writeFuture = clientChannel.writeAndFlush(request, writePromise);
|
||||
|
||||
assertTrue(writePromise.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
|
||||
assertTrue(writePromise.isSuccess());
|
||||
assertTrue(writeFuture.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
|
||||
assertTrue(writeFuture.isSuccess());
|
||||
awaitRequests();
|
||||
verify(serverListener).onHeadersRead(any(ChannelHandlerContext.class), eq(5),
|
||||
eq(http2Headers), eq(0), anyShort(), anyBoolean(), eq(0), eq(true));
|
||||
verify(serverListener, never()).onDataRead(any(ChannelHandlerContext.class), anyInt(),
|
||||
any(ByteBuf.class), anyInt(), anyBoolean());
|
||||
ChannelPromise writePromise = newPromise();
|
||||
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -241,18 +207,9 @@ public class HttpToHttp2ConnectionHandlerTest {
|
||||
new DefaultHttp2Headers().method(new AsciiString("GET"))
|
||||
.path(new AsciiString("/pub/WWW/TheProject.html"))
|
||||
.authority(new AsciiString("www.example.org:5555")).scheme(new AsciiString("http"));
|
||||
ChannelPromise writePromise = newPromise();
|
||||
ChannelFuture writeFuture = clientChannel.writeAndFlush(request, writePromise);
|
||||
|
||||
assertTrue(writePromise.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
|
||||
assertTrue(writePromise.isSuccess());
|
||||
assertTrue(writeFuture.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
|
||||
assertTrue(writeFuture.isSuccess());
|
||||
awaitRequests();
|
||||
verify(serverListener).onHeadersRead(any(ChannelHandlerContext.class), eq(5),
|
||||
eq(http2Headers), eq(0), anyShort(), anyBoolean(), eq(0), eq(true));
|
||||
verify(serverListener, never()).onDataRead(any(ChannelHandlerContext.class), anyInt(),
|
||||
any(ByteBuf.class), anyInt(), anyBoolean());
|
||||
ChannelPromise writePromise = newPromise();
|
||||
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -264,18 +221,9 @@ public class HttpToHttp2ConnectionHandlerTest {
|
||||
final Http2Headers http2Headers =
|
||||
new DefaultHttp2Headers().method(new AsciiString("CONNECT")).path(new AsciiString("/"))
|
||||
.scheme(new AsciiString("http")).authority(new AsciiString("www.example.com:80"));
|
||||
ChannelPromise writePromise = newPromise();
|
||||
ChannelFuture writeFuture = clientChannel.writeAndFlush(request, writePromise);
|
||||
|
||||
assertTrue(writePromise.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
|
||||
assertTrue(writePromise.isSuccess());
|
||||
assertTrue(writeFuture.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
|
||||
assertTrue(writeFuture.isSuccess());
|
||||
awaitRequests();
|
||||
verify(serverListener).onHeadersRead(any(ChannelHandlerContext.class), eq(5),
|
||||
eq(http2Headers), eq(0), anyShort(), anyBoolean(), eq(0), eq(true));
|
||||
verify(serverListener, never()).onDataRead(any(ChannelHandlerContext.class), anyInt(),
|
||||
any(ByteBuf.class), anyInt(), anyBoolean());
|
||||
ChannelPromise writePromise = newPromise();
|
||||
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -284,22 +232,14 @@ public class HttpToHttp2ConnectionHandlerTest {
|
||||
final FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, OPTIONS, "*");
|
||||
final HttpHeaders httpHeaders = request.headers();
|
||||
httpHeaders.setInt(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 5);
|
||||
httpHeaders.set(HttpHeaderNames.HOST, "http://www.example.com:80");
|
||||
httpHeaders.set(HttpHeaderNames.HOST, "www.example.com:80");
|
||||
httpHeaders.set(HttpUtil.ExtensionHeaderNames.SCHEME.text(), "http");
|
||||
final Http2Headers http2Headers =
|
||||
new DefaultHttp2Headers().method(new AsciiString("OPTIONS")).path(new AsciiString("*"))
|
||||
.scheme(new AsciiString("http")).authority(new AsciiString("www.example.com:80"));
|
||||
ChannelPromise writePromise = newPromise();
|
||||
ChannelFuture writeFuture = clientChannel.writeAndFlush(request, writePromise);
|
||||
|
||||
assertTrue(writePromise.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
|
||||
assertTrue(writePromise.isSuccess());
|
||||
assertTrue(writeFuture.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
|
||||
assertTrue(writeFuture.isSuccess());
|
||||
awaitRequests();
|
||||
verify(serverListener).onHeadersRead(any(ChannelHandlerContext.class), eq(5),
|
||||
eq(http2Headers), eq(0), anyShort(), anyBoolean(), eq(0), eq(true));
|
||||
verify(serverListener, never()).onDataRead(any(ChannelHandlerContext.class), anyInt(),
|
||||
any(ByteBuf.class), anyInt(), anyBoolean());
|
||||
ChannelPromise writePromise = newPromise();
|
||||
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -310,77 +250,55 @@ public class HttpToHttp2ConnectionHandlerTest {
|
||||
final FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, GET, "/");
|
||||
final HttpHeaders httpHeaders = request.headers();
|
||||
httpHeaders.setInt(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 5);
|
||||
httpHeaders.set(HttpHeaderNames.HOST, "http://[::1]:80");
|
||||
httpHeaders.set(HttpHeaderNames.HOST, "[::1]:80");
|
||||
httpHeaders.set(HttpUtil.ExtensionHeaderNames.SCHEME.text(), "http");
|
||||
final Http2Headers http2Headers =
|
||||
new DefaultHttp2Headers().method(new AsciiString("GET")).path(new AsciiString("/"))
|
||||
.scheme(new AsciiString("http")).authority(new AsciiString("[::1]:80"));
|
||||
ChannelPromise writePromise = newPromise();
|
||||
ChannelFuture writeFuture = clientChannel.writeAndFlush(request, writePromise);
|
||||
|
||||
assertTrue(writePromise.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
|
||||
assertTrue(writePromise.isSuccess());
|
||||
assertTrue(writeFuture.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
|
||||
assertTrue(writeFuture.isSuccess());
|
||||
awaitRequests();
|
||||
verify(serverListener).onHeadersRead(any(ChannelHandlerContext.class), eq(5),
|
||||
eq(http2Headers), eq(0), anyShort(), anyBoolean(), eq(0), eq(true));
|
||||
verify(serverListener, never()).onDataRead(any(ChannelHandlerContext.class), anyInt(),
|
||||
any(ByteBuf.class), anyInt(), anyBoolean());
|
||||
ChannelPromise writePromise = newPromise();
|
||||
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHostNoSchemeFormRequestTargetHandled() throws Exception {
|
||||
public void testHostFormRequestTargetHandled() throws Exception {
|
||||
bootstrapEnv(2, 1, 0);
|
||||
final FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, GET, "/");
|
||||
final HttpHeaders httpHeaders = request.headers();
|
||||
httpHeaders.setInt(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 5);
|
||||
// This is an "irregular" host in that the scheme is "localhost"
|
||||
httpHeaders.set(HttpHeaderNames.HOST, "localhost:80");
|
||||
httpHeaders.set(HttpUtil.ExtensionHeaderNames.SCHEME.text(), "http");
|
||||
final Http2Headers http2Headers =
|
||||
new DefaultHttp2Headers().method(new AsciiString("GET")).path(new AsciiString("/"))
|
||||
.scheme(new AsciiString("localhost"));
|
||||
ChannelPromise writePromise = newPromise();
|
||||
ChannelFuture writeFuture = clientChannel.writeAndFlush(request, writePromise);
|
||||
.scheme(new AsciiString("http")).authority(new AsciiString("localhost:80"));
|
||||
|
||||
assertTrue(writePromise.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
|
||||
assertTrue(writePromise.isSuccess());
|
||||
assertTrue(writeFuture.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
|
||||
assertTrue(writeFuture.isSuccess());
|
||||
awaitRequests();
|
||||
verify(serverListener).onHeadersRead(any(ChannelHandlerContext.class), eq(5),
|
||||
eq(http2Headers), eq(0), anyShort(), anyBoolean(), eq(0), eq(true));
|
||||
verify(serverListener, never()).onDataRead(any(ChannelHandlerContext.class), anyInt(),
|
||||
any(ByteBuf.class), anyInt(), anyBoolean());
|
||||
ChannelPromise writePromise = newPromise();
|
||||
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadHostIPv4FormRequestTargetHandled() throws Exception {
|
||||
// Invalid according to
|
||||
// https://tools.ietf.org/html/rfc7230#section-2.7.1 -> https://tools.ietf.org/html/rfc3986#section-3
|
||||
public void testHostIPv4FormRequestTargetHandled() throws Exception {
|
||||
bootstrapEnv(2, 1, 0);
|
||||
final FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, GET, "/");
|
||||
final HttpHeaders httpHeaders = request.headers();
|
||||
httpHeaders.setInt(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 5);
|
||||
httpHeaders.set(HttpHeaderNames.HOST, "1.2.3.4:80");
|
||||
ChannelPromise writePromise = newPromise();
|
||||
ChannelFuture writeFuture = clientChannel.writeAndFlush(request, writePromise);
|
||||
httpHeaders.set(HttpUtil.ExtensionHeaderNames.SCHEME.text(), "http");
|
||||
final Http2Headers http2Headers =
|
||||
new DefaultHttp2Headers().method(new AsciiString("GET")).path(new AsciiString("/"))
|
||||
.scheme(new AsciiString("http")).authority(new AsciiString("1.2.3.4:80"));
|
||||
|
||||
assertTrue(writePromise.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
|
||||
assertTrue(writePromise.isDone());
|
||||
assertFalse(writePromise.isSuccess());
|
||||
assertTrue(writeFuture.isDone());
|
||||
assertFalse(writeFuture.isSuccess());
|
||||
ChannelPromise writePromise = newPromise();
|
||||
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadHostIPv6FormRequestTargetHandled() throws Exception {
|
||||
// Invalid according to
|
||||
// https://tools.ietf.org/html/rfc7230#section-2.7.1 -> https://tools.ietf.org/html/rfc3986#section-3
|
||||
public void testNoSchemeRequestTargetHandled() throws Exception {
|
||||
bootstrapEnv(2, 1, 0);
|
||||
final FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, GET, "/");
|
||||
final HttpHeaders httpHeaders = request.headers();
|
||||
httpHeaders.setInt(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 5);
|
||||
httpHeaders.set(HttpHeaderNames.HOST, "[::1]:80");
|
||||
httpHeaders.set(HttpHeaderNames.HOST, "localhost");
|
||||
ChannelPromise writePromise = newPromise();
|
||||
ChannelFuture writeFuture = clientChannel.writeAndFlush(request, writePromise);
|
||||
|
||||
@ -404,16 +322,17 @@ public class HttpToHttp2ConnectionHandlerTest {
|
||||
}).when(serverListener).onDataRead(any(ChannelHandlerContext.class), eq(3),
|
||||
any(ByteBuf.class), eq(0), eq(true));
|
||||
bootstrapEnv(3, 1, 0);
|
||||
final FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, POST, "/example",
|
||||
final FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, POST,
|
||||
"http://your_user-name123@www.example.org:5555/example",
|
||||
Unpooled.copiedBuffer(text, UTF_8));
|
||||
final HttpHeaders httpHeaders = request.headers();
|
||||
httpHeaders.set(HttpHeaderNames.HOST, "http://your_user-name123@www.example.org:5555/example");
|
||||
httpHeaders.set(HttpHeaderNames.HOST, "www.example-origin.org:5555");
|
||||
httpHeaders.add("foo", "goo");
|
||||
httpHeaders.add("foo", "goo2");
|
||||
httpHeaders.add("foo2", "goo2");
|
||||
final Http2Headers http2Headers =
|
||||
new DefaultHttp2Headers().method(new AsciiString("POST")).path(new AsciiString("/example"))
|
||||
.authority(new AsciiString("www.example.org:5555")).scheme(new AsciiString("http"))
|
||||
.authority(new AsciiString("www.example-origin.org:5555")).scheme(new AsciiString("http"))
|
||||
.add(new AsciiString("foo"), new AsciiString("goo"))
|
||||
.add(new AsciiString("foo"), new AsciiString("goo2"))
|
||||
.add(new AsciiString("foo2"), new AsciiString("goo2"));
|
||||
@ -446,10 +365,11 @@ public class HttpToHttp2ConnectionHandlerTest {
|
||||
}).when(serverListener).onDataRead(any(ChannelHandlerContext.class), eq(3),
|
||||
any(ByteBuf.class), eq(0), eq(false));
|
||||
bootstrapEnv(4, 1, 1);
|
||||
final FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, POST, "/example",
|
||||
final FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, POST,
|
||||
"http://your_user-name123@www.example.org:5555/example",
|
||||
Unpooled.copiedBuffer(text, UTF_8));
|
||||
final HttpHeaders httpHeaders = request.headers();
|
||||
httpHeaders.set(HttpHeaderNames.HOST, "http://your_user-name123@www.example.org:5555/example");
|
||||
httpHeaders.set(HttpHeaderNames.HOST, "www.example.org:5555");
|
||||
httpHeaders.add("foo", "goo");
|
||||
httpHeaders.add("foo", "goo2");
|
||||
httpHeaders.add("foo2", "goo2");
|
||||
@ -497,9 +417,10 @@ public class HttpToHttp2ConnectionHandlerTest {
|
||||
}).when(serverListener).onDataRead(any(ChannelHandlerContext.class), eq(3),
|
||||
any(ByteBuf.class), eq(0), eq(false));
|
||||
bootstrapEnv(4, 1, 1);
|
||||
final HttpRequest request = new DefaultHttpRequest(HTTP_1_1, POST, "/example");
|
||||
final HttpRequest request = new DefaultHttpRequest(HTTP_1_1, POST,
|
||||
"http://your_user-name123@www.example.org:5555/example");
|
||||
final HttpHeaders httpHeaders = request.headers();
|
||||
httpHeaders.set(HttpHeaderNames.HOST, "http://your_user-name123@www.example.org:5555/example");
|
||||
httpHeaders.set(HttpHeaderNames.HOST, "www.example.org:5555");
|
||||
httpHeaders.add(HttpHeaderNames.TRANSFER_ENCODING, "chunked");
|
||||
httpHeaders.add("foo", "goo");
|
||||
httpHeaders.add("foo", "goo2");
|
||||
@ -593,6 +514,19 @@ public class HttpToHttp2ConnectionHandlerTest {
|
||||
clientChannel = ccf.channel();
|
||||
}
|
||||
|
||||
private void verifyHeadersOnly(Http2Headers expected, ChannelPromise writePromise, ChannelFuture writeFuture)
|
||||
throws Exception {
|
||||
assertTrue(writePromise.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
|
||||
assertTrue(writePromise.isSuccess());
|
||||
assertTrue(writeFuture.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
|
||||
assertTrue(writeFuture.isSuccess());
|
||||
awaitRequests();
|
||||
verify(serverListener).onHeadersRead(any(ChannelHandlerContext.class), eq(5),
|
||||
eq(expected), eq(0), anyShort(), anyBoolean(), eq(0), eq(true));
|
||||
verify(serverListener, never()).onDataRead(any(ChannelHandlerContext.class), anyInt(),
|
||||
any(ByteBuf.class), anyInt(), anyBoolean());
|
||||
}
|
||||
|
||||
private void awaitRequests() throws Exception {
|
||||
assertTrue(requestLatch.await(WAIT_TIME_SECONDS, SECONDS));
|
||||
if (trailersLatch != null) {
|
||||
|
Loading…
Reference in New Issue
Block a user