Skip to content

Commit de9c9fe

Browse files
committed
Compare encoded params in AbstractFlashMapManager
AbstractFlashMapManager no longer decodes the target query parameters it needs to use to match to the request after the redirect. Instead it stores query parameters as-is adn then relies on parsing the encoded query string after the redirect. Issue: SPR-12569
1 parent 46537a7 commit de9c9fe

File tree

3 files changed

+67
-37
lines changed

3 files changed

+67
-37
lines changed

spring-webmvc/src/main/java/org/springframework/web/servlet/support/AbstractFlashMapManager.java

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,11 +16,11 @@
1616

1717
package org.springframework.web.servlet.support;
1818

19-
import java.util.ArrayList;
2019
import java.util.Collections;
2120
import java.util.LinkedList;
2221
import java.util.List;
2322
import java.util.concurrent.CopyOnWriteArrayList;
23+
2424
import javax.servlet.http.HttpServletRequest;
2525
import javax.servlet.http.HttpServletResponse;
2626

@@ -30,12 +30,13 @@
3030
import org.springframework.util.Assert;
3131
import org.springframework.util.CollectionUtils;
3232
import org.springframework.util.MultiValueMap;
33-
import org.springframework.util.ObjectUtils;
3433
import org.springframework.util.StringUtils;
3534
import org.springframework.web.servlet.FlashMap;
3635
import org.springframework.web.servlet.FlashMapManager;
36+
import org.springframework.web.util.UriComponents;
3737
import org.springframework.web.util.UrlPathHelper;
3838

39+
3940
/**
4041
* A base class for {@link FlashMapManager} implementations.
4142
*
@@ -172,10 +173,16 @@ protected boolean isFlashMapForRequest(FlashMap flashMap, HttpServletRequest req
172173
return false;
173174
}
174175
}
175-
MultiValueMap<String, String> targetParams = flashMap.getTargetRequestParams();
176-
for (String expectedName : targetParams.keySet()) {
177-
for (String expectedValue : targetParams.get(expectedName)) {
178-
if (!ObjectUtils.containsElement(request.getParameterValues(expectedName), expectedValue)) {
176+
UriComponents uriComponents = ServletUriComponentsBuilder.fromRequest(request).build();
177+
MultiValueMap<String, String> actualParams = uriComponents.getQueryParams();
178+
MultiValueMap<String, String> expectedParams = flashMap.getTargetRequestParams();
179+
for (String expectedName : expectedParams.keySet()) {
180+
List<String> actualValues = actualParams.get(expectedName);
181+
if (actualValues == null) {
182+
return false;
183+
}
184+
for (String expectedValue : expectedParams.get(expectedName)) {
185+
if (!actualValues.contains(expectedValue)) {
179186
return false;
180187
}
181188
}
@@ -191,7 +198,6 @@ public final void saveOutputFlashMap(FlashMap flashMap, HttpServletRequest reque
191198

192199
String path = decodeAndNormalizePath(flashMap.getTargetRequestPath(), request);
193200
flashMap.setTargetRequestPath(path);
194-
decodeParameters(flashMap.getTargetRequestParams(), request);
195201

196202
if (logger.isDebugEnabled()) {
197203
logger.debug("Saving FlashMap=" + flashMap);
@@ -227,17 +233,6 @@ private String decodeAndNormalizePath(String path, HttpServletRequest request) {
227233
return path;
228234
}
229235

230-
private void decodeParameters(MultiValueMap<String, String> params, HttpServletRequest request) {
231-
for (String name : new ArrayList<String>(params.keySet())) {
232-
for (String value : new ArrayList<String>(params.remove(name))) {
233-
name = getUrlPathHelper().decodeRequestString(request, name);
234-
value = getUrlPathHelper().decodeRequestString(request, value);
235-
params.add(name, value);
236-
}
237-
}
238-
}
239-
240-
241236
/**
242237
* Retrieve saved FlashMap instances from the underlying storage.
243238
* @param request the current request

spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletAnnotationControllerHandlerMethodTests.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.web.servlet.mvc.method.annotation;
1818

19+
import static org.junit.Assert.*;
20+
1921
import java.beans.PropertyEditorSupport;
2022
import java.io.IOException;
2123
import java.io.Serializable;
@@ -42,6 +44,7 @@
4244
import java.util.Locale;
4345
import java.util.Map;
4446
import java.util.Set;
47+
4548
import javax.servlet.ServletConfig;
4649
import javax.servlet.ServletContext;
4750
import javax.servlet.ServletException;
@@ -137,8 +140,6 @@
137140
import org.springframework.web.servlet.support.RequestContextUtils;
138141
import org.springframework.web.servlet.view.InternalResourceViewResolver;
139142

140-
import static org.junit.Assert.*;
141-
142143
/**
143144
* The origin of this test class is {@link ServletAnnotationControllerHandlerMethodTests}.
144145
*
@@ -1532,7 +1533,7 @@ public void redirectAttribute() throws Exception {
15321533

15331534
// GET after POST
15341535
request = new MockHttpServletRequest("GET", "/messages/1");
1535-
request.addParameter("name", "value");
1536+
request.setQueryString("name=value");
15361537
request.setSession(session);
15371538
response = new MockHttpServletResponse();
15381539
getServlet().service(request, response);

spring-webmvc/src/test/java/org/springframework/web/servlet/support/FlashMapManagerTests.java

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import static org.junit.Assert.*;
2020

21+
import java.net.URLEncoder;
2122
import java.util.ArrayList;
2223
import java.util.Arrays;
2324
import java.util.List;
@@ -31,7 +32,6 @@
3132

3233
import org.springframework.mock.web.test.MockHttpServletRequest;
3334
import org.springframework.mock.web.test.MockHttpServletResponse;
34-
import org.springframework.util.MultiValueMap;
3535
import org.springframework.web.servlet.FlashMap;
3636
import org.springframework.web.util.WebUtils;
3737

@@ -113,19 +113,19 @@ public void retrieveAndUpdateMatchByParams() {
113113

114114
this.flashMapManager.setFlashMaps(Arrays.asList(flashMap));
115115

116-
this.request.setParameter("number", (String) null);
116+
this.request.setQueryString("number=");
117117
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(this.request, this.response);
118118

119119
assertNull(inputFlashMap);
120120
assertEquals("FlashMap should not have been removed", 1, this.flashMapManager.getFlashMaps().size());
121121

122-
this.request.setParameter("number", "two");
122+
this.request.setQueryString("number=two");
123123
inputFlashMap = this.flashMapManager.retrieveAndUpdate(this.request, this.response);
124124

125125
assertNull(inputFlashMap);
126126
assertEquals("FlashMap should not have been removed", 1, this.flashMapManager.getFlashMaps().size());
127127

128-
this.request.setParameter("number", "one");
128+
this.request.setQueryString("number=one");
129129
inputFlashMap = this.flashMapManager.retrieveAndUpdate(this.request, this.response);
130130

131131
assertEquals(flashMap, inputFlashMap);
@@ -143,13 +143,13 @@ public void retrieveAndUpdateMatchWithMultiValueParam() {
143143

144144
this.flashMapManager.setFlashMaps(Arrays.asList(flashMap));
145145

146-
this.request.setParameter("id", "1");
146+
this.request.setQueryString("id=1");
147147
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(this.request, this.response);
148148

149149
assertNull(inputFlashMap);
150150
assertEquals("FlashMap should not have been removed", 1, this.flashMapManager.getFlashMaps().size());
151151

152-
this.request.addParameter("id", "2");
152+
this.request.setQueryString("id=1&id=2");
153153
inputFlashMap = this.flashMapManager.retrieveAndUpdate(this.request, this.response);
154154

155155
assertEquals(flashMap, inputFlashMap);
@@ -268,20 +268,54 @@ public void saveOutputFlashMapNormalizeTargetPath() throws InterruptedException
268268

269269
@Test
270270
public void saveOutputFlashMapDecodeParameters() throws Exception {
271+
272+
FlashMap flashMap = new FlashMap();
273+
flashMap.put("key", "value");
274+
flashMap.setTargetRequestPath("/path");
275+
flashMap.addTargetRequestParam("param", "%D0%90%D0%90");
276+
flashMap.addTargetRequestParam("param", "%D0%91%D0%91");
277+
flashMap.addTargetRequestParam("param", "%D0%92%D0%92");
278+
flashMap.addTargetRequestParam("%3A%2F%3F%23%5B%5D%40", "value");
279+
271280
this.request.setCharacterEncoding("UTF-8");
281+
this.flashMapManager.saveOutputFlashMap(flashMap, this.request, this.response);
282+
283+
MockHttpServletRequest requestAfterRedirect = new MockHttpServletRequest("GET", "/path");
284+
requestAfterRedirect.setQueryString("param=%D0%90%D0%90&param=%D0%91%D0%91&param=%D0%92%D0%92&%3A%2F%3F%23%5B%5D%40=value");
285+
requestAfterRedirect.addParameter("param", "\u0410\u0410");
286+
requestAfterRedirect.addParameter("param", "\u0411\u0411");
287+
requestAfterRedirect.addParameter("param", "\u0412\u0412");
288+
requestAfterRedirect.addParameter(":/?#[]@", "value");
289+
290+
flashMap = this.flashMapManager.retrieveAndUpdate(requestAfterRedirect, new MockHttpServletResponse());
291+
assertNotNull(flashMap);
292+
assertEquals(1, flashMap.size());
293+
assertEquals("value", flashMap.get("key"));
294+
}
295+
296+
// SPR-12569
297+
298+
@Test
299+
public void flashAttributesWithQueryParamsWithSpace() throws Exception {
300+
301+
String encodedValue = URLEncoder.encode("1 2", "UTF-8");
272302

273303
FlashMap flashMap = new FlashMap();
274-
flashMap.put("anyKey", "anyValue");
304+
flashMap.put("key", "value");
305+
flashMap.setTargetRequestPath("/path");
306+
flashMap.addTargetRequestParam("param", encodedValue);
275307

276-
flashMap.addTargetRequestParam("key", "%D0%90%D0%90");
277-
flashMap.addTargetRequestParam("key", "%D0%91%D0%91");
278-
flashMap.addTargetRequestParam("key", "%D0%92%D0%92");
279-
flashMap.addTargetRequestParam("%3A%2F%3F%23%5B%5D%40", "value");
308+
this.request.setCharacterEncoding("UTF-8");
280309
this.flashMapManager.saveOutputFlashMap(flashMap, this.request, this.response);
281310

282-
MultiValueMap<String,String> targetRequestParams = flashMap.getTargetRequestParams();
283-
assertEquals(Arrays.asList("\u0410\u0410", "\u0411\u0411", "\u0412\u0412"), targetRequestParams.get("key"));
284-
assertEquals(Arrays.asList("value"), targetRequestParams.get(":/?#[]@"));
311+
MockHttpServletRequest requestAfterRedirect = new MockHttpServletRequest("GET", "/path");
312+
requestAfterRedirect.setQueryString("param=" + encodedValue);
313+
requestAfterRedirect.addParameter("param", "1 2");
314+
315+
flashMap = this.flashMapManager.retrieveAndUpdate(requestAfterRedirect, new MockHttpServletResponse());
316+
assertNotNull(flashMap);
317+
assertEquals(1, flashMap.size());
318+
assertEquals("value", flashMap.get("key"));
285319
}
286320

287321

0 commit comments

Comments
 (0)