From 5b0ec3400dc0777e6dfaeaded1e497ace710e5ff Mon Sep 17 00:00:00 2001 From: JCgH4164838Gh792C124B5 <43964333+JCgH4164838Gh792C124B5@users.noreply.github.com> Date: Mon, 25 Mar 2019 01:00:10 -0400 Subject: [PATCH] Fix issue introduced with earlier WW-4873 fix: - Fixes error 500 processing failures for double-submit results with TokenSessionStoreInterceptor processing - Fix to InvocationSessionStore, new unit test confirming fix in InvocationSessionStoreTest - Minor whitespace fix to TokenSessionStoreInterceptor --- .../TokenSessionStoreInterceptor.java | 7 +++-- .../struts2/util/InvocationSessionStore.java | 18 +++++++++-- .../util/InvocationSessionStoreTest.java | 31 +++++++++++++++++++ 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/apache/struts2/interceptor/TokenSessionStoreInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/TokenSessionStoreInterceptor.java index e08fb07be..345115f0a 100644 --- a/core/src/main/java/org/apache/struts2/interceptor/TokenSessionStoreInterceptor.java +++ b/core/src/main/java/org/apache/struts2/interceptor/TokenSessionStoreInterceptor.java @@ -126,11 +126,12 @@ public class TokenSessionStoreInterceptor extends TokenInterceptor { params.remove(tokenName); params.remove(TokenHelper.TOKEN_NAME_FIELD); - String sessionTokenName = TokenHelper.buildTokenSessionAttributeName(tokenName); + String sessionTokenName = TokenHelper.buildTokenSessionAttributeName(tokenName); ActionInvocation savedInvocation = InvocationSessionStore.loadInvocation(sessionTokenName, token); if (savedInvocation != null) { // set the valuestack to the request scope + // Note: loadInvocation() restored invocation's PageContext (as savedInvocation's will already be closed) ValueStack stack = savedInvocation.getStack(); request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack); @@ -158,8 +159,8 @@ public class TokenSessionStoreInterceptor extends TokenInterceptor { // we know the token name and token must be there String key = TokenHelper.getTokenName(); String token = TokenHelper.getToken(key); - String sessionTokenName = TokenHelper.buildTokenSessionAttributeName(key); - InvocationSessionStore.storeInvocation(sessionTokenName, token, invocation); + String sessionTokenName = TokenHelper.buildTokenSessionAttributeName(key); + InvocationSessionStore.storeInvocation(sessionTokenName, token, invocation); return invocation.invoke(); } diff --git a/core/src/main/java/org/apache/struts2/util/InvocationSessionStore.java b/core/src/main/java/org/apache/struts2/util/InvocationSessionStore.java index 15662de38..2e1483415 100644 --- a/core/src/main/java/org/apache/struts2/util/InvocationSessionStore.java +++ b/core/src/main/java/org/apache/struts2/util/InvocationSessionStore.java @@ -20,6 +20,7 @@ package org.apache.struts2.util; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionInvocation; +import org.apache.struts2.ServletActionContext; import java.io.Serializable; import java.util.HashMap; @@ -57,9 +58,22 @@ public class InvocationSessionStore { ActionInvocation savedInvocation = null; if (invocationContext.invocation != null) { + // WW-5026 - Preserve the previous PageContext (even if null) and restore it to the + // ActionContext after loading the savedInvocation context. The saved context's PageContext + // would already be closed at this point (causing failures if used for output). + final ActionContext savedActionContext; + final ActionContext previousActionContext; savedInvocation = invocationContext.invocation; - ActionContext.setContext(savedInvocation.getInvocationContext()); - ActionContext.getContext().setValueStack(savedInvocation.getStack()); + savedActionContext = savedInvocation.getInvocationContext(); + previousActionContext = ActionContext.getContext(); + ActionContext.setContext(savedActionContext); + savedActionContext.setValueStack(savedInvocation.getStack()); + savedActionContext.setValueStack(savedInvocation.getStack()); + if (previousActionContext != null) { + savedActionContext.put(ServletActionContext.PAGE_CONTEXT, previousActionContext.get(ServletActionContext.PAGE_CONTEXT)); + } else { + savedActionContext.put(ServletActionContext.PAGE_CONTEXT, null); + } } return savedInvocation; diff --git a/core/src/test/java/org/apache/struts2/util/InvocationSessionStoreTest.java b/core/src/test/java/org/apache/struts2/util/InvocationSessionStoreTest.java index 8b5b8cd0d..8cfc3f4d0 100644 --- a/core/src/test/java/org/apache/struts2/util/InvocationSessionStoreTest.java +++ b/core/src/test/java/org/apache/struts2/util/InvocationSessionStoreTest.java @@ -31,6 +31,8 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.HashMap; import java.util.Map; +import org.apache.struts.mock.MockPageContext; +import org.apache.struts2.ServletActionContext; /** @@ -100,6 +102,35 @@ public class InvocationSessionStoreTest extends StrutsInternalTestCase { assertNull(savedInvocation);//Currently we don't support invocation restore from serialized session } + public void testStoreAndLoadPreservesPageContext() { + ActionContext actionContext = ActionContext.getContext(); + + // Create mock PageContext to put with the saved context (simulating a PageContext previously + // used and closed after generating JSP output). + MockPageContext mockSavedPageContext = new MockPageContext(); + actionContext.put(ServletActionContext.PAGE_CONTEXT, mockSavedPageContext); + assertEquals(mockSavedPageContext, ActionContext.getContext().get(ServletActionContext.PAGE_CONTEXT)); + + InvocationSessionStore.storeInvocation(INVOCATION_KEY, TOKEN_VALUE, invocation); + + ActionContext actionContext2 = new ActionContext(new HashMap()); + actionContext2.setSession(session); + ActionContext.setContext(actionContext2); + assertEquals(actionContext2, ActionContext.getContext()); + + // Create mock PageContext to put with the current context (simulating a PageContext + // associated with the current (active) process flow). In real-world processing it + // will usually be null, but if non-null it should be preserved/restored upon load of the + // saved context. + MockPageContext mockPreviousPageContext = new MockPageContext(); + actionContext2.put(ServletActionContext.PAGE_CONTEXT, mockPreviousPageContext); + assertEquals(mockPreviousPageContext, ActionContext.getContext().get(ServletActionContext.PAGE_CONTEXT)); + + InvocationSessionStore.loadInvocation(INVOCATION_KEY, TOKEN_VALUE); + assertEquals(actionContext, ActionContext.getContext()); + assertEquals(mockPreviousPageContext, ActionContext.getContext().get(ServletActionContext.PAGE_CONTEXT)); + } + protected void setUp() throws Exception { super.setUp(); stack = ActionContext.getContext().getValueStack();