Move ServeAs code to Request, so it can be used elsewhere

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
Lachlan Roberts 2023-08-23 12:32:46 +10:00
parent 7e875d1411
commit 5a28d48b93
8 changed files with 79 additions and 126 deletions

View File

@ -555,14 +555,7 @@ public class HTTPServerDocs
HttpURI newURI = HttpURI.build(uri).path(newPath).asImmutable();
// Modify the request object by wrapping the HttpURI
Request newRequest = new Request.Wrapper(request)
{
@Override
public HttpURI getHttpURI()
{
return newURI;
}
};
Request newRequest = Request.serveAs(request, newURI);
// Forward to the next Handler using the wrapped Request.
return super.handle(newRequest, response, callback);

View File

@ -17,7 +17,6 @@ import java.security.Principal;
import org.eclipse.jetty.http.HttpException;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.security.IdentityService.RunAsToken;
import org.eclipse.jetty.security.authentication.LoginAuthenticator;
import org.eclipse.jetty.security.internal.DeferredAuthenticationState;
@ -275,45 +274,9 @@ public interface AuthenticationState extends Request.AuthenticationState
* The {@link SecurityHandler} will use this to wrap the {@link Request}.
* And then will return a {@link Deferred} authentication to bypass security constraints.
*/
class ServeAs implements AuthenticationState
interface ServeAs extends AuthenticationState
{
private final HttpURI _uri;
public ServeAs(HttpURI uri)
{
_uri = uri;
}
public Request wrap(Request request)
{
if (request.getHttpURI().equals(_uri))
return request;
return new Request.Wrapper(request)
{
@Override
public HttpURI getHttpURI()
{
return _uri;
}
};
}
/**
* This interface can be used inside a {@link ServeAs} implementation to wrap the request
* changing its target to a given path. If a {@link Request} implements this interface it can
* be obtained with the {@link Request#as(Request, Class)} method.
*/
public interface PathWrapper
{
/**
* Wraps a request but changes the path so that it can be served to a different target.
* @param request the original request.
* @param uri the uri of the new target.
* @return the request wrapped to the new target.
*/
Request serveAs(Request request, HttpURI uri);
}
Request wrap(Request request);
}
static Deferred defer(LoginAuthenticator loginAuthenticator)

View File

@ -360,17 +360,7 @@ public class FormAuthenticator extends LoginAuthenticator
{
String newPath = URIUtil.addPaths(request.getContext().getContextPath(), path);
HttpURI.Mutable newUri = HttpURI.build(request.getHttpURI()).pathQuery(newPath);
return new AuthenticationState.ServeAs(newUri)
{
@Override
public Request wrap(Request request)
{
PathWrapper serveAs = Request.as(request, PathWrapper.class);
if (serveAs != null)
return serveAs.serveAs(request, newUri);
return super.wrap(request);
}
};
return (AuthenticationState.ServeAs)req -> Request.serveAs(req, newUri);
}
catch (Throwable t)
{
@ -383,7 +373,7 @@ public class FormAuthenticator extends LoginAuthenticator
{
if (_formErrorPage == null)
Response.writeError(request, response, callback, HttpStatus.FORBIDDEN_403);
else if (_dispatch && _formErrorPage != null)
else if (_dispatch)
return dispatch(_formErrorPage, request, response, callback);
else
Response.sendRedirect(request, response, callback, encodeURL(URIUtil.addPaths(request.getContext().getContextPath(), _formErrorPage), request), true);

View File

@ -583,6 +583,50 @@ public interface Request extends Attributes, Content.Source
return location;
}
/**
* This interface will be detected by the {@link #wrap(Request, HttpURI)} static method to wrap the request
* changing its target to a given path. If a {@link Request} implements this interface it can
* be obtained with the {@link Request#as(Request, Class)} method.
* @see #serveAs(Request, HttpURI)
*/
interface ServeAs extends Request
{
/**
* Wraps a request but changes the uri so that it can be served to a different target.
* @param request the original request.
* @param uri the uri of the new target.
* @return the request wrapped to the new target.
*/
Request wrap(Request request, HttpURI uri);
}
/**
* Return a request with its {@link HttpURI} changed to the supplied target.
* If the passed request or any of the requests that it wraps implements {@link ServeAs} then
* {@link ServeAs#wrap(Request, HttpURI)} will be used to do the wrap,
* otherwise a simple {@link Request.Wrapper} may be returned.
* @param request the original request.
* @param uri the new URI to target.
* @return the possibly wrapped request to target the new URI.
*/
static Request serveAs(Request request, HttpURI uri)
{
if (request.getHttpURI().equals(uri))
return request;
ServeAs serveAs = Request.as(request, ServeAs.class);
if (serveAs != null)
return serveAs.wrap(request, uri);
return new Request.Wrapper(request)
{
@Override
public HttpURI getHttpURI()
{
return uri;
}
};
}
/**
* <p>A handler for an HTTP request and response.</p>
* <p>The handling typically involves reading the request content (if any) and producing a response.</p>

View File

@ -57,7 +57,7 @@ public abstract class ReHandlingErrorHandler extends ErrorHandler
{
request.setAttribute(ReHandlingErrorHandler.class.getName(), pathInContext);
HttpURI uri = Request.newHttpURIFrom(request, pathInContext);
ReHandleRequestWrapper reRequest = new ReHandleRequestWrapper(request, uri);
Request reRequest = Request.serveAs(request, uri);
try
{
@ -112,21 +112,4 @@ public abstract class ReHandlingErrorHandler extends ErrorHandler
return _statusMap.remove(code);
}
}
private static class ReHandleRequestWrapper extends Request.Wrapper
{
private final HttpURI _uri;
public ReHandleRequestWrapper(Request request, HttpURI uri)
{
super(request);
_uri = uri;
}
@Override
public HttpURI getHttpURI()
{
return _uri;
}
}
}

View File

@ -388,14 +388,7 @@ public class ResourceHandler extends Handler.Wrapper
protected void rehandleWelcome(Request request, Response response, Callback callback, String welcomeTarget) throws Exception
{
HttpURI newHttpURI = HttpURI.build(request.getHttpURI()).pathQuery(welcomeTarget);
Request newRequest = new Request.Wrapper(request)
{
@Override
public HttpURI getHttpURI()
{
return newHttpURI;
}
};
Request newRequest = Request.serveAs(request, newHttpURI);
if (getServer().handle(newRequest, response, callback))
return;

View File

@ -150,7 +150,7 @@ public class TryPathsHandler extends Handler.Wrapper
for (String path : paths)
{
String interpolated = interpolate(request, path);
TryPathsRequest tryRequest = new TryPathsRequest(request, interpolated);
Request tryRequest = tryPath(request, interpolated);
if (LOG.isDebugEnabled())
LOG.debug("rewritten request URI {} -> {}", request.getHttpURI(), tryRequest.getHttpURI());
boolean handled = super.handle(tryRequest, response, callback);
@ -168,49 +168,37 @@ public class TryPathsHandler extends Handler.Wrapper
return value.replace("$path", path);
}
private class TryPathsRequest extends Request.Wrapper
private Request tryPath(Request wrapped, String newPathQuery)
{
private final HttpURI uri;
HttpURI originalURI = wrapped.getHttpURI();
public TryPathsRequest(Request wrapped, String newPathQuery)
String originalPathAttribute = getOriginalPathAttribute();
if (originalPathAttribute != null)
{
super(wrapped);
HttpURI originalURI = wrapped.getHttpURI();
String originalPathAttribute = getOriginalPathAttribute();
if (originalPathAttribute != null)
{
if (getAttribute(originalPathAttribute) == null)
setAttribute(originalPathAttribute, Request.getPathInContext(wrapped));
}
String originalQueryAttribute = getOriginalQueryAttribute();
if (originalQueryAttribute != null)
{
if (getAttribute(originalQueryAttribute) == null)
setAttribute(originalQueryAttribute, originalURI.getQuery());
}
String originalContextPath = Request.getContextPath(wrapped);
HttpURI.Mutable rewrittenURI = HttpURI.build(originalURI);
int queryIdx = newPathQuery.indexOf('?');
if (queryIdx >= 0)
{
String path = newPathQuery.substring(0, queryIdx);
rewrittenURI.path(URIUtil.addPaths(originalContextPath, path));
rewrittenURI.query(newPathQuery.substring(queryIdx + 1));
}
else
{
rewrittenURI.path(URIUtil.addPaths(originalContextPath, newPathQuery));
}
uri = rewrittenURI.asImmutable();
if (wrapped.getAttribute(originalPathAttribute) == null)
wrapped.setAttribute(originalPathAttribute, Request.getPathInContext(wrapped));
}
String originalQueryAttribute = getOriginalQueryAttribute();
if (originalQueryAttribute != null)
{
if (wrapped.getAttribute(originalQueryAttribute) == null)
wrapped.setAttribute(originalQueryAttribute, originalURI.getQuery());
}
@Override
public HttpURI getHttpURI()
String originalContextPath = Request.getContextPath(wrapped);
HttpURI.Mutable rewrittenURI = HttpURI.build(originalURI);
int queryIdx = newPathQuery.indexOf('?');
if (queryIdx >= 0)
{
return uri;
String path = newPathQuery.substring(0, queryIdx);
rewrittenURI.path(URIUtil.addPaths(originalContextPath, path));
rewrittenURI.query(newPathQuery.substring(queryIdx + 1));
}
else
{
rewrittenURI.path(URIUtil.addPaths(originalContextPath, newPathQuery));
}
HttpURI uri = rewrittenURI.asImmutable();
return Request.serveAs(wrapped, uri);
}
}

View File

@ -32,7 +32,6 @@ import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.http.UriCompliance;
import org.eclipse.jetty.http.pathmap.MatchedResource;
import org.eclipse.jetty.security.AuthenticationState.ServeAs;
import org.eclipse.jetty.server.FormFields;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
@ -55,7 +54,7 @@ import org.eclipse.jetty.util.URIUtil;
* This class is single use only.
* </p>
*/
public class ServletContextRequest extends ContextRequest implements ServletContextHandler.ServletRequestInfo, ServeAs.PathWrapper
public class ServletContextRequest extends ContextRequest implements ServletContextHandler.ServletRequestInfo, Request.ServeAs
{
public static final String MULTIPART_CONFIG_ELEMENT = "org.eclipse.jetty.multipartConfig";
static final int INPUT_NONE = 0;
@ -120,7 +119,7 @@ public class ServletContextRequest extends ContextRequest implements ServletCont
}
@Override
public Request serveAs(Request request, HttpURI uri)
public Request wrap(Request request, HttpURI uri)
{
String decodedPathInContext = URIUtil.decodePath(getContext().getPathInContext(request.getHttpURI().getCanonicalPath()));
MatchedResource<ServletHandler.MappedServlet> matchedResource = getServletContextHandler()