Servlet 4.0 getMappings rough implementation #746
This commit is contained in:
parent
75f4af1355
commit
53c07a5a83
|
@ -1,251 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
|
||||
/** Build a request to be pushed.
|
||||
*
|
||||
* <p>A PushBuilder is obtained by calling {@link
|
||||
* Request#getPushBuilder()} (<code>Eventually HttpServletRequest.getPushBuilder()</code>).
|
||||
* Each call to this method will
|
||||
* return a new instance of a PushBuilder based off the current {@code
|
||||
* HttpServletRequest}. Any mutations to the returned PushBuilder are
|
||||
* not reflected on future returns.</p>
|
||||
*
|
||||
* <p>The instance is initialized as follows:</p>
|
||||
*
|
||||
* <ul>
|
||||
*
|
||||
* <li>The method is initialized to "GET"</li>
|
||||
*
|
||||
* <li>The existing headers of the current {@link HttpServletRequest}
|
||||
* are added to the builder, except for:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Conditional headers (eg. If-Modified-Since)
|
||||
* <li>Range headers
|
||||
* <li>Expect headers
|
||||
* <li>Authorization headers
|
||||
* <li>Referrer headers
|
||||
* </ul>
|
||||
*
|
||||
* </li>
|
||||
*
|
||||
* <li>If the request was authenticated, an Authorization header will
|
||||
* be set with a container generated token that will result in equivalent
|
||||
* Authorization for the pushed request.</li>
|
||||
*
|
||||
* <li>The {@link HttpServletRequest#getRequestedSessionId()} value,
|
||||
* unless at the time of the call {@link
|
||||
* HttpServletRequest#getSession(boolean)} has previously been called to
|
||||
* create a new {@link HttpSession}, in which case the new session ID
|
||||
* will be used as the PushBuilder's requested session ID. The source of
|
||||
* the requested session id will be the same as for the request</li>
|
||||
*
|
||||
* <li>The Referer(sic) header will be set to {@link
|
||||
* HttpServletRequest#getRequestURL()} plus any {@link
|
||||
* HttpServletRequest#getQueryString()} </li>
|
||||
*
|
||||
* <li>If {@link HttpServletResponse#addCookie(Cookie)} has been called
|
||||
* on the associated response, then a corresponding Cookie header will be added
|
||||
* to the PushBuilder, unless the {@link Cookie#getMaxAge()} is <=0, in which
|
||||
* case the Cookie will be removed from the builder.</li>
|
||||
*
|
||||
* <li>If this request has has the conditional headers If-Modified-Since
|
||||
* or If-None-Match, then the {@link #isConditional()} header is set to
|
||||
* true.</li>
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* <p>The {@link #path} method must be called on the {@code PushBuilder}
|
||||
* instance before the call to {@link #push}. Failure to do so must
|
||||
* cause an exception to be thrown from {@link
|
||||
* #push}, as specified in that method.</p>
|
||||
*
|
||||
* <p>A PushBuilder can be customized by chained calls to mutator
|
||||
* methods before the {@link #push()} method is called to initiate an
|
||||
* asynchronous push request with the current state of the builder.
|
||||
* After the call to {@link #push()}, the builder may be reused for
|
||||
* another push, however the implementation must make it so the {@link
|
||||
* #path(String)}, {@link #etag(String)} and {@link
|
||||
* #lastModified(String)} values are cleared before returning from
|
||||
* {@link #push}. All other values are retained over calls to {@link
|
||||
* #push()}.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public interface PushBuilder
|
||||
{
|
||||
/**
|
||||
* <p>Set the method to be used for the push.</p>
|
||||
*
|
||||
* <p>Any non-empty String may be used for the method.</p>
|
||||
*
|
||||
* @param method the method to be used for the push.
|
||||
* @return this builder.
|
||||
* @throws NullPointerException if the argument is {@code null}
|
||||
* @throws IllegalArgumentException if the argument is the empty String
|
||||
*/
|
||||
public abstract PushBuilder method(String method);
|
||||
|
||||
/** Set the query string to be used for the push.
|
||||
*
|
||||
* Will be appended to any query String included in a call to {@link
|
||||
* #path(String)}. Any duplicate parameters must be preserved. This
|
||||
* method should be used instead of a query in {@link #path(String)}
|
||||
* when multiple {@link #push()} calls are to be made with the same
|
||||
* query string.
|
||||
* @param queryString the query string to be used for the push.
|
||||
* @return this builder.
|
||||
*/
|
||||
public abstract PushBuilder queryString(String queryString);
|
||||
|
||||
/** Set the SessionID to be used for the push.
|
||||
* The session ID will be set in the same way it was on the associated request (ie
|
||||
* as a cookie if the associated request used a cookie, or as a url parameter if
|
||||
* the associated request used a url parameter).
|
||||
* Defaults to the requested session ID or any newly assigned session id from
|
||||
* a newly created session.
|
||||
* @param sessionId the SessionID to be used for the push.
|
||||
* @return this builder.
|
||||
*/
|
||||
public abstract PushBuilder sessionId(String sessionId);
|
||||
|
||||
/** Set if the request is to be conditional.
|
||||
* If the request is conditional, any available values from {@link #etag(String)} or
|
||||
* {@link #lastModified(String)} will be set in the appropriate headers. If the request
|
||||
* is not conditional, then etag and lastModified values are ignored.
|
||||
* Defaults to true if the associated request was conditional.
|
||||
* @param conditional true if the push request is conditional
|
||||
* @return this builder.
|
||||
*/
|
||||
public abstract PushBuilder conditional(boolean conditional);
|
||||
|
||||
/**
|
||||
* <p>Set a header to be used for the push. If the builder has an
|
||||
* existing header with the same name, its value is overwritten.</p>
|
||||
*
|
||||
* @param name The header name to set
|
||||
* @param value The header value to set
|
||||
* @return this builder.
|
||||
*/
|
||||
public abstract PushBuilder setHeader(String name, String value);
|
||||
|
||||
|
||||
/**
|
||||
* <p>Add a header to be used for the push.</p>
|
||||
* @param name The header name to add
|
||||
* @param value The header value to add
|
||||
* @return this builder.
|
||||
*/
|
||||
public abstract PushBuilder addHeader(String name, String value);
|
||||
|
||||
|
||||
/**
|
||||
* <p>Remove the named header. If the header does not exist, take
|
||||
* no action.</p>
|
||||
*
|
||||
* @param name The name of the header to remove
|
||||
* @return this builder.
|
||||
*/
|
||||
public abstract PushBuilder removeHeader(String name);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set the URI path to be used for the push. The path may start
|
||||
* with "/" in which case it is treated as an absolute path,
|
||||
* otherwise it is relative to the context path of the associated
|
||||
* request. There is no path default and <code>path(String)</code> must
|
||||
* be called before every call to {@link #push()}. If a query
|
||||
* string is present in the argument {@code path}, its contents must
|
||||
* be merged with the contents previously passed to {@link
|
||||
* #queryString}, preserving duplicates.
|
||||
*
|
||||
* @param path the URI path to be used for the push, which may include a
|
||||
* query string.
|
||||
* @return this builder.
|
||||
*/
|
||||
public abstract PushBuilder path(String path);
|
||||
|
||||
/**
|
||||
* Set the etag to be used for conditional pushes.
|
||||
* The etag will be used only if {@link #isConditional()} is true.
|
||||
* Defaults to no etag. The value is nulled after every call to
|
||||
* {@link #push()}
|
||||
* @param etag the etag to be used for the push.
|
||||
* @return this builder.
|
||||
*/
|
||||
public abstract PushBuilder etag(String etag);
|
||||
|
||||
/**
|
||||
* Set the last modified date to be used for conditional pushes.
|
||||
* The last modified date will be used only if {@link
|
||||
* #isConditional()} is true. Defaults to no date. The value is
|
||||
* nulled after every call to {@link #push()}
|
||||
* @param lastModified the last modified date to be used for the push.
|
||||
* @return this builder.
|
||||
*/
|
||||
public abstract PushBuilder lastModified(String lastModified);
|
||||
|
||||
|
||||
/** Push a resource given the current state of the builder,
|
||||
* returning immediately without blocking.
|
||||
*
|
||||
* <p>Push a resource based on the current state of the PushBuilder.
|
||||
* If {@link #isConditional()} is true and an etag or lastModified
|
||||
* value is provided, then an appropriate conditional header will be
|
||||
* generated. If both an etag and lastModified value are provided
|
||||
* only an If-None-Match header will be generated. If the builder
|
||||
* has a session ID, then the pushed request will include the
|
||||
* session ID either as a Cookie or as a URI parameter as
|
||||
* appropriate. The builders query string is merged with any passed
|
||||
* query string.</p>
|
||||
*
|
||||
* <p>Before returning from this method, the builder has its path,
|
||||
* etag and lastModified fields nulled. All other fields are left as
|
||||
* is for possible reuse in another push.</p>
|
||||
*
|
||||
* @throws IllegalArgumentException if the method set expects a
|
||||
* request body (eg POST)
|
||||
*
|
||||
* @throws IllegalStateException if there was no call to {@link
|
||||
* #path} on this instance either between its instantiation or the
|
||||
* last call to {@code push()} that did not throw an
|
||||
* IllegalStateException.
|
||||
*/
|
||||
public abstract void push();
|
||||
|
||||
public abstract String getMethod();
|
||||
public abstract String getQueryString();
|
||||
public abstract String getSessionId();
|
||||
public abstract boolean isConditional();
|
||||
public abstract Set<String> getHeaderNames();
|
||||
public abstract String getHeader(String name);
|
||||
public abstract String getPath();
|
||||
public abstract String getEtag();
|
||||
public abstract String getLastModified();
|
||||
}
|
|
@ -20,6 +20,8 @@ package org.eclipse.jetty.server;
|
|||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.PushBuilder;
|
||||
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
|
|
|
@ -60,6 +60,7 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import javax.servlet.http.HttpSession;
|
||||
import javax.servlet.http.HttpUpgradeHandler;
|
||||
import javax.servlet.http.Part;
|
||||
import javax.servlet.http.PushBuilder;
|
||||
|
||||
import org.eclipse.jetty.http.BadMessageException;
|
||||
import org.eclipse.jetty.http.HostPortHttpField;
|
||||
|
@ -74,6 +75,8 @@ import org.eclipse.jetty.http.HttpURI;
|
|||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.http.MetaData;
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.http.pathmap.PathSpec;
|
||||
import org.eclipse.jetty.http.pathmap.ServletPathSpec;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler.Context;
|
||||
import org.eclipse.jetty.server.session.Session;
|
||||
|
@ -173,6 +176,7 @@ public class Request implements HttpServletRequest
|
|||
private String _contextPath;
|
||||
private String _servletPath;
|
||||
private String _pathInfo;
|
||||
private PathSpec _pathSpec;
|
||||
|
||||
private boolean _secure;
|
||||
private String _asyncNotSupportedSource = null;
|
||||
|
@ -236,42 +240,7 @@ public class Request implements HttpServletRequest
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get a PushBuilder associated with this request initialized as follows:<ul>
|
||||
* <li>The method is initialized to "GET"</li>
|
||||
* <li>The headers from this request are copied to the Builder, except for:<ul>
|
||||
* <li>Conditional headers (eg. If-Modified-Since)
|
||||
* <li>Range headers
|
||||
* <li>Expect headers
|
||||
* <li>Authorization headers
|
||||
* <li>Referrer headers
|
||||
* </ul></li>
|
||||
* <li>If the request was Authenticated, an Authorization header will
|
||||
* be set with a container generated token that will result in equivalent
|
||||
* Authorization</li>
|
||||
* <li>The query string from {@link #getQueryString()}
|
||||
* <li>The {@link #getRequestedSessionId()} value, unless at the time
|
||||
* of the call {@link #getSession(boolean)}
|
||||
* has previously been called to create a new {@link HttpSession}, in
|
||||
* which case the new session ID will be used as the PushBuilders
|
||||
* requested session ID.</li>
|
||||
* <li>The source of the requested session id will be the same as for
|
||||
* this request</li>
|
||||
* <li>The builders Referer header will be set to {@link #getRequestURL()}
|
||||
* plus any {@link #getQueryString()} </li>
|
||||
* <li>If {@link HttpServletResponse#addCookie(Cookie)} has been called
|
||||
* on the associated response, then a corresponding Cookie header will be added
|
||||
* to the PushBuilder, unless the {@link Cookie#getMaxAge()} is <=0, in which
|
||||
* case the Cookie will be removed from the builder.</li>
|
||||
* <li>If this request has has the conditional headers If-Modified-Since or
|
||||
* If-None-Match then the {@link PushBuilderImpl#isConditional()} header is set
|
||||
* to true.
|
||||
* </ul>
|
||||
*
|
||||
* <p>Each call to getPushBuilder() will return a new instance
|
||||
* of a PushBuilder based off this Request. Any mutations to the
|
||||
* returned PushBuilder are not reflected on future returns.
|
||||
* @return A new PushBuilder or null if push is not supported
|
||||
*/
|
||||
@Override
|
||||
public PushBuilder getPushBuilder()
|
||||
{
|
||||
if (!isPushSupported())
|
||||
|
@ -1840,6 +1809,7 @@ public class Request implements HttpServletRequest
|
|||
_queryParameters = null;
|
||||
_contentParameters = null;
|
||||
_parameters = null;
|
||||
_pathSpec = null;
|
||||
_contentParamsExtracted = false;
|
||||
_inputState = __NONE;
|
||||
_multiPartInputStream = null;
|
||||
|
@ -2427,4 +2397,106 @@ public class Request implements HttpServletRequest
|
|||
{
|
||||
throw new ServletException("HttpServletRequest.upgrade() not supported in Jetty");
|
||||
}
|
||||
|
||||
|
||||
public void setPathSpec(PathSpec pathSpec)
|
||||
{
|
||||
_pathSpec = pathSpec;
|
||||
}
|
||||
|
||||
public PathSpec getPathSpec()
|
||||
{
|
||||
return _pathSpec;
|
||||
}
|
||||
|
||||
|
||||
// TODO replace with overriden version from API
|
||||
public Mapping getMapping()
|
||||
{
|
||||
final PathSpec pathSpec = _pathSpec;
|
||||
final String servletPath = _servletPath;
|
||||
return new Mapping()
|
||||
{
|
||||
@Override
|
||||
public String getMatchValue()
|
||||
{
|
||||
return servletPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPattern()
|
||||
{
|
||||
if (pathSpec!=null)
|
||||
pathSpec.toString();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingMatch getMatchType()
|
||||
{
|
||||
if (pathSpec instanceof ServletPathSpec)
|
||||
{
|
||||
switch(((ServletPathSpec)pathSpec).getGroup())
|
||||
{
|
||||
case EXACT:
|
||||
return MappingMatch.EXACT;
|
||||
case ROOT:
|
||||
return MappingMatch.CONTEXT_ROOT;
|
||||
case PREFIX_GLOB:
|
||||
return MappingMatch.PATH;
|
||||
case SUFFIX_GLOB:
|
||||
return MappingMatch.EXTENSION;
|
||||
|
||||
default:
|
||||
return MappingMatch.UNKNOWN;
|
||||
}
|
||||
}
|
||||
else
|
||||
return MappingMatch.UNKNOWN;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents how the request from which this object was obtained was mapped to
|
||||
* the associated servlet.
|
||||
* TODO replace with API version
|
||||
* @since 4.0
|
||||
*/
|
||||
public interface Mapping {
|
||||
/**
|
||||
* @return The value that was matched or the empty String if not known.
|
||||
*/
|
||||
String getMatchValue();
|
||||
|
||||
/**
|
||||
* @return The {@code url-pattern} that matched this request or the empty
|
||||
* String if not known.
|
||||
*/
|
||||
String getPattern();
|
||||
|
||||
/**
|
||||
* @return The type of match ({@link MappingMatch#UNKNOWN} if not known)
|
||||
*/
|
||||
MappingMatch getMatchType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the ways that a request can be mapped to a servlet
|
||||
* TODO replace with API version
|
||||
* @since 4.0
|
||||
*/
|
||||
public enum MappingMatch
|
||||
{
|
||||
CONTEXT_ROOT,
|
||||
DEFAULT,
|
||||
EXACT,
|
||||
EXTENSION,
|
||||
IMPLICIT,
|
||||
PATH,
|
||||
UNKNOWN
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -457,6 +457,7 @@ public class ServletHandler extends ScopedHandler
|
|||
}
|
||||
else
|
||||
{
|
||||
baseRequest.setPathSpec(pathSpec);
|
||||
baseRequest.setServletPath(servlet_path);
|
||||
baseRequest.setPathInfo(path_info);
|
||||
}
|
||||
|
|
|
@ -39,13 +39,13 @@ import javax.servlet.ServletException;
|
|||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.PushBuilder;
|
||||
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpURI;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.server.PushBuilder;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
|
|
|
@ -33,10 +33,10 @@ import javax.servlet.ServletRequestEvent;
|
|||
import javax.servlet.ServletRequestListener;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import javax.servlet.http.PushBuilder;
|
||||
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpURI;
|
||||
import org.eclipse.jetty.server.PushBuilder;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
|
Loading…
Reference in New Issue