diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncAttributes.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncAttributes.java index 90f0b452896..9d040cb9a06 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncAttributes.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncAttributes.java @@ -26,28 +26,27 @@ import org.eclipse.jetty.util.Attributes; class AsyncAttributes extends Attributes.Wrapper { - /** - * Async dispatch attribute name prefix. - */ - public static final String __ASYNC_PREFIX = "javax.servlet.async."; - private String _requestURI; private String _contextPath; private String _servletPath; private String _pathInfo; - private String _query; + private String _queryString; - AsyncAttributes(Attributes attributes) + public AsyncAttributes(Attributes attributes, String requestUri, String contextPath, String servletPath, String pathInfo, String queryString) { super(attributes); + + // TODO: make fields final in jetty-10 and NOOP when one of these attributes is set. + _requestURI = requestUri; + _contextPath = contextPath; + _servletPath = servletPath; + _pathInfo = pathInfo; + _queryString = queryString; } @Override public Object getAttribute(String key) { - if (!key.startsWith(__ASYNC_PREFIX)) - return super.getAttribute(key); - switch (key) { case AsyncContext.ASYNC_REQUEST_URI: @@ -59,7 +58,7 @@ class AsyncAttributes extends Attributes.Wrapper case AsyncContext.ASYNC_PATH_INFO: return _pathInfo; case AsyncContext.ASYNC_QUERY_STRING: - return _query; + return _queryString; default: return super.getAttribute(key); } @@ -68,13 +67,7 @@ class AsyncAttributes extends Attributes.Wrapper @Override public Set getAttributeNameSet() { - HashSet set = new HashSet<>(); - for (String name : _attributes.getAttributeNameSet()) - { - if (!name.startsWith(__ASYNC_PREFIX)) - set.add(name); - } - + Set set = new HashSet<>(super.getAttributeNameSet()); if (_requestURI != null) set.add(AsyncContext.ASYNC_REQUEST_URI); if (_contextPath != null) @@ -83,18 +76,14 @@ class AsyncAttributes extends Attributes.Wrapper set.add(AsyncContext.ASYNC_SERVLET_PATH); if (_pathInfo != null) set.add(AsyncContext.ASYNC_PATH_INFO); - if (_query != null) + if (_queryString != null) set.add(AsyncContext.ASYNC_QUERY_STRING); - return set; } @Override public void setAttribute(String key, Object value) { - if (!key.startsWith(__ASYNC_PREFIX)) - super.setAttribute(key, value); - switch (key) { case AsyncContext.ASYNC_REQUEST_URI: @@ -110,10 +99,11 @@ class AsyncAttributes extends Attributes.Wrapper _pathInfo = (String)value; break; case AsyncContext.ASYNC_QUERY_STRING: - _query = (String)value; + _queryString = (String)value; break; default: super.setAttribute(key, value); + break; } } @@ -124,7 +114,21 @@ class AsyncAttributes extends Attributes.Wrapper _contextPath = null; _servletPath = null; _pathInfo = null; - _query = null; + _queryString = null; super.clearAttributes(); } + + public void applyToAttributes(Attributes attributes) + { + if (_requestURI != null) + attributes.setAttribute(AsyncContext.ASYNC_REQUEST_URI, _requestURI); + if (_contextPath != null) + attributes.setAttribute(AsyncContext.ASYNC_CONTEXT_PATH, _contextPath); + if (_servletPath != null) + attributes.setAttribute(AsyncContext.ASYNC_SERVLET_PATH, _servletPath); + if (_pathInfo != null) + attributes.setAttribute(AsyncContext.ASYNC_PATH_INFO, _pathInfo); + if (_queryString != null) + attributes.setAttribute(AsyncContext.ASYNC_QUERY_STRING, _queryString); + } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextEvent.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextEvent.java index 9be11f7f39e..cc413f9ec8f 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextEvent.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextEvent.java @@ -20,7 +20,6 @@ package org.eclipse.jetty.server; import javax.servlet.AsyncContext; import javax.servlet.AsyncEvent; -import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; @@ -32,7 +31,7 @@ public class AsyncContextEvent extends AsyncEvent implements Runnable { private final Context _context; private final AsyncContextState _asyncContext; - private volatile HttpChannelState _state; + private final HttpChannelState _state; private ServletContext _dispatchContext; private String _dispatchPath; private volatile Scheduler.Task _timeoutTask; @@ -45,31 +44,9 @@ public class AsyncContextEvent extends AsyncEvent implements Runnable _asyncContext = asyncContext; _state = state; - // If we haven't been async dispatched before - if (baseRequest.getAttribute(AsyncContext.ASYNC_REQUEST_URI) == null) - { - // We are setting these attributes during startAsync, when the spec implies that - // they are only available after a call to AsyncContext.dispatch(...); - - // have we been forwarded before? - String uri = (String)baseRequest.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI); - if (uri != null) - { - baseRequest.setAttribute(AsyncContext.ASYNC_REQUEST_URI, uri); - baseRequest.setAttribute(AsyncContext.ASYNC_CONTEXT_PATH, baseRequest.getAttribute(RequestDispatcher.FORWARD_CONTEXT_PATH)); - baseRequest.setAttribute(AsyncContext.ASYNC_SERVLET_PATH, baseRequest.getAttribute(RequestDispatcher.FORWARD_SERVLET_PATH)); - baseRequest.setAttribute(AsyncContext.ASYNC_PATH_INFO, baseRequest.getAttribute(RequestDispatcher.FORWARD_PATH_INFO)); - baseRequest.setAttribute(AsyncContext.ASYNC_QUERY_STRING, baseRequest.getAttribute(RequestDispatcher.FORWARD_QUERY_STRING)); - } - else - { - baseRequest.setAttribute(AsyncContext.ASYNC_REQUEST_URI, baseRequest.getRequestURI()); - baseRequest.setAttribute(AsyncContext.ASYNC_CONTEXT_PATH, baseRequest.getContextPath()); - baseRequest.setAttribute(AsyncContext.ASYNC_SERVLET_PATH, baseRequest.getServletPath()); - baseRequest.setAttribute(AsyncContext.ASYNC_PATH_INFO, baseRequest.getPathInfo()); - baseRequest.setAttribute(AsyncContext.ASYNC_QUERY_STRING, baseRequest.getQueryString()); - } - } + // We are setting these attributes during startAsync, when the spec implies that + // they are only available after a call to AsyncContext.dispatch(...); + baseRequest.setAsyncAttributes(); } public ServletContext getSuspendedContext() diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 07495e906a3..0b8939f6dcb 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -39,7 +39,6 @@ import java.util.EventListener; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Objects; import java.util.function.Supplier; import java.util.stream.Collectors; import javax.servlet.AsyncContext; @@ -200,7 +199,7 @@ public class Request implements HttpServletRequest private boolean _handled = false; private boolean _contentParamsExtracted; private boolean _requestedSessionIdFromCookie = false; - private Attributes _attributes = new ServletAttributes(); + private Attributes _attributes; private Authentication _authentication; private String _contentType; private String _characterEncoding; @@ -627,7 +626,7 @@ public class Request implements HttpServletRequest _channel.getHttpTransport() instanceof HttpConnection) return _channel.getHttpTransport(); } - return _attributes.getAttribute(name); + return (_attributes == null) ? null : _attributes.getAttribute(name); } /* @@ -636,11 +635,16 @@ public class Request implements HttpServletRequest @Override public Enumeration getAttributeNames() { + if (_attributes == null) + return Collections.enumeration(Collections.emptyList()); + return AttributesMap.getAttributeNamesCopy(_attributes); } public Attributes getAttributes() { + if (_attributes == null) + _attributes = new ServletAttributes(); return _attributes; } @@ -1904,7 +1908,7 @@ public class Request implements HttpServletRequest @Override public void removeAttribute(String name) { - Object oldValue = _attributes.getAttribute(name); + Object oldValue = _attributes == null ? null : _attributes.getAttribute(name); if (_attributes != null) _attributes.removeAttribute(name); @@ -1938,13 +1942,15 @@ public class Request implements HttpServletRequest @Override public void setAttribute(String name, Object value) { - Object oldValue = _attributes.getAttribute(name); + Object oldValue = _attributes == null ? null : _attributes.getAttribute(name); if ("org.eclipse.jetty.server.Request.queryEncoding".equals(name)) setQueryEncoding(value == null ? null : value.toString()); else if ("org.eclipse.jetty.server.sendContent".equals(name)) LOG.warn("Deprecated: org.eclipse.jetty.server.sendContent"); + if (_attributes == null) + _attributes = new ServletAttributes(); _attributes.setAttribute(name, value); if (!_requestAttributeListeners.isEmpty()) @@ -1964,7 +1970,47 @@ public class Request implements HttpServletRequest public void setAttributes(Attributes attributes) { - _attributes = Objects.requireNonNull(attributes); + _attributes = attributes; + } + + public void setAsyncAttributes() + { + // Return if we have been async dispatched before. + if (getAttribute(AsyncContext.ASYNC_REQUEST_URI) != null) + return; + + // Unwrap the _attributes to get the base attributes instance. + Attributes baseAttributes; + if (_attributes == null) + _attributes = baseAttributes = new ServletAttributes(); + else + baseAttributes = Attributes.unwrap(_attributes); + + AsyncAttributes asyncAttributes; + // Have we been forwarded before? + String uri = (String)getAttribute(RequestDispatcher.FORWARD_REQUEST_URI); + if (uri != null) + { + String contextPath = (String)getAttribute(RequestDispatcher.FORWARD_CONTEXT_PATH); + String servletPath = (String)getAttribute(RequestDispatcher.FORWARD_SERVLET_PATH); + String pathInfo = (String)getAttribute(RequestDispatcher.FORWARD_PATH_INFO); + String queryString = (String)getAttribute(RequestDispatcher.FORWARD_QUERY_STRING); + asyncAttributes = new AsyncAttributes(baseAttributes, uri, contextPath, servletPath, pathInfo, queryString); + } + else + { + String requestURI = getRequestURI(); + String contextPath = getContextPath(); + String servletPath = getServletPath(); + String pathInfo = getPathInfo(); + String queryString = getQueryString(); + asyncAttributes = new AsyncAttributes(baseAttributes, requestURI, contextPath, servletPath, pathInfo, queryString); + } + + if (baseAttributes instanceof ServletAttributes) + ((ServletAttributes)_attributes).setAsyncAttributes(asyncAttributes); + else + asyncAttributes.applyToAttributes(_attributes); } /** diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ServletAttributes.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ServletAttributes.java index 08df2f498de..18c1dd8e305 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ServletAttributes.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ServletAttributes.java @@ -25,40 +25,59 @@ import org.eclipse.jetty.util.AttributesMap; public class ServletAttributes implements Attributes { - private final Attributes _attributes; + private final Attributes _attributes = new AttributesMap(); + private AsyncAttributes _asyncAttributes; - public ServletAttributes() + public void setAsyncAttributes(AsyncAttributes attributes) { - _attributes = new AsyncAttributes(new AttributesMap()); + _asyncAttributes = attributes; } @Override public void removeAttribute(String name) { - _attributes.removeAttribute(name); + if (_asyncAttributes == null) + _attributes.removeAttribute(name); + else + _asyncAttributes.removeAttribute(name); } @Override public void setAttribute(String name, Object attribute) { - _attributes.setAttribute(name, attribute); + if (_asyncAttributes == null) + _attributes.setAttribute(name, attribute); + else + _asyncAttributes.setAttribute(name, attribute); } @Override public Object getAttribute(String name) { - return _attributes.getAttribute(name); + if (_asyncAttributes == null) + return _attributes.getAttribute(name); + else + return _asyncAttributes.getAttribute(name); } @Override public Set getAttributeNameSet() { - return _attributes.getAttributeNameSet(); + if (_asyncAttributes == null) + return _attributes.getAttributeNameSet(); + else + return _asyncAttributes.getAttributeNameSet(); } @Override public void clearAttributes() { - _attributes.clearAttributes(); + if (_asyncAttributes == null) + _attributes.clearAttributes(); + else + { + _asyncAttributes.clearAttributes(); + _asyncAttributes = null; + } } }