diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java index b468f97582b..a2cc06b17fc 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java @@ -30,7 +30,10 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpScheme; +import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.Stream; @@ -199,4 +202,41 @@ public class HTTP2Test extends AbstractTest Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); } + + @Test + public void testHostHeader() throws Exception + { + final String host = "fooBar"; + final int port = 1313; + final String authority = host + ":" + port; + start(new HttpServlet() + { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + Assert.assertEquals(host, request.getServerName()); + Assert.assertEquals(port, request.getServerPort()); + Assert.assertEquals(authority, request.getHeader("Host")); + } + }); + + Session session = newClient(new Session.Listener.Adapter()); + HostPortHttpField hostHeader = new HostPortHttpField(authority); + MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP, hostHeader, servletPath, HttpVersion.HTTP_2, new HttpFields()); + HeadersFrame frame = new HeadersFrame(1, metaData, null, true); + final CountDownLatch latch = new CountDownLatch(1); + session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter() + { + @Override + public void onHeaders(Stream stream, HeadersFrame frame) + { + MetaData.Response response = (MetaData.Response)frame.getMetaData(); + Assert.assertEquals(200, response.getStatus()); + if (frame.isEndStream()) + latch.countDown(); + } + }); + + Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); + } } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java index 4836bfae128..fc2941031cb 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java @@ -56,7 +56,7 @@ public class HttpChannelOverHTTP2 extends HttpChannel { super(connector, configuration, endPoint, transport); } - + private IStream getStream() { return getHttpTransport().getStream(); @@ -73,6 +73,18 @@ public class HttpChannelOverHTTP2 extends HttpChannel MetaData.Request request = (MetaData.Request)frame.getMetaData(); HttpFields fields = request.getFields(); + // HTTP/2 sends the Host header as the :authority + // pseudo-header, so we need to synthesize a Host header. + if (!fields.contains(HttpHeader.HOST)) + { + String authority = request.getURI().getAuthority(); + if (authority != null) + { + // Lower-case to be consistent with other HTTP/2 headers. + fields.put("host", authority); + } + } + _expect100Continue = fields.contains(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString()); HttpFields response = getResponse().getHttpFields(); @@ -169,7 +181,7 @@ public class HttpChannelOverHTTP2 extends HttpChannel { return callback.isNonBlocking(); } - + @Override public void succeeded() {