Decode target parameters prior to saving a FlashMap

The target parameters for a FlashMap must be decoded to be able to
match them to the parameters of incoming requests given that the
HttpServletRequest returns decoded request parameters.

SPR-9657
master
Rossen Stoyanchev 12 years ago
parent af1561634c
commit 364bb696e0
  1. 2
      spring-webmvc/src/main/java/org/springframework/web/servlet/FlashMap.java
  2. 39
      spring-webmvc/src/main/java/org/springframework/web/servlet/support/AbstractFlashMapManager.java
  3. 15
      spring-webmvc/src/test/java/org/springframework/web/servlet/support/AbstractFlashMapManagerTests.java

@ -105,7 +105,7 @@ public final class FlashMap extends HashMap<String, Object> implements Comparabl
* Return the parameters identifying the target request, or an empty map. * Return the parameters identifying the target request, or an empty map.
*/ */
public MultiValueMap<String, String> getTargetRequestParams() { public MultiValueMap<String, String> getTargetRequestParams() {
return targetRequestParams; return this.targetRequestParams;
} }
/** /**

@ -83,28 +83,33 @@ public abstract class AbstractFlashMapManager implements FlashMapManager {
} }
public final FlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response) { public final FlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response) {
List<FlashMap> allMaps = retrieveFlashMaps(request);
if (CollectionUtils.isEmpty(allMaps)) { List<FlashMap> maps = retrieveFlashMaps(request);
if (CollectionUtils.isEmpty(maps)) {
return null; return null;
} }
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Retrieved FlashMap(s): " + allMaps); logger.debug("Retrieved FlashMap(s): " + maps);
} }
List<FlashMap> mapsToRemove = getExpiredFlashMaps(allMaps);
FlashMap match = getMatchingFlashMap(allMaps, request); List<FlashMap> mapsToRemove = getExpiredFlashMaps(maps);
FlashMap match = getMatchingFlashMap(maps, request);
if (match != null) { if (match != null) {
mapsToRemove.add(match); mapsToRemove.add(match);
} }
if (!mapsToRemove.isEmpty()) { if (!mapsToRemove.isEmpty()) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Removing FlashMap(s): " + allMaps); logger.debug("Removing FlashMap(s): " + mapsToRemove);
} }
synchronized (writeLock) { synchronized (writeLock) {
allMaps = retrieveFlashMaps(request); maps = retrieveFlashMaps(request);
allMaps.removeAll(mapsToRemove); maps.removeAll(mapsToRemove);
updateFlashMaps(allMaps, request, response); updateFlashMaps(maps, request, response);
} }
} }
return match; return match;
} }
@ -177,12 +182,18 @@ public abstract class AbstractFlashMapManager implements FlashMapManager {
if (CollectionUtils.isEmpty(flashMap)) { if (CollectionUtils.isEmpty(flashMap)) {
return; return;
} }
String path = decodeAndNormalizePath(flashMap.getTargetRequestPath(), request); String path = decodeAndNormalizePath(flashMap.getTargetRequestPath(), request);
flashMap.setTargetRequestPath(path); flashMap.setTargetRequestPath(path);
flashMap.startExpirationPeriod(this.flashMapTimeout);
decodeParameters(flashMap.getTargetRequestParams(), request);
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Saving FlashMap=" + flashMap); logger.debug("Saving FlashMap=" + flashMap);
} }
flashMap.startExpirationPeriod(this.flashMapTimeout);
synchronized (writeLock) { synchronized (writeLock) {
List<FlashMap> allMaps = retrieveFlashMaps(request); List<FlashMap> allMaps = retrieveFlashMaps(request);
allMaps = (allMaps == null) ? new CopyOnWriteArrayList<FlashMap>() : allMaps; allMaps = (allMaps == null) ? new CopyOnWriteArrayList<FlashMap>() : allMaps;
@ -203,6 +214,14 @@ public abstract class AbstractFlashMapManager implements FlashMapManager {
return path; return path;
} }
private void decodeParameters(MultiValueMap<String, String> params, HttpServletRequest request) {
for (String name : new ArrayList<String>(params.keySet())) {
for (String value : new ArrayList<String>(params.remove(name))) {
params.add(name, this.urlPathHelper.decodeRequestString(request, value));
}
}
}
/** /**
* Update the FlashMap instances in some underlying storage. * Update the FlashMap instances in some underlying storage.
* @param flashMaps a non-empty list of FlashMap instances to save * @param flashMaps a non-empty list of FlashMap instances to save

@ -264,6 +264,21 @@ public class AbstractFlashMapManagerTests {
assertEquals("/once/only", flashMap.getTargetRequestPath()); assertEquals("/once/only", flashMap.getTargetRequestPath());
} }
@Test
public void saveOutputFlashMapDecodeParameters() throws Exception {
this.request.setCharacterEncoding("UTF-8");
FlashMap flashMap = new FlashMap();
flashMap.put("anyKey", "anyValue");
flashMap.addTargetRequestParam("key", "%D0%90%D0%90");
flashMap.addTargetRequestParam("key", "%D0%91%D0%91");
flashMap.addTargetRequestParam("key", "%D0%92%D0%92");
this.flashMapManager.saveOutputFlashMap(flashMap, this.request, this.response);
assertEquals(Arrays.asList("АА", "ББ", "ВВ"), flashMap.getTargetRequestParams().get("key"));
}
private static class TestFlashMapManager extends AbstractFlashMapManager { private static class TestFlashMapManager extends AbstractFlashMapManager {

Loading…
Cancel
Save