Skip to content

Commit 528098d

Browse files
committed
Cleanup request attributes after a forward. Fixes #10443
1 parent 98c199d commit 528098d

File tree

2 files changed

+86
-7
lines changed

2 files changed

+86
-7
lines changed

grails-plugin-controllers/src/main/groovy/grails/artefact/controller/support/RequestForwarder.groovy

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ import org.springframework.web.context.request.WebRequest
2828
import org.springframework.web.filter.OncePerRequestFilter
2929

3030
import javax.servlet.RequestDispatcher
31+
import javax.servlet.http.HttpServletRequest
32+
import javax.servlet.http.HttpServletResponse
33+
3134
/**
3235
* A Trait for classes that forward the request
3336
*
@@ -88,28 +91,37 @@ trait RequestForwarder implements WebAttributes {
8891
}
8992
}
9093

91-
def model = params.model instanceof Map ? params.model : Collections.EMPTY_MAP
94+
Map model = params.model instanceof Map ? (Map)params.model : Collections.EMPTY_MAP
9295

93-
def request = webRequest.currentRequest
94-
def response = webRequest.currentResponse
96+
HttpServletRequest request = webRequest.currentRequest
97+
HttpServletResponse response = webRequest.currentResponse
9598

9699
WebUtils.exposeRequestAttributes(request, (Map)model);
97100

98101
request.setAttribute(GrailsApplicationAttributes.FORWARD_IN_PROGRESS, true)
99102
params.includeContext = false
100-
def fowardURI = lookupLinkGenerator().link(params)
103+
String fowardURI = lookupLinkGenerator().link(params)
101104

102105

103106
RequestDispatcher dispatcher = request.getRequestDispatcher(fowardURI)
104107

105-
def requestScope = WebRequest.SCOPE_REQUEST
108+
int requestScope = WebRequest.SCOPE_REQUEST
106109
webRequest.removeAttribute(GrailsApplicationAttributes.MODEL_AND_VIEW, requestScope)
107110
webRequest.removeAttribute(GrailsApplicationAttributes.GRAILS_CONTROLLER_CLASS_AVAILABLE, requestScope)
108111
webRequest.removeAttribute(UrlMappingsHandlerMapping.MATCHED_REQUEST, requestScope)
109112
webRequest.removeAttribute(WebUtils.ERROR_STATUS_CODE_ATTRIBUTE, requestScope)
110113
webRequest.removeAttribute("grailsWebRequestFilter" + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX, requestScope)
111-
dispatcher.forward(request, response);
112-
request.setAttribute(GrailsApplicationAttributes.FORWARD_ISSUED, true)
114+
try {
115+
dispatcher.forward(request, response)
116+
request.setAttribute(GrailsApplicationAttributes.FORWARD_ISSUED, true)
117+
} finally {
118+
// cleanup after forward
119+
webRequest.removeAttribute(GrailsApplicationAttributes.MODEL_AND_VIEW, requestScope)
120+
webRequest.removeAttribute(GrailsApplicationAttributes.GRAILS_CONTROLLER_CLASS_AVAILABLE, requestScope)
121+
webRequest.removeAttribute(UrlMappingsHandlerMapping.MATCHED_REQUEST, requestScope)
122+
webRequest.removeAttribute(WebUtils.ERROR_STATUS_CODE_ATTRIBUTE, requestScope)
123+
webRequest.removeAttribute("grailsWebRequestFilter" + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX, requestScope)
124+
}
113125
return fowardURI
114126
}
115127

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package grails.artefact.controller.support
2+
3+
import grails.util.GrailsWebMockUtil
4+
import grails.web.mapping.LinkGenerator
5+
import org.grails.web.servlet.mvc.GrailsWebRequest
6+
import org.grails.web.servlet.mvc.ParameterCreationListener
7+
import org.grails.web.util.GrailsApplicationAttributes
8+
import org.springframework.mock.web.MockHttpServletRequest
9+
import org.springframework.mock.web.MockHttpServletResponse
10+
import org.springframework.mock.web.MockRequestDispatcher
11+
import org.springframework.web.context.WebApplicationContext
12+
import org.springframework.web.context.request.RequestContextHolder
13+
import org.springframework.web.servlet.ModelAndView
14+
import spock.lang.Specification
15+
16+
import javax.servlet.RequestDispatcher
17+
import javax.servlet.ServletRequest
18+
import javax.servlet.ServletResponse
19+
20+
/**
21+
* Created by graemerocher on 21/02/2017.
22+
*/
23+
class RequestForwarderSpec extends Specification {
24+
25+
void "test request forward cleans up request attributes after forward"() {
26+
27+
setup:
28+
def applicationContext = Mock(WebApplicationContext)
29+
def linkGenerator = Mock(LinkGenerator)
30+
linkGenerator.link(_) >> "/test"
31+
applicationContext.getBean(LinkGenerator) >> linkGenerator
32+
applicationContext.getBeansOfType(ParameterCreationListener) >> [:]
33+
MockRequestDispatcher mockRequestDispatcher = new MockRequestDispatcher("test") {
34+
@Override
35+
void forward(ServletRequest request, ServletResponse response) {
36+
request.setAttribute(GrailsApplicationAttributes.MODEL_AND_VIEW, new ModelAndView())
37+
super.forward(request, response)
38+
}
39+
};
40+
41+
GrailsWebRequest webRequest = GrailsWebMockUtil.bindMockWebRequest(applicationContext, new MockHttpServletRequest() {
42+
@Override
43+
RequestDispatcher getRequestDispatcher(String path) {
44+
return mockRequestDispatcher
45+
}
46+
}, new MockHttpServletResponse())
47+
48+
when:"A forward is issued that populates the model"
49+
TestForwarder forwarder = new TestForwarder()
50+
51+
forwarder.doForward()
52+
53+
then:"The model and view attribute is cleared"
54+
webRequest.request.getAttribute(GrailsApplicationAttributes.MODEL_AND_VIEW) == null
55+
56+
57+
58+
cleanup:
59+
RequestContextHolder.setRequestAttributes(null)
60+
}
61+
}
62+
63+
class TestForwarder implements RequestForwarder {
64+
void doForward() {
65+
forward(controller:"blah")
66+
}
67+
}

0 commit comments

Comments
 (0)