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:
Scott Mitchell 2015-08-24 16:13:17 -07:00
parent 6046adef2b
commit 99d6a97b4a
2 changed files with 92 additions and 162 deletions

View File

@ -39,7 +39,6 @@ import java.util.Iterator;
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;
@ -289,24 +288,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) {
@ -364,15 +354,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
@ -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();
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;
}
/**

View File

@ -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) {