Skip to content

Instantly share code, notes, and snippets.

@gissuebot
Created July 7, 2014 19:15
Show Gist options
  • Save gissuebot/0bb14cbebdb458d02c25 to your computer and use it in GitHub Desktop.
Save gissuebot/0bb14cbebdb458d02c25 to your computer and use it in GitHub Desktop.
Migrated attachment for Guice issue 807, comment 5
From 6b7a884bb097aa3d70e71fbc5e5c6143d8d5be43 Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Thu, 12 Jun 2014 11:26:46 -0400
Subject: [PATCH] Properly construct a wrapped servlet request before calling
Filter.doFilter()
---
.../inject/servlet/FilterChainInvocation.java | 8 ++-
.../google/inject/servlet/FilterDefinition.java | 79 ++++++++++++++++++++++
.../com/google/inject/servlet/ServletTest.java | 3 +-
3 files changed, 88 insertions(+), 2 deletions(-)
diff --git a/extensions/servlet/src/com/google/inject/servlet/FilterChainInvocation.java b/extensions/servlet/src/com/google/inject/servlet/FilterChainInvocation.java
index b4112cf..278815f 100644
--- a/extensions/servlet/src/com/google/inject/servlet/FilterChainInvocation.java
+++ b/extensions/servlet/src/com/google/inject/servlet/FilterChainInvocation.java
@@ -76,10 +76,16 @@ class FilterChainInvocation implements FilterChain {
try {
Filter filter = findNextFilter(request);
if (filter != null) {
+ // wrap the servlet request with filter-specific request info
+ FilterDefinition filterDefinition = filterDefinitions[index];
+ HttpServletRequest filterRequest = filterDefinition.wrapRequest(request);
+ // replace the filter context
+ GuiceFilter.localContext.set(new GuiceFilter.Context(originalRequest, filterRequest, response));
+
// call to the filter, which can either consume the request or
// recurse back into this method. (in which case we will go to find the next filter,
// or dispatch to the servlet if no more filters are left)
- filter.doFilter(servletRequest, servletResponse, this);
+ filter.doFilter(filterRequest, servletResponse, this);
} else {
//we've reached the end of the filterchain, let's try to dispatch to a servlet
final boolean serviced = servletPipeline.service(servletRequest, servletResponse);
diff --git a/extensions/servlet/src/com/google/inject/servlet/FilterDefinition.java b/extensions/servlet/src/com/google/inject/servlet/FilterDefinition.java
index ff1e5b6..f900937 100644
--- a/extensions/servlet/src/com/google/inject/servlet/FilterDefinition.java
+++ b/extensions/servlet/src/com/google/inject/servlet/FilterDefinition.java
@@ -15,6 +15,8 @@
*/
package com.google.inject.servlet;
+import static com.google.inject.servlet.ManagedServletPipeline.REQUEST_DISPATCHER_REQUEST;
+
import com.google.common.collect.Iterators;
import com.google.inject.Injector;
import com.google.inject.Key;
@@ -35,6 +37,7 @@ import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
/**
* An internal representation of a filter definition against a particular URI pattern.
@@ -160,6 +163,82 @@ class FilterDefinition implements ProviderWithExtensionVisitor<FilterDefinition>
}
}
+ HttpServletRequest wrapRequest(final HttpServletRequest servletRequest) {
+ HttpServletRequest request = new HttpServletRequestWrapper(servletRequest) {
+ private boolean pathComputed;
+ private String path;
+
+ private boolean pathInfoComputed;
+ private String pathInfo;
+
+ @Override
+ public String getPathInfo() {
+ if (!isPathInfoComputed()) {
+ String servletPath = getServletPath();
+ int servletPathLength = servletPath.length();
+ String requestUri = getRequestURI();
+ pathInfo = requestUri.substring(getContextPath().length()).replaceAll("[/]{2,}", "/");
+ // See: http://code.google.com/p/google-guice/issues/detail?id=372
+ if (pathInfo.startsWith(servletPath)) {
+ pathInfo = pathInfo.substring(servletPathLength);
+ // Corner case: when servlet path & request path match exactly (without trailing '/'),
+ // then pathinfo is null.
+ if (pathInfo.isEmpty() && servletPathLength > 0) {
+ pathInfo = null;
+ }
+ } else {
+ pathInfo = null; // we know nothing additional about the URI.
+ }
+ pathInfoComputed = true;
+ }
+
+ return pathInfo;
+ }
+
+ // NOTE(dhanji): These two are a bit of a hack to help ensure that request dispatcher-sent
+ // requests don't use the same path info that was memoized for the original request.
+ // NOTE(iqshum): I don't think this is possible, since the dispatcher-sent request would
+ // perform its own wrapping.
+ private boolean isPathInfoComputed() {
+ return pathInfoComputed
+ && !(null != servletRequest.getAttribute(REQUEST_DISPATCHER_REQUEST));
+ }
+
+ private boolean isPathComputed() {
+ return pathComputed
+ && !(null != servletRequest.getAttribute(REQUEST_DISPATCHER_REQUEST));
+ }
+
+ @Override
+ public String getServletPath() {
+ return computePath();
+ }
+
+ @Override
+ public String getPathTranslated() {
+ final String info = getPathInfo();
+
+ return (null == info) ? null : getRealPath(info);
+ }
+
+ // Memoizer pattern.
+ private String computePath() {
+ if (!isPathComputed()) {
+ String servletPath = super.getServletPath();
+ path = patternMatcher.extractPath(servletPath);
+ pathComputed = true;
+
+ if (null == path) {
+ path = servletPath;
+ }
+ }
+
+ return path;
+ }
+ };
+ return request;
+ }
+
//VisibleForTesting
Filter getFilter() {
return filter.get();
diff --git a/extensions/servlet/test/com/google/inject/servlet/ServletTest.java b/extensions/servlet/test/com/google/inject/servlet/ServletTest.java
index beb0873..2645857 100644
--- a/extensions/servlet/test/com/google/inject/servlet/ServletTest.java
+++ b/extensions/servlet/test/com/google/inject/servlet/ServletTest.java
@@ -240,7 +240,8 @@ public class ServletTest extends TestCase {
assertSame(req, servletReqProvider.get());
assertSame(req, reqProvider.get());
if (previousReq[0] != null) {
- assertEquals(req, previousReq[0]);
+ ServletRequest wrappedReq = ((HttpServletRequestWrapper) req).getRequest();
+ assertEquals(wrappedReq, previousReq[0]);
}
assertSame(resp, servletRespProvider.get());
--
1.9.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment