Skip to content

Fix request parameter comparison bug in isFlashMapForRequest() method of AbstractFlashMapManager.java. #565

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.mock.web;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;

import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.TimeZone;


/**
* Utility class to generate HTTP dates.
* <p>
* This class is based on code in Apache Tomcat.
*
* @author Remy Maucherat
* @author Andrey Grebnev
*/
public class FastHttpDateFormat {
//~ Static fields/initializers =====================================================================================

/** HTTP date format. */
protected static final SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);

/** The set of SimpleDateFormat formats to use in <code>getDateHeader()</code>. */
protected static final SimpleDateFormat[] formats = {
new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US)
};

/** GMT time zone - all HTTP dates are on GMT */
protected static final TimeZone gmtZone = TimeZone.getTimeZone("GMT");

static {
format.setTimeZone(gmtZone);

formats[0].setTimeZone(gmtZone);
formats[1].setTimeZone(gmtZone);
formats[2].setTimeZone(gmtZone);
}

/** Instant on which the currentDate object was generated. */
protected static long currentDateGenerated = 0L;

/** Current formatted date. */
protected static String currentDate = null;

/** Formatter cache. */
protected static final HashMap<Long,String> formatCache = new HashMap<Long,String>();

/** Parser cache. */
protected static final HashMap<String,Long> parseCache = new HashMap<String,Long>();

//~ Methods ========================================================================================================

/**
* Formats a specified date to HTTP format. If local format is not <code>null</code>, it's used instead.
*
* @param value Date value to format
* @param threadLocalformat The format to use (or <code>null</code> -- then HTTP format will be used)
*
* @return Formatted date
*/
public static String formatDate(long value, DateFormat threadLocalformat) {
String cachedDate = null;
Long longValue = Long.valueOf(value);

try {
cachedDate = formatCache.get(longValue);
} catch (Exception ignored) {}

if (cachedDate != null) {
return cachedDate;
}

String newDate;
Date dateValue = new Date(value);

if (threadLocalformat != null) {
newDate = threadLocalformat.format(dateValue);

synchronized (formatCache) {
updateCache(formatCache, longValue, newDate);
}
} else {
synchronized (formatCache) {
newDate = format.format(dateValue);
updateCache(formatCache, longValue, newDate);
}
}

return newDate;
}

/**
* Gets the current date in HTTP format.
*
* @return Current date in HTTP format
*/
public static String getCurrentDate() {
long now = System.currentTimeMillis();

if ((now - currentDateGenerated) > 1000) {
synchronized (format) {
if ((now - currentDateGenerated) > 1000) {
currentDateGenerated = now;
currentDate = format.format(new Date(now));
}
}
}

return currentDate;
}

/**
* Parses date with given formatters.
*
* @param value The string to parse
* @param formats Array of formats to use
*
* @return Parsed date (or <code>null</code> if no formatter mached)
*/
private static Long internalParseDate(String value, DateFormat[] formats) {
Date date = null;

for (int i = 0; (date == null) && (i < formats.length); i++) {
try {
date = formats[i].parse(value);
} catch (ParseException ignored) {
}
}

if (date == null) {
return null;
}

return new Long(date.getTime());
}

/**
* Tries to parse the given date as an HTTP date. If local format list is not <code>null</code>, it's used
* instead.
*
* @param value The string to parse
* @param threadLocalformats Array of formats to use for parsing. If <code>null</code>, HTTP formats are used.
*
* @return Parsed date (or -1 if error occurred)
*/
public static long parseDate(String value, DateFormat[] threadLocalformats) {
Long cachedDate = null;

try {
cachedDate = (Long) parseCache.get(value);
} catch (Exception ignored) {}

if (cachedDate != null) {
return cachedDate.longValue();
}

Long date;

if (threadLocalformats != null) {
date = internalParseDate(value, threadLocalformats);

synchronized (parseCache) {
updateCache(parseCache, value, date);
}
} else {
synchronized (parseCache) {
date = internalParseDate(value, formats);
updateCache(parseCache, value, date);
}
}

if (date == null) {
return (-1L);
} else {
return date.longValue();
}
}

/**
* Updates cache.
*
* @param cache Cache to be updated
* @param key Key to be updated
* @param value New value
*/
@SuppressWarnings("unchecked")
private static void updateCache(HashMap cache, Object key, Object value) {
if (value == null) {
return;
}

if (cache.size() > 1000) {
cache.clear();
}

cache.put(key, value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.security.Principal;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
Expand All @@ -36,6 +37,7 @@
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;

import javax.servlet.AsyncContext;
import javax.servlet.DispatcherType;
Expand Down Expand Up @@ -197,7 +199,8 @@ public class MockHttpServletRequest implements HttpServletRequest {
private boolean requestedSessionIdFromURL = false;

private final Map<String, Part> parts = new LinkedHashMap<String, Part>();


private SimpleDateFormat[] formats;

// ---------------------------------------------------------------------
// Constructors
Expand Down Expand Up @@ -253,9 +256,16 @@ public MockHttpServletRequest(ServletContext servletContext, String method, Stri
this.method = method;
this.requestURI = requestURI;
this.locales.add(Locale.ENGLISH);

this.formats = new SimpleDateFormat[3];
this.formats[0] = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", this.getLocale());
this.formats[1] = new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", this.getLocale());
this.formats[2] = new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", this.getLocale());
this.formats[0].setTimeZone(TimeZone.getTimeZone("GMT"));
this.formats[1].setTimeZone(TimeZone.getTimeZone("GMT"));
this.formats[2].setTimeZone(TimeZone.getTimeZone("GMT"));
}


// ---------------------------------------------------------------------
// Lifecycle methods
// ---------------------------------------------------------------------
Expand Down Expand Up @@ -820,6 +830,9 @@ public long getDateHeader(String name) {
else if (value instanceof Number) {
return ((Number) value).longValue();
}
else if (value instanceof String) {
return FastHttpDateFormat.parseDate((String)value, this.formats);
}
else if (value != null) {
throw new IllegalArgumentException(
"Value for header '" + name + "' is neither a Date nor a Number: " + value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,16 @@
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
Expand Down Expand Up @@ -460,9 +464,16 @@ public String getRedirectedUrl() {
return getHeader(LOCATION_HEADER);
}

private DateFormat format = null;

@Override
public void setDateHeader(String name, long value) {
setHeaderValue(name, value);
if (this.format == null) {
this.format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", this.locale);
this.format.setTimeZone(TimeZone.getTimeZone("GMT"));
}

setHeaderValue(name, FastHttpDateFormat.formatDate(value, this.format));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,18 @@

package org.springframework.mock.web;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;

import org.junit.Test;

Expand Down Expand Up @@ -232,6 +236,20 @@ public void getRequestURLWithNegativePort() {
StringBuffer requestURL = request.getRequestURL();
assertEquals("http://localhost", requestURL.toString());
}

/**
* SPR-11912
*/
@Test
public void getDateHeaderWithString() {
DateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", request.getLocale());
format.setTimeZone(TimeZone.getTimeZone("GMT"));
long currentTime = System.currentTimeMillis();
String formatStr = format.format(new Date(currentTime));
request.addHeader("testDate", formatStr);
assertEquals(Long.toString(currentTime).substring(0, 10),
Long.toString(request.getDateHeader("testDate")).subSequence(0, 10));
}

private void assertEqualEnumerations(Enumeration<?> enum1, Enumeration<?> enum2) {
assertNotNull(enum1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,16 @@
package org.springframework.mock.web;

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.TimeZone;

import javax.servlet.http.HttpServletResponse;

import org.junit.Test;

import org.springframework.web.util.WebUtils;

import static org.junit.Assert.*;
Expand Down Expand Up @@ -243,4 +246,15 @@ public void modifyStatusMessageAfterSendError() throws IOException {
assertEquals(response.getStatus(),HttpServletResponse.SC_NOT_FOUND);
}

/**
* SPR-11912
*/
@Test
public void getDateHeader() {
DateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", response.getLocale());
format.setTimeZone(TimeZone.getTimeZone("GMT"));
long currentTime = System.currentTimeMillis();
response.setDateHeader("testTime", currentTime);
assertEquals(format.format(new Date(currentTime)), response.getHeader("testTime"));
}
}
Loading