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
6046adef2b
commit
99d6a97b4a
@ -39,7 +39,6 @@ import java.util.Iterator;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
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.HTTP;
|
||||||
import static io.netty.handler.codec.http.HttpScheme.HTTPS;
|
import static io.netty.handler.codec.http.HttpScheme.HTTPS;
|
||||||
@ -289,24 +288,15 @@ public final class HttpUtil {
|
|||||||
URI requestTargetUri = URI.create(request.uri());
|
URI requestTargetUri = URI.create(request.uri());
|
||||||
out.path(toHttp2Path(requestTargetUri));
|
out.path(toHttp2Path(requestTargetUri));
|
||||||
out.method(request.method().asciiName());
|
out.method(request.method().asciiName());
|
||||||
|
setHttp2Scheme(inHeaders, requestTargetUri, out);
|
||||||
|
|
||||||
|
if (!isOriginForm(requestTargetUri) && !isAsteriskForm(requestTargetUri)) {
|
||||||
// Attempt to take from HOST header before taking from the request-line
|
// Attempt to take from HOST header before taking from the request-line
|
||||||
String host = inHeaders.getAsString(HttpHeaderNames.HOST);
|
String host = inHeaders.getAsString(HttpHeaderNames.HOST);
|
||||||
boolean shouldSetAuthroity = !isOriginForm(requestTargetUri) && !isAsteriskForm(requestTargetUri);
|
if (host == null || host.isEmpty()) {
|
||||||
if (host == null) {
|
setHttp2Authority(inHeaders, requestTargetUri.getAuthority(), out);
|
||||||
if (shouldSetAuthroity) {
|
|
||||||
setHttp2Authority(inHeaders, requestTargetUri, out);
|
|
||||||
}
|
|
||||||
setHttp2Scheme(inHeaders, requestTargetUri, true, out);
|
|
||||||
} else {
|
} else {
|
||||||
URI hostUri = URI.create(host);
|
setHttp2Authority(inHeaders, host, out);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (in instanceof HttpResponse) {
|
} else if (in instanceof HttpResponse) {
|
||||||
@ -364,15 +354,16 @@ public final class HttpUtil {
|
|||||||
return path.isEmpty() ? EMPTY_REQUEST_PATH : new AsciiString(path);
|
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
|
// The authority MUST NOT include the deprecated "userinfo" subcomponent
|
||||||
String value = uri.getAuthority();
|
if (autority != null) {
|
||||||
if (value != null) {
|
int endOfUserInfo = autority.indexOf('@');
|
||||||
int endOfUserInfo = value.indexOf('@');
|
|
||||||
if (endOfUserInfo < 0) {
|
if (endOfUserInfo < 0) {
|
||||||
out.authority(new AsciiString(value));
|
out.authority(new AsciiString(autority));
|
||||||
} else if (endOfUserInfo + 1 < value.length()) {
|
} else if (endOfUserInfo + 1 < autority.length()) {
|
||||||
out.authority(new AsciiString(value.substring(endOfUserInfo + 1)));
|
out.authority(new AsciiString(autority.substring(endOfUserInfo + 1)));
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("autority: " + autority);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Consume the Authority extension header if present
|
// Consume the Authority extension header if present
|
||||||
@ -384,23 +375,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();
|
String value = uri.getScheme();
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
out.scheme(new AsciiString(value));
|
out.scheme(new AsciiString(value));
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consume the Scheme extension header if present
|
// Consume the Scheme extension header if present
|
||||||
CharSequence cValue = in.get(ExtensionHeaderNames.SCHEME.text());
|
CharSequence cValue = in.get(ExtensionHeaderNames.SCHEME.text());
|
||||||
if (cValue != null) {
|
if (cValue != null) {
|
||||||
out.scheme(AsciiString.of(cValue));
|
out.scheme(AsciiString.of(cValue));
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
if (uri.getPort() >= 0 || mustSet) {
|
|
||||||
out.scheme(uri.getPort() == HTTPS.port() ? HTTPS.name() : HTTP.name());
|
if (uri.getPort() == HTTPS.port()) {
|
||||||
return true;
|
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
|
@Test
|
||||||
public void testJustHeadersRequest() throws Exception {
|
public void testHeadersOnlyRequest() throws Exception {
|
||||||
bootstrapEnv(2, 1, 0);
|
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();
|
final HttpHeaders httpHeaders = request.headers();
|
||||||
httpHeaders.setInt(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 5);
|
httpHeaders.setInt(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 5);
|
||||||
httpHeaders.set(HttpHeaderNames.HOST,
|
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.AUTHORITY.text(), "www.example.org:5555");
|
||||||
httpHeaders.set(HttpUtil.ExtensionHeaderNames.SCHEME.text(), "http");
|
httpHeaders.set(HttpUtil.ExtensionHeaderNames.SCHEME.text(), "http");
|
||||||
httpHeaders.add("foo", "goo");
|
httpHeaders.add("foo", "goo");
|
||||||
@ -136,18 +137,9 @@ public class HttpToHttp2ConnectionHandlerTest {
|
|||||||
.add(new AsciiString("foo"), new AsciiString("goo"))
|
.add(new AsciiString("foo"), new AsciiString("goo"))
|
||||||
.add(new AsciiString("foo"), new AsciiString("goo2"))
|
.add(new AsciiString("foo"), new AsciiString("goo2"))
|
||||||
.add(new AsciiString("foo2"), 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));
|
ChannelPromise writePromise = newPromise();
|
||||||
assertTrue(writePromise.isSuccess());
|
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -156,22 +148,14 @@ public class HttpToHttp2ConnectionHandlerTest {
|
|||||||
final FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, GET, "/where?q=now&f=then#section1");
|
final FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, GET, "/where?q=now&f=then#section1");
|
||||||
final HttpHeaders httpHeaders = request.headers();
|
final HttpHeaders httpHeaders = request.headers();
|
||||||
httpHeaders.setInt(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 5);
|
httpHeaders.setInt(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 5);
|
||||||
|
httpHeaders.set(HttpUtil.ExtensionHeaderNames.SCHEME.text(), "http");
|
||||||
final Http2Headers http2Headers =
|
final Http2Headers http2Headers =
|
||||||
new DefaultHttp2Headers().method(new AsciiString("GET"))
|
new DefaultHttp2Headers().method(new AsciiString("GET"))
|
||||||
.path(new AsciiString("/where?q=now&f=then#section1"))
|
.path(new AsciiString("/where?q=now&f=then#section1"))
|
||||||
.scheme(new AsciiString("http"));
|
.scheme(new AsciiString("http"));
|
||||||
ChannelPromise writePromise = newPromise();
|
|
||||||
ChannelFuture writeFuture = clientChannel.writeAndFlush(request, writePromise);
|
|
||||||
|
|
||||||
assertTrue(writePromise.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
|
ChannelPromise writePromise = newPromise();
|
||||||
assertTrue(writePromise.isSuccess());
|
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -181,26 +165,17 @@ public class HttpToHttp2ConnectionHandlerTest {
|
|||||||
final HttpHeaders httpHeaders = request.headers();
|
final HttpHeaders httpHeaders = request.headers();
|
||||||
httpHeaders.setInt(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 5);
|
httpHeaders.setInt(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 5);
|
||||||
httpHeaders.set(HttpHeaderNames.HOST,
|
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.PATH.text(), "ignored_path");
|
||||||
httpHeaders.set(HttpUtil.ExtensionHeaderNames.AUTHORITY.text(), "ignored_authority");
|
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 =
|
final Http2Headers http2Headers =
|
||||||
new DefaultHttp2Headers().method(new AsciiString("GET"))
|
new DefaultHttp2Headers().method(new AsciiString("GET"))
|
||||||
.path(new AsciiString("/pub/WWW/TheProject.html"))
|
.path(new AsciiString("/pub/WWW/TheProject.html"))
|
||||||
.authority(new AsciiString("www.example.org:5555")).scheme(new AsciiString("https"));
|
.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));
|
ChannelPromise writePromise = newPromise();
|
||||||
assertTrue(writePromise.isSuccess());
|
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -216,18 +191,9 @@ public class HttpToHttp2ConnectionHandlerTest {
|
|||||||
new DefaultHttp2Headers().method(new AsciiString("GET"))
|
new DefaultHttp2Headers().method(new AsciiString("GET"))
|
||||||
.path(new AsciiString("/pub/WWW/TheProject.html"))
|
.path(new AsciiString("/pub/WWW/TheProject.html"))
|
||||||
.authority(new AsciiString("www.example.org:5555")).scheme(new AsciiString("https"));
|
.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));
|
ChannelPromise writePromise = newPromise();
|
||||||
assertTrue(writePromise.isSuccess());
|
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -241,18 +207,9 @@ public class HttpToHttp2ConnectionHandlerTest {
|
|||||||
new DefaultHttp2Headers().method(new AsciiString("GET"))
|
new DefaultHttp2Headers().method(new AsciiString("GET"))
|
||||||
.path(new AsciiString("/pub/WWW/TheProject.html"))
|
.path(new AsciiString("/pub/WWW/TheProject.html"))
|
||||||
.authority(new AsciiString("www.example.org:5555")).scheme(new AsciiString("http"));
|
.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));
|
ChannelPromise writePromise = newPromise();
|
||||||
assertTrue(writePromise.isSuccess());
|
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -264,18 +221,9 @@ public class HttpToHttp2ConnectionHandlerTest {
|
|||||||
final Http2Headers http2Headers =
|
final Http2Headers http2Headers =
|
||||||
new DefaultHttp2Headers().method(new AsciiString("CONNECT")).path(new AsciiString("/"))
|
new DefaultHttp2Headers().method(new AsciiString("CONNECT")).path(new AsciiString("/"))
|
||||||
.scheme(new AsciiString("http")).authority(new AsciiString("www.example.com:80"));
|
.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));
|
ChannelPromise writePromise = newPromise();
|
||||||
assertTrue(writePromise.isSuccess());
|
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -284,22 +232,14 @@ public class HttpToHttp2ConnectionHandlerTest {
|
|||||||
final FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, OPTIONS, "*");
|
final FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, OPTIONS, "*");
|
||||||
final HttpHeaders httpHeaders = request.headers();
|
final HttpHeaders httpHeaders = request.headers();
|
||||||
httpHeaders.setInt(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 5);
|
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 =
|
final Http2Headers http2Headers =
|
||||||
new DefaultHttp2Headers().method(new AsciiString("OPTIONS")).path(new AsciiString("*"))
|
new DefaultHttp2Headers().method(new AsciiString("OPTIONS")).path(new AsciiString("*"))
|
||||||
.scheme(new AsciiString("http")).authority(new AsciiString("www.example.com:80"));
|
.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));
|
ChannelPromise writePromise = newPromise();
|
||||||
assertTrue(writePromise.isSuccess());
|
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -310,77 +250,55 @@ public class HttpToHttp2ConnectionHandlerTest {
|
|||||||
final FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, GET, "/");
|
final FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, GET, "/");
|
||||||
final HttpHeaders httpHeaders = request.headers();
|
final HttpHeaders httpHeaders = request.headers();
|
||||||
httpHeaders.setInt(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 5);
|
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 =
|
final Http2Headers http2Headers =
|
||||||
new DefaultHttp2Headers().method(new AsciiString("GET")).path(new AsciiString("/"))
|
new DefaultHttp2Headers().method(new AsciiString("GET")).path(new AsciiString("/"))
|
||||||
.scheme(new AsciiString("http")).authority(new AsciiString("[::1]:80"));
|
.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));
|
ChannelPromise writePromise = newPromise();
|
||||||
assertTrue(writePromise.isSuccess());
|
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHostNoSchemeFormRequestTargetHandled() throws Exception {
|
public void testHostFormRequestTargetHandled() throws Exception {
|
||||||
bootstrapEnv(2, 1, 0);
|
bootstrapEnv(2, 1, 0);
|
||||||
final FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, GET, "/");
|
final FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, GET, "/");
|
||||||
final HttpHeaders httpHeaders = request.headers();
|
final HttpHeaders httpHeaders = request.headers();
|
||||||
httpHeaders.setInt(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 5);
|
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(HttpHeaderNames.HOST, "localhost:80");
|
||||||
|
httpHeaders.set(HttpUtil.ExtensionHeaderNames.SCHEME.text(), "http");
|
||||||
final Http2Headers http2Headers =
|
final Http2Headers http2Headers =
|
||||||
new DefaultHttp2Headers().method(new AsciiString("GET")).path(new AsciiString("/"))
|
new DefaultHttp2Headers().method(new AsciiString("GET")).path(new AsciiString("/"))
|
||||||
.scheme(new AsciiString("localhost"));
|
.scheme(new AsciiString("http")).authority(new AsciiString("localhost:80"));
|
||||||
ChannelPromise writePromise = newPromise();
|
|
||||||
ChannelFuture writeFuture = clientChannel.writeAndFlush(request, writePromise);
|
|
||||||
|
|
||||||
assertTrue(writePromise.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
|
ChannelPromise writePromise = newPromise();
|
||||||
assertTrue(writePromise.isSuccess());
|
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBadHostIPv4FormRequestTargetHandled() throws Exception {
|
public void testHostIPv4FormRequestTargetHandled() throws Exception {
|
||||||
// Invalid according to
|
|
||||||
// https://tools.ietf.org/html/rfc7230#section-2.7.1 -> https://tools.ietf.org/html/rfc3986#section-3
|
|
||||||
bootstrapEnv(2, 1, 0);
|
bootstrapEnv(2, 1, 0);
|
||||||
final FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, GET, "/");
|
final FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, GET, "/");
|
||||||
final HttpHeaders httpHeaders = request.headers();
|
final HttpHeaders httpHeaders = request.headers();
|
||||||
httpHeaders.setInt(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 5);
|
httpHeaders.setInt(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 5);
|
||||||
httpHeaders.set(HttpHeaderNames.HOST, "1.2.3.4:80");
|
httpHeaders.set(HttpHeaderNames.HOST, "1.2.3.4:80");
|
||||||
ChannelPromise writePromise = newPromise();
|
httpHeaders.set(HttpUtil.ExtensionHeaderNames.SCHEME.text(), "http");
|
||||||
ChannelFuture writeFuture = clientChannel.writeAndFlush(request, writePromise);
|
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));
|
ChannelPromise writePromise = newPromise();
|
||||||
assertTrue(writePromise.isDone());
|
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
|
||||||
assertFalse(writePromise.isSuccess());
|
|
||||||
assertTrue(writeFuture.isDone());
|
|
||||||
assertFalse(writeFuture.isSuccess());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBadHostIPv6FormRequestTargetHandled() throws Exception {
|
public void testNoSchemeRequestTargetHandled() throws Exception {
|
||||||
// Invalid according to
|
|
||||||
// https://tools.ietf.org/html/rfc7230#section-2.7.1 -> https://tools.ietf.org/html/rfc3986#section-3
|
|
||||||
bootstrapEnv(2, 1, 0);
|
bootstrapEnv(2, 1, 0);
|
||||||
final FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, GET, "/");
|
final FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, GET, "/");
|
||||||
final HttpHeaders httpHeaders = request.headers();
|
final HttpHeaders httpHeaders = request.headers();
|
||||||
httpHeaders.setInt(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 5);
|
httpHeaders.setInt(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 5);
|
||||||
httpHeaders.set(HttpHeaderNames.HOST, "[::1]:80");
|
httpHeaders.set(HttpHeaderNames.HOST, "localhost");
|
||||||
ChannelPromise writePromise = newPromise();
|
ChannelPromise writePromise = newPromise();
|
||||||
ChannelFuture writeFuture = clientChannel.writeAndFlush(request, writePromise);
|
ChannelFuture writeFuture = clientChannel.writeAndFlush(request, writePromise);
|
||||||
|
|
||||||
@ -404,16 +322,17 @@ public class HttpToHttp2ConnectionHandlerTest {
|
|||||||
}).when(serverListener).onDataRead(any(ChannelHandlerContext.class), eq(3),
|
}).when(serverListener).onDataRead(any(ChannelHandlerContext.class), eq(3),
|
||||||
any(ByteBuf.class), eq(0), eq(true));
|
any(ByteBuf.class), eq(0), eq(true));
|
||||||
bootstrapEnv(3, 1, 0);
|
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));
|
Unpooled.copiedBuffer(text, UTF_8));
|
||||||
final HttpHeaders httpHeaders = request.headers();
|
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", "goo");
|
||||||
httpHeaders.add("foo", "goo2");
|
httpHeaders.add("foo", "goo2");
|
||||||
httpHeaders.add("foo2", "goo2");
|
httpHeaders.add("foo2", "goo2");
|
||||||
final Http2Headers http2Headers =
|
final Http2Headers http2Headers =
|
||||||
new DefaultHttp2Headers().method(new AsciiString("POST")).path(new AsciiString("/example"))
|
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("goo"))
|
||||||
.add(new AsciiString("foo"), new AsciiString("goo2"))
|
.add(new AsciiString("foo"), new AsciiString("goo2"))
|
||||||
.add(new AsciiString("foo2"), 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),
|
}).when(serverListener).onDataRead(any(ChannelHandlerContext.class), eq(3),
|
||||||
any(ByteBuf.class), eq(0), eq(false));
|
any(ByteBuf.class), eq(0), eq(false));
|
||||||
bootstrapEnv(4, 1, 1);
|
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));
|
Unpooled.copiedBuffer(text, UTF_8));
|
||||||
final HttpHeaders httpHeaders = request.headers();
|
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", "goo");
|
||||||
httpHeaders.add("foo", "goo2");
|
httpHeaders.add("foo", "goo2");
|
||||||
httpHeaders.add("foo2", "goo2");
|
httpHeaders.add("foo2", "goo2");
|
||||||
@ -497,9 +417,10 @@ public class HttpToHttp2ConnectionHandlerTest {
|
|||||||
}).when(serverListener).onDataRead(any(ChannelHandlerContext.class), eq(3),
|
}).when(serverListener).onDataRead(any(ChannelHandlerContext.class), eq(3),
|
||||||
any(ByteBuf.class), eq(0), eq(false));
|
any(ByteBuf.class), eq(0), eq(false));
|
||||||
bootstrapEnv(4, 1, 1);
|
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();
|
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(HttpHeaderNames.TRANSFER_ENCODING, "chunked");
|
||||||
httpHeaders.add("foo", "goo");
|
httpHeaders.add("foo", "goo");
|
||||||
httpHeaders.add("foo", "goo2");
|
httpHeaders.add("foo", "goo2");
|
||||||
@ -593,6 +514,19 @@ public class HttpToHttp2ConnectionHandlerTest {
|
|||||||
clientChannel = ccf.channel();
|
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 {
|
private void awaitRequests() throws Exception {
|
||||||
assertTrue(requestLatch.await(WAIT_TIME_SECONDS, SECONDS));
|
assertTrue(requestLatch.await(WAIT_TIME_SECONDS, SECONDS));
|
||||||
if (trailersLatch != null) {
|
if (trailersLatch != null) {
|
||||||
|
Loading…
Reference in New Issue
Block a user