Permalink
Browse files

Merge branch '2.1.x' into 2.2.x

Conflicts:
	build.gradle
	grails-bootstrap/src/main/groovy/org/codehaus/groovy/grails/resolve/GrailsCoreDependencies.java
	grails-core/src/main/groovy/org/codehaus/groovy/grails/compiler/GrailsProjectWatcher.java
  • Loading branch information...
2 parents 8d68694 + 5a9fd65 commit 8049ed114a3183cb1ce5078f8ad5dc91c035e000 @graemerocher graemerocher committed Feb 18, 2013
@@ -159,7 +159,8 @@ public void onChange(File file) {
public void onNew(File file) {
if (fileIsReloadable(file)) {
LOG.info("File [" + file + "] added. Applying changes to application.");
- if (!file.getName().toLowerCase().endsWith(".properties")) {
+ String fileName = file.getName();
+ if (fileName.endsWith(".groovy") || fileName.endsWith(".java")) {
// only sleep for source files, not i18n files
sleep(5000);
}
@@ -89,8 +89,11 @@ class WithFormMethod {
final request = webRequest.getCurrentRequest()
SynchronizerTokensHolder tokensHolderInSession = request.getSession(false)?.getAttribute(SynchronizerTokensHolder.HOLDER)
String urlInRequest = webRequest.params[SynchronizerTokensHolder.TOKEN_URI]
+ String tokenInRequest = webRequest.params[SynchronizerTokensHolder.TOKEN_KEY]
- tokensHolderInSession.resetToken(urlInRequest)
+ if (urlInRequest && tokenInRequest) {
+ tokensHolderInSession.resetToken(urlInRequest, tokenInRequest)
+ }
if (tokensHolderInSession.isEmpty()) request.getSession(false)?.removeAttribute(SynchronizerTokensHolder.HOLDER)
}
}
@@ -242,4 +242,47 @@ class WithFormMethodTests extends GroovyTestCase {
assertEquals "bar", result2.foo
}
+ void testHandleSubmitOfTwoFormsWithSameURL() {
+ def withForm = new WithFormMethod()
+ def url1 = "http://grails.org/submit"
+ def url2 = "http://grails.org/submit"
+
+ SynchronizerTokensHolder tokensHolder = new SynchronizerTokensHolder()
+ def token1 = tokensHolder.generateToken(url1)
+ def token2 = tokensHolder.generateToken(url2)
+
+ def request1 = GrailsWebUtil.bindMockWebRequest()
+ request1.session.setAttribute(SynchronizerTokensHolder.HOLDER,tokensHolder)
+ request1.currentRequest.addParameter(SynchronizerTokensHolder.TOKEN_URI,url1)
+ request1.currentRequest.addParameter(SynchronizerTokensHolder.TOKEN_KEY,token1)
+
+ def result1 = withForm.withForm(request1) {
+ return [foo:"bar"]
+ }.invalidToken {
+ throw new GrailsRuntimeException("invalid token")
+ }
+
+ assertEquals "bar", result1.foo
+
+ def request2 = GrailsWebUtil.bindMockWebRequest()
+ request2.session.setAttribute(SynchronizerTokensHolder.HOLDER,tokensHolder)
+ request2.currentRequest.addParameter(SynchronizerTokensHolder.TOKEN_URI,url2)
+ request2.currentRequest.addParameter(SynchronizerTokensHolder.TOKEN_KEY,token2)
+
+ def result2 = withForm.withForm(request2) {
+ return [foo:"bar"]
+ }.invalidToken {
+ throw new GrailsRuntimeException("invalid token")
+ }
+
+ assertEquals "bar", result2.foo
+
+ shouldFail(GrailsRuntimeException) {
+ withForm.withForm(request2) {
+ return [foo:"bar"]
+ }.invalidToken {
+ throw new GrailsRuntimeException("invalid token")
+ }
+ }
+ }
}
@@ -15,6 +15,7 @@
package org.codehaus.groovy.grails.web.servlet.mvc
import javax.servlet.http.HttpSession
+import java.util.concurrent.CopyOnWriteArraySet
/**
* A token used to handle double-submits.
@@ -29,28 +30,38 @@ class SynchronizerTokensHolder implements Serializable {
public static final String TOKEN_KEY = "org.codehaus.groovy.grails.SYNCHRONIZER_TOKEN"
public static final String TOKEN_URI = "org.codehaus.groovy.grails.SYNCHRONIZER_URI"
- Map<String, UUID> currentTokens;
+ Map<String, Set<UUID>> currentTokens= [:].withDefault { new CopyOnWriteArraySet<UUID>() };
SynchronizerTokensHolder() {
- // generateToken(url)
- currentTokens = new HashMap<String, UUID>();
}
boolean isValid(String url, String token) {
- currentTokens[url]?.equals(UUID.fromString(token))
+ final uuid = UUID.fromString(token)
+ currentTokens[url]?.contains(uuid)
}
String generateToken(String url) {
- currentTokens[url] = UUID.randomUUID()
- return currentTokens[url]
+ final uuid = UUID.randomUUID()
+ currentTokens[url].add(uuid)
+ return uuid
}
void resetToken(String url) {
currentTokens.remove(url)
}
+ void resetToken(String url, String token) {
+ if (url && token) {
+ final set = currentTokens[url]
+ set.remove(UUID.fromString(token))
+ if (set.isEmpty()) {
+ currentTokens.remove(url)
+ }
+ }
+ }
+
boolean isEmpty() {
- return currentTokens.isEmpty()
+ return currentTokens.isEmpty() || currentTokens.every { String url, Set<UUID> uuids -> uuids.isEmpty() }
}
static SynchronizerTokensHolder store(HttpSession session) {

0 comments on commit 8049ed1

Please sign in to comment.