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) if (!mandatory)
return new DeferredAuthentication(this); 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); return new DeferredAuthentication(this);
try try

View File

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

View File

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

View File

@ -254,7 +254,7 @@ public class FormAuthenticator extends LoginAuthenticator
if (!mandatory) if (!mandatory)
return new DeferredAuthentication(this); 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); return new DeferredAuthentication(this);
try try

View File

@ -90,6 +90,8 @@ public class Dispatcher implements RequestDispatcher
final DispatcherType old_type = baseRequest.getDispatcherType(); final DispatcherType old_type = baseRequest.getDispatcherType();
final Attributes old_attr = baseRequest.getAttributes(); final Attributes old_attr = baseRequest.getAttributes();
final MultiMap<String> old_query_params = baseRequest.getQueryParameters(); final MultiMap<String> old_query_params = baseRequest.getQueryParameters();
final ContextHandler.Context old_context = baseRequest.getContext();
final ServletPathMapping old_mapping = baseRequest.getServletPathMapping();
try try
{ {
baseRequest.setDispatcherType(DispatcherType.INCLUDE); baseRequest.setDispatcherType(DispatcherType.INCLUDE);
@ -100,7 +102,14 @@ public class Dispatcher implements RequestDispatcher
} }
else 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) if (attr._query != null)
baseRequest.mergeQueryParameters(baseRequest.getQueryString(), attr._query); baseRequest.mergeQueryParameters(baseRequest.getQueryString(), attr._query);
baseRequest.setAttributes(attr); baseRequest.setAttributes(attr);
@ -136,11 +145,10 @@ public class Dispatcher implements RequestDispatcher
response = new ServletResponseHttpWrapper(response); response = new ServletResponseHttpWrapper(response);
final HttpURI old_uri = baseRequest.getHttpURI(); final HttpURI old_uri = baseRequest.getHttpURI();
final String old_context_path = baseRequest.getContextPath(); final ContextHandler.Context old_context = baseRequest.getContext();
final String old_servlet_path = baseRequest.getServletPath(); final String old_path_in_context = baseRequest.getPathInContext();
final String old_path_info = baseRequest.getPathInfo();
final ServletPathMapping old_mapping = baseRequest.getServletPathMapping(); final ServletPathMapping old_mapping = baseRequest.getServletPathMapping();
final ServletPathMapping source_mapping = baseRequest.findServletPathMapping();
final MultiMap<String> old_query_params = baseRequest.getQueryParameters(); final MultiMap<String> old_query_params = baseRequest.getQueryParameters();
final Attributes old_attr = baseRequest.getAttributes(); final Attributes old_attr = baseRequest.getAttributes();
final DispatcherType old_type = baseRequest.getDispatcherType(); 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. // 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 // 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. // 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 if (old_attr.getAttribute(FORWARD_REQUEST_URI) == null)
ForwardAttributes attr = old_attr.getAttribute(FORWARD_REQUEST_URI) != null baseRequest.setAttributes(new ForwardAttributes(old_attr,
? new ForwardAttributes(old_attr, old_uri.getPath(),
(String)old_attr.getAttribute(FORWARD_REQUEST_URI), old_context == null ? null : old_context.getContextHandler().getContextPathEncoded(),
(String)old_attr.getAttribute(FORWARD_CONTEXT_PATH), baseRequest.getPathInContext(),
(String)old_attr.getAttribute(FORWARD_PATH_INFO), source_mapping,
(ServletPathMapping)old_attr.getAttribute(FORWARD_MAPPING), old_uri.getQuery()));
(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());
String query = _uri.getQuery(); String query = _uri.getQuery();
if (query == null) if (query == null)
query = old_uri.getQuery(); query = old_uri.getQuery();
baseRequest.setHttpURI(HttpURI.build(old_uri, _uri.getPath(), _uri.getParam(), query)); baseRequest.setHttpURI(HttpURI.build(old_uri, _uri.getPath(), _uri.getParam(), query));
baseRequest.setContextPath(_contextHandler.getContextPath()); baseRequest.setContext(_contextHandler.getServletContext(), _pathInContext);
baseRequest.setServletPathMapping(null); baseRequest.setServletPathMapping(null);
baseRequest.setServletPath(null);
baseRequest.setPathInfo(_pathInContext);
if (_uri.getQuery() != null || old_uri.getQuery() != null) 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); _contextHandler.handle(_pathInContext, baseRequest, (HttpServletRequest)request, (HttpServletResponse)response);
// If we are not async and not closed already, then close via the possibly wrapped 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 finally
{ {
baseRequest.setHttpURI(old_uri); baseRequest.setHttpURI(old_uri);
baseRequest.setContextPath(old_context_path); baseRequest.setContext(old_context, old_path_in_context);
baseRequest.setServletPath(old_servlet_path); baseRequest.setServletPathMapping(old_mapping);
baseRequest.setPathInfo(old_path_info);
baseRequest.setQueryParameters(old_query_params); baseRequest.setQueryParameters(old_query_params);
baseRequest.resetParameters(); baseRequest.resetParameters();
baseRequest.setAttributes(old_attr); 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 _requestURI;
private final String _contextPath;
private final String _pathInContext; private final String _pathInContext;
private ServletPathMapping _servletPathMapping; // Set later by ServletHandler
private final String _query; 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); super(attributes);
_baseRequest = baseRequest;
_sourceMapping = sourceMapping;
_requestURI = requestURI; _requestURI = requestURI;
_contextPath = contextPath; _sourceContext = sourceContext;
_pathInContext = pathInContext; _pathInContext = pathInContext;
_query = query; _query = query;
} }
ContextHandler.Context getSourceContext()
{
return _sourceContext;
}
ServletPathMapping getSourceMapping()
{
return _sourceMapping;
}
@Override @Override
public Object getAttribute(String key) public Object getAttribute(String key)
{ {
@ -371,17 +388,26 @@ public class Dispatcher implements RequestDispatcher
switch (key) switch (key)
{ {
case INCLUDE_PATH_INFO: case INCLUDE_PATH_INFO:
return _servletPathMapping == null ? _pathInContext : _servletPathMapping.getPathInfo(); {
ServletPathMapping mapping = _baseRequest.getServletPathMapping();
return mapping == null ? _pathInContext : mapping.getPathInfo();
}
case INCLUDE_SERVLET_PATH: case INCLUDE_SERVLET_PATH:
return _servletPathMapping == null ? null : _servletPathMapping.getServletPath(); {
ServletPathMapping mapping = _baseRequest.getServletPathMapping();
return mapping == null ? null : mapping.getServletPath();
}
case INCLUDE_CONTEXT_PATH: case INCLUDE_CONTEXT_PATH:
return _contextPath; {
ContextHandler.Context context = _baseRequest.getContext();
return context == null ? null : context.getContextHandler().getContextPathEncoded();
}
case INCLUDE_QUERY_STRING: case INCLUDE_QUERY_STRING:
return _query; return _query;
case INCLUDE_REQUEST_URI: case INCLUDE_REQUEST_URI:
return _requestURI; return _requestURI;
case INCLUDE_MAPPING: case INCLUDE_MAPPING:
return _servletPathMapping; return _baseRequest.getServletPathMapping();
default: default:
break; break;
} }
@ -416,12 +442,9 @@ public class Dispatcher implements RequestDispatcher
@Override @Override
public void setAttribute(String key, Object value) public void setAttribute(String key, Object value)
{ {
if (_servletPathMapping == null && _named == null && INCLUDE_MAPPING.equals(key)) // Allow any attribute to be set, even if a reserved name. If a reserved
_servletPathMapping = (ServletPathMapping)value; // name is set here, it will be revealed after the include is complete.
else _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 @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 * request object to be as lightweight as possible and not actually implement any significant behavior. For example
* <ul> * <ul>
* *
* <li>The {@link Request#getContextPath()} method will return null, until the request has been passed to a {@link ContextHandler} which matches the * <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> * {@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 * <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> * {@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> * <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#setServletPath(String)} called as a result.</li> * and the pathInfo matched against the servlet URL patterns and {@link Request#setServletPathMapping(ServletPathMapping)} called as a result.</li>
* </ul> * </ul>
* *
* <p> * <p>
@ -198,9 +200,7 @@ public class Request implements HttpServletRequest
private HttpFields _trailers; private HttpFields _trailers;
private HttpURI _uri; private HttpURI _uri;
private String _method; private String _method;
private String _contextPath; private String _pathInContext;
private String _servletPath;
private String _pathInfo;
private ServletPathMapping _servletPathMapping; private ServletPathMapping _servletPathMapping;
private boolean _secure; private boolean _secure;
private String _asyncNotSupportedSource = null; private String _asyncNotSupportedSource = null;
@ -777,7 +777,44 @@ public class Request implements HttpServletRequest
@Override @Override
public String getContextPath() 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 @Override
@ -1048,15 +1085,20 @@ public class Request implements HttpServletRequest
@Override @Override
public String getPathInfo() 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 @Override
public String getPathTranslated() public String getPathTranslated()
{ {
if (_pathInfo == null || _context == null) String pathInfo = getPathInfo();
if (pathInfo == null || _context == null)
return null; return null;
return _context.getRealPath(_pathInfo); return _context.getRealPath(pathInfo);
} }
@Override @Override
@ -1207,7 +1249,7 @@ public class Request implements HttpServletRequest
// handle relative path // handle relative path
if (!path.startsWith("/")) if (!path.startsWith("/"))
{ {
String relTo = URIUtil.addPaths(_servletPath, _pathInfo); String relTo = _pathInContext;
int slash = relTo.lastIndexOf("/"); int slash = relTo.lastIndexOf("/");
if (slash > 1) if (slash > 1)
relTo = relTo.substring(0, slash + 1); relTo = relTo.substring(0, slash + 1);
@ -1335,9 +1377,11 @@ public class Request implements HttpServletRequest
@Override @Override
public String getServletPath() public String getServletPath()
{ {
if (_servletPath == null) // The servletPath returned is normally for the current servlet. Except during an
_servletPath = ""; // INCLUDE dispatch, in which case this method returns the servletPath of the source servlet,
return _servletPath; // which we recover from the IncludeAttributes wrapper.
ServletPathMapping mapping = findServletPathMapping();
return mapping == null ? "" : mapping.getServletPath();
} }
public ServletResponse getServletResponse() public ServletResponse getServletResponse()
@ -1678,10 +1722,10 @@ public class Request implements HttpServletRequest
if (path == null || path.isEmpty()) if (path == null || path.isEmpty())
{ {
setPathInfo(encoded == null ? "" : encoded); _pathInContext = encoded == null ? "" : encoded;
throw new BadMessageException(400, "Bad URI"); throw new BadMessageException(400, "Bad URI");
} }
setPathInfo(path); _pathInContext = path;
} }
public org.eclipse.jetty.http.MetaData.Request getMetaData() public org.eclipse.jetty.http.MetaData.Request getMetaData()
@ -1740,13 +1784,12 @@ public class Request implements HttpServletRequest
} }
_contentType = null; _contentType = null;
_characterEncoding = null; _characterEncoding = null;
_contextPath = null; _pathInContext = null;
if (_cookies != null) if (_cookies != null)
_cookies.reset(); _cookies.reset();
_cookiesExtracted = false; _cookiesExtracted = false;
_context = null; _context = null;
_newContext = false; _newContext = false;
_pathInfo = null;
_queryEncoding = null; _queryEncoding = null;
_requestedSessionId = null; _requestedSessionId = null;
_requestedSessionIdFromCookie = false; _requestedSessionIdFromCookie = false;
@ -1754,7 +1797,6 @@ public class Request implements HttpServletRequest
_session = null; _session = null;
_sessionHandler = null; _sessionHandler = null;
_scope = null; _scope = null;
_servletPath = null;
_timeStamp = 0; _timeStamp = 0;
_queryParameters = null; _queryParameters = null;
_contentParameters = 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) public void setAttributes(Attributes attributes)
{ {
_attributes = attributes; _attributes = attributes;
@ -1864,7 +1913,7 @@ public class Request implements HttpServletRequest
// attributes there, under any other wrappers. // attributes there, under any other wrappers.
((ServletAttributes)baseAttributes).setAsyncAttributes(getRequestURI(), ((ServletAttributes)baseAttributes).setAsyncAttributes(getRequestURI(),
getContextPath(), getContextPath(),
getPathInfo(), // TODO change to pathInContext when cheaply available getPathInContext(),
getServletPathMapping(), getServletPathMapping(),
getQueryString()); 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 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; _newContext = _context != context;
if (context == null) _context = context;
_context = null; _pathInContext = pathInContext;
else if (context != null)
{
_context = context;
_errorContext = context; _errorContext = context;
}
} }
/** /**
* @return True if this is the first call of <code>takeNewContext()</code> since the last * @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() public boolean takeNewContext()
{ {
@ -1982,17 +2030,6 @@ public class Request implements HttpServletRequest
return nc; 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. * @param cookies The cookies to set.
*/ */
@ -2026,14 +2063,6 @@ public class Request implements HttpServletRequest
return HttpMethod.HEAD.is(getMethod()); 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 * 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. * getParameter methods.
@ -2071,14 +2100,6 @@ public class Request implements HttpServletRequest
_requestedSessionIdFromCookie = requestedSessionIdCookie; _requestedSessionIdFromCookie = requestedSessionIdCookie;
} }
/**
* @param servletPath The servletPath to set.
*/
public void setServletPath(String servletPath)
{
_servletPath = servletPath;
}
/** /**
* @param session The session to set. * @param session The session to set.
*/ */
@ -2347,32 +2368,48 @@ public class Request implements HttpServletRequest
/** /**
* Set the servletPathMapping, the servletPath and the pathInfo. * 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()} * @param servletPathMapping The mapping used to return from {@link #getHttpServletMapping()}
*/ */
public void setServletPathMapping(ServletPathMapping servletPathMapping) public void setServletPathMapping(ServletPathMapping servletPathMapping)
{ {
_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() public ServletPathMapping getServletPathMapping()
{ {
return _servletPathMapping; 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 @Override
public HttpServletMapping getHttpServletMapping() 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; return url;
if (request.getServerPort() != port) if (request.getServerPort() != port)
return url; 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; return url;
} }

View File

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

View File

@ -40,7 +40,6 @@ import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.IncludeExclude; import org.eclipse.jetty.util.IncludeExclude;
import org.eclipse.jetty.util.IteratingCallback; import org.eclipse.jetty.util.IteratingCallback;
import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.URIUtil;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 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 public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{ {
final ServletContext context = baseRequest.getServletContext(); 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); LOG.debug("{} handle {} in {}", this, baseRequest, context);
HttpOutput out = baseRequest.getResponse().getHttpOutput(); HttpOutput out = baseRequest.getResponse().getHttpOutput();

View File

@ -1150,13 +1150,11 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("scope {}|{}|{} @ {}", baseRequest.getContextPath(), baseRequest.getServletPath(), baseRequest.getPathInfo(), this); LOG.debug("scope {}|{}|{} @ {}", baseRequest.getContextPath(), baseRequest.getServletPath(), baseRequest.getPathInfo(), this);
final Thread currentThread = Thread.currentThread();
final ClassLoader oldClassloader = currentThread.getContextClassLoader();
Context oldContext; Context oldContext;
String oldContextPath = null; String oldPathInContext = null;
String oldServletPath = null; String pathInContext = target;
String oldPathInfo = null;
ClassLoader oldClassloader = null;
Thread currentThread = null;
String pathInfo = target;
DispatcherType dispatch = baseRequest.getDispatcherType(); DispatcherType dispatch = baseRequest.getDispatcherType();
@ -1177,47 +1175,31 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
{ {
if (_contextPath.length() > 1) if (_contextPath.length() > 1)
target = target.substring(_contextPath.length()); target = target.substring(_contextPath.length());
pathInfo = target; pathInContext = target;
} }
else if (_contextPath.length() == 1) else if (_contextPath.length() == 1)
{ {
target = URIUtil.SLASH; target = URIUtil.SLASH;
pathInfo = URIUtil.SLASH; pathInContext = URIUtil.SLASH;
} }
else else
{ {
target = URIUtil.SLASH; 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 try
{ {
oldContextPath = baseRequest.getContextPath(); oldPathInContext = baseRequest.getPathInContext();
oldServletPath = baseRequest.getServletPath();
oldPathInfo = baseRequest.getPathInfo();
// Update the paths // Update the paths
baseRequest.setContext(_scontext); baseRequest.setContext(_scontext, pathInContext);
__context.set(_scontext); __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) if (oldContext != _scontext)
enterScope(baseRequest, dispatch); enterScope(baseRequest, dispatch);
@ -1234,17 +1216,12 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
exitScope(baseRequest); exitScope(baseRequest);
// reset the classloader // reset the classloader
if (_classLoader != null && currentThread != null) if (_classLoader != null)
{
currentThread.setContextClassLoader(oldClassloader); currentThread.setContextClassLoader(oldClassloader);
}
// reset the context and servlet path. // reset the context and servlet path.
baseRequest.setContext(oldContext); baseRequest.setContext(oldContext, oldPathInContext);
__context.set(oldContext); __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.IncludeExclude;
import org.eclipse.jetty.util.RegexSet; import org.eclipse.jetty.util.RegexSet;
import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.compression.DeflaterPool; import org.eclipse.jetty.util.compression.DeflaterPool;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 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 public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{ {
final ServletContext context = baseRequest.getServletContext(); 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); LOG.debug("{} handle {} in {}", this, baseRequest, context);
if (!_dispatchers.contains(baseRequest.getDispatcherType())) if (!_dispatchers.contains(baseRequest.getDispatcherType()))

View File

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

View File

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

View File

@ -43,6 +43,10 @@ public interface Attributes
void clearAttributes(); 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) static Attributes unwrap(Attributes attributes)
{ {
while (attributes instanceof Wrapper) while (attributes instanceof Wrapper)
@ -52,6 +56,26 @@ public interface Attributes
return 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 abstract class Wrapper implements Attributes
{ {
protected final Attributes _attributes; protected final Attributes _attributes;