Merge pull request #4648 from eclipse/jetty-9.4.x-4645-forwardedPortException

Issue #4645 - better error message for empty X-Forwarded-Port value
This commit is contained in:
Lachlan 2020-03-16 10:35:08 +11:00 committed by GitHub
commit b497827df0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 67 additions and 21 deletions

View File

@ -24,6 +24,7 @@ import java.lang.invoke.MethodType;
import java.net.InetSocketAddress;
import javax.servlet.ServletRequest;
import org.eclipse.jetty.http.BadMessageException;
import org.eclipse.jetty.http.HostPortHttpField;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields;
@ -376,18 +377,18 @@ public class ForwardedRequestCustomizer implements Customizer
// Do a single pass through the header fields as it is a more efficient single iteration.
Forwarded forwarded = new Forwarded(request, config);
try
for (HttpField field : httpFields)
{
for (HttpField field : httpFields)
try
{
MethodHandle handle = _handles.get(field.getName());
if (handle != null)
handle.invoke(forwarded, field);
}
}
catch (Throwable e)
{
throw new RuntimeException(e);
catch (Throwable t)
{
onError(field, t);
}
}
if (forwarded._proto != null)
@ -420,6 +421,11 @@ public class ForwardedRequestCustomizer implements Customizer
}
}
protected void onError(HttpField field, Throwable t)
{
throw new BadMessageException("Bad header value for " + field.getName(), t);
}
protected String getLeftMost(String headerValue)
{
if (headerValue == null)
@ -623,35 +629,37 @@ public class ForwardedRequestCustomizer implements Customizer
@SuppressWarnings("unused")
public void handleFor(HttpField field)
{
String authority = getLeftMost(field.getValue());
if (!getForwardedPortAsAuthority() && !StringUtil.isEmpty(getForwardedPortHeader()))
{
if (_for == null)
_for = new PossiblyPartialHostPort(getLeftMost(field.getValue()));
_for = new PossiblyPartialHostPort(authority);
else if (_for instanceof PortSetHostPort)
_for = new HostPort(HostPort.normalizeHost(getLeftMost(field.getValue())), _for.getPort());
_for = new HostPort(HostPort.normalizeHost(authority), _for.getPort());
}
else if (_for == null)
{
_for = new HostPort(getLeftMost(field.getValue()));
_for = new HostPort(authority);
}
}
@SuppressWarnings("unused")
public void handlePort(HttpField field)
{
int port = HostPort.parsePort(getLeftMost(field.getValue()));
if (!getForwardedPortAsAuthority())
{
if (_for == null)
_for = new PortSetHostPort(_request.getRemoteHost(), Integer.parseInt(getLeftMost(field.getValue())));
_for = new PortSetHostPort(_request.getRemoteHost(), port);
else if (_for instanceof PossiblyPartialHostPort && _for.getPort() <= 0)
_for = new HostPort(HostPort.normalizeHost(_for.getHost()), Integer.parseInt(getLeftMost(field.getValue())));
_for = new HostPort(HostPort.normalizeHost(_for.getHost()), port);
}
else
{
if (_host == null)
_host = new PortSetHostPort(_request.getServerName(), Integer.parseInt(getLeftMost(field.getValue())));
_host = new PortSetHostPort(_request.getServerName(), port);
else if (_host instanceof PossiblyPartialHostPort && _host.getPort() <= 0)
_host = new HostPort(HostPort.normalizeHost(_host.getHost()), Integer.parseInt(getLeftMost(field.getValue())));
_host = new HostPort(HostPort.normalizeHost(_host.getHost()), port);
}
}

View File

@ -32,6 +32,7 @@ import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
@ -619,6 +620,25 @@ public class ForwardedRequestCustomizerTest
expectations.accept(actual);
}
@Test
public void testBadInput() throws Exception
{
Request request = new Request("Bad port value")
.headers(
"GET / HTTP/1.1",
"Host: myhost",
"X-Forwarded-Port: "
);
request.configure(customizer);
String rawRequest = request.getRawRequest((header) -> header);
System.out.println(rawRequest);
HttpTester.Response response = HttpTester.parseResponse(connector.getResponse(rawRequest));
assertThat("status", response.getStatus(), is(400));
}
private static class Request
{
String description;

View File

@ -32,7 +32,7 @@ public class HostPort
private final String _host;
private final int _port;
public HostPort(String host, int port) throws IllegalArgumentException
public HostPort(String host, int port)
{
_host = host;
_port = port;
@ -61,7 +61,7 @@ public class HostPort
{
if (authority.charAt(close + 1) != ':')
throw new IllegalArgumentException("Bad IPv6 port");
_port = StringUtil.toInt(authority, close + 2);
_port = parsePort(authority.substring(close + 2));
}
else
_port = 0;
@ -80,7 +80,7 @@ public class HostPort
else
{
_host = authority.substring(0, c);
_port = StringUtil.toInt(authority, c + 1);
_port = parsePort(authority.substring(c + 1));
}
}
else
@ -103,10 +103,6 @@ public class HostPort
}
};
}
if (_host == null)
throw new IllegalArgumentException("Bad host");
if (_port < 0)
throw new IllegalArgumentException("Bad port");
}
/**
@ -163,4 +159,23 @@ public class HostPort
// normalize with [ ]
return "[" + host + "]";
}
/**
* Parse a string representing a port validating it is a valid port value.
*
* @param rawPort the port string.
* @return the integer value for the port.
* @throws IllegalArgumentException
*/
public static int parsePort(String rawPort) throws IllegalArgumentException
{
if (StringUtil.isEmpty(rawPort))
throw new IllegalArgumentException("Bad port");
int port = Integer.parseInt(rawPort);
if (port <= 0 || port > 65535)
throw new IllegalArgumentException("Bad port");
return port;
}
}

View File

@ -43,6 +43,7 @@ public class HostPortTest
Arguments.of("[0::0::0::1]", "[0::0::0::1]", null),
Arguments.of("[0::0::0::1]:80", "[0::0::0::1]", "80"),
Arguments.of("0:1:2:3:4:5:6", "[0:1:2:3:4:5:6]", null),
Arguments.of("127.0.0.1:65535", "127.0.0.1", "65535"),
// Localhost tests
Arguments.of("localhost:80", "localhost", "80"),
Arguments.of("127.0.0.1:80", "127.0.0.1", "80"),
@ -79,7 +80,9 @@ public class HostPortTest
"[0::0::0::0::1]:xxx",
"host:-80",
"127.0.0.1:-80",
"[0::0::0::0::1]:-80")
"[0::0::0::0::1]:-80",
"127.0.0.1:65536"
)
.map(Arguments::of);
}