|
|
249b5c |
Description: Let sub-classes of GuiceFilter customize the servlet filter pipeline
|
|
|
249b5c |
Author: Stuart McCulloch <mcculls@gmail.com>
|
|
|
249b5c |
Bug-Google: http://code.google.com/p/google-guice/issues/detail?id=618
|
|
|
249b5c |
Last-Update: 2015-01-20
|
|
|
249b5c |
|
|
|
249b5c |
diff --git a/extensions/servlet/src/com/google/inject/servlet/AbstractFilterPipeline.java b/extensions/servlet/src/com/google/inject/servlet/AbstractFilterPipeline.java
|
|
|
249b5c |
new file mode 100644
|
|
|
249b5c |
index 0000000..ab8f746
|
|
|
249b5c |
--- /dev/null
|
|
|
249b5c |
+++ b/extensions/servlet/src/com/google/inject/servlet/AbstractFilterPipeline.java
|
|
|
249b5c |
@@ -0,0 +1,150 @@
|
|
|
249b5c |
+/**
|
|
|
249b5c |
+ * Copyright (C) 2008 Google Inc.
|
|
|
249b5c |
+ *
|
|
|
249b5c |
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
249b5c |
+ * you may not use this file except in compliance with the License.
|
|
|
249b5c |
+ * You may obtain a copy of the License at
|
|
|
249b5c |
+ *
|
|
|
249b5c |
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
|
249b5c |
+ *
|
|
|
249b5c |
+ * Unless required by applicable law or agreed to in writing, software
|
|
|
249b5c |
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
249b5c |
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
249b5c |
+ * See the License for the specific language governing permissions and
|
|
|
249b5c |
+ * limitations under the License.
|
|
|
249b5c |
+ */
|
|
|
249b5c |
+package com.google.inject.servlet;
|
|
|
249b5c |
+
|
|
|
249b5c |
+import com.google.common.collect.Sets;
|
|
|
249b5c |
+import com.google.inject.Injector;
|
|
|
249b5c |
+import com.google.inject.Provider;
|
|
|
249b5c |
+
|
|
|
249b5c |
+import java.io.IOException;
|
|
|
249b5c |
+import java.util.Set;
|
|
|
249b5c |
+
|
|
|
249b5c |
+import javax.servlet.Filter;
|
|
|
249b5c |
+import javax.servlet.FilterChain;
|
|
|
249b5c |
+import javax.servlet.RequestDispatcher;
|
|
|
249b5c |
+import javax.servlet.ServletContext;
|
|
|
249b5c |
+import javax.servlet.ServletException;
|
|
|
249b5c |
+import javax.servlet.ServletRequest;
|
|
|
249b5c |
+import javax.servlet.ServletResponse;
|
|
|
249b5c |
+import javax.servlet.http.HttpServletRequest;
|
|
|
249b5c |
+import javax.servlet.http.HttpServletRequestWrapper;
|
|
|
249b5c |
+
|
|
|
249b5c |
+/**
|
|
|
249b5c |
+ * Skeleton implementation of a central routing/dispatch class which uses a sequence of
|
|
|
249b5c |
+ * {@link FilterDefinition}s to filter requests before delegating to the servlet pipeline.
|
|
|
249b5c |
+ *
|
|
|
249b5c |
+ * @author dhanji@gmail.com (Dhanji R. Prasanna)
|
|
|
249b5c |
+ */
|
|
|
249b5c |
+public abstract class AbstractFilterPipeline implements FilterPipeline {
|
|
|
249b5c |
+
|
|
|
249b5c |
+ private final AbstractServletPipeline servletPipeline;
|
|
|
249b5c |
+ private final Provider<ServletContext> servletContext;
|
|
|
249b5c |
+
|
|
|
249b5c |
+ //Unfortunately, we need the injector itself in order to create filters + servlets
|
|
|
249b5c |
+ private final Injector injector;
|
|
|
249b5c |
+
|
|
|
249b5c |
+ //Guards a DCL, so needs to be volatile
|
|
|
249b5c |
+ private volatile boolean initialized = false;
|
|
|
249b5c |
+
|
|
|
249b5c |
+ protected AbstractFilterPipeline(Injector injector, AbstractServletPipeline servletPipeline,
|
|
|
249b5c |
+ Provider<ServletContext> servletContext) {
|
|
|
249b5c |
+ this.injector = injector;
|
|
|
249b5c |
+ this.servletPipeline = servletPipeline;
|
|
|
249b5c |
+ this.servletContext = servletContext;
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+
|
|
|
249b5c |
+ /**
|
|
|
249b5c |
+ * @return {@code true} if any filter mappings exist; otherwise {@code false}
|
|
|
249b5c |
+ */
|
|
|
249b5c |
+ protected abstract boolean hasFiltersMapped();
|
|
|
249b5c |
+
|
|
|
249b5c |
+ /**
|
|
|
249b5c |
+ * @return snapshot of the filter mappings currently defined for this pipeline
|
|
|
249b5c |
+ */
|
|
|
249b5c |
+ protected abstract FilterDefinition[] filterDefinitions();
|
|
|
249b5c |
+
|
|
|
249b5c |
+ public synchronized void initPipeline(ServletContext servletContext)
|
|
|
249b5c |
+ throws ServletException {
|
|
|
249b5c |
+
|
|
|
249b5c |
+ //double-checked lock, prevents duplicate initialization
|
|
|
249b5c |
+ if (initialized)
|
|
|
249b5c |
+ return;
|
|
|
249b5c |
+
|
|
|
249b5c |
+ // Used to prevent duplicate initialization.
|
|
|
249b5c |
+ Set<Filter> initializedSoFar = Sets.newIdentityHashSet();
|
|
|
249b5c |
+
|
|
|
249b5c |
+ for (FilterDefinition filterDefinition : filterDefinitions()) {
|
|
|
249b5c |
+ filterDefinition.init(servletContext, injector, initializedSoFar);
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+
|
|
|
249b5c |
+ //next, initialize servlets...
|
|
|
249b5c |
+ servletPipeline.init(servletContext, injector);
|
|
|
249b5c |
+
|
|
|
249b5c |
+ //everything was ok...
|
|
|
249b5c |
+ initialized = true;
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+
|
|
|
249b5c |
+ public void dispatch(ServletRequest request, ServletResponse response,
|
|
|
249b5c |
+ FilterChain proceedingFilterChain) throws IOException, ServletException {
|
|
|
249b5c |
+
|
|
|
249b5c |
+ //lazy init of filter pipeline (OK by the servlet specification). This is needed
|
|
|
249b5c |
+ //in order for us not to force users to create a GuiceServletContextListener subclass.
|
|
|
249b5c |
+ if (!initialized) {
|
|
|
249b5c |
+ initPipeline(servletContext.get());
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+
|
|
|
249b5c |
+ //obtain the servlet pipeline to dispatch against
|
|
|
249b5c |
+ new FilterChainInvocation(filterDefinitions(), servletPipeline, proceedingFilterChain)
|
|
|
249b5c |
+ .doFilter(withDispatcher(request, servletPipeline), response);
|
|
|
249b5c |
+
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+
|
|
|
249b5c |
+ /**
|
|
|
249b5c |
+ * Used to create an proxy that dispatches either to the guice-servlet pipeline or the regular
|
|
|
249b5c |
+ * pipeline based on uri-path match. This proxy also provides minimal forwarding support.
|
|
|
249b5c |
+ *
|
|
|
249b5c |
+ * We cannot forward from a web.xml Servlet/JSP to a guice-servlet (because the filter pipeline
|
|
|
249b5c |
+ * is not called again). However, we can wrap requests with our own dispatcher to forward the
|
|
|
249b5c |
+ * *other* way. web.xml Servlets/JSPs can forward to themselves as per normal.
|
|
|
249b5c |
+ *
|
|
|
249b5c |
+ * This is not a problem cuz we intend for people to migrate from web.xml to guice-servlet,
|
|
|
249b5c |
+ * incrementally, but not the other way around (which, we should actively discourage).
|
|
|
249b5c |
+ */
|
|
|
249b5c |
+ @SuppressWarnings({ "JavaDoc", "deprecation" })
|
|
|
249b5c |
+ private ServletRequest withDispatcher(ServletRequest servletRequest,
|
|
|
249b5c |
+ final AbstractServletPipeline servletPipeline) {
|
|
|
249b5c |
+
|
|
|
249b5c |
+ // don't wrap the request if there are no servlets mapped. This prevents us from inserting our
|
|
|
249b5c |
+ // wrapper unless it's actually going to be used. This is necessary for compatibility for apps
|
|
|
249b5c |
+ // that downcast their HttpServletRequests to a concrete implementation.
|
|
|
249b5c |
+ if (!servletPipeline.hasServletsMapped()) {
|
|
|
249b5c |
+ return servletRequest;
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+
|
|
|
249b5c |
+ HttpServletRequest request = (HttpServletRequest) servletRequest;
|
|
|
249b5c |
+ //noinspection OverlyComplexAnonymousInnerClass
|
|
|
249b5c |
+ return new HttpServletRequestWrapper(request) {
|
|
|
249b5c |
+
|
|
|
249b5c |
+ @Override
|
|
|
249b5c |
+ public RequestDispatcher getRequestDispatcher(String path) {
|
|
|
249b5c |
+ final RequestDispatcher dispatcher = servletPipeline.getRequestDispatcher(path);
|
|
|
249b5c |
+
|
|
|
249b5c |
+ return (null != dispatcher) ? dispatcher : super.getRequestDispatcher(path);
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+ };
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+
|
|
|
249b5c |
+ public void destroyPipeline() {
|
|
|
249b5c |
+ //destroy servlets first
|
|
|
249b5c |
+ servletPipeline.destroy();
|
|
|
249b5c |
+
|
|
|
249b5c |
+ //go down chain and destroy all our filters
|
|
|
249b5c |
+ Set<Filter> destroyedSoFar = Sets.newIdentityHashSet();
|
|
|
249b5c |
+ for (FilterDefinition filterDefinition : filterDefinitions()) {
|
|
|
249b5c |
+ filterDefinition.destroy(destroyedSoFar);
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+}
|
|
|
249b5c |
diff --git a/extensions/servlet/src/com/google/inject/servlet/AbstractServletPipeline.java b/extensions/servlet/src/com/google/inject/servlet/AbstractServletPipeline.java
|
|
|
249b5c |
new file mode 100644
|
|
|
249b5c |
index 0000000..811820a
|
|
|
249b5c |
--- /dev/null
|
|
|
249b5c |
+++ b/extensions/servlet/src/com/google/inject/servlet/AbstractServletPipeline.java
|
|
|
249b5c |
@@ -0,0 +1,187 @@
|
|
|
249b5c |
+/**
|
|
|
249b5c |
+ * Copyright (C) 2008 Google Inc.
|
|
|
249b5c |
+ *
|
|
|
249b5c |
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
249b5c |
+ * you may not use this file except in compliance with the License.
|
|
|
249b5c |
+ * You may obtain a copy of the License at
|
|
|
249b5c |
+ *
|
|
|
249b5c |
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
|
249b5c |
+ *
|
|
|
249b5c |
+ * Unless required by applicable law or agreed to in writing, software
|
|
|
249b5c |
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
249b5c |
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
249b5c |
+ * See the License for the specific language governing permissions and
|
|
|
249b5c |
+ * limitations under the License.
|
|
|
249b5c |
+ */
|
|
|
249b5c |
+package com.google.inject.servlet;
|
|
|
249b5c |
+
|
|
|
249b5c |
+import com.google.common.base.Preconditions;
|
|
|
249b5c |
+import com.google.common.collect.Sets;
|
|
|
249b5c |
+import com.google.inject.Injector;
|
|
|
249b5c |
+
|
|
|
249b5c |
+import java.io.IOException;
|
|
|
249b5c |
+import java.util.Set;
|
|
|
249b5c |
+
|
|
|
249b5c |
+import javax.servlet.RequestDispatcher;
|
|
|
249b5c |
+import javax.servlet.ServletContext;
|
|
|
249b5c |
+import javax.servlet.ServletException;
|
|
|
249b5c |
+import javax.servlet.ServletRequest;
|
|
|
249b5c |
+import javax.servlet.ServletResponse;
|
|
|
249b5c |
+import javax.servlet.http.HttpServlet;
|
|
|
249b5c |
+import javax.servlet.http.HttpServletRequest;
|
|
|
249b5c |
+import javax.servlet.http.HttpServletRequestWrapper;
|
|
|
249b5c |
+
|
|
|
249b5c |
+/**
|
|
|
249b5c |
+ * Skeleton implementation of a wrapping dispatcher for servlets based on a sequence of
|
|
|
249b5c |
+ * {@link ServletDefinition}s, much like {@link AbstractFilterPipeline} is for filters.
|
|
|
249b5c |
+ *
|
|
|
249b5c |
+ * @author dhanji@gmail.com (Dhanji R. Prasanna)
|
|
|
249b5c |
+ */
|
|
|
249b5c |
+public abstract class AbstractServletPipeline {
|
|
|
249b5c |
+
|
|
|
249b5c |
+ /**
|
|
|
249b5c |
+ * @return {@code true} if any servlet mappings exist; otherwise {@code false}
|
|
|
249b5c |
+ */
|
|
|
249b5c |
+ protected abstract boolean hasServletsMapped();
|
|
|
249b5c |
+
|
|
|
249b5c |
+ /**
|
|
|
249b5c |
+ * @return snapshot of the servlet mappings currently defined for this pipeline
|
|
|
249b5c |
+ */
|
|
|
249b5c |
+ protected abstract ServletDefinition[] servletDefinitions();
|
|
|
249b5c |
+
|
|
|
249b5c |
+ void init(ServletContext servletContext, Injector injector) throws ServletException {
|
|
|
249b5c |
+ Set<HttpServlet> initializedSoFar = Sets.newIdentityHashSet();
|
|
|
249b5c |
+
|
|
|
249b5c |
+ for (ServletDefinition servletDefinition : servletDefinitions()) {
|
|
|
249b5c |
+ servletDefinition.init(servletContext, injector, initializedSoFar);
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+
|
|
|
249b5c |
+ boolean service(ServletRequest request, ServletResponse response)
|
|
|
249b5c |
+ throws IOException, ServletException {
|
|
|
249b5c |
+
|
|
|
249b5c |
+ //stop at the first matching servlet and service
|
|
|
249b5c |
+ for (ServletDefinition servletDefinition : servletDefinitions()) {
|
|
|
249b5c |
+ if (servletDefinition.service(request, response)) {
|
|
|
249b5c |
+ return true;
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+
|
|
|
249b5c |
+ //there was no match...
|
|
|
249b5c |
+ return false;
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+
|
|
|
249b5c |
+ void destroy() {
|
|
|
249b5c |
+ Set<HttpServlet> destroyedSoFar = Sets.newIdentityHashSet();
|
|
|
249b5c |
+ for (ServletDefinition servletDefinition : servletDefinitions()) {
|
|
|
249b5c |
+ servletDefinition.destroy(destroyedSoFar);
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+
|
|
|
249b5c |
+ /**
|
|
|
249b5c |
+ * @return Returns a request dispatcher wrapped with a servlet mapped to
|
|
|
249b5c |
+ * the given path or null if no mapping was found.
|
|
|
249b5c |
+ */
|
|
|
249b5c |
+ RequestDispatcher getRequestDispatcher(String path) {
|
|
|
249b5c |
+ final String newRequestUri = path;
|
|
|
249b5c |
+
|
|
|
249b5c |
+ // TODO(dhanji): check servlet spec to see if the following is legal or not.
|
|
|
249b5c |
+ // Need to strip query string if requested...
|
|
|
249b5c |
+
|
|
|
249b5c |
+ for (final ServletDefinition servletDefinition : servletDefinitions()) {
|
|
|
249b5c |
+ if (servletDefinition.shouldServe(path)) {
|
|
|
249b5c |
+ return new RequestDispatcher() {
|
|
|
249b5c |
+ public void forward(ServletRequest servletRequest, ServletResponse servletResponse)
|
|
|
249b5c |
+ throws ServletException, IOException {
|
|
|
249b5c |
+ Preconditions.checkState(!servletResponse.isCommitted(),
|
|
|
249b5c |
+ "Response has been committed--you can only call forward before"
|
|
|
249b5c |
+ + " committing the response (hint: don't flush buffers)");
|
|
|
249b5c |
+
|
|
|
249b5c |
+ // clear buffer before forwarding
|
|
|
249b5c |
+ servletResponse.resetBuffer();
|
|
|
249b5c |
+
|
|
|
249b5c |
+ ServletRequest requestToProcess;
|
|
|
249b5c |
+ if (servletRequest instanceof HttpServletRequest) {
|
|
|
249b5c |
+ requestToProcess = wrapRequest((HttpServletRequest)servletRequest, newRequestUri);
|
|
|
249b5c |
+ } else {
|
|
|
249b5c |
+ // This should never happen, but instead of throwing an exception
|
|
|
249b5c |
+ // we will allow a happy case pass thru for maximum tolerance to
|
|
|
249b5c |
+ // legacy (and internal) code.
|
|
|
249b5c |
+ requestToProcess = servletRequest;
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+
|
|
|
249b5c |
+ // now dispatch to the servlet
|
|
|
249b5c |
+ doServiceImpl(servletDefinition, requestToProcess, servletResponse);
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+
|
|
|
249b5c |
+ public void include(ServletRequest servletRequest, ServletResponse servletResponse)
|
|
|
249b5c |
+ throws ServletException, IOException {
|
|
|
249b5c |
+ // route to the target servlet
|
|
|
249b5c |
+ doServiceImpl(servletDefinition, servletRequest, servletResponse);
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+
|
|
|
249b5c |
+ private void doServiceImpl(ServletDefinition servletDefinition, ServletRequest servletRequest,
|
|
|
249b5c |
+ ServletResponse servletResponse) throws ServletException, IOException {
|
|
|
249b5c |
+ servletRequest.setAttribute(REQUEST_DISPATCHER_REQUEST, Boolean.TRUE);
|
|
|
249b5c |
+
|
|
|
249b5c |
+ try {
|
|
|
249b5c |
+ servletDefinition.doService(servletRequest, servletResponse);
|
|
|
249b5c |
+ } finally {
|
|
|
249b5c |
+ servletRequest.removeAttribute(REQUEST_DISPATCHER_REQUEST);
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+ };
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+
|
|
|
249b5c |
+ //otherwise, can't process
|
|
|
249b5c |
+ return null;
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+
|
|
|
249b5c |
+ // visible for testing
|
|
|
249b5c |
+ static HttpServletRequest wrapRequest(HttpServletRequest request, String newUri) {
|
|
|
249b5c |
+ return new RequestDispatcherRequestWrapper(request, newUri);
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+
|
|
|
249b5c |
+ /**
|
|
|
249b5c |
+ * A Marker constant attribute that when present in the request indicates to Guice servlet that
|
|
|
249b5c |
+ * this request has been generated by a request dispatcher rather than the servlet pipeline.
|
|
|
249b5c |
+ * In accordance with section 8.4.2 of the Servlet 2.4 specification.
|
|
|
249b5c |
+ */
|
|
|
249b5c |
+ static final String REQUEST_DISPATCHER_REQUEST = "javax.servlet.forward.servlet_path";
|
|
|
249b5c |
+
|
|
|
249b5c |
+ private static class RequestDispatcherRequestWrapper extends HttpServletRequestWrapper {
|
|
|
249b5c |
+ private final String newRequestUri;
|
|
|
249b5c |
+
|
|
|
249b5c |
+ RequestDispatcherRequestWrapper(HttpServletRequest servletRequest, String newRequestUri) {
|
|
|
249b5c |
+ super(servletRequest);
|
|
|
249b5c |
+ this.newRequestUri = newRequestUri;
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+
|
|
|
249b5c |
+ @Override
|
|
|
249b5c |
+ public String getRequestURI() {
|
|
|
249b5c |
+ return newRequestUri;
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+
|
|
|
249b5c |
+ @Override
|
|
|
249b5c |
+ public StringBuffer getRequestURL() {
|
|
|
249b5c |
+ StringBuffer url = new StringBuffer();
|
|
|
249b5c |
+ String scheme = getScheme();
|
|
|
249b5c |
+ int port = getServerPort();
|
|
|
249b5c |
+
|
|
|
249b5c |
+ url.append(scheme);
|
|
|
249b5c |
+ url.append("://");
|
|
|
249b5c |
+ url.append(getServerName());
|
|
|
249b5c |
+ // port might be -1 in some cases (see java.net.URL.getPort)
|
|
|
249b5c |
+ if (port > 0 &&
|
|
|
249b5c |
+ (("http".equals(scheme) && (port != 80)) ||
|
|
|
249b5c |
+ ("https".equals(scheme) && (port != 443)))) {
|
|
|
249b5c |
+ url.append(':');
|
|
|
249b5c |
+ url.append(port);
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+ url.append(getRequestURI());
|
|
|
249b5c |
+
|
|
|
249b5c |
+ return (url);
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+}
|
|
|
249b5c |
diff --git a/extensions/servlet/src/com/google/inject/servlet/FilterChainInvocation.java b/extensions/servlet/src/com/google/inject/servlet/FilterChainInvocation.java
|
|
|
249b5c |
index b4112cf..bfe5a83 100644
|
|
|
249b5c |
--- a/extensions/servlet/src/com/google/inject/servlet/FilterChainInvocation.java
|
|
|
249b5c |
+++ b/extensions/servlet/src/com/google/inject/servlet/FilterChainInvocation.java
|
|
|
249b5c |
@@ -50,7 +50,7 @@ class FilterChainInvocation implements FilterChain {
|
|
|
249b5c |
|
|
|
249b5c |
private final FilterDefinition[] filterDefinitions;
|
|
|
249b5c |
private final FilterChain proceedingChain;
|
|
|
249b5c |
- private final ManagedServletPipeline servletPipeline;
|
|
|
249b5c |
+ private final AbstractServletPipeline servletPipeline;
|
|
|
249b5c |
|
|
|
249b5c |
//state variable tracks current link in filterchain
|
|
|
249b5c |
private int index = -1;
|
|
|
249b5c |
@@ -58,7 +58,7 @@ class FilterChainInvocation implements FilterChain {
|
|
|
249b5c |
private boolean cleanedStacks = false;
|
|
|
249b5c |
|
|
|
249b5c |
public FilterChainInvocation(FilterDefinition[] filterDefinitions,
|
|
|
249b5c |
- ManagedServletPipeline servletPipeline, FilterChain proceedingChain) {
|
|
|
249b5c |
+ AbstractServletPipeline servletPipeline, FilterChain proceedingChain) {
|
|
|
249b5c |
|
|
|
249b5c |
this.filterDefinitions = filterDefinitions;
|
|
|
249b5c |
this.servletPipeline = servletPipeline;
|
|
|
249b5c |
diff --git a/extensions/servlet/src/com/google/inject/servlet/FilterDefinition.java b/extensions/servlet/src/com/google/inject/servlet/FilterDefinition.java
|
|
|
249b5c |
index ff1e5b6..76ece31 100644
|
|
|
249b5c |
--- a/extensions/servlet/src/com/google/inject/servlet/FilterDefinition.java
|
|
|
249b5c |
+++ b/extensions/servlet/src/com/google/inject/servlet/FilterDefinition.java
|
|
|
249b5c |
@@ -37,11 +37,11 @@ import javax.servlet.ServletException;
|
|
|
249b5c |
import javax.servlet.http.HttpServletRequest;
|
|
|
249b5c |
|
|
|
249b5c |
/**
|
|
|
249b5c |
- * An internal representation of a filter definition against a particular URI pattern.
|
|
|
249b5c |
+ * Defines a filter mapped to a URI pattern and performs the request filtering for that filter.
|
|
|
249b5c |
*
|
|
|
249b5c |
* @author dhanji@gmail.com (Dhanji R. Prasanna)
|
|
|
249b5c |
*/
|
|
|
249b5c |
-class FilterDefinition implements ProviderWithExtensionVisitor<FilterDefinition> {
|
|
|
249b5c |
+public class FilterDefinition implements ProviderWithExtensionVisitor<FilterDefinition> {
|
|
|
249b5c |
private final String pattern;
|
|
|
249b5c |
private final Key filterKey;
|
|
|
249b5c |
private final UriPatternMatcher patternMatcher;
|
|
|
249b5c |
@@ -90,7 +90,7 @@ class FilterDefinition implements ProviderWithExtensionVisitor<FilterDefinition>
|
|
|
249b5c |
return uri != null && patternMatcher.matches(uri);
|
|
|
249b5c |
}
|
|
|
249b5c |
|
|
|
249b5c |
- public void init(final ServletContext servletContext, Injector injector,
|
|
|
249b5c |
+ void init(final ServletContext servletContext, Injector injector,
|
|
|
249b5c |
Set<Filter> initializedSoFar) throws ServletException {
|
|
|
249b5c |
|
|
|
249b5c |
// This absolutely must be a singleton, and so is only initialized once.
|
|
|
249b5c |
@@ -130,7 +130,7 @@ class FilterDefinition implements ProviderWithExtensionVisitor<FilterDefinition>
|
|
|
249b5c |
initializedSoFar.add(filter);
|
|
|
249b5c |
}
|
|
|
249b5c |
|
|
|
249b5c |
- public void destroy(Set<Filter> destroyedSoFar) {
|
|
|
249b5c |
+ void destroy(Set<Filter> destroyedSoFar) {
|
|
|
249b5c |
// filters are always singletons
|
|
|
249b5c |
Filter reference = filter.get();
|
|
|
249b5c |
|
|
|
249b5c |
@@ -150,7 +150,7 @@ class FilterDefinition implements ProviderWithExtensionVisitor<FilterDefinition>
|
|
|
249b5c |
}
|
|
|
249b5c |
}
|
|
|
249b5c |
|
|
|
249b5c |
- public Filter getFilterIfMatching(HttpServletRequest request) {
|
|
|
249b5c |
+ Filter getFilterIfMatching(HttpServletRequest request) {
|
|
|
249b5c |
|
|
|
249b5c |
final String path = ServletUtils.getContextRelativePath(request);
|
|
|
249b5c |
if (shouldFilter(path)) {
|
|
|
249b5c |
diff --git a/extensions/servlet/src/com/google/inject/servlet/FilterPipeline.java b/extensions/servlet/src/com/google/inject/servlet/FilterPipeline.java
|
|
|
249b5c |
index 985064b..c745d20 100644
|
|
|
249b5c |
--- a/extensions/servlet/src/com/google/inject/servlet/FilterPipeline.java
|
|
|
249b5c |
+++ b/extensions/servlet/src/com/google/inject/servlet/FilterPipeline.java
|
|
|
249b5c |
@@ -26,7 +26,7 @@ import javax.servlet.ServletRequest;
|
|
|
249b5c |
import javax.servlet.ServletResponse;
|
|
|
249b5c |
|
|
|
249b5c |
/**
|
|
|
249b5c |
- * An internal dispatcher for guice-servlet registered servlets and filters.
|
|
|
249b5c |
+ * A dispatcher abstraction for guice-servlet registered servlets and filters.
|
|
|
249b5c |
* By default, we assume a Guice 1.0 style servlet module is in play. In other
|
|
|
249b5c |
* words, we dispatch directly to the web.xml pipeline after setting up scopes.
|
|
|
249b5c |
*
|
|
|
249b5c |
@@ -39,10 +39,27 @@ import javax.servlet.ServletResponse;
|
|
|
249b5c |
* @author dhanji@gmail.com (Dhanji R. Prasanna)
|
|
|
249b5c |
*/
|
|
|
249b5c |
@ImplementedBy(DefaultFilterPipeline.class)
|
|
|
249b5c |
-interface FilterPipeline {
|
|
|
249b5c |
+public interface FilterPipeline {
|
|
|
249b5c |
+
|
|
|
249b5c |
+ /**
|
|
|
249b5c |
+ * Initializes the pipeline, putting it into service.
|
|
|
249b5c |
+ *
|
|
|
249b5c |
+ * @param context of the web application
|
|
|
249b5c |
+ */
|
|
|
249b5c |
void initPipeline(ServletContext context) throws ServletException;
|
|
|
249b5c |
+
|
|
|
249b5c |
+ /**
|
|
|
249b5c |
+ * Destroys the pipeline, taking it out of service.
|
|
|
249b5c |
+ */
|
|
|
249b5c |
void destroyPipeline();
|
|
|
249b5c |
|
|
|
249b5c |
+ /**
|
|
|
249b5c |
+ * Dispatches a request against the pipeline.
|
|
|
249b5c |
+ *
|
|
|
249b5c |
+ * @param request to dispatch
|
|
|
249b5c |
+ * @param response to populate
|
|
|
249b5c |
+ * @param defaultFilterChain for last resort filtering
|
|
|
249b5c |
+ */
|
|
|
249b5c |
void dispatch(ServletRequest request, ServletResponse response,
|
|
|
249b5c |
FilterChain defaultFilterChain) throws IOException, ServletException;
|
|
|
249b5c |
}
|
|
|
249b5c |
diff --git a/extensions/servlet/src/com/google/inject/servlet/GuiceFilter.java b/extensions/servlet/src/com/google/inject/servlet/GuiceFilter.java
|
|
|
249b5c |
index ba7a5af..0737b38 100644
|
|
|
249b5c |
--- a/extensions/servlet/src/com/google/inject/servlet/GuiceFilter.java
|
|
|
249b5c |
+++ b/extensions/servlet/src/com/google/inject/servlet/GuiceFilter.java
|
|
|
249b5c |
@@ -89,7 +89,7 @@ public class GuiceFilter implements Filter {
|
|
|
249b5c |
this(null);
|
|
|
249b5c |
}
|
|
|
249b5c |
|
|
|
249b5c |
- @Inject GuiceFilter(FilterPipeline filterPipeline) {
|
|
|
249b5c |
+ @Inject protected GuiceFilter(FilterPipeline filterPipeline) {
|
|
|
249b5c |
injectedPipeline = filterPipeline;
|
|
|
249b5c |
}
|
|
|
249b5c |
|
|
|
249b5c |
diff --git a/extensions/servlet/src/com/google/inject/servlet/ManagedFilterPipeline.java b/extensions/servlet/src/com/google/inject/servlet/ManagedFilterPipeline.java
|
|
|
249b5c |
index 538e10a..76bc269 100644
|
|
|
249b5c |
--- a/extensions/servlet/src/com/google/inject/servlet/ManagedFilterPipeline.java
|
|
|
249b5c |
+++ b/extensions/servlet/src/com/google/inject/servlet/ManagedFilterPipeline.java
|
|
|
249b5c |
@@ -16,7 +16,6 @@
|
|
|
249b5c |
package com.google.inject.servlet;
|
|
|
249b5c |
|
|
|
249b5c |
import com.google.common.collect.Lists;
|
|
|
249b5c |
-import com.google.common.collect.Sets;
|
|
|
249b5c |
import com.google.inject.Binding;
|
|
|
249b5c |
import com.google.inject.Inject;
|
|
|
249b5c |
import com.google.inject.Injector;
|
|
|
249b5c |
@@ -24,50 +23,41 @@ import com.google.inject.Provider;
|
|
|
249b5c |
import com.google.inject.Singleton;
|
|
|
249b5c |
import com.google.inject.TypeLiteral;
|
|
|
249b5c |
|
|
|
249b5c |
-import java.io.IOException;
|
|
|
249b5c |
import java.util.List;
|
|
|
249b5c |
-import java.util.Set;
|
|
|
249b5c |
|
|
|
249b5c |
-import javax.servlet.Filter;
|
|
|
249b5c |
-import javax.servlet.FilterChain;
|
|
|
249b5c |
-import javax.servlet.RequestDispatcher;
|
|
|
249b5c |
import javax.servlet.ServletContext;
|
|
|
249b5c |
-import javax.servlet.ServletException;
|
|
|
249b5c |
-import javax.servlet.ServletRequest;
|
|
|
249b5c |
-import javax.servlet.ServletResponse;
|
|
|
249b5c |
-import javax.servlet.http.HttpServletRequest;
|
|
|
249b5c |
-import javax.servlet.http.HttpServletRequestWrapper;
|
|
|
249b5c |
|
|
|
249b5c |
/**
|
|
|
249b5c |
- * Central routing/dispatch class handles lifecycle of managed filters, and delegates to the servlet
|
|
|
249b5c |
- * pipeline.
|
|
|
249b5c |
+ * Managed implementation of a central routing/dispatch class which handles lifecycle of managed
|
|
|
249b5c |
+ * filters, and delegates to a managed servlet pipeline.
|
|
|
249b5c |
*
|
|
|
249b5c |
* @author dhanji@gmail.com (Dhanji R. Prasanna)
|
|
|
249b5c |
*/
|
|
|
249b5c |
@Singleton
|
|
|
249b5c |
-class ManagedFilterPipeline implements FilterPipeline{
|
|
|
249b5c |
+class ManagedFilterPipeline extends AbstractFilterPipeline {
|
|
|
249b5c |
private final FilterDefinition[] filterDefinitions;
|
|
|
249b5c |
- private final ManagedServletPipeline servletPipeline;
|
|
|
249b5c |
- private final Provider<ServletContext> servletContext;
|
|
|
249b5c |
|
|
|
249b5c |
- //Unfortunately, we need the injector itself in order to create filters + servlets
|
|
|
249b5c |
- private final Injector injector;
|
|
|
249b5c |
-
|
|
|
249b5c |
- //Guards a DCL, so needs to be volatile
|
|
|
249b5c |
- private volatile boolean initialized = false;
|
|
|
249b5c |
private static final TypeLiteral<FilterDefinition> FILTER_DEFS =
|
|
|
249b5c |
TypeLiteral.get(FilterDefinition.class);
|
|
|
249b5c |
|
|
|
249b5c |
@Inject
|
|
|
249b5c |
public ManagedFilterPipeline(Injector injector, ManagedServletPipeline servletPipeline,
|
|
|
249b5c |
Provider<ServletContext> servletContext) {
|
|
|
249b5c |
- this.injector = injector;
|
|
|
249b5c |
- this.servletPipeline = servletPipeline;
|
|
|
249b5c |
- this.servletContext = servletContext;
|
|
|
249b5c |
+ super(injector, servletPipeline, servletContext);
|
|
|
249b5c |
|
|
|
249b5c |
this.filterDefinitions = collectFilterDefinitions(injector);
|
|
|
249b5c |
}
|
|
|
249b5c |
|
|
|
249b5c |
+ @Override
|
|
|
249b5c |
+ protected boolean hasFiltersMapped() {
|
|
|
249b5c |
+ return filterDefinitions.length > 0;
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+
|
|
|
249b5c |
+ @Override
|
|
|
249b5c |
+ protected FilterDefinition[] filterDefinitions() {
|
|
|
249b5c |
+ return filterDefinitions;
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+
|
|
|
249b5c |
/**
|
|
|
249b5c |
* Introspects the injector and collects all instances of bound {@code List<FilterDefinition>}
|
|
|
249b5c |
* into a master list.
|
|
|
249b5c |
@@ -84,86 +74,4 @@ class ManagedFilterPipeline implements FilterPipeline{
|
|
|
249b5c |
// Copy to a fixed-size array for speed of iteration.
|
|
|
249b5c |
return filterDefinitions.toArray(new FilterDefinition[filterDefinitions.size()]);
|
|
|
249b5c |
}
|
|
|
249b5c |
-
|
|
|
249b5c |
- public synchronized void initPipeline(ServletContext servletContext)
|
|
|
249b5c |
- throws ServletException {
|
|
|
249b5c |
-
|
|
|
249b5c |
- //double-checked lock, prevents duplicate initialization
|
|
|
249b5c |
- if (initialized)
|
|
|
249b5c |
- return;
|
|
|
249b5c |
-
|
|
|
249b5c |
- // Used to prevent duplicate initialization.
|
|
|
249b5c |
- Set<Filter> initializedSoFar = Sets.newIdentityHashSet();
|
|
|
249b5c |
-
|
|
|
249b5c |
- for (FilterDefinition filterDefinition : filterDefinitions) {
|
|
|
249b5c |
- filterDefinition.init(servletContext, injector, initializedSoFar);
|
|
|
249b5c |
- }
|
|
|
249b5c |
-
|
|
|
249b5c |
- //next, initialize servlets...
|
|
|
249b5c |
- servletPipeline.init(servletContext, injector);
|
|
|
249b5c |
-
|
|
|
249b5c |
- //everything was ok...
|
|
|
249b5c |
- initialized = true;
|
|
|
249b5c |
- }
|
|
|
249b5c |
-
|
|
|
249b5c |
- public void dispatch(ServletRequest request, ServletResponse response,
|
|
|
249b5c |
- FilterChain proceedingFilterChain) throws IOException, ServletException {
|
|
|
249b5c |
-
|
|
|
249b5c |
- //lazy init of filter pipeline (OK by the servlet specification). This is needed
|
|
|
249b5c |
- //in order for us not to force users to create a GuiceServletContextListener subclass.
|
|
|
249b5c |
- if (!initialized) {
|
|
|
249b5c |
- initPipeline(servletContext.get());
|
|
|
249b5c |
- }
|
|
|
249b5c |
-
|
|
|
249b5c |
- //obtain the servlet pipeline to dispatch against
|
|
|
249b5c |
- new FilterChainInvocation(filterDefinitions, servletPipeline, proceedingFilterChain)
|
|
|
249b5c |
- .doFilter(withDispatcher(request, servletPipeline), response);
|
|
|
249b5c |
-
|
|
|
249b5c |
- }
|
|
|
249b5c |
-
|
|
|
249b5c |
- /**
|
|
|
249b5c |
- * Used to create an proxy that dispatches either to the guice-servlet pipeline or the regular
|
|
|
249b5c |
- * pipeline based on uri-path match. This proxy also provides minimal forwarding support.
|
|
|
249b5c |
- *
|
|
|
249b5c |
- * We cannot forward from a web.xml Servlet/JSP to a guice-servlet (because the filter pipeline
|
|
|
249b5c |
- * is not called again). However, we can wrap requests with our own dispatcher to forward the
|
|
|
249b5c |
- * *other* way. web.xml Servlets/JSPs can forward to themselves as per normal.
|
|
|
249b5c |
- *
|
|
|
249b5c |
- * This is not a problem cuz we intend for people to migrate from web.xml to guice-servlet,
|
|
|
249b5c |
- * incrementally, but not the other way around (which, we should actively discourage).
|
|
|
249b5c |
- */
|
|
|
249b5c |
- @SuppressWarnings({ "JavaDoc", "deprecation" })
|
|
|
249b5c |
- private ServletRequest withDispatcher(ServletRequest servletRequest,
|
|
|
249b5c |
- final ManagedServletPipeline servletPipeline) {
|
|
|
249b5c |
-
|
|
|
249b5c |
- // don't wrap the request if there are no servlets mapped. This prevents us from inserting our
|
|
|
249b5c |
- // wrapper unless it's actually going to be used. This is necessary for compatibility for apps
|
|
|
249b5c |
- // that downcast their HttpServletRequests to a concrete implementation.
|
|
|
249b5c |
- if (!servletPipeline.hasServletsMapped()) {
|
|
|
249b5c |
- return servletRequest;
|
|
|
249b5c |
- }
|
|
|
249b5c |
-
|
|
|
249b5c |
- HttpServletRequest request = (HttpServletRequest) servletRequest;
|
|
|
249b5c |
- //noinspection OverlyComplexAnonymousInnerClass
|
|
|
249b5c |
- return new HttpServletRequestWrapper(request) {
|
|
|
249b5c |
-
|
|
|
249b5c |
- @Override
|
|
|
249b5c |
- public RequestDispatcher getRequestDispatcher(String path) {
|
|
|
249b5c |
- final RequestDispatcher dispatcher = servletPipeline.getRequestDispatcher(path);
|
|
|
249b5c |
-
|
|
|
249b5c |
- return (null != dispatcher) ? dispatcher : super.getRequestDispatcher(path);
|
|
|
249b5c |
- }
|
|
|
249b5c |
- };
|
|
|
249b5c |
- }
|
|
|
249b5c |
-
|
|
|
249b5c |
- public void destroyPipeline() {
|
|
|
249b5c |
- //destroy servlets first
|
|
|
249b5c |
- servletPipeline.destroy();
|
|
|
249b5c |
-
|
|
|
249b5c |
- //go down chain and destroy all our filters
|
|
|
249b5c |
- Set<Filter> destroyedSoFar = Sets.newIdentityHashSet();
|
|
|
249b5c |
- for (FilterDefinition filterDefinition : filterDefinitions) {
|
|
|
249b5c |
- filterDefinition.destroy(destroyedSoFar);
|
|
|
249b5c |
- }
|
|
|
249b5c |
- }
|
|
|
249b5c |
}
|
|
|
249b5c |
diff --git a/extensions/servlet/src/com/google/inject/servlet/ManagedServletPipeline.java b/extensions/servlet/src/com/google/inject/servlet/ManagedServletPipeline.java
|
|
|
249b5c |
index 455551a..ab58a8e 100644
|
|
|
249b5c |
--- a/extensions/servlet/src/com/google/inject/servlet/ManagedServletPipeline.java
|
|
|
249b5c |
+++ b/extensions/servlet/src/com/google/inject/servlet/ManagedServletPipeline.java
|
|
|
249b5c |
@@ -15,27 +15,14 @@
|
|
|
249b5c |
*/
|
|
|
249b5c |
package com.google.inject.servlet;
|
|
|
249b5c |
|
|
|
249b5c |
-import com.google.common.base.Preconditions;
|
|
|
249b5c |
import com.google.common.collect.Lists;
|
|
|
249b5c |
-import com.google.common.collect.Sets;
|
|
|
249b5c |
import com.google.inject.Binding;
|
|
|
249b5c |
import com.google.inject.Inject;
|
|
|
249b5c |
import com.google.inject.Injector;
|
|
|
249b5c |
import com.google.inject.Singleton;
|
|
|
249b5c |
import com.google.inject.TypeLiteral;
|
|
|
249b5c |
|
|
|
249b5c |
-import java.io.IOException;
|
|
|
249b5c |
import java.util.List;
|
|
|
249b5c |
-import java.util.Set;
|
|
|
249b5c |
-
|
|
|
249b5c |
-import javax.servlet.RequestDispatcher;
|
|
|
249b5c |
-import javax.servlet.ServletContext;
|
|
|
249b5c |
-import javax.servlet.ServletException;
|
|
|
249b5c |
-import javax.servlet.ServletRequest;
|
|
|
249b5c |
-import javax.servlet.ServletResponse;
|
|
|
249b5c |
-import javax.servlet.http.HttpServlet;
|
|
|
249b5c |
-import javax.servlet.http.HttpServletRequest;
|
|
|
249b5c |
-import javax.servlet.http.HttpServletRequestWrapper;
|
|
|
249b5c |
|
|
|
249b5c |
/**
|
|
|
249b5c |
* A wrapping dispatcher for servlets, in much the same way as {@link ManagedFilterPipeline} is for
|
|
|
249b5c |
@@ -44,7 +31,7 @@ import javax.servlet.http.HttpServletRequestWrapper;
|
|
|
249b5c |
* @author dhanji@gmail.com (Dhanji R. Prasanna)
|
|
|
249b5c |
*/
|
|
|
249b5c |
@Singleton
|
|
|
249b5c |
-class ManagedServletPipeline {
|
|
|
249b5c |
+class ManagedServletPipeline extends AbstractServletPipeline {
|
|
|
249b5c |
private final ServletDefinition[] servletDefinitions;
|
|
|
249b5c |
private static final TypeLiteral<ServletDefinition> SERVLET_DEFS =
|
|
|
249b5c |
TypeLiteral.get(ServletDefinition.class);
|
|
|
249b5c |
@@ -54,10 +41,16 @@ class ManagedServletPipeline {
|
|
|
249b5c |
this.servletDefinitions = collectServletDefinitions(injector);
|
|
|
249b5c |
}
|
|
|
249b5c |
|
|
|
249b5c |
- boolean hasServletsMapped() {
|
|
|
249b5c |
+ @Override
|
|
|
249b5c |
+ protected boolean hasServletsMapped() {
|
|
|
249b5c |
return servletDefinitions.length > 0;
|
|
|
249b5c |
}
|
|
|
249b5c |
|
|
|
249b5c |
+ @Override
|
|
|
249b5c |
+ protected ServletDefinition[] servletDefinitions() {
|
|
|
249b5c |
+ return servletDefinitions;
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+
|
|
|
249b5c |
/**
|
|
|
249b5c |
* Introspects the injector and collects all instances of bound {@code List<ServletDefinition>}
|
|
|
249b5c |
* into a master list.
|
|
|
249b5c |
@@ -74,140 +67,4 @@ class ManagedServletPipeline {
|
|
|
249b5c |
// Copy to a fixed size array for speed.
|
|
|
249b5c |
return servletDefinitions.toArray(new ServletDefinition[servletDefinitions.size()]);
|
|
|
249b5c |
}
|
|
|
249b5c |
-
|
|
|
249b5c |
- public void init(ServletContext servletContext, Injector injector) throws ServletException {
|
|
|
249b5c |
- Set<HttpServlet> initializedSoFar = Sets.newIdentityHashSet();
|
|
|
249b5c |
-
|
|
|
249b5c |
- for (ServletDefinition servletDefinition : servletDefinitions) {
|
|
|
249b5c |
- servletDefinition.init(servletContext, injector, initializedSoFar);
|
|
|
249b5c |
- }
|
|
|
249b5c |
- }
|
|
|
249b5c |
-
|
|
|
249b5c |
- public boolean service(ServletRequest request, ServletResponse response)
|
|
|
249b5c |
- throws IOException, ServletException {
|
|
|
249b5c |
-
|
|
|
249b5c |
- //stop at the first matching servlet and service
|
|
|
249b5c |
- for (ServletDefinition servletDefinition : servletDefinitions) {
|
|
|
249b5c |
- if (servletDefinition.service(request, response)) {
|
|
|
249b5c |
- return true;
|
|
|
249b5c |
- }
|
|
|
249b5c |
- }
|
|
|
249b5c |
-
|
|
|
249b5c |
- //there was no match...
|
|
|
249b5c |
- return false;
|
|
|
249b5c |
- }
|
|
|
249b5c |
-
|
|
|
249b5c |
- public void destroy() {
|
|
|
249b5c |
- Set<HttpServlet> destroyedSoFar = Sets.newIdentityHashSet();
|
|
|
249b5c |
- for (ServletDefinition servletDefinition : servletDefinitions) {
|
|
|
249b5c |
- servletDefinition.destroy(destroyedSoFar);
|
|
|
249b5c |
- }
|
|
|
249b5c |
- }
|
|
|
249b5c |
-
|
|
|
249b5c |
- /**
|
|
|
249b5c |
- * @return Returns a request dispatcher wrapped with a servlet mapped to
|
|
|
249b5c |
- * the given path or null if no mapping was found.
|
|
|
249b5c |
- */
|
|
|
249b5c |
- RequestDispatcher getRequestDispatcher(String path) {
|
|
|
249b5c |
- final String newRequestUri = path;
|
|
|
249b5c |
-
|
|
|
249b5c |
- // TODO(dhanji): check servlet spec to see if the following is legal or not.
|
|
|
249b5c |
- // Need to strip query string if requested...
|
|
|
249b5c |
-
|
|
|
249b5c |
- for (final ServletDefinition servletDefinition : servletDefinitions) {
|
|
|
249b5c |
- if (servletDefinition.shouldServe(path)) {
|
|
|
249b5c |
- return new RequestDispatcher() {
|
|
|
249b5c |
- public void forward(ServletRequest servletRequest, ServletResponse servletResponse)
|
|
|
249b5c |
- throws ServletException, IOException {
|
|
|
249b5c |
- Preconditions.checkState(!servletResponse.isCommitted(),
|
|
|
249b5c |
- "Response has been committed--you can only call forward before"
|
|
|
249b5c |
- + " committing the response (hint: don't flush buffers)");
|
|
|
249b5c |
-
|
|
|
249b5c |
- // clear buffer before forwarding
|
|
|
249b5c |
- servletResponse.resetBuffer();
|
|
|
249b5c |
-
|
|
|
249b5c |
- ServletRequest requestToProcess;
|
|
|
249b5c |
- if (servletRequest instanceof HttpServletRequest) {
|
|
|
249b5c |
- requestToProcess = wrapRequest((HttpServletRequest)servletRequest, newRequestUri);
|
|
|
249b5c |
- } else {
|
|
|
249b5c |
- // This should never happen, but instead of throwing an exception
|
|
|
249b5c |
- // we will allow a happy case pass thru for maximum tolerance to
|
|
|
249b5c |
- // legacy (and internal) code.
|
|
|
249b5c |
- requestToProcess = servletRequest;
|
|
|
249b5c |
- }
|
|
|
249b5c |
-
|
|
|
249b5c |
- // now dispatch to the servlet
|
|
|
249b5c |
- doServiceImpl(servletDefinition, requestToProcess, servletResponse);
|
|
|
249b5c |
- }
|
|
|
249b5c |
-
|
|
|
249b5c |
- public void include(ServletRequest servletRequest, ServletResponse servletResponse)
|
|
|
249b5c |
- throws ServletException, IOException {
|
|
|
249b5c |
- // route to the target servlet
|
|
|
249b5c |
- doServiceImpl(servletDefinition, servletRequest, servletResponse);
|
|
|
249b5c |
- }
|
|
|
249b5c |
-
|
|
|
249b5c |
- private void doServiceImpl(ServletDefinition servletDefinition, ServletRequest servletRequest,
|
|
|
249b5c |
- ServletResponse servletResponse) throws ServletException, IOException {
|
|
|
249b5c |
- servletRequest.setAttribute(REQUEST_DISPATCHER_REQUEST, Boolean.TRUE);
|
|
|
249b5c |
-
|
|
|
249b5c |
- try {
|
|
|
249b5c |
- servletDefinition.doService(servletRequest, servletResponse);
|
|
|
249b5c |
- } finally {
|
|
|
249b5c |
- servletRequest.removeAttribute(REQUEST_DISPATCHER_REQUEST);
|
|
|
249b5c |
- }
|
|
|
249b5c |
- }
|
|
|
249b5c |
- };
|
|
|
249b5c |
- }
|
|
|
249b5c |
- }
|
|
|
249b5c |
-
|
|
|
249b5c |
- //otherwise, can't process
|
|
|
249b5c |
- return null;
|
|
|
249b5c |
- }
|
|
|
249b5c |
-
|
|
|
249b5c |
- // visible for testing
|
|
|
249b5c |
- static HttpServletRequest wrapRequest(HttpServletRequest request, String newUri) {
|
|
|
249b5c |
- return new RequestDispatcherRequestWrapper(request, newUri);
|
|
|
249b5c |
- }
|
|
|
249b5c |
-
|
|
|
249b5c |
- /**
|
|
|
249b5c |
- * A Marker constant attribute that when present in the request indicates to Guice servlet that
|
|
|
249b5c |
- * this request has been generated by a request dispatcher rather than the servlet pipeline.
|
|
|
249b5c |
- * In accordance with section 8.4.2 of the Servlet 2.4 specification.
|
|
|
249b5c |
- */
|
|
|
249b5c |
- public static final String REQUEST_DISPATCHER_REQUEST = "javax.servlet.forward.servlet_path";
|
|
|
249b5c |
-
|
|
|
249b5c |
- private static class RequestDispatcherRequestWrapper extends HttpServletRequestWrapper {
|
|
|
249b5c |
- private final String newRequestUri;
|
|
|
249b5c |
-
|
|
|
249b5c |
- public RequestDispatcherRequestWrapper(HttpServletRequest servletRequest, String newRequestUri) {
|
|
|
249b5c |
- super(servletRequest);
|
|
|
249b5c |
- this.newRequestUri = newRequestUri;
|
|
|
249b5c |
- }
|
|
|
249b5c |
-
|
|
|
249b5c |
- @Override
|
|
|
249b5c |
- public String getRequestURI() {
|
|
|
249b5c |
- return newRequestUri;
|
|
|
249b5c |
- }
|
|
|
249b5c |
-
|
|
|
249b5c |
- @Override
|
|
|
249b5c |
- public StringBuffer getRequestURL() {
|
|
|
249b5c |
- StringBuffer url = new StringBuffer();
|
|
|
249b5c |
- String scheme = getScheme();
|
|
|
249b5c |
- int port = getServerPort();
|
|
|
249b5c |
-
|
|
|
249b5c |
- url.append(scheme);
|
|
|
249b5c |
- url.append("://");
|
|
|
249b5c |
- url.append(getServerName());
|
|
|
249b5c |
- // port might be -1 in some cases (see java.net.URL.getPort)
|
|
|
249b5c |
- if (port > 0 &&
|
|
|
249b5c |
- (("http".equals(scheme) && (port != 80)) ||
|
|
|
249b5c |
- ("https".equals(scheme) && (port != 443)))) {
|
|
|
249b5c |
- url.append(':');
|
|
|
249b5c |
- url.append(port);
|
|
|
249b5c |
- }
|
|
|
249b5c |
- url.append(getRequestURI());
|
|
|
249b5c |
-
|
|
|
249b5c |
- return (url);
|
|
|
249b5c |
- }
|
|
|
249b5c |
- }
|
|
|
249b5c |
}
|
|
|
249b5c |
diff --git a/extensions/servlet/src/com/google/inject/servlet/ServletDefinition.java b/extensions/servlet/src/com/google/inject/servlet/ServletDefinition.java
|
|
|
249b5c |
index 11328ed..285ff31 100644
|
|
|
249b5c |
--- a/extensions/servlet/src/com/google/inject/servlet/ServletDefinition.java
|
|
|
249b5c |
+++ b/extensions/servlet/src/com/google/inject/servlet/ServletDefinition.java
|
|
|
249b5c |
@@ -46,12 +46,11 @@ import javax.servlet.http.HttpServletRequestWrapper;
|
|
|
249b5c |
import javax.servlet.http.HttpServletResponse;
|
|
|
249b5c |
|
|
|
249b5c |
/**
|
|
|
249b5c |
- * An internal representation of a servlet definition mapped to a particular URI pattern. Also
|
|
|
249b5c |
- * performs the request dispatch to that servlet. How nice and OO =)
|
|
|
249b5c |
+ * Defines a servlet mapped to a URI pattern and performs the request dispatch to that servlet.
|
|
|
249b5c |
*
|
|
|
249b5c |
* @author dhanji@gmail.com (Dhanji R. Prasanna)
|
|
|
249b5c |
*/
|
|
|
249b5c |
-class ServletDefinition implements ProviderWithExtensionVisitor<ServletDefinition> {
|
|
|
249b5c |
+public class ServletDefinition implements ProviderWithExtensionVisitor<ServletDefinition> {
|
|
|
249b5c |
private final String pattern;
|
|
|
249b5c |
private final Key servletKey;
|
|
|
249b5c |
private final UriPatternMatcher patternMatcher;
|
|
|
249b5c |
@@ -100,7 +99,7 @@ class ServletDefinition implements ProviderWithExtensionVisitor
|
|
|
249b5c |
return uri != null && patternMatcher.matches(uri);
|
|
|
249b5c |
}
|
|
|
249b5c |
|
|
|
249b5c |
- public void init(final ServletContext servletContext, Injector injector,
|
|
|
249b5c |
+ void init(final ServletContext servletContext, Injector injector,
|
|
|
249b5c |
Set<HttpServlet> initializedSoFar) throws ServletException {
|
|
|
249b5c |
|
|
|
249b5c |
// This absolutely must be a singleton, and so is only initialized once.
|
|
|
249b5c |
@@ -140,7 +139,7 @@ class ServletDefinition implements ProviderWithExtensionVisitor
|
|
|
249b5c |
initializedSoFar.add(httpServlet);
|
|
|
249b5c |
}
|
|
|
249b5c |
|
|
|
249b5c |
- public void destroy(Set<HttpServlet> destroyedSoFar) {
|
|
|
249b5c |
+ void destroy(Set<HttpServlet> destroyedSoFar) {
|
|
|
249b5c |
HttpServlet reference = httpServlet.get();
|
|
|
249b5c |
|
|
|
249b5c |
// Do nothing if this Servlet was invalid (usually due to not being scoped
|
|
|
249b5c |
@@ -169,7 +168,7 @@ class ServletDefinition implements ProviderWithExtensionVisitor
|
|
|
249b5c |
* @throws IOException If thrown by underlying servlet
|
|
|
249b5c |
* @throws ServletException If thrown by underlying servlet
|
|
|
249b5c |
*/
|
|
|
249b5c |
- public boolean service(ServletRequest servletRequest,
|
|
|
249b5c |
+ boolean service(ServletRequest servletRequest,
|
|
|
249b5c |
ServletResponse servletResponse) throws IOException, ServletException {
|
|
|
249b5c |
|
|
|
249b5c |
final HttpServletRequest request = (HttpServletRequest) servletRequest;
|
|
|
249b5c |
diff --git a/extensions/servlet/src/com/google/inject/servlet/UriPatternMatcher.java b/extensions/servlet/src/com/google/inject/servlet/UriPatternMatcher.java
|
|
|
249b5c |
index d8bac74..169dd89 100644
|
|
|
249b5c |
--- a/extensions/servlet/src/com/google/inject/servlet/UriPatternMatcher.java
|
|
|
249b5c |
+++ b/extensions/servlet/src/com/google/inject/servlet/UriPatternMatcher.java
|
|
|
249b5c |
@@ -22,7 +22,7 @@ package com.google.inject.servlet;
|
|
|
249b5c |
*
|
|
|
249b5c |
* @author dhanji@gmail.com (Dhanji R. Prasanna)
|
|
|
249b5c |
*/
|
|
|
249b5c |
-interface UriPatternMatcher {
|
|
|
249b5c |
+public interface UriPatternMatcher {
|
|
|
249b5c |
/**
|
|
|
249b5c |
* @param uri A "contextual" (i.e. relative) Request URI, *not* a complete one.
|
|
|
249b5c |
* @return Returns true if the uri matches the pattern.
|
|
|
249b5c |
diff --git a/extensions/servlet/src/com/google/inject/servlet/UriPatternType.java b/extensions/servlet/src/com/google/inject/servlet/UriPatternType.java
|
|
|
249b5c |
index 80d6aea..c76199d 100644
|
|
|
249b5c |
--- a/extensions/servlet/src/com/google/inject/servlet/UriPatternType.java
|
|
|
249b5c |
+++ b/extensions/servlet/src/com/google/inject/servlet/UriPatternType.java
|
|
|
249b5c |
@@ -26,7 +26,14 @@ import java.util.regex.Pattern;
|
|
|
249b5c |
public enum UriPatternType {
|
|
|
249b5c |
SERVLET, REGEX;
|
|
|
249b5c |
|
|
|
249b5c |
- static UriPatternMatcher get(UriPatternType type, String pattern) {
|
|
|
249b5c |
+ /**
|
|
|
249b5c |
+ * Returns the appropriate {@link UriPatternMatcher} for {@code pattern}.
|
|
|
249b5c |
+ *
|
|
|
249b5c |
+ * @param type of pattern matching
|
|
|
249b5c |
+ * @param pattern for matching URI
|
|
|
249b5c |
+ * @return {@link UriPatternMatcher} that matches the given pattern
|
|
|
249b5c |
+ */
|
|
|
249b5c |
+ public static UriPatternMatcher get(UriPatternType type, String pattern) {
|
|
|
249b5c |
switch (type) {
|
|
|
249b5c |
case SERVLET:
|
|
|
249b5c |
return new ServletStyleUriPatternMatcher(pattern);
|
|
|
249b5c |
commit c2a5f1b0d3dc946bf4c9c240bce600ccf65230fa
|
|
|
249b5c |
Author: Stuart McCulloch <mcculls@gmail.com>
|
|
|
249b5c |
Date: Tue Jan 20 18:51:01 2015 +0000
|
|
|
249b5c |
|
|
|
249b5c |
Enhance logging in filter/servlet definitions
|
|
|
249b5c |
|
|
|
249b5c |
diff --git a/extensions/servlet/src/com/google/inject/servlet/FilterDefinition.java b/extensions/servlet/src/com/google/inject/servlet/FilterDefinition.java
|
|
|
249b5c |
index 76ece31..6819665 100644
|
|
|
249b5c |
--- a/extensions/servlet/src/com/google/inject/servlet/FilterDefinition.java
|
|
|
249b5c |
+++ b/extensions/servlet/src/com/google/inject/servlet/FilterDefinition.java
|
|
|
249b5c |
@@ -15,6 +15,7 @@
|
|
|
249b5c |
*/
|
|
|
249b5c |
package com.google.inject.servlet;
|
|
|
249b5c |
|
|
|
249b5c |
+import com.google.common.base.Strings;
|
|
|
249b5c |
import com.google.common.collect.Iterators;
|
|
|
249b5c |
import com.google.inject.Injector;
|
|
|
249b5c |
import com.google.inject.Key;
|
|
|
249b5c |
@@ -29,6 +30,8 @@ import java.util.HashMap;
|
|
|
249b5c |
import java.util.Map;
|
|
|
249b5c |
import java.util.Set;
|
|
|
249b5c |
import java.util.concurrent.atomic.AtomicReference;
|
|
|
249b5c |
+import java.util.logging.Level;
|
|
|
249b5c |
+import java.util.logging.Logger;
|
|
|
249b5c |
|
|
|
249b5c |
import javax.servlet.Filter;
|
|
|
249b5c |
import javax.servlet.FilterConfig;
|
|
|
249b5c |
@@ -42,6 +45,8 @@ import javax.servlet.http.HttpServletRequest;
|
|
|
249b5c |
* @author dhanji@gmail.com (Dhanji R. Prasanna)
|
|
|
249b5c |
*/
|
|
|
249b5c |
public class FilterDefinition implements ProviderWithExtensionVisitor<FilterDefinition> {
|
|
|
249b5c |
+ private static final Logger logger = Logger.getLogger(FilterDefinition.class.getName());
|
|
|
249b5c |
+
|
|
|
249b5c |
private final String pattern;
|
|
|
249b5c |
private final Key filterKey;
|
|
|
249b5c |
private final UriPatternMatcher patternMatcher;
|
|
|
249b5c |
@@ -154,7 +159,11 @@ public class FilterDefinition implements ProviderWithExtensionVisitor
|
|
|
249b5c |
|
|
|
249b5c |
final String path = ServletUtils.getContextRelativePath(request);
|
|
|
249b5c |
if (shouldFilter(path)) {
|
|
|
249b5c |
- return filter.get();
|
|
|
249b5c |
+ Filter reference = filter.get();
|
|
|
249b5c |
+ if (logger.isLoggable(Level.FINEST)) {
|
|
|
249b5c |
+ logger.finest("Filtering " + path + " with " + reference);
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+ return reference;
|
|
|
249b5c |
} else {
|
|
|
249b5c |
return null;
|
|
|
249b5c |
}
|
|
|
249b5c |
@@ -164,4 +173,10 @@ public class FilterDefinition implements ProviderWithExtensionVisitor
|
|
|
249b5c |
Filter getFilter() {
|
|
|
249b5c |
return filter.get();
|
|
|
249b5c |
}
|
|
|
249b5c |
+
|
|
|
249b5c |
+ public String toPaddedString(int padding) {
|
|
|
249b5c |
+ Filter reference = filter.get();
|
|
|
249b5c |
+ return Strings.padEnd(pattern, padding, ' ') + ' '
|
|
|
249b5c |
+ + (reference != null ? reference : filterKey);
|
|
|
249b5c |
+ }
|
|
|
249b5c |
}
|
|
|
249b5c |
diff --git a/extensions/servlet/src/com/google/inject/servlet/GuiceFilter.java b/extensions/servlet/src/com/google/inject/servlet/GuiceFilter.java
|
|
|
249b5c |
index 0737b38..1a98bf4 100644
|
|
|
249b5c |
--- a/extensions/servlet/src/com/google/inject/servlet/GuiceFilter.java
|
|
|
249b5c |
+++ b/extensions/servlet/src/com/google/inject/servlet/GuiceFilter.java
|
|
|
249b5c |
@@ -99,9 +99,9 @@ public class GuiceFilter implements Filter {
|
|
|
249b5c |
|
|
|
249b5c |
// This can happen if you create many injectors and they all have their own
|
|
|
249b5c |
// servlet module. This is legal, caveat a small warning.
|
|
|
249b5c |
- if (GuiceFilter.pipeline instanceof ManagedFilterPipeline) {
|
|
|
249b5c |
- LOGGER.warning(MULTIPLE_INJECTORS_WARNING);
|
|
|
249b5c |
- }
|
|
|
249b5c |
+ //if (GuiceFilter.pipeline instanceof ManagedFilterPipeline) {
|
|
|
249b5c |
+ // LOGGER.warning(MULTIPLE_INJECTORS_WARNING);
|
|
|
249b5c |
+ //}
|
|
|
249b5c |
|
|
|
249b5c |
// We overwrite the default pipeline
|
|
|
249b5c |
GuiceFilter.pipeline = pipeline;
|
|
|
249b5c |
diff --git a/extensions/servlet/src/com/google/inject/servlet/ServletDefinition.java b/extensions/servlet/src/com/google/inject/servlet/ServletDefinition.java
|
|
|
249b5c |
index 285ff31..9e49ce5 100644
|
|
|
249b5c |
--- a/extensions/servlet/src/com/google/inject/servlet/ServletDefinition.java
|
|
|
249b5c |
+++ b/extensions/servlet/src/com/google/inject/servlet/ServletDefinition.java
|
|
|
249b5c |
@@ -17,6 +17,7 @@ package com.google.inject.servlet;
|
|
|
249b5c |
|
|
|
249b5c |
import static com.google.inject.servlet.ManagedServletPipeline.REQUEST_DISPATCHER_REQUEST;
|
|
|
249b5c |
|
|
|
249b5c |
+import com.google.common.base.Strings;
|
|
|
249b5c |
import com.google.common.collect.Iterators;
|
|
|
249b5c |
import com.google.inject.Injector;
|
|
|
249b5c |
import com.google.inject.Key;
|
|
|
249b5c |
@@ -34,6 +35,8 @@ import java.util.HashMap;
|
|
|
249b5c |
import java.util.Map;
|
|
|
249b5c |
import java.util.Set;
|
|
|
249b5c |
import java.util.concurrent.atomic.AtomicReference;
|
|
|
249b5c |
+import java.util.logging.Level;
|
|
|
249b5c |
+import java.util.logging.Logger;
|
|
|
249b5c |
|
|
|
249b5c |
import javax.servlet.ServletConfig;
|
|
|
249b5c |
import javax.servlet.ServletContext;
|
|
|
249b5c |
@@ -51,6 +54,8 @@ import javax.servlet.http.HttpServletResponse;
|
|
|
249b5c |
* @author dhanji@gmail.com (Dhanji R. Prasanna)
|
|
|
249b5c |
*/
|
|
|
249b5c |
public class ServletDefinition implements ProviderWithExtensionVisitor<ServletDefinition> {
|
|
|
249b5c |
+ private static final Logger logger = Logger.getLogger(ServletDefinition.class.getName());
|
|
|
249b5c |
+
|
|
|
249b5c |
private final String pattern;
|
|
|
249b5c |
private final Key servletKey;
|
|
|
249b5c |
private final UriPatternMatcher patternMatcher;
|
|
|
249b5c |
@@ -283,7 +288,14 @@ public class ServletDefinition implements ProviderWithExtensionVisitor
|
|
|
249b5c |
= (previous != null) ? previous.getOriginalRequest() : request;
|
|
|
249b5c |
GuiceFilter.localContext.set(new GuiceFilter.Context(originalRequest, request, response));
|
|
|
249b5c |
try {
|
|
|
249b5c |
- httpServlet.get().service(request, response);
|
|
|
249b5c |
+ HttpServlet reference = httpServlet.get();
|
|
|
249b5c |
+ if (logger.isLoggable(Level.FINEST)) {
|
|
|
249b5c |
+ String path = ServletUtils.getContextRelativePath(request);
|
|
|
249b5c |
+ logger.finest("Serving " + path + " with " + reference);
|
|
|
249b5c |
+ }
|
|
|
249b5c |
+ if (reference != null) {
|
|
|
249b5c |
+ reference.service(request, response);
|
|
|
249b5c |
+ }
|
|
|
249b5c |
} finally {
|
|
|
249b5c |
GuiceFilter.localContext.set(previous);
|
|
|
249b5c |
}
|
|
|
249b5c |
@@ -296,4 +308,10 @@ public class ServletDefinition implements ProviderWithExtensionVisitor
|
|
|
249b5c |
String getPattern() {
|
|
|
249b5c |
return pattern;
|
|
|
249b5c |
}
|
|
|
249b5c |
+
|
|
|
249b5c |
+ public String toPaddedString(int padding) {
|
|
|
249b5c |
+ HttpServlet reference = httpServlet.get();
|
|
|
249b5c |
+ return Strings.padEnd(pattern, padding, ' ') + ' '
|
|
|
249b5c |
+ + (reference != null ? reference : servletKey);
|
|
|
249b5c |
+ }
|
|
|
249b5c |
}
|