diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index c46236a7a242..492c23cf5ab1 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -57,6 +57,7 @@ import org.eclipse.jetty.server.handler.ErrorHandler; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.HostPort; import org.eclipse.jetty.util.SharedBlockingCallback.Blocker; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.log.Log; @@ -132,6 +133,15 @@ public boolean isSendError() return _state.isSendError(); } + /** Format the address or host returned from Request methods + * @param addr The address or host + * @return Default implementation returns {@link HostPort#normalizeHost(String)} + */ + protected String formatAddrOrHost(String addr) + { + return HostPort.normalizeHost(addr); + } + protected HttpInput newHttpInput(HttpChannelState state) { return new HttpInput(state); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 635550aec58e..a3e06d9fd347 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -998,7 +998,7 @@ public String getLocalAddr() String name = InetAddress.getLocalHost().getHostAddress(); if (StringUtil.ALL_INTERFACES.equals(name)) return null; - return HostPort.normalizeHost(name); + return formatAddrOrHost(name); } catch (UnknownHostException e) { @@ -1014,7 +1014,7 @@ public String getLocalAddr() String result = address == null ? local.getHostString() : address.getHostAddress(); - return HostPort.normalizeHost(result); + return formatAddrOrHost(result); } /* @@ -1027,7 +1027,7 @@ public String getLocalName() { InetSocketAddress local = _channel.getLocalAddress(); if (local != null) - return HostPort.normalizeHost(local.getHostString()); + return formatAddrOrHost(local.getHostString()); } try @@ -1035,7 +1035,7 @@ public String getLocalName() String name = InetAddress.getLocalHost().getHostName(); if (StringUtil.ALL_INTERFACES.equals(name)) return null; - return HostPort.normalizeHost(name); + return formatAddrOrHost(name); } catch (UnknownHostException e) { @@ -1257,12 +1257,10 @@ public String getRemoteAddr() InetAddress address = remote.getAddress(); String result = address == null - ? remote.getHostString() - : address.getHostAddress(); - // Add IPv6 brackets if necessary, to be consistent - // with cases where _remote has been built from other - // sources such as forward headers or PROXY protocol. - return HostPort.normalizeHost(result); + ? remote.getHostString() + : address.getHostAddress(); + + return formatAddrOrHost(result); } /* @@ -1276,8 +1274,9 @@ public String getRemoteHost() remote = _channel.getRemoteAddress(); if (remote == null) return ""; + // We want the URI host, so add IPv6 brackets if necessary. - return HostPort.normalizeHost(remote.getHostString()); + return formatAddrOrHost(remote.getHostString()); } /* @@ -1403,7 +1402,7 @@ public String getScheme() public String getServerName() { MetaData.Request metadata = _metaData; - String name = metadata == null ? null : metadata.getURI().getHost(); + String name = metadata == null ? null : formatAddrOrHost(metadata.getURI().getHost()); // Return already determined host if (name != null) @@ -1425,19 +1424,19 @@ private String findServerName() { HostPortHttpField authority = (HostPortHttpField)host; metadata.getURI().setAuthority(authority.getHost(), authority.getPort()); - return authority.getHost(); + return formatAddrOrHost(authority.getHost()); } } // Return host from connection String name = getLocalName(); if (name != null) - return HostPort.normalizeHost(name); + return formatAddrOrHost(name); // Return the local host try { - return HostPort.normalizeHost(InetAddress.getLocalHost().getHostAddress()); + return formatAddrOrHost(InetAddress.getLocalHost().getHostAddress()); } catch (UnknownHostException e) { @@ -2604,4 +2603,9 @@ public T upgrade(Class handlerClass) throws IO { throw new ServletException("HttpServletRequest.upgrade() not supported in Jetty"); } + + private String formatAddrOrHost(String name) + { + return _channel == null ? HostPort.normalizeHost(name) : _channel.formatAddrOrHost(name); + } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java index 97ef7e7442cd..45cef634bccc 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java @@ -188,7 +188,7 @@ public enum ContextStatus INITIALIZED, DESTROYED } - + protected ContextStatus _contextStatus = ContextStatus.NOTSET; protected Context _scontext; private final AttributesMap _attributes; diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java index 8b6eeed62102..02ff5ba48314 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java @@ -26,6 +26,9 @@ import java.io.InputStream; import java.io.Reader; import java.io.UnsupportedEncodingException; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; @@ -52,6 +55,8 @@ import org.eclipse.jetty.http.HttpComplianceSection; import org.eclipse.jetty.http.HttpTester; import org.eclipse.jetty.http.MimeTypes; +import org.eclipse.jetty.io.Connection; +import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.server.LocalConnector.LocalEndPoint; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.handler.ContextHandler; @@ -96,12 +101,37 @@ public class RequestTest private Server _server; private LocalConnector _connector; private RequestHandler _handler; + private boolean _normalizeAddress = true; @BeforeEach public void init() throws Exception { _server = new Server(); - HttpConnectionFactory http = new HttpConnectionFactory(); + HttpConnectionFactory http = new HttpConnectionFactory() + { + @Override + public Connection newConnection(Connector connector, EndPoint endPoint) + { + HttpConnection conn = new HttpConnection(getHttpConfiguration(), connector, endPoint, getHttpCompliance(), isRecordHttpComplianceViolations()) + { + @Override + protected HttpChannelOverHttp newHttpChannel() + { + return new HttpChannelOverHttp(this, getConnector(), getHttpConfiguration(), getEndPoint(), this) + { + @Override + protected String formatAddrOrHost(String addr) + { + if (_normalizeAddress) + return super.formatAddrOrHost(addr); + return addr; + } + }; + } + }; + return configure(conn, connector, endPoint); + } + }; http.setInputBufferSize(1024); http.getHttpConfiguration().setRequestHeaderSize(512); http.getHttpConfiguration().setResponseHeaderSize(512); @@ -933,6 +963,65 @@ public boolean check(HttpServletRequest request, HttpServletResponse response) assertEquals("8888", results.get(i++)); } + @Test + public void testIPv6() throws Exception + { + final ArrayList results = new ArrayList<>(); + final InetAddress local = Inet6Address.getByAddress("localIPv6", new byte[]{ + 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8 + }); + final InetSocketAddress localAddr = new InetSocketAddress(local, 32768); + _handler._checker = new RequestTester() + { + @Override + public boolean check(HttpServletRequest request, HttpServletResponse response) + { + ((Request)request).setRemoteAddr(localAddr); + results.add(request.getRemoteAddr()); + results.add(request.getRemoteHost()); + results.add(Integer.toString(request.getRemotePort())); + results.add(request.getServerName()); + results.add(Integer.toString(request.getServerPort())); + results.add(request.getLocalAddr()); + results.add(Integer.toString(request.getLocalPort())); + return true; + } + }; + + _normalizeAddress = true; + String response = _connector.getResponse( + "GET / HTTP/1.1\n" + + "Host: [::1]:8888\n" + + "Connection: close\n" + + "\n"); + int i = 0; + assertThat(response, containsString("200 OK")); + assertEquals("[1:2:3:4:5:6:7:8]", results.get(i++)); + assertEquals("localIPv6", results.get(i++)); + assertEquals("32768", results.get(i++)); + assertEquals("[::1]", results.get(i++)); + assertEquals("8888", results.get(i++)); + assertEquals("0.0.0.0", results.get(i++)); + assertEquals("0", results.get(i)); + + _normalizeAddress = false; + results.clear(); + response = _connector.getResponse( + "GET / HTTP/1.1\n" + + "Host: [::1]:8888\n" + + "Connection: close\n" + + "\n"); + i = 0; + assertThat(response, containsString("200 OK")); + assertEquals("1:2:3:4:5:6:7:8", results.get(i++)); + assertEquals("localIPv6", results.get(i++)); + assertEquals("32768", results.get(i++)); + assertEquals("[::1]", results.get(i++)); + assertEquals("8888", results.get(i++)); + assertEquals("0.0.0.0", results.get(i++)); + assertEquals("0", results.get(i)); + } + @Test public void testContent() throws Exception { diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/HostPort.java b/jetty-util/src/main/java/org/eclipse/jetty/util/HostPort.java index a1aebd72e315..9888e2e9d646 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/HostPort.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/HostPort.java @@ -149,7 +149,7 @@ public String toString() public static String normalizeHost(String host) { // if it is normalized IPv6 or could not be IPv6, return - if (host.isEmpty() || host.charAt(0) == '[' || host.indexOf(':') < 0) + if (host == null || host.isEmpty() || host.charAt(0) == '[' || host.indexOf(':') < 0) return host; // normalize with [ ]