Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #7277 - Allow Request.getLocalName() and .getLocalPort() to be overridden #7283

Closed
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.ssl.SslConnection;
import org.eclipse.jetty.util.HostPort;
import org.eclipse.jetty.util.ProcessorUtils;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
Expand Down Expand Up @@ -161,7 +162,10 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co
private long _idleTimeout = 30000;
private String _defaultProtocol;
private ConnectionFactory _defaultConnectionFactory;
/* The name used to link up virtual host configuration to named connectors */
private String _name;
/* The authority used to override the connection local name/port (see ServletRequest.getLocalName(), and ServletRequest.getLocalPort()) */
private HostPort _localAuthority;
private int _acceptorPriorityDelta = -2;
private boolean _accepting = true;
private ThreadPoolBudget.Lease _lease;
Expand Down Expand Up @@ -298,6 +302,42 @@ public int getAcceptors()
return _acceptors.length;
}

/**
* @return Returns the optional local authority override
*/
@ManagedAttribute("local authority")
public HostPort getLocalAuthority()
{
return _localAuthority;
}
Comment on lines +306 to +309
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method should always return a local authority, either one set explicitly or one that is determined dynamically in doStart (or open).
Then the layers about can just ask for the authority and not have to check if null and then look at the address etc.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also make this a method on NetworkConnector

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a NetworkConnector specific concept.
We have UnixDomainConnector and LocalConnector that can benefit from setLocalAuthority() and are not network connectors.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We cannot "always return a local authority".
I tried it.
Going this route breaks expectations in ForwardRequestCustomizer and DetectorConnection and ProxyEndPoint behaviors, so I reverted it.


/**
* Optional override of connection local name/port used within application API layer
* when identifying the local host name/port of a connected endpoint.
*
* @param authority the full authority including host and port, or null to unset
*/
public void setLocalAuthority(String authority)
{
setLocalAuthority(new HostPort(authority));
}

/**
* Optional override of connection local name/port used within application API layer
* when identifying the local host name/port of a connected endpoint.
*
* @param authority the full authority including host and port, or null to unset
*/
public void setLocalAuthority(HostPort authority)
{
if (authority == null)
_localAuthority = null;
else if (!authority.hasHost() || !authority.hasPort())
throw new IllegalStateException("Local Authority must have host and port declared");
else
_localAuthority = authority;
}

@Override
protected void doStart() throws Exception
{
Expand All @@ -318,6 +358,7 @@ protected void doStart() throws Exception
}

_lease = ThreadPoolBudget.leaseFrom(getExecutor(), this, _acceptors.length);

super.doStart();

_stopping = new CountDownLatch(_acceptors.length);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
private MetaData.Response _committedMetaData;
private RequestLog _requestLog;
private long _oldIdleTimeout;
private String overriddenLocalName;

/**
* Bytes written after interception (eg after compression)
Expand Down Expand Up @@ -298,6 +299,73 @@ public EndPoint getEndPoint()
return _endPoint;
}

/**
* <p>Return the Local Name of the connected channel.</p>
*
* <p>
* This is the name after the connector is bound and the connection is accepted.
* The value is typically the local address and optionally the local host name
* if the local address is unavailable.
* </p>
* <p>
* Value can be overridden by {@link AbstractConnector#setLocalAuthority(HostPort)} for
* scenarios where Jetty is being an intermediary and the local name
* needs to be changed to satisfy public (pre-intermediary) HTTP behaviors
* such as absolute-URI creation (eg: Location response header).
* </p>
*
* @return the local name if overridden, or the local address, or
* null in the case of no local address (usually seen in connectors not based on IP networking).
*/
public String getLocalName()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not keep the getLocalAuthority() here and only convert to host/port in Request

{
Connector connector = getConnector();

if (connector instanceof AbstractConnector)
{
HostPort localAuthority = ((AbstractConnector)connector).getLocalAuthority();
if (localAuthority != null)
return localAuthority.getHost();
}

InetSocketAddress local = getLocalAddress();
if (local != null)
return local.getHostString();

Comment on lines +325 to +328
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should never fall through to here. If there Connector is a NetworkConnector it should always provide a local authority, otherwise return null.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment above about this feature not being NetworkConnector specific.

return null;
}

/**
* <p>Return the Local Port of the connected channel.</p>
*
* <p>
* This is the port the connector is bound to and is accepting connection on.
* </p>
* <p>
* Value can be overridden by {@link AbstractConnector#setLocalAuthority(HostPort)} for
* scenarios where Jetty is being an intermediary and the local port
* needs to be changed to satisfy public (pre-intermediary) HTTP behaviors
* such as absolute-URI creation (eg: Location response header).
* </p>
*
* @return the local authority port if overridden, or the local address port, or
* 0 in the case of no local address (usually seen in connectors not based on IP networking).
*/
public int getLocalPort()
{
Connector connector = getConnector();

if (connector instanceof AbstractConnector)
{
HostPort localAuthority = ((AbstractConnector)connector).getLocalAuthority();
if (localAuthority != null)
return localAuthority.getPort();
}

InetSocketAddress local = getLocalAddress();
return local == null ? 0 : local.getPort();
}

public InetSocketAddress getLocalAddress()
{
return _endPoint.getLocalAddress();
Expand Down
44 changes: 19 additions & 25 deletions jetty-server/src/main/java/org/eclipse/jetty/server/Request.java
Original file line number Diff line number Diff line change
Expand Up @@ -1025,22 +1025,11 @@ public String getLocalName()
{
if (_channel != null)
{
InetSocketAddress local = _channel.getLocalAddress();
if (local != null)
return formatAddrOrHost(local.getHostString());
String localName = _channel.getLocalName();
if (localName != null)
return formatAddrOrHost(localName);
}

try
{
String name = InetAddress.getLocalHost().getHostName();
if (StringUtil.ALL_INTERFACES.equals(name))
return null;
return formatAddrOrHost(name);
}
catch (UnknownHostException e)
{
LOG.ignore(e);
}
return null;
}

Expand All @@ -1050,10 +1039,16 @@ public String getLocalName()
@Override
public int getLocalPort()
{
if (_channel == null)
return 0;
InetSocketAddress local = _channel.getLocalAddress();
return local == null ? 0 : local.getPort();
if (_channel != null)
{
int localPort = _channel.getLocalPort();
if (localPort > 0)
return localPort;
InetSocketAddress local = _channel.getLocalAddress();
if (local != null)
return local.getPort();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not have to do this fall back yet again here. Either is a local authority (so we have a port) or there is not (and we don't)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried this.
Going this route breaks expectations in ForwardRequestCustomizer and DetectorConnection and ProxyEndPoint behaviors, so I reverted it.

}
return 0;
}

/*
Expand Down Expand Up @@ -1474,19 +1469,18 @@ private int findServerPort()
HttpField host = metadata == null ? null : metadata.getFields().getField(HttpHeader.HOST);
if (host != null)
{
// TODO is this needed now?
HostPortHttpField authority = (host instanceof HostPortHttpField)
? ((HostPortHttpField)host)
: new HostPortHttpField(host.getValue());
metadata.getURI().setAuthority(authority.getHost(), authority.getPort());
return authority.getPort();
if (authority.getHostPort().hasHost() && authority.getHostPort().hasPort())
{
metadata.getURI().setAuthority(authority.getHost(), authority.getPort());
return authority.getPort();
}
}

// Return host from connection
if (_channel != null)
return getLocalPort();

return -1;
return getLocalPort();
}

@Override
Expand Down
Loading