Index: includes/form.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/form.inc,v retrieving revision 1.512 diff -u -p -r1.512 form.inc --- includes/form.inc 27 Nov 2010 19:12:56 -0000 1.512 +++ includes/form.inc 30 Nov 2010 05:22:01 -0000 @@ -1069,11 +1069,10 @@ function drupal_validate_form($form_id, // If the session token was set by drupal_prepare_form(), ensure that it // matches the current user's session. - if (isset($form['#token'])) { - if (!drupal_valid_token($form_state['values']['form_token'], $form['#token'])) { - // Setting this error will cause the form to fail validation. - form_set_error('form_token', t('This form is outdated. Reload the page and try again. Contact the site administrator if the problem persists.')); - } + if (isset($form['#token']) && !drupal_valid_token($form_state['values']['form_token'], $form['#token'])) { + // Setting this error will cause the form to fail validation. + form_set_error('form_token', t('The form was outdated. If you still want to perform this action, submit the form again.')); + $reset_token = TRUE; } _form_validate($form, $form_state, $form_id); @@ -1118,6 +1117,14 @@ function drupal_validate_form($form_id, } $form_state['values'] = $values; } + + // Reset the token if we found out above that the submitted one was invalid. + if (!empty($reset_token)) { + // Setting this value will cause the form to have an up-to-date token + // when it is re-rendered, therefore allowing the new copy of the form + // to be submitted successfully. + $form['form_token']['#value'] = drupal_get_token($form['#token']); + } } /** Index: modules/simpletest/tests/form.test =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/tests/form.test,v retrieving revision 1.76 diff -u -p -r1.76 form.test --- modules/simpletest/tests/form.test 21 Nov 2010 10:14:25 -0000 1.76 +++ modules/simpletest/tests/form.test 30 Nov 2010 05:22:01 -0000 @@ -558,6 +558,34 @@ class FormValidationTestCase extends Dru $this->assertText(t('!name field is required.', array('!name' => 'Title'))); $this->assertText('Test element is invalid'); } + + /** + * Tests re-submitting a form that contains an expired session token. + */ + function testExpiredToken() { + $this->web_user = $this->drupalCreateUser(array()); + + $this->drupalLogin($this->web_user); + $this->drupalGet('form-test/validate'); + $copy = $this->drupalGetContent(); + $url = $this->getUrl(); + $this->drupalLogout(); + + $this->drupalLogin($this->web_user); + $this->drupalSetContent($copy, $url); + + $edit = array( + 'name' => 'Drupal', + ); + $this->drupalPost(NULL, $edit, 'Save'); + $this->assertText(t('The form was outdated. If you still want to perform this action, submit the form again.')); + $this->assertNoText(t('@label value: @value', array('@label' => 'Name', '@value' => $edit['name']))); + + // Do what it suggests us to do. + $this->drupalPost(NULL, array(), 'Save'); + $this->assertNoText(t('The form was outdated. If you still want to perform this action, submit the form again.')); + $this->assertText(t('@label value: @value', array('@label' => 'Name', '@value' => $edit['name']))); + } } /** Index: modules/simpletest/tests/form_test.module =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/tests/form_test.module,v retrieving revision 1.56 diff -u -p -r1.56 form_test.module --- modules/simpletest/tests/form_test.module 27 Nov 2010 19:12:56 -0000 1.56 +++ modules/simpletest/tests/form_test.module 30 Nov 2010 05:22:02 -0000 @@ -325,6 +325,17 @@ function form_test_validate_form_validat } /** + * Form submit handler for form_test_validate_form(). + */ +function form_test_validate_form_submit(&$form, &$form_state) { + // Output the element's value from $form_state. + drupal_set_message(t('@label value: @value', array( + '@label' => $form['name']['#title'], + '@value' => $form_state['values']['name'], + ))); +} + +/** * Builds a simple form with a button triggering partial validation. */ function form_test_limit_validation_errors_form($form, &$form_state) {