Issue #4741 No Servlet Path (#4898)

* Issue #4741 HttpServletMapping

This completes the refactoring started in #4851, using
the HttpServletMapping field to avoid having the servletPath field
in the Request and instead have a pathInContext field.

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* Issue #4741 HttpServletMapping

reverted ResourceService changes

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* Issue #4741 HttpServletMapping

fixed gzip handler

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* Issue #4741 HttpServletMapping

Fixed several TODOs left in the code
removed _contextPath field and used an attributes lookup for include
replaced setContextPaths with setContext

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* Issue #4741 HttpServletMapping

Used the same pattern from the contextPath changes for servletPath and pathInfo.   Now the servletPathMapping is always set on the request and only if the dispatch is an include do the effected methods look deeper for the source values.

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* Issue #4741 HttpServletMapping

Improved javadoc

Signed-off-by: Greg Wilkins <gregw@webtide.com>
This commit is contained in:
Greg Wilkins 2020-05-28 12:17:22 +02:00 committed by GitHub
parent 46f8705b8c
commit fb6a445639
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 262 additions and 216 deletions

View File

@ -249,7 +249,7 @@ public class OpenIdAuthenticator extends LoginAuthenticator
if (!mandatory)
return new DeferredAuthentication(this);
if (isErrorPage(URIUtil.addPaths(request.getServletPath(), request.getPathInfo())) && !DeferredAuthentication.isDeferred(response))
if (isErrorPage(baseRequest.getPathInContext()) && !DeferredAuthentication.isDeferred(response))
return new DeferredAuthentication(this);
try

View File

@ -195,7 +195,7 @@ public class RuleContainer extends Rule implements Dumpable
}
if (_rewritePathInfo)
baseRequest.setPathInfo(applied);
baseRequest.setContext(baseRequest.getContext(), applied);
target = applied;

View File

@ -85,7 +85,7 @@ public class RewriteHandlerTest extends AbstractRuleTestCase
_handler.setRewriteRequestURI(true);
_handler.setRewritePathInfo(true);
_request.setHttpURI(HttpURI.build(_request.getHttpURI(), "/xxx/bar"));
_request.setPathInfo("/xxx/bar");
_request.setContext(_request.getContext(), "/xxx/bar");
_handler.handle("/xxx/bar", _request, _request, _response);
assertEquals(201, _response.getStatus());
assertEquals("/bar/zzz", _request.getAttribute("target"));
@ -99,7 +99,7 @@ public class RewriteHandlerTest extends AbstractRuleTestCase
_handler.setRewriteRequestURI(false);
_handler.setRewritePathInfo(false);
_request.setHttpURI(HttpURI.build(_request.getHttpURI(), "/foo/bar"));
_request.setPathInfo("/foo/bar");
_request.setContext(_request.getContext(), "/foo/bar");
_handler.handle("/foo/bar", _request, _request, _response);
assertEquals(201, _response.getStatus());
@ -112,7 +112,7 @@ public class RewriteHandlerTest extends AbstractRuleTestCase
_request.setHandled(false);
_handler.setOriginalPathAttribute(null);
_request.setHttpURI(HttpURI.build(_request.getHttpURI(), "/aaa/bar"));
_request.setPathInfo("/aaa/bar");
_request.setContext(_request.getContext(), "/aaa/bar");
_handler.handle("/aaa/bar", _request, _request, _response);
assertEquals(201, _response.getStatus());
assertEquals("/ddd/bar", _request.getAttribute("target"));
@ -126,7 +126,7 @@ public class RewriteHandlerTest extends AbstractRuleTestCase
_handler.setRewriteRequestURI(true);
_handler.setRewritePathInfo(true);
_request.setHttpURI(HttpURI.build(_request.getHttpURI(), "/aaa/bar"));
_request.setPathInfo("/aaa/bar");
_request.setContext(_request.getContext(), "/aaa/bar");
_handler.handle("/aaa/bar", _request, _request, _response);
assertEquals(201, _response.getStatus());
assertEquals("/ddd/bar", _request.getAttribute("target"));
@ -138,7 +138,7 @@ public class RewriteHandlerTest extends AbstractRuleTestCase
_request.setHandled(false);
_rule2.setTerminating(true);
_request.setHttpURI(HttpURI.build(_request.getHttpURI(), "/aaa/bar"));
_request.setPathInfo("/aaa/bar");
_request.setContext(_request.getContext(), "/aaa/bar");
_handler.handle("/aaa/bar", _request, _request, _response);
assertEquals(201, _response.getStatus());
assertEquals("/ccc/bar", _request.getAttribute("target"));
@ -154,7 +154,7 @@ public class RewriteHandlerTest extends AbstractRuleTestCase
_request.setAttribute("URI", null);
_request.setAttribute("info", null);
_request.setHttpURI(HttpURI.build(_request.getHttpURI(), "/aaa/bar"));
_request.setPathInfo("/aaa/bar");
_request.setContext(_request.getContext(), "/aaa/bar");
_handler.handle("/aaa/bar", _request, _request, _response);
assertEquals(200, _response.getStatus());
assertEquals(null, _request.getAttribute("target"));
@ -173,7 +173,7 @@ public class RewriteHandlerTest extends AbstractRuleTestCase
_handler.setRewriteRequestURI(true);
_handler.setRewritePathInfo(false);
_request.setHttpURI(HttpURI.build(_request.getHttpURI(), "/ccc/x%20y"));
_request.setPathInfo("/ccc/x y");
_request.setContext(_request.getContext(), "/ccc/x y");
_handler.handle("/ccc/x y", _request, _request, _response);
assertEquals(201, _response.getStatus());
assertEquals("/ddd/x y", _request.getAttribute("target"));
@ -190,7 +190,7 @@ public class RewriteHandlerTest extends AbstractRuleTestCase
_handler.setRewriteRequestURI(true);
_handler.setRewritePathInfo(false);
_request.setHttpURI(HttpURI.build(_request.getHttpURI(), "/xxx/x%20y"));
_request.setPathInfo("/xxx/x y");
_request.setContext(_request.getContext(), "/xxx/x y");
_handler.handle("/xxx/x y", _request, _request, _response);
assertEquals(201, _response.getStatus());
assertEquals("/x y/zzz", _request.getAttribute("target"));

View File

@ -254,7 +254,7 @@ public class FormAuthenticator extends LoginAuthenticator
if (!mandatory)
return new DeferredAuthentication(this);
if (isLoginOrErrorPage(URIUtil.addPaths(request.getServletPath(), request.getPathInfo())) && !DeferredAuthentication.isDeferred(response))
if (isLoginOrErrorPage(baseRequest.getPathInContext()) && !DeferredAuthentication.isDeferred(response))
return new DeferredAuthentication(this);
try

View File

@ -90,6 +90,8 @@ public class Dispatcher implements RequestDispatcher
final DispatcherType old_type = baseRequest.getDispatcherType();
final Attributes old_attr = baseRequest.getAttributes();
final MultiMap<String> old_query_params = baseRequest.getQueryParameters();
final ContextHandler.Context old_context = baseRequest.getContext();
final ServletPathMapping old_mapping = baseRequest.getServletPathMapping();
try
{
baseRequest.setDispatcherType(DispatcherType.INCLUDE);
@ -100,7 +102,14 @@ public class Dispatcher implements RequestDispatcher
}
else
{
IncludeAttributes attr = new IncludeAttributes(old_attr, _uri.getPath(), _contextHandler.getContextPath(), _pathInContext, _uri.getQuery());
IncludeAttributes attr = new IncludeAttributes(
old_attr,
baseRequest,
old_context,
old_mapping,
_uri.getPath(),
_pathInContext,
_uri.getQuery());
if (attr._query != null)
baseRequest.mergeQueryParameters(baseRequest.getQueryString(), attr._query);
baseRequest.setAttributes(attr);
@ -136,11 +145,10 @@ public class Dispatcher implements RequestDispatcher
response = new ServletResponseHttpWrapper(response);
final HttpURI old_uri = baseRequest.getHttpURI();
final String old_context_path = baseRequest.getContextPath();
final String old_servlet_path = baseRequest.getServletPath();
final String old_path_info = baseRequest.getPathInfo();
final ContextHandler.Context old_context = baseRequest.getContext();
final String old_path_in_context = baseRequest.getPathInContext();
final ServletPathMapping old_mapping = baseRequest.getServletPathMapping();
final ServletPathMapping source_mapping = baseRequest.findServletPathMapping();
final MultiMap<String> old_query_params = baseRequest.getQueryParameters();
final Attributes old_attr = baseRequest.getAttributes();
final DispatcherType old_type = baseRequest.getDispatcherType();
@ -161,30 +169,21 @@ public class Dispatcher implements RequestDispatcher
// for queryString is allowed to be null, but cannot be null for the other values.
// Note: the pathInfo is passed as the pathInContext since it is only used when there is
// no mapping, and when there is no mapping the pathInfo is the pathInContext.
// TODO Ultimately it is intended for the request to carry the pathInContext for easy access
ForwardAttributes attr = old_attr.getAttribute(FORWARD_REQUEST_URI) != null
? new ForwardAttributes(old_attr,
(String)old_attr.getAttribute(FORWARD_REQUEST_URI),
(String)old_attr.getAttribute(FORWARD_CONTEXT_PATH),
(String)old_attr.getAttribute(FORWARD_PATH_INFO),
(ServletPathMapping)old_attr.getAttribute(FORWARD_MAPPING),
(String)old_attr.getAttribute(FORWARD_QUERY_STRING))
: new ForwardAttributes(old_attr,
old_uri.getPath(),
old_context_path,
baseRequest.getPathInfo(), // TODO replace with pathInContext
old_mapping,
old_uri.getQuery());
if (old_attr.getAttribute(FORWARD_REQUEST_URI) == null)
baseRequest.setAttributes(new ForwardAttributes(old_attr,
old_uri.getPath(),
old_context == null ? null : old_context.getContextHandler().getContextPathEncoded(),
baseRequest.getPathInContext(),
source_mapping,
old_uri.getQuery()));
String query = _uri.getQuery();
if (query == null)
query = old_uri.getQuery();
baseRequest.setHttpURI(HttpURI.build(old_uri, _uri.getPath(), _uri.getParam(), query));
baseRequest.setContextPath(_contextHandler.getContextPath());
baseRequest.setContext(_contextHandler.getServletContext(), _pathInContext);
baseRequest.setServletPathMapping(null);
baseRequest.setServletPath(null);
baseRequest.setPathInfo(_pathInContext);
if (_uri.getQuery() != null || old_uri.getQuery() != null)
{
@ -207,8 +206,6 @@ public class Dispatcher implements RequestDispatcher
}
}
baseRequest.setAttributes(attr);
_contextHandler.handle(_pathInContext, baseRequest, (HttpServletRequest)request, (HttpServletResponse)response);
// If we are not async and not closed already, then close via the possibly wrapped response.
@ -228,9 +225,8 @@ public class Dispatcher implements RequestDispatcher
finally
{
baseRequest.setHttpURI(old_uri);
baseRequest.setContextPath(old_context_path);
baseRequest.setServletPath(old_servlet_path);
baseRequest.setPathInfo(old_path_info);
baseRequest.setContext(old_context, old_path_in_context);
baseRequest.setServletPathMapping(old_mapping);
baseRequest.setQueryParameters(old_query_params);
baseRequest.resetParameters();
baseRequest.setAttributes(old_attr);
@ -346,23 +342,44 @@ public class Dispatcher implements RequestDispatcher
}
}
private class IncludeAttributes extends Attributes.Wrapper
/**
* Attributes Wrapper to provide the {@link DispatcherType#INCLUDE} attributes.
*
* The source {@link org.eclipse.jetty.server.handler.ContextHandler.Context} and
* {@link ServletPathMapping} instances are also retained by this wrapper so they
* may be used by {@link Request#getContextPath()}, {@link Request#getServletPath()},
* {@link Request#getPathInfo()} and {@link Request#getHttpServletMapping()}.
*/
class IncludeAttributes extends Attributes.Wrapper
{
private final Request _baseRequest;
private final ContextHandler.Context _sourceContext;
private final ServletPathMapping _sourceMapping;
private final String _requestURI;
private final String _contextPath;
private final String _pathInContext;
private ServletPathMapping _servletPathMapping; // Set later by ServletHandler
private final String _query;
public IncludeAttributes(Attributes attributes, String requestURI, String contextPath, String pathInContext, String query)
public IncludeAttributes(Attributes attributes, Request baseRequest, ContextHandler.Context sourceContext, ServletPathMapping sourceMapping, String requestURI, String pathInContext, String query)
{
super(attributes);
_baseRequest = baseRequest;
_sourceMapping = sourceMapping;
_requestURI = requestURI;
_contextPath = contextPath;
_sourceContext = sourceContext;
_pathInContext = pathInContext;
_query = query;
}
ContextHandler.Context getSourceContext()
{
return _sourceContext;
}
ServletPathMapping getSourceMapping()
{
return _sourceMapping;
}
@Override
public Object getAttribute(String key)
{
@ -371,17 +388,26 @@ public class Dispatcher implements RequestDispatcher
switch (key)
{
case INCLUDE_PATH_INFO:
return _servletPathMapping == null ? _pathInContext : _servletPathMapping.getPathInfo();
{
ServletPathMapping mapping = _baseRequest.getServletPathMapping();
return mapping == null ? _pathInContext : mapping.getPathInfo();
}
case INCLUDE_SERVLET_PATH:
return _servletPathMapping == null ? null : _servletPathMapping.getServletPath();
{
ServletPathMapping mapping = _baseRequest.getServletPathMapping();
return mapping == null ? null : mapping.getServletPath();
}
case INCLUDE_CONTEXT_PATH:
return _contextPath;
{
ContextHandler.Context context = _baseRequest.getContext();
return context == null ? null : context.getContextHandler().getContextPathEncoded();
}
case INCLUDE_QUERY_STRING:
return _query;
case INCLUDE_REQUEST_URI:
return _requestURI;
case INCLUDE_MAPPING:
return _servletPathMapping;
return _baseRequest.getServletPathMapping();
default:
break;
}
@ -416,12 +442,9 @@ public class Dispatcher implements RequestDispatcher
@Override
public void setAttribute(String key, Object value)
{
if (_servletPathMapping == null && _named == null && INCLUDE_MAPPING.equals(key))
_servletPathMapping = (ServletPathMapping)value;
else
// Allow any attribute to be set, even if a reserved name. If a reserved
// name is set here, it will be revealed after the include is complete.
_attributes.setAttribute(key, value);
// Allow any attribute to be set, even if a reserved name. If a reserved
// name is set here, it will be revealed after the include is complete.
_attributes.setAttribute(key, value);
}
@Override

View File

@ -107,14 +107,16 @@ import org.slf4j.LoggerFactory;
* request object to be as lightweight as possible and not actually implement any significant behavior. For example
* <ul>
*
* <li>The {@link Request#getContextPath()} method will return null, until the request has been passed to a {@link ContextHandler} which matches the
* {@link Request#getPathInfo()} with a context path and calls {@link Request#setContextPath(String)} as a result.</li>
* <li>the {@link Request#getContextPath()} method will return null, until the request has been passed to a {@link ContextHandler} which matches the
* {@link Request#getPathInfo()} with a context path and calls {@link Request#setContext(Context,String)} as a result. For
* some dispatch types (ie include and named dispatch) the context path may not reflect the {@link ServletContext} set
* by {@link Request#setContext(Context, String)}.</li>
*
* <li>the HTTP session methods will all return null sessions until such time as a request has been passed to a
* {@link org.eclipse.jetty.server.session.SessionHandler} which checks for session cookies and enables the ability to create new sessions.</li>
*
* <li>The {@link Request#getServletPath()} method will return null until the request has been passed to a <code>org.eclipse.jetty.servlet.ServletHandler</code>
* and the pathInfo matched against the servlet URL patterns and {@link Request#setServletPath(String)} called as a result.</li>
* <li>The {@link Request#getServletPath()} method will return "" until the request has been passed to a <code>org.eclipse.jetty.servlet.ServletHandler</code>
* and the pathInfo matched against the servlet URL patterns and {@link Request#setServletPathMapping(ServletPathMapping)} called as a result.</li>
* </ul>
*
* <p>
@ -198,9 +200,7 @@ public class Request implements HttpServletRequest
private HttpFields _trailers;
private HttpURI _uri;
private String _method;
private String _contextPath;
private String _servletPath;
private String _pathInfo;
private String _pathInContext;
private ServletPathMapping _servletPathMapping;
private boolean _secure;
private String _asyncNotSupportedSource = null;
@ -777,7 +777,44 @@ public class Request implements HttpServletRequest
@Override
public String getContextPath()
{
return _contextPath;
// The context path returned is normally for the current context. Except during a cross context
// INCLUDE dispatch, in which case this method returns the context path of the source context,
// which we recover from the IncludeAttributes wrapper.
Context context;
if (_dispatcherType == DispatcherType.INCLUDE)
{
Dispatcher.IncludeAttributes include = Attributes.unwrap(_attributes, Dispatcher.IncludeAttributes.class);
context = (include == null) ? _context : include.getSourceContext();
}
else
{
context = _context;
}
if (context == null)
return null;
// For some reason the spec requires the context path to be encoded (unlike getServletPath).
String contextPath = context.getContextHandler().getContextPathEncoded();
// For the root context, the spec requires that the empty string is returned instead of the leading '/'
// which is included in the pathInContext
if (URIUtil.SLASH.equals(contextPath))
return "";
return contextPath;
}
/** Get the path in the context.
*
* The path relative to the context path, analogous to {@link #getServletPath()} + {@link #getPathInfo()}.
* If no context is set, then the path in context is the full path.
* @return The decoded part of the {@link #getRequestURI()} path after any {@link #getContextPath()}
* up to any {@link #getQueryString()}, excluding path parameters.
* @see #setContext(Context, String)
*/
public String getPathInContext()
{
return _pathInContext;
}
@Override
@ -1048,15 +1085,20 @@ public class Request implements HttpServletRequest
@Override
public String getPathInfo()
{
return _pathInfo;
// The pathInfo returned is normally for the current servlet. Except during an
// INCLUDE dispatch, in which case this method returns the pathInfo of the source servlet,
// which we recover from the IncludeAttributes wrapper.
ServletPathMapping mapping = findServletPathMapping();
return mapping == null ? _pathInContext : mapping.getPathInfo();
}
@Override
public String getPathTranslated()
{
if (_pathInfo == null || _context == null)
String pathInfo = getPathInfo();
if (pathInfo == null || _context == null)
return null;
return _context.getRealPath(_pathInfo);
return _context.getRealPath(pathInfo);
}
@Override
@ -1207,7 +1249,7 @@ public class Request implements HttpServletRequest
// handle relative path
if (!path.startsWith("/"))
{
String relTo = URIUtil.addPaths(_servletPath, _pathInfo);
String relTo = _pathInContext;
int slash = relTo.lastIndexOf("/");
if (slash > 1)
relTo = relTo.substring(0, slash + 1);
@ -1335,9 +1377,11 @@ public class Request implements HttpServletRequest
@Override
public String getServletPath()
{
if (_servletPath == null)
_servletPath = "";
return _servletPath;
// The servletPath returned is normally for the current servlet. Except during an
// INCLUDE dispatch, in which case this method returns the servletPath of the source servlet,
// which we recover from the IncludeAttributes wrapper.
ServletPathMapping mapping = findServletPathMapping();
return mapping == null ? "" : mapping.getServletPath();
}
public ServletResponse getServletResponse()
@ -1678,10 +1722,10 @@ public class Request implements HttpServletRequest
if (path == null || path.isEmpty())
{
setPathInfo(encoded == null ? "" : encoded);
_pathInContext = encoded == null ? "" : encoded;
throw new BadMessageException(400, "Bad URI");
}
setPathInfo(path);
_pathInContext = path;
}
public org.eclipse.jetty.http.MetaData.Request getMetaData()
@ -1740,13 +1784,12 @@ public class Request implements HttpServletRequest
}
_contentType = null;
_characterEncoding = null;
_contextPath = null;
_pathInContext = null;
if (_cookies != null)
_cookies.reset();
_cookiesExtracted = false;
_context = null;
_newContext = false;
_pathInfo = null;
_queryEncoding = null;
_requestedSessionId = null;
_requestedSessionIdFromCookie = false;
@ -1754,7 +1797,6 @@ public class Request implements HttpServletRequest
_session = null;
_sessionHandler = null;
_scope = null;
_servletPath = null;
_timeStamp = 0;
_queryParameters = null;
_contentParameters = null;
@ -1831,6 +1873,13 @@ public class Request implements HttpServletRequest
}
}
/**
* Set the attributes for the request.
*
* @param attributes The attributes, which must be a {@link org.eclipse.jetty.util.Attributes.Wrapper}
* for which {@link Attributes#unwrap(Attributes)} will return the
* original {@link ServletAttributes}.
*/
public void setAttributes(Attributes attributes)
{
_attributes = attributes;
@ -1864,7 +1913,7 @@ public class Request implements HttpServletRequest
// attributes there, under any other wrappers.
((ServletAttributes)baseAttributes).setAsyncAttributes(getRequestURI(),
getContextPath(),
getPathInfo(), // TODO change to pathInContext when cheaply available
getPathInContext(),
getServletPathMapping(),
getQueryString());
}
@ -1955,25 +2004,24 @@ public class Request implements HttpServletRequest
}
/**
* Set request context
* Set request context and path in the context.
*
* @param context context object
* @param pathInContext the part of the URI path that is withing the context.
* For servlets, this is equal to servletPath + pathInfo
*/
public void setContext(Context context)
public void setContext(Context context, String pathInContext)
{
_newContext = _context != context;
if (context == null)
_context = null;
else
{
_context = context;
_context = context;
_pathInContext = pathInContext;
if (context != null)
_errorContext = context;
}
}
/**
* @return True if this is the first call of <code>takeNewContext()</code> since the last
* {@link #setContext(org.eclipse.jetty.server.handler.ContextHandler.Context)} call.
* {@link #setContext(org.eclipse.jetty.server.handler.ContextHandler.Context, String)} call.
*/
public boolean takeNewContext()
{
@ -1982,17 +2030,6 @@ public class Request implements HttpServletRequest
return nc;
}
/**
* Sets the "context path" for this request
*
* @param contextPath the context path for this request
* @see HttpServletRequest#getContextPath()
*/
public void setContextPath(String contextPath)
{
_contextPath = contextPath;
}
/**
* @param cookies The cookies to set.
*/
@ -2026,14 +2063,6 @@ public class Request implements HttpServletRequest
return HttpMethod.HEAD.is(getMethod());
}
/**
* @param pathInfo The pathInfo to set.
*/
public void setPathInfo(String pathInfo)
{
_pathInfo = pathInfo;
}
/**
* Set the character encoding used for the query string. This call will effect the return of getQueryString and getParamaters. It must be called before any
* getParameter methods.
@ -2071,14 +2100,6 @@ public class Request implements HttpServletRequest
_requestedSessionIdFromCookie = requestedSessionIdCookie;
}
/**
* @param servletPath The servletPath to set.
*/
public void setServletPath(String servletPath)
{
_servletPath = servletPath;
}
/**
* @param session The session to set.
*/
@ -2347,32 +2368,48 @@ public class Request implements HttpServletRequest
/**
* Set the servletPathMapping, the servletPath and the pathInfo.
* TODO remove the side effect on servletPath and pathInfo by removing those fields.
* @param servletPathMapping The mapping used to return from {@link #getHttpServletMapping()}
*/
public void setServletPathMapping(ServletPathMapping servletPathMapping)
{
_servletPathMapping = servletPathMapping;
if (servletPathMapping == null)
{
// TODO reset the servletPath and pathInfo, but currently cannot do that
// as we don't know the pathInContext.
}
else
{
_servletPath = servletPathMapping.getServletPath();
_pathInfo = servletPathMapping.getPathInfo();
}
}
/**
* @return The mapping for the current target servlet, regardless of dispatch type.
*/
public ServletPathMapping getServletPathMapping()
{
return _servletPathMapping;
}
/**
* @return The mapping for the target servlet reported by the {@link #getServletPath()} and
* {@link #getPathInfo()} methods. For {@link DispatcherType#INCLUDE} dispatches, this
* method returns the mapping of the source servlet, otherwise it returns the mapping of
* the target servlet.
*/
ServletPathMapping findServletPathMapping()
{
ServletPathMapping mapping;
if (_dispatcherType == DispatcherType.INCLUDE)
{
Dispatcher.IncludeAttributes include = Attributes.unwrap(_attributes, Dispatcher.IncludeAttributes.class);
mapping = (include == null) ? _servletPathMapping : include.getSourceMapping();
}
else
{
mapping = _servletPathMapping;
}
return mapping;
}
@Override
public HttpServletMapping getHttpServletMapping()
{
return _servletPathMapping;
// The mapping returned is normally for the current servlet. Except during an
// INCLUDE dispatch, in which case this method returns the mapping of the source servlet,
// which we recover from the IncludeAttributes wrapper.
return findServletPathMapping();
}
}

View File

@ -335,7 +335,7 @@ public class Response implements HttpServletResponse
return url;
if (request.getServerPort() != port)
return url;
if (!path.startsWith(request.getContextPath())) //TODO the root context path is "", with which every non null string starts
if (request.getContext() != null && !path.startsWith(request.getContextPath()))
return url;
}

View File

@ -619,7 +619,7 @@ public class Server extends HandlerWrapper implements Attributes
baseRequest.mergeQueryParameters(oldUri.getQuery(), baseRequest.getQueryString());
}
baseRequest.setPathInfo(baseRequest.getHttpURI().getDecodedPath());
baseRequest.setContext(null, baseRequest.getHttpURI().getDecodedPath());
handleAsync(channel, event, baseRequest);
}
finally

View File

@ -40,7 +40,6 @@ import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.IncludeExclude;
import org.eclipse.jetty.util.IteratingCallback;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.URIUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -104,7 +103,7 @@ public class BufferedResponseHandler extends HandlerWrapper
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
final ServletContext context = baseRequest.getServletContext();
final String path = context == null ? baseRequest.getRequestURI() : URIUtil.addPaths(baseRequest.getServletPath(), baseRequest.getPathInfo());
final String path = baseRequest.getPathInContext();
LOG.debug("{} handle {} in {}", this, baseRequest, context);
HttpOutput out = baseRequest.getResponse().getHttpOutput();

View File

@ -1150,13 +1150,11 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
if (LOG.isDebugEnabled())
LOG.debug("scope {}|{}|{} @ {}", baseRequest.getContextPath(), baseRequest.getServletPath(), baseRequest.getPathInfo(), this);
final Thread currentThread = Thread.currentThread();
final ClassLoader oldClassloader = currentThread.getContextClassLoader();
Context oldContext;
String oldContextPath = null;
String oldServletPath = null;
String oldPathInfo = null;
ClassLoader oldClassloader = null;
Thread currentThread = null;
String pathInfo = target;
String oldPathInContext = null;
String pathInContext = target;
DispatcherType dispatch = baseRequest.getDispatcherType();
@ -1177,47 +1175,31 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
{
if (_contextPath.length() > 1)
target = target.substring(_contextPath.length());
pathInfo = target;
pathInContext = target;
}
else if (_contextPath.length() == 1)
{
target = URIUtil.SLASH;
pathInfo = URIUtil.SLASH;
pathInContext = URIUtil.SLASH;
}
else
{
target = URIUtil.SLASH;
pathInfo = null;
pathInContext = null;
}
}
// Set the classloader
if (_classLoader != null)
{
currentThread = Thread.currentThread();
oldClassloader = currentThread.getContextClassLoader();
currentThread.setContextClassLoader(_classLoader);
}
}
if (_classLoader != null)
currentThread.setContextClassLoader(_classLoader);
try
{
oldContextPath = baseRequest.getContextPath();
oldServletPath = baseRequest.getServletPath();
oldPathInfo = baseRequest.getPathInfo();
oldPathInContext = baseRequest.getPathInContext();
// Update the paths
baseRequest.setContext(_scontext);
baseRequest.setContext(_scontext, pathInContext);
__context.set(_scontext);
if (!DispatcherType.INCLUDE.equals(dispatch) && target.startsWith("/"))
{
if (_contextPath.length() == 1)
baseRequest.setContextPath("");
else
baseRequest.setContextPath(getContextPathEncoded());
baseRequest.setServletPath(null);
baseRequest.setPathInfo(pathInfo);
}
if (oldContext != _scontext)
enterScope(baseRequest, dispatch);
@ -1234,17 +1216,12 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
exitScope(baseRequest);
// reset the classloader
if (_classLoader != null && currentThread != null)
{
if (_classLoader != null)
currentThread.setContextClassLoader(oldClassloader);
}
// reset the context and servlet path.
baseRequest.setContext(oldContext);
baseRequest.setContext(oldContext, oldPathInContext);
__context.set(oldContext);
baseRequest.setContextPath(oldContextPath);
baseRequest.setServletPath(oldServletPath);
baseRequest.setPathInfo(oldPathInfo);
}
}
}

View File

@ -45,7 +45,6 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.util.IncludeExclude;
import org.eclipse.jetty.util.RegexSet;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.compression.DeflaterPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -582,7 +581,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
final ServletContext context = baseRequest.getServletContext();
final String path = context == null ? baseRequest.getRequestURI() : URIUtil.addPaths(baseRequest.getServletPath(), baseRequest.getPathInfo());
final String path = baseRequest.getPathInContext();
LOG.debug("{} handle {} in {}", this, baseRequest, context);
if (!_dispatchers.contains(baseRequest.getDispatcherType()))

View File

@ -43,7 +43,6 @@ import javax.servlet.MultipartConfigElement;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@ -2175,29 +2174,4 @@ public class RequestTest
return null;
}
}
private class PathMappingHandler extends AbstractHandler
{
private ServletPathSpec _spec;
private String _servletPath;
private String _servletName;
public PathMappingHandler(ServletPathSpec spec, String servletPath, String servletName)
{
_spec = spec;
_servletPath = servletPath;
_servletName = servletName;
}
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
((Request)request).setHandled(true);
baseRequest.setServletPath(_servletPath);
if (_servletName != null)
baseRequest.setUserIdentityScope(new TestUserIdentityScope(null, null, _servletName));
HttpServletMapping mapping = baseRequest.getHttpServletMapping();
response.getWriter().println(mapping);
}
}
}

View File

@ -95,7 +95,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
// @checkstyle-disable-check : AvoidEscapedUnicodeCharactersCheck
public class ResponseTest
{
static final InetSocketAddress LOCALADDRESS;
static
@ -353,7 +352,7 @@ public class ResponseTest
ContextHandler context = new ContextHandler();
context.addLocaleEncoding(Locale.ENGLISH.toString(), "ISO-8859-1");
context.addLocaleEncoding(Locale.ITALIAN.toString(), "ISO-8859-2");
response.getHttpChannel().getRequest().setContext(context.getServletContext());
response.getHttpChannel().getRequest().setContext(context.getServletContext(), "/");
response.setLocale(java.util.Locale.ITALIAN);
assertNull(response.getContentType());
@ -376,7 +375,7 @@ public class ResponseTest
ContextHandler context = new ContextHandler();
context.addLocaleEncoding(Locale.ENGLISH.toString(), "ISO-8859-1");
context.addLocaleEncoding(Locale.ITALIAN.toString(), "ISO-8859-2");
response.getHttpChannel().getRequest().setContext(context.getServletContext());
response.getHttpChannel().getRequest().setContext(context.getServletContext(), "/");
response.setLocale(java.util.Locale.ITALIAN);
@ -425,46 +424,46 @@ public class ResponseTest
//test setting the default response character encoding
Response response = getResponse();
_channel.getRequest().setContext(handler.getServletContext());
response.getHttpChannel().getRequest().setContext(handler.getServletContext(), "/");
assertThat("utf-16", Matchers.equalTo(response.getCharacterEncoding()));
_channel.getRequest().setContext(null);
_channel.getRequest().setContext(null, "/");
response.recycle();
//test that explicit overrides default
response = getResponse();
_channel.getRequest().setContext(handler.getServletContext());
_channel.getRequest().setContext(handler.getServletContext(), "/");
response.setCharacterEncoding("ascii");
assertThat("ascii", Matchers.equalTo(response.getCharacterEncoding()));
//getWriter should not change explicit character encoding
response.getWriter();
assertThat("ascii", Matchers.equalTo(response.getCharacterEncoding()));
_channel.getRequest().setContext(null);
_channel.getRequest().setContext(null, "/");
response.recycle();
//test that assumed overrides default
response = getResponse();
_channel.getRequest().setContext(handler.getServletContext());
_channel.getRequest().setContext(handler.getServletContext(), "/");
response.setContentType("application/json");
assertThat("utf-8", Matchers.equalTo(response.getCharacterEncoding()));
response.getWriter();
//getWriter should not have modified character encoding
assertThat("utf-8", Matchers.equalTo(response.getCharacterEncoding()));
_channel.getRequest().setContext(null);
_channel.getRequest().setContext(null, "/");
response.recycle();
//test that inferred overrides default
response = getResponse();
_channel.getRequest().setContext(handler.getServletContext());
_channel.getRequest().setContext(handler.getServletContext(), "/");
response.setContentType("application/xhtml+xml");
assertThat("utf-8", Matchers.equalTo(response.getCharacterEncoding()));
//getWriter should not have modified character encoding
response.getWriter();
assertThat("utf-8", Matchers.equalTo(response.getCharacterEncoding()));
_channel.getRequest().setContext(null);
_channel.getRequest().setContext(null, "/");
response.recycle();
//test that without a default or any content type, use iso-8859-1
@ -488,7 +487,7 @@ public class ResponseTest
_server.start();
Response response = getResponse();
response.getHttpChannel().getRequest().setContext(handler.getServletContext());
response.getHttpChannel().getRequest().setContext(handler.getServletContext(), "/");
response.setContentType("text/html");
assertEquals("iso-8859-1", response.getCharacterEncoding());
@ -859,10 +858,11 @@ public class ResponseTest
@Test
public void testEncodeRedirect()
{
ContextHandler context = new ContextHandler("/path");
Response response = getResponse();
Request request = response.getHttpChannel().getRequest();
request.setHttpURI(HttpURI.build(request.getHttpURI()).host("myhost").port(8888));
request.setContextPath("/path");
request.setContext(context.getServletContext(), "/info");
assertEquals("http://myhost:8888/path/info;param?query=0&more=1#target", response.encodeURL("http://myhost:8888/path/info;param?query=0&more=1#target"));
@ -893,7 +893,23 @@ public class ResponseTest
assertEquals("http://myhost/path/info;param?query=0&more=1#target", response.encodeURL("http://myhost/path/info;param?query=0&more=1#target"));
assertEquals("http://myhost:8888/other/info;param?query=0&more=1#target", response.encodeURL("http://myhost:8888/other/info;param?query=0&more=1#target"));
request.setContextPath("");
context = new ContextHandler("/");
request.setContext(context.getServletContext(), "/");
assertEquals("http://myhost:8888/;jsessionid=12345", response.encodeURL("http://myhost:8888"));
assertEquals("https://myhost:8888/;jsessionid=12345", response.encodeURL("https://myhost:8888"));
assertEquals("mailto:/foo", response.encodeURL("mailto:/foo"));
assertEquals("http://myhost:8888/;jsessionid=12345", response.encodeURL("http://myhost:8888/"));
assertEquals("http://myhost:8888/;jsessionid=12345", response.encodeURL("http://myhost:8888/;jsessionid=7777"));
assertEquals("http://myhost:8888/;param;jsessionid=12345?query=0&more=1#target", response.encodeURL("http://myhost:8888/;param?query=0&more=1#target"));
assertEquals("http://other:8888/path/info;param?query=0&more=1#target", response.encodeURL("http://other:8888/path/info;param?query=0&more=1#target"));
handler.setCheckingRemoteSessionIdEncoding(false);
assertEquals("/foo;jsessionid=12345", response.encodeURL("/foo"));
assertEquals("/;jsessionid=12345", response.encodeURL("/"));
assertEquals("/foo.html;jsessionid=12345#target", response.encodeURL("/foo.html#target"));
assertEquals(";jsessionid=12345", response.encodeURL(""));
request.setContext(null, "/");
handler.setCheckingRemoteSessionIdEncoding(true);
assertEquals("http://myhost:8888/;jsessionid=12345", response.encodeURL("http://myhost:8888"));
assertEquals("https://myhost:8888/;jsessionid=12345", response.encodeURL("https://myhost:8888"));
assertEquals("mailto:/foo", response.encodeURL("mailto:/foo"));
@ -937,6 +953,7 @@ public class ResponseTest
{"http://somehost.com/other/location", "http://somehost.com/other/location"},
};
ContextHandler context = new ContextHandler("/path");
int[] ports = new int[]{8080, 80};
String[] hosts = new String[]{null, "myhost", "192.168.0.1", "0::1"};
for (int port : ports)
@ -956,7 +973,7 @@ public class ResponseTest
if (host != null)
uri.host(host).port(port);
request.setHttpURI(uri);
request.setContextPath("/path");
request.setContext(context.getServletContext(), "/info");
request.setRequestedSessionId("12345");
request.setRequestedSessionIdFromCookie(i > 2);
SessionHandler handler = new SessionHandler();
@ -980,6 +997,7 @@ public class ResponseTest
.replace("@HOST@", host == null ? request.getLocalAddr() : (host.contains(":") ? ("[" + host + "]") : host))
.replace("@PORT@", host == null ? ":8888" : (port == 80 ? "" : (":" + port)));
assertEquals(expected, location, "test-" + i + " " + host + ":" + port);
request.setContext(null, "/info");
}
}
}
@ -1116,7 +1134,7 @@ public class ResponseTest
{
Response response = getResponse();
TestServletContextHandler context = new TestServletContextHandler();
_channel.getRequest().setContext(context.getServletContext());
_channel.getRequest().setContext(context.getServletContext(), "/");
context.setAttribute(HttpCookie.SAME_SITE_DEFAULT_ATTRIBUTE, HttpCookie.SameSite.STRICT);
Cookie cookie = new Cookie("name", "value");
cookie.setDomain("domain");
@ -1282,7 +1300,7 @@ public class ResponseTest
Response response = getResponse();
TestServletContextHandler context = new TestServletContextHandler();
context.setAttribute(HttpCookie.SAME_SITE_DEFAULT_ATTRIBUTE, "LAX");
_channel.getRequest().setContext(context.getServletContext());
_channel.getRequest().setContext(context.getServletContext(), "/");
//replace with no prior does an add
response.replaceCookie(new HttpCookie("Foo", "123456"));
String set = response.getHttpFields().get("Set-Cookie");
@ -1324,7 +1342,7 @@ public class ResponseTest
Response response = getResponse();
TestServletContextHandler context = new TestServletContextHandler();
context.setAttribute(HttpCookie.SAME_SITE_DEFAULT_ATTRIBUTE, "LAX");
_channel.getRequest().setContext(context.getServletContext());
_channel.getRequest().setContext(context.getServletContext(), "/");
response.addHeader(HttpHeader.SET_COOKIE.asString(), "Foo=123456");
response.replaceCookie(new HttpCookie("Foo", "value"));

View File

@ -37,7 +37,6 @@ import java.util.stream.Stream;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.RequestDispatcher;
import javax.servlet.Servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
@ -66,7 +65,6 @@ import org.eclipse.jetty.util.ArrayUtil;
import org.eclipse.jetty.util.LazyList;
import org.eclipse.jetty.util.MultiException;
import org.eclipse.jetty.util.MultiMap;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.DumpableCollection;
@ -431,10 +429,7 @@ public class ServletHandler extends ScopedHandler
if (servletPathMapping != null)
{
// Setting the servletPathMapping also provides the servletPath and pathInfo
if (DispatcherType.INCLUDE.equals(type))
baseRequest.setAttribute(RequestDispatcher.INCLUDE_MAPPING, servletPathMapping);
else
baseRequest.setServletPathMapping(servletPathMapping);
baseRequest.setServletPathMapping(servletPathMapping);
}
}
@ -1405,7 +1400,7 @@ public class ServletHandler extends ScopedHandler
if (LOG.isDebugEnabled())
LOG.debug("Not Found {}", request.getRequestURI());
if (getHandler() != null)
nextHandle(URIUtil.addPaths(request.getServletPath(), request.getPathInfo()), baseRequest, request, response);
nextHandle(baseRequest.getPathInContext(), baseRequest, request, response);
}
protected synchronized boolean containsFilterHolder(FilterHolder holder)

View File

@ -43,6 +43,10 @@ public interface Attributes
void clearAttributes();
/** Unwrap all {@link Wrapper}s of the attributes
* @param attributes The attributes to unwrap, which may be a {@link Wrapper}.
* @return The core attributes
*/
static Attributes unwrap(Attributes attributes)
{
while (attributes instanceof Wrapper)
@ -52,6 +56,26 @@ public interface Attributes
return attributes;
}
/** Unwrap attributes to a specific attribute {@link Wrapper}.
* @param attributes The attributes to unwrap, which may be a {@link Wrapper}
* @param target The target {@link Wrapper} class.
* @param <T> The type of the target {@link Wrapper}.
* @return The outermost {@link Wrapper} of the matching type of null if not found.
*/
static <T extends Attributes.Wrapper> T unwrap(Attributes attributes, Class<T> target)
{
while (attributes instanceof Wrapper)
{
if (target.isAssignableFrom(attributes.getClass()))
return (T)attributes;
attributes = ((Wrapper)attributes).getAttributes();
}
return null;
}
/**
* A Wrapper of attributes
*/
abstract class Wrapper implements Attributes
{
protected final Attributes _attributes;