From c8f3d1a1ec829347100d89df3247806d3dc5b83f Mon Sep 17 00:00:00 2001 From: Josh Cummings Date: Fri, 2 Nov 2018 21:18:53 +0100 Subject: [PATCH] Commit Session on Include Dispatch The servlet spec disallows any writing of headers after an include has been issued. This commit intercepts the include and commits the session, then allowing the include to proceed. See: #1243 --- .../web/http/SessionRepositoryFilter.java | 28 +++++++++++++++++++ .../http/SessionRepositoryFilterTests.java | 15 ++++++++++ 2 files changed, 43 insertions(+) diff --git a/spring-session-core/src/main/java/org/springframework/session/web/http/SessionRepositoryFilter.java b/spring-session-core/src/main/java/org/springframework/session/web/http/SessionRepositoryFilter.java index 80001306..19fb86fa 100644 --- a/spring-session-core/src/main/java/org/springframework/session/web/http/SessionRepositoryFilter.java +++ b/spring-session-core/src/main/java/org/springframework/session/web/http/SessionRepositoryFilter.java @@ -21,8 +21,11 @@ import java.time.Instant; import java.util.List; import javax.servlet.FilterChain; +import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; @@ -358,6 +361,12 @@ public class SessionRepositoryFilter extends OncePerRequestFi return this.requestedSessionId; } + @Override + public RequestDispatcher getRequestDispatcher(String path) { + RequestDispatcher requestDispatcher = super.getRequestDispatcher(path); + return new SessionCommittingRequestDispatcher(requestDispatcher); + } + private S getRequestedSession() { if (!this.requestedSessionCached) { List sessionIds = SessionRepositoryFilter.this.httpSessionIdResolver @@ -407,6 +416,25 @@ public class SessionRepositoryFilter extends OncePerRequestFi } } + private final class SessionCommittingRequestDispatcher implements RequestDispatcher { + private final RequestDispatcher delegate; + + SessionCommittingRequestDispatcher(RequestDispatcher delegate) { + this.delegate = delegate; + } + + @Override + public void forward(ServletRequest request, ServletResponse response) throws ServletException, IOException { + this.delegate.forward(request, response); + } + + @Override + public void include(ServletRequest request, ServletResponse response) throws ServletException, IOException { + SessionRepositoryRequestWrapper.this.commitSession(); + this.delegate.include(request, response); + } + } + } } diff --git a/spring-session-core/src/test/java/org/springframework/session/web/http/SessionRepositoryFilterTests.java b/spring-session-core/src/test/java/org/springframework/session/web/http/SessionRepositoryFilterTests.java index 3d7eac31..c24aa0a0 100644 --- a/spring-session-core/src/test/java/org/springframework/session/web/http/SessionRepositoryFilterTests.java +++ b/spring-session-core/src/test/java/org/springframework/session/web/http/SessionRepositoryFilterTests.java @@ -1170,6 +1170,21 @@ public class SessionRepositoryFilterTests { }); } + @Test + public void doFilterInclude() throws Exception { + doFilter(new DoInFilter() { + @Override + public void doFilter(HttpServletRequest wrappedRequest, + HttpServletResponse wrappedResponse) throws IOException, ServletException { + String id = wrappedRequest.getSession().getId(); + wrappedRequest.getRequestDispatcher("/").include(wrappedRequest, wrappedResponse); + assertThat( + SessionRepositoryFilterTests.this.sessionRepository.findById(id)) + .isNotNull(); + } + }); + } + // --- HttpSessionIdResolver @Test