Fix #6860 IPv6 Format (#6861) (#6885)

Fix #6860 IPv6 format by adding an extensible HttpChannel method

Signed-off-by: Greg Wilkins <gregw@webtide.com>
Co-authored-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
Greg Wilkins 2021-09-22 21:03:23 +10:00 committed by GitHub
parent f12c5b668c
commit 9a14de058d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 119 additions and 16 deletions

View File

@ -50,6 +50,7 @@ import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ErrorHandler; import org.eclipse.jetty.server.handler.ErrorHandler;
import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.HostPort;
import org.eclipse.jetty.util.SharedBlockingCallback.Blocker; import org.eclipse.jetty.util.SharedBlockingCallback.Blocker;
import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.thread.Scheduler; import org.eclipse.jetty.util.thread.Scheduler;
@ -122,6 +123,15 @@ public abstract class HttpChannel implements Runnable, HttpOutput.Interceptor
return _state.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);
}
private HttpInput newHttpInput(HttpChannelState state) private HttpInput newHttpInput(HttpChannelState state)
{ {
return new HttpInput(state); return new HttpInput(state);

View File

@ -985,7 +985,7 @@ public class Request implements HttpServletRequest
String name = InetAddress.getLocalHost().getHostAddress(); String name = InetAddress.getLocalHost().getHostAddress();
if (StringUtil.ALL_INTERFACES.equals(name)) if (StringUtil.ALL_INTERFACES.equals(name))
return null; return null;
return HostPort.normalizeHost(name); return formatAddrOrHost(name);
} }
catch (UnknownHostException e) catch (UnknownHostException e)
{ {
@ -1001,7 +1001,7 @@ public class Request implements HttpServletRequest
String result = address == null String result = address == null
? local.getHostString() ? local.getHostString()
: address.getHostAddress(); : address.getHostAddress();
return HostPort.normalizeHost(result); return formatAddrOrHost(result);
} }
@Override @Override
@ -1011,7 +1011,7 @@ public class Request implements HttpServletRequest
{ {
InetSocketAddress local = _channel.getLocalAddress(); InetSocketAddress local = _channel.getLocalAddress();
if (local != null) if (local != null)
return HostPort.normalizeHost(local.getHostString()); return formatAddrOrHost(local.getHostString());
} }
try try
@ -1019,7 +1019,7 @@ public class Request implements HttpServletRequest
String name = InetAddress.getLocalHost().getHostName(); String name = InetAddress.getLocalHost().getHostName();
if (StringUtil.ALL_INTERFACES.equals(name)) if (StringUtil.ALL_INTERFACES.equals(name))
return null; return null;
return HostPort.normalizeHost(name); return formatAddrOrHost(name);
} }
catch (UnknownHostException e) catch (UnknownHostException e)
{ {
@ -1211,12 +1211,10 @@ public class Request implements HttpServletRequest
InetAddress address = remote.getAddress(); InetAddress address = remote.getAddress();
String result = address == null String result = address == null
? remote.getHostString() ? remote.getHostString()
: address.getHostAddress(); : address.getHostAddress();
// Add IPv6 brackets if necessary, to be consistent
// with cases where _remote has been built from other return formatAddrOrHost(result);
// sources such as forward headers or PROXY protocol.
return HostPort.normalizeHost(result);
} }
@Override @Override
@ -1227,8 +1225,9 @@ public class Request implements HttpServletRequest
remote = _channel.getRemoteAddress(); remote = _channel.getRemoteAddress();
if (remote == null) if (remote == null)
return ""; return "";
// We want the URI host, so add IPv6 brackets if necessary. // We want the URI host, so add IPv6 brackets if necessary.
return HostPort.normalizeHost(remote.getHostString()); return formatAddrOrHost(remote.getHostString());
} }
@Override @Override
@ -1322,7 +1321,7 @@ public class Request implements HttpServletRequest
@Override @Override
public String getServerName() public String getServerName()
{ {
return _uri == null ? findServerName() : _uri.getHost(); return _uri == null ? findServerName() : formatAddrOrHost(_uri.getHost());
} }
private String findServerName() private String findServerName()
@ -1330,12 +1329,12 @@ public class Request implements HttpServletRequest
// Return host from connection // Return host from connection
String name = getLocalName(); String name = getLocalName();
if (name != null) if (name != null)
return HostPort.normalizeHost(name); return formatAddrOrHost(name);
// Return the local host // Return the local host
try try
{ {
return HostPort.normalizeHost(InetAddress.getLocalHost().getHostAddress()); return formatAddrOrHost(InetAddress.getLocalHost().getHostAddress());
} }
catch (UnknownHostException e) catch (UnknownHostException e)
{ {
@ -2541,4 +2540,9 @@ public class Request implements HttpServletRequest
// which we recover from the IncludeAttributes wrapper. // which we recover from the IncludeAttributes wrapper.
return findServletPathMapping(); return findServletPathMapping();
} }
private String formatAddrOrHost(String name)
{
return _channel == null ? HostPort.normalizeHost(name) : _channel.formatAddrOrHost(name);
}
} }

View File

@ -20,6 +20,9 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.Reader; import java.io.Reader;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@ -59,6 +62,8 @@ import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.http.UriCompliance; import org.eclipse.jetty.http.UriCompliance;
import org.eclipse.jetty.http.pathmap.ServletPathSpec; import org.eclipse.jetty.http.pathmap.ServletPathSpec;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.logging.StacklessLogging; import org.eclipse.jetty.logging.StacklessLogging;
import org.eclipse.jetty.server.LocalConnector.LocalEndPoint; import org.eclipse.jetty.server.LocalConnector.LocalEndPoint;
import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.handler.AbstractHandler;
@ -105,12 +110,37 @@ public class RequestTest
private Server _server; private Server _server;
private LocalConnector _connector; private LocalConnector _connector;
private RequestHandler _handler; private RequestHandler _handler;
private boolean _normalizeAddress = true;
@BeforeEach @BeforeEach
public void init() throws Exception public void init() throws Exception
{ {
_server = new Server(); _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, 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.setInputBufferSize(1024);
http.getHttpConfiguration().setRequestHeaderSize(512); http.getHttpConfiguration().setRequestHeaderSize(512);
http.getHttpConfiguration().setResponseHeaderSize(512); http.getHttpConfiguration().setResponseHeaderSize(512);
@ -858,6 +888,65 @@ public class RequestTest
assertEquals("8888", results.get(i)); assertEquals("8888", results.get(i));
} }
@Test
public void testIPv6() throws Exception
{
final ArrayList<String> 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 @Test
public void testContent() throws Exception public void testContent() throws Exception
{ {

View File

@ -144,7 +144,7 @@ public class HostPort
public static String normalizeHost(String host) public static String normalizeHost(String host)
{ {
// if it is normalized IPv6 or could not be IPv6, return // 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; return host;
// normalize with [ ] // normalize with [ ]