Issue #5247 - Priority based ForwardedRequestCustomizer
Signed-off-by: Joakim Erdfelt <joakim.erdfelt@gmail.com>
This commit is contained in:
parent
165e59b3e2
commit
f74cada660
|
@ -30,6 +30,7 @@ import org.eclipse.jetty.http.HttpField;
|
||||||
import org.eclipse.jetty.http.HttpFields;
|
import org.eclipse.jetty.http.HttpFields;
|
||||||
import org.eclipse.jetty.http.HttpHeader;
|
import org.eclipse.jetty.http.HttpHeader;
|
||||||
import org.eclipse.jetty.http.HttpScheme;
|
import org.eclipse.jetty.http.HttpScheme;
|
||||||
|
import org.eclipse.jetty.http.HttpURI;
|
||||||
import org.eclipse.jetty.http.QuotedCSVParser;
|
import org.eclipse.jetty.http.QuotedCSVParser;
|
||||||
import org.eclipse.jetty.server.HttpConfiguration.Customizer;
|
import org.eclipse.jetty.server.HttpConfiguration.Customizer;
|
||||||
import org.eclipse.jetty.util.ArrayTrie;
|
import org.eclipse.jetty.util.ArrayTrie;
|
||||||
|
@ -151,7 +152,7 @@ public class ForwardedRequestCustomizer implements Customizer
|
||||||
*/
|
*/
|
||||||
public void setForcedHost(String hostAndPort)
|
public void setForcedHost(String hostAndPort)
|
||||||
{
|
{
|
||||||
_forcedHost = new HostPortHttpField(new ForcedHostPort(hostAndPort));
|
_forcedHost = new HostPortHttpField(hostAndPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -398,26 +399,16 @@ public class ForwardedRequestCustomizer implements Customizer
|
||||||
request.setSecure(true);
|
request.setSecure(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (forwarded._server != null && forwarded._host instanceof PortSetHostPort)
|
if (forwarded.hasAuthority())
|
||||||
{
|
{
|
||||||
httpFields.put(new HostPortHttpField(forwarded._server, forwarded._host.getPort()));
|
httpFields.put(new HostPortHttpField(forwarded._authority._host, forwarded._authority._port));
|
||||||
request.setAuthority(forwarded._server, forwarded._host.getPort());
|
request.setAuthority(forwarded._authority._host, forwarded._authority._port);
|
||||||
}
|
|
||||||
else if (forwarded._host != null)
|
|
||||||
{
|
|
||||||
httpFields.put(new HostPortHttpField(forwarded._host));
|
|
||||||
request.setAuthority(forwarded._host.getHost(), forwarded._host.getPort());
|
|
||||||
}
|
|
||||||
else if (forwarded._server != null)
|
|
||||||
{
|
|
||||||
httpFields.put(new HostPortHttpField(forwarded._server));
|
|
||||||
request.setAuthority(forwarded._server, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (forwarded._for != null)
|
if (forwarded.hasFor())
|
||||||
{
|
{
|
||||||
int port = forwarded._for.getPort() > 0 ? forwarded._for.getPort() : request.getRemotePort();
|
int port = forwarded._for._port > 0 ? forwarded._for._port : request.getRemotePort();
|
||||||
request.setRemoteAddr(InetSocketAddress.createUnresolved(forwarded._for.getHost(), port));
|
request.setRemoteAddr(InetSocketAddress.createUnresolved(forwarded._for._host, port));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,7 +417,7 @@ public class ForwardedRequestCustomizer implements Customizer
|
||||||
throw new BadMessageException("Bad header value for " + field.getName(), t);
|
throw new BadMessageException("Bad header value for " + field.getName(), t);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getLeftMost(String headerValue)
|
protected static String getLeftMost(String headerValue)
|
||||||
{
|
{
|
||||||
if (headerValue == null)
|
if (headerValue == null)
|
||||||
return null;
|
return null;
|
||||||
|
@ -479,23 +470,23 @@ public class ForwardedRequestCustomizer implements Customizer
|
||||||
size += 128; // experimented good baseline size
|
size += 128; // experimented good baseline size
|
||||||
_handles = new ArrayTrie<>(size);
|
_handles = new ArrayTrie<>(size);
|
||||||
|
|
||||||
if (updateForwardedHandle(lookup, getForwardedCipherSuiteHeader(), "handleCipherSuite"))
|
|
||||||
continue;
|
|
||||||
if (updateForwardedHandle(lookup, getForwardedSslSessionIdHeader(), "handleSslSessionId"))
|
|
||||||
continue;
|
|
||||||
if (updateForwardedHandle(lookup, getForwardedHeader(), "handleRFC7239"))
|
if (updateForwardedHandle(lookup, getForwardedHeader(), "handleRFC7239"))
|
||||||
continue;
|
continue;
|
||||||
if (updateForwardedHandle(lookup, getForwardedForHeader(), "handleFor"))
|
if (updateForwardedHandle(lookup, getForwardedHostHeader(), "handleForwardedHost"))
|
||||||
continue;
|
continue;
|
||||||
if (updateForwardedHandle(lookup, getForwardedPortHeader(), "handlePort"))
|
if (updateForwardedHandle(lookup, getForwardedForHeader(), "handleForwardedFor"))
|
||||||
continue;
|
continue;
|
||||||
if (updateForwardedHandle(lookup, getForwardedHostHeader(), "handleHost"))
|
if (updateForwardedHandle(lookup, getForwardedPortHeader(), "handleForwardedPort"))
|
||||||
continue;
|
continue;
|
||||||
if (updateForwardedHandle(lookup, getForwardedProtoHeader(), "handleProto"))
|
if (updateForwardedHandle(lookup, getForwardedProtoHeader(), "handleProto"))
|
||||||
continue;
|
continue;
|
||||||
if (updateForwardedHandle(lookup, getForwardedHttpsHeader(), "handleHttps"))
|
if (updateForwardedHandle(lookup, getForwardedHttpsHeader(), "handleHttps"))
|
||||||
continue;
|
continue;
|
||||||
if (updateForwardedHandle(lookup, getForwardedServerHeader(), "handleServer"))
|
if (updateForwardedHandle(lookup, getForwardedServerHeader(), "handleForwardedServer"))
|
||||||
|
continue;
|
||||||
|
if (updateForwardedHandle(lookup, getForwardedCipherSuiteHeader(), "handleCipherSuite"))
|
||||||
|
continue;
|
||||||
|
if (updateForwardedHandle(lookup, getForwardedSslSessionIdHeader(), "handleSslSessionId"))
|
||||||
continue;
|
continue;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -516,53 +507,84 @@ public class ForwardedRequestCustomizer implements Customizer
|
||||||
return !_handles.put(headerName, lookup.findVirtual(Forwarded.class, forwardedMethodName, type));
|
return !_handles.put(headerName, lookup.findVirtual(Forwarded.class, forwardedMethodName, type));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ForcedHostPort extends HostPort
|
private static class MutableHostPort
|
||||||
{
|
{
|
||||||
ForcedHostPort(String authority)
|
String _host;
|
||||||
|
int _hostPriority = -1;
|
||||||
|
int _port = -1;
|
||||||
|
int _portPriority = -1;
|
||||||
|
|
||||||
|
public void setHost(String host, int priority)
|
||||||
{
|
{
|
||||||
super(authority);
|
if (priority > _hostPriority)
|
||||||
|
{
|
||||||
|
_host = host;
|
||||||
|
_hostPriority = priority;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPort(int port, int priority)
|
||||||
|
{
|
||||||
|
if (port > 0 && priority > _portPriority)
|
||||||
|
{
|
||||||
|
_port = port;
|
||||||
|
_portPriority = priority;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHostPort(HostPort hostPort, int priority)
|
||||||
|
{
|
||||||
|
if (_host == null || priority > _hostPriority)
|
||||||
|
{
|
||||||
|
_host = hostPort.getHost();
|
||||||
|
_hostPriority = priority;
|
||||||
|
|
||||||
|
// Is this an authoritative port?
|
||||||
|
if (priority == FORWARDED_PRIORITY)
|
||||||
|
{
|
||||||
|
// Trust port (even if 0/unset)
|
||||||
|
_port = hostPort.getPort();
|
||||||
|
_portPriority = priority;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setPort(hostPort.getPort(), priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
final StringBuilder sb = new StringBuilder("MutableHostPort{");
|
||||||
|
sb.append("host='").append(_host).append("'/").append(_hostPriority);
|
||||||
|
sb.append(", port=").append(_port);
|
||||||
|
sb.append("/").append(_portPriority);
|
||||||
|
sb.append('}');
|
||||||
|
return sb.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class PossiblyPartialHostPort extends HostPort
|
private static final int MAX_PRIORITY = 999;
|
||||||
{
|
private static final int FORWARDED_PRIORITY = 8;
|
||||||
PossiblyPartialHostPort(String authority)
|
private static final int XFORWARDED_HOST_PRIORITY = 7;
|
||||||
{
|
private static final int XFORWARDED_FOR_PRIORITY = 6;
|
||||||
super(authority);
|
private static final int XFORWARDED_PORT_PRIORITY = 5;
|
||||||
}
|
private static final int XFORWARDED_SERVER_PRIORITY = 4;
|
||||||
|
// HostPort seen in Request metadata
|
||||||
protected PossiblyPartialHostPort(String host, int port)
|
private static final int REQUEST_PRIORITY = 3;
|
||||||
{
|
private static final int XFORWARDED_PROTO_PRIORITY = 2;
|
||||||
super(host, port);
|
private static final int XPROXIED_HTTPS_PRIORITY = 1;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class PortSetHostPort extends PossiblyPartialHostPort
|
|
||||||
{
|
|
||||||
PortSetHostPort(String host, int port)
|
|
||||||
{
|
|
||||||
super(host, port);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class Rfc7239HostPort extends HostPort
|
|
||||||
{
|
|
||||||
Rfc7239HostPort(String authority)
|
|
||||||
{
|
|
||||||
super(authority);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class Forwarded extends QuotedCSVParser
|
private class Forwarded extends QuotedCSVParser
|
||||||
{
|
{
|
||||||
HttpConfiguration _config;
|
HttpConfiguration _config;
|
||||||
Request _request;
|
Request _request;
|
||||||
|
|
||||||
boolean _protoRfc7239;
|
MutableHostPort _authority;
|
||||||
|
MutableHostPort _for;
|
||||||
String _proto;
|
String _proto;
|
||||||
HostPort _for;
|
int _protoPriority = -1;
|
||||||
HostPort _host;
|
|
||||||
String _server;
|
|
||||||
|
|
||||||
public Forwarded(Request request, HttpConfiguration config)
|
public Forwarded(Request request, HttpConfiguration config)
|
||||||
{
|
{
|
||||||
|
@ -570,7 +592,45 @@ public class ForwardedRequestCustomizer implements Customizer
|
||||||
_request = request;
|
_request = request;
|
||||||
_config = config;
|
_config = config;
|
||||||
if (_forcedHost != null)
|
if (_forcedHost != null)
|
||||||
_host = _forcedHost.getHostPort();
|
{
|
||||||
|
getAuthority().setHostPort(_forcedHost.getHostPort(), MAX_PRIORITY);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HttpURI requestURI = request.getMetaData().getURI();
|
||||||
|
if (requestURI.getHost() != null)
|
||||||
|
{
|
||||||
|
getAuthority().setHostPort(new HostPort(requestURI.getHost(), requestURI.getPort()), REQUEST_PRIORITY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasAuthority()
|
||||||
|
{
|
||||||
|
return _authority != null && _authority._host != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasFor()
|
||||||
|
{
|
||||||
|
return _for != null && _for._host != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MutableHostPort getAuthority()
|
||||||
|
{
|
||||||
|
if (_authority == null)
|
||||||
|
{
|
||||||
|
_authority = new MutableHostPort();
|
||||||
|
}
|
||||||
|
return _authority;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MutableHostPort getFor()
|
||||||
|
{
|
||||||
|
if (_for == null)
|
||||||
|
{
|
||||||
|
_for = new MutableHostPort();
|
||||||
|
}
|
||||||
|
return _for;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
|
@ -596,80 +656,47 @@ public class ForwardedRequestCustomizer implements Customizer
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public void handleHost(HttpField field)
|
public void handleForwardedHost(HttpField field)
|
||||||
{
|
{
|
||||||
HostPort hostField = new HostPort(getLeftMost(field.getValue()));
|
updateAuthority(getLeftMost(field.getValue()), XFORWARDED_HOST_PRIORITY);
|
||||||
|
|
||||||
if (getForwardedPortAsAuthority() && !StringUtil.isEmpty(getForwardedPortHeader()))
|
|
||||||
{
|
|
||||||
if (_host == null)
|
|
||||||
_host = new PossiblyPartialHostPort(hostField.getHost(), hostField.getPort());
|
|
||||||
else if (_host instanceof PortSetHostPort)
|
|
||||||
_host = new HostPort(hostField.getHost(), hostField.getPort() > 0 ? hostField.getPort() : _host.getPort());
|
|
||||||
}
|
|
||||||
else if (_host == null)
|
|
||||||
{
|
|
||||||
_host = hostField;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public void handleServer(HttpField field)
|
public void handleForwardedFor(HttpField field)
|
||||||
|
{
|
||||||
|
getFor().setHostPort(new HostPort(getLeftMost(field.getValue())), XFORWARDED_FOR_PRIORITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public void handleForwardedServer(HttpField field)
|
||||||
{
|
{
|
||||||
if (getProxyAsAuthority())
|
if (getProxyAsAuthority())
|
||||||
return;
|
return;
|
||||||
_server = getLeftMost(field.getValue());
|
updateAuthority(getLeftMost(field.getValue()), XFORWARDED_SERVER_PRIORITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public void handleForwardedPort(HttpField field)
|
||||||
|
{
|
||||||
|
int port = HostPort.parsePort(getLeftMost(field.getValue()));
|
||||||
|
|
||||||
|
updatePort(port, XFORWARDED_PORT_PRIORITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public void handleProto(HttpField field)
|
public void handleProto(HttpField field)
|
||||||
{
|
{
|
||||||
if (_proto == null)
|
updateProto(getLeftMost(field.getValue()), XFORWARDED_PROTO_PRIORITY);
|
||||||
_proto = getLeftMost(field.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public void handleFor(HttpField field)
|
|
||||||
{
|
|
||||||
String authority = getLeftMost(field.getValue());
|
|
||||||
if (!getForwardedPortAsAuthority() && !StringUtil.isEmpty(getForwardedPortHeader()))
|
|
||||||
{
|
|
||||||
if (_for == null)
|
|
||||||
_for = new PossiblyPartialHostPort(authority);
|
|
||||||
else if (_for instanceof PortSetHostPort)
|
|
||||||
_for = new HostPort(HostPort.normalizeHost(authority), _for.getPort());
|
|
||||||
}
|
|
||||||
else if (_for == null)
|
|
||||||
{
|
|
||||||
_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(), port);
|
|
||||||
else if (_for instanceof PossiblyPartialHostPort && _for.getPort() <= 0)
|
|
||||||
_for = new HostPort(HostPort.normalizeHost(_for.getHost()), port);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (_host == null)
|
|
||||||
_host = new PortSetHostPort(_request.getServerName(), port);
|
|
||||||
else if (_host instanceof PossiblyPartialHostPort && _host.getPort() <= 0)
|
|
||||||
_host = new HostPort(HostPort.normalizeHost(_host.getHost()), port);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public void handleHttps(HttpField field)
|
public void handleHttps(HttpField field)
|
||||||
{
|
{
|
||||||
if (_proto == null && ("on".equalsIgnoreCase(field.getValue()) || "true".equalsIgnoreCase(field.getValue())))
|
if ("on".equalsIgnoreCase(field.getValue()) || "true".equalsIgnoreCase(field.getValue()))
|
||||||
_proto = HttpScheme.HTTPS.asString();
|
{
|
||||||
|
updateProto(HttpScheme.HTTPS.asString(), XPROXIED_HTTPS_PRIORITY);
|
||||||
|
updatePort(443, XPROXIED_HTTPS_PRIORITY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
|
@ -692,30 +719,60 @@ public class ForwardedRequestCustomizer implements Customizer
|
||||||
break;
|
break;
|
||||||
if (value.startsWith("_") || "unknown".equals(value))
|
if (value.startsWith("_") || "unknown".equals(value))
|
||||||
break;
|
break;
|
||||||
if (_host == null || !(_host instanceof Rfc7239HostPort))
|
getAuthority().setHostPort(new HostPort(value), FORWARDED_PRIORITY);
|
||||||
_host = new Rfc7239HostPort(value);
|
|
||||||
break;
|
break;
|
||||||
case "for":
|
case "for":
|
||||||
if (value.startsWith("_") || "unknown".equals(value))
|
if (value.startsWith("_") || "unknown".equals(value))
|
||||||
break;
|
break;
|
||||||
if (_for == null || !(_for instanceof Rfc7239HostPort))
|
getFor().setHostPort(new HostPort(value), FORWARDED_PRIORITY);
|
||||||
_for = new Rfc7239HostPort(value);
|
|
||||||
break;
|
break;
|
||||||
case "host":
|
case "host":
|
||||||
if (value.startsWith("_") || "unknown".equals(value))
|
if (value.startsWith("_") || "unknown".equals(value))
|
||||||
break;
|
break;
|
||||||
if (_host == null || !(_host instanceof Rfc7239HostPort))
|
getAuthority().setHostPort(new HostPort(value), FORWARDED_PRIORITY);
|
||||||
_host = new Rfc7239HostPort(value);
|
|
||||||
break;
|
break;
|
||||||
case "proto":
|
case "proto":
|
||||||
if (_proto == null || !_protoRfc7239)
|
updateProto(value, FORWARDED_PRIORITY);
|
||||||
{
|
getAuthority().setPort(getPortForProto(value), FORWARDED_PRIORITY);
|
||||||
_protoRfc7239 = true;
|
|
||||||
_proto = value;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int getPortForProto(String proto)
|
||||||
|
{
|
||||||
|
if ("http".equalsIgnoreCase(proto))
|
||||||
|
return 80;
|
||||||
|
if ("https".equalsIgnoreCase(proto))
|
||||||
|
return 443;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateAuthority(String value, int priority)
|
||||||
|
{
|
||||||
|
HostPort hostField = new HostPort(value);
|
||||||
|
getAuthority().setHostPort(hostField, priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updatePort(int port, int priority)
|
||||||
|
{
|
||||||
|
if (getForwardedPortAsAuthority())
|
||||||
|
{
|
||||||
|
getAuthority().setPort(port, priority);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
getFor().setPort(port, priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateProto(String proto, int priority)
|
||||||
|
{
|
||||||
|
if (priority > _protoPriority)
|
||||||
|
{
|
||||||
|
_proto = proto;
|
||||||
|
_protoPriority = priority;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue