Skip to content

Commit

Permalink
Issue #7277 - Allow Request.getLocalName() and .getLocalPort() to…
Browse files Browse the repository at this point in the history
… be overridden (#7357)

* Issue #7277 - Allow `Request.getLocalName()` and `.getLocalPort()` to be overridden (#7316)

* Introduce `HttpConfiguration.setServerAuthority(HostPort)`
  to influence `ServletRequest.getServerName()` and `ServletRequest.getServerPort()`
* Introduce `HttpConfiguration.setLocalAddress(SocketAddress)`
  to influence `ServletRequest.getLocalName()`, `ServletRequest.getLocalPort()`, and `ServletRequest.getLocalAddr()`
* Correcting Request URI logic on abs-uri without authority
* Adding test cases

Signed-off-by: Joakim Erdfelt <[email protected]>
  • Loading branch information
joakime authored Jan 6, 2022
1 parent 3042f2b commit 1984d2d
Show file tree
Hide file tree
Showing 8 changed files with 996 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co
private long _shutdownIdleTimeout = 1000L;
private String _defaultProtocol;
private ConnectionFactory _defaultConnectionFactory;
/* The name used to link up virtual host configuration to named connectors */
private String _name;
private int _acceptorPriorityDelta = -2;
private boolean _accepting = true;
Expand Down Expand Up @@ -348,6 +349,7 @@ public boolean isShutdownDone()
}

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

super.doStart();

for (int i = 0; i < _acceptors.length; i++)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.ArrayList;
import java.util.EventListener;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicLong;
Expand Down Expand Up @@ -97,7 +98,7 @@ public abstract class HttpChannel implements Runnable, HttpOutput.Interceptor
public HttpChannel(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport)
{
_connector = connector;
_configuration = configuration;
_configuration = Objects.requireNonNull(configuration);
_endPoint = endPoint;
_transport = transport;

Expand Down Expand Up @@ -325,8 +326,81 @@ public EndPoint getEndPoint()
return _endPoint;
}

/**
* <p>Return the local name of the connected channel.</p>
*
* <p>
* This is the host name after the connector is bound and the connection is accepted.
* </p>
* <p>
* Value can be overridden by {@link HttpConfiguration#setLocalAddress(SocketAddress)}.
* </p>
* <p>
* Note: some connectors are not based on IP networking, and default behavior here will
* result in a null return. Use {@link HttpConfiguration#setLocalAddress(SocketAddress)}
* to set the value to an acceptable host name.
* </p>
*
* @return the local name, or null
*/
public String getLocalName()
{
HttpConfiguration httpConfiguration = getHttpConfiguration();
if (httpConfiguration != null)
{
SocketAddress localAddress = httpConfiguration.getLocalAddress();
if (localAddress instanceof InetSocketAddress)
return ((InetSocketAddress)localAddress).getHostName();
}

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

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 connections on.
* </p>
* <p>
* Value can be overridden by {@link HttpConfiguration#setLocalAddress(SocketAddress)}.
* </p>
* <p>
* Note: some connectors are not based on IP networking, and default behavior here will
* result in a value of 0 returned. Use {@link HttpConfiguration#setLocalAddress(SocketAddress)}
* to set the value to an acceptable port.
* </p>
*
* @return the local port, or 0 if unspecified
*/
public int getLocalPort()
{
HttpConfiguration httpConfiguration = getHttpConfiguration();
if (httpConfiguration != null)
{
SocketAddress localAddress = httpConfiguration.getLocalAddress();
if (localAddress instanceof InetSocketAddress)
return ((InetSocketAddress)localAddress).getPort();
}

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

public InetSocketAddress getLocalAddress()
{
HttpConfiguration httpConfiguration = getHttpConfiguration();
if (httpConfiguration != null)
{
SocketAddress localAddress = httpConfiguration.getLocalAddress();
if (localAddress instanceof InetSocketAddress)
return ((InetSocketAddress)localAddress);
}

SocketAddress local = _endPoint.getLocalSocketAddress();
if (local instanceof InetSocketAddress)
return (InetSocketAddress)local;
Expand All @@ -341,6 +415,18 @@ public InetSocketAddress getRemoteAddress()
return null;
}

/**
* @return return the HttpConfiguration server authority override
*/
public HostPort getServerAuthority()
{
HttpConfiguration httpConfiguration = getHttpConfiguration();
if (httpConfiguration != null)
return httpConfiguration.getServerAuthority();

return null;
}

/**
* If the associated response has the Expect header set to 100 Continue,
* then accessing the input stream indicates that the handler/servlet
Expand Down Expand Up @@ -551,7 +637,7 @@ public boolean handle()
// If send error is called we need to break.
if (checkAndPrepareUpgrade())
break;

// Set a close callback on the HttpOutput to make it an async callback
_response.completeOutput(Callback.from(NON_BLOCKING, () -> _state.completed(null), _state::completed));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package org.eclipse.jetty.server;

import java.io.IOException;
import java.net.SocketAddress;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
Expand All @@ -23,6 +24,7 @@
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http.UriCompliance;
import org.eclipse.jetty.util.HostPort;
import org.eclipse.jetty.util.Index;
import org.eclipse.jetty.util.Jetty;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
Expand Down Expand Up @@ -75,6 +77,8 @@ public class HttpConfiguration implements Dumpable
private CookieCompliance _responseCookieCompliance = CookieCompliance.RFC6265;
private boolean _notifyRemoteAsyncErrors = true;
private boolean _relativeRedirectAllowed;
private HostPort _serverAuthority;
private SocketAddress _localAddress;

/**
* <p>An interface that allows a request object to be customized
Expand Down Expand Up @@ -145,6 +149,8 @@ public HttpConfiguration(HttpConfiguration config)
_notifyRemoteAsyncErrors = config._notifyRemoteAsyncErrors;
_relativeRedirectAllowed = config._relativeRedirectAllowed;
_uriCompliance = config._uriCompliance;
_serverAuthority = config._serverAuthority;
_localAddress = config._localAddress;
}

/**
Expand Down Expand Up @@ -651,6 +657,69 @@ public boolean isRelativeRedirectAllowed()
return _relativeRedirectAllowed;
}

/**
* Get the SocketAddress override to be reported as the local address of all connections
*
* @return Returns the connection local address override or null.
*/
@ManagedAttribute("Local SocketAddress override")
public SocketAddress getLocalAddress()
{
return _localAddress;
}

/**
* <p>
* Specify the connection local address used within application API layer
* when identifying the local host name/port of a connected endpoint.
* </p>
* <p>
* This allows an override of higher level APIs, such as
* {@code ServletRequest.getLocalName()}, {@code ServletRequest.getLocalAddr()},
* and {@code ServletRequest.getLocalPort()}.
* </p>
*
* @param localAddress the address to use for host/addr/port, or null to reset to default behavior
*/
public void setLocalAddress(SocketAddress localAddress)
{
_localAddress = localAddress;
}

/**
* Get the Server authority override to be used if no authority is provided by a request.
*
* @return Returns the connection server authority (name/port) or null
*/
@ManagedAttribute("The server authority if none provided by requests")
public HostPort getServerAuthority()
{
return _serverAuthority;
}

/**
* <p>
* Specify the connection server authority (name/port) used within application API layer
* when identifying the server host name/port of a connected endpoint.
* </p>
*
* <p>
* This allows an override of higher level APIs, such as
* {@code ServletRequest.getServerName()}, and {@code ServletRequest.getServerPort()}.
* </p>
*
* @param authority the authority host (and optional port), or null to reset to default behavior
*/
public void setServerAuthority(HostPort authority)
{
if (authority == null)
_serverAuthority = null;
else if (!authority.hasHost())
throw new IllegalStateException("Server Authority must have host declared");
else
_serverAuthority = authority;
}

@Override
public String dump()
{
Expand Down
Loading

0 comments on commit 1984d2d

Please sign in to comment.