The commit to issue #2147153: Replace the last instance of $_GET/$_POST; Create a special exception listener / exception controller which allows to use POST requests introduced a regression. Steps to reproduce:

a) Create a form whose submit method is a redirect:

    $form_state['redirect_route'] = array(
      'route_name' => 'some.module.route',
    );

b) Put the form in a block.

c) Display the block on a 404 page, such as example.com/foo.

d) Attempt to submit the form. It will not work -- you'll end up back on the starting URL example.com/foo instead of your intended destination.

This used to work before the commit to #2147153: Replace the last instance of $_GET/$_POST; Create a special exception listener / exception controller which allows to use POST requests, which caused a failure in the patch for #1366020: Overhaul SearchQuery; make search redirects use GET query params for keywords.

I've marked it Major because 1366020 is Major and is blocked on this being fixed. dawehner is working on a solution, and jhodgdon will create a clean test for this problem.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

dawehner’s picture

Status: Active » Needs review
FileSize
3.81 KB

People talked a lot in IRC, I could not follow.

jhodgdon’s picture

To summarize a bit on the IRC discussion:

It seems as though the parent issue here decided that the normal case should be that forms submitted from 403/404 pages should, after submission, be routed back to the starting 403/404 pages.

The reason for this decision was really for the user login form, which is a special case: after logging in, there's a good chance you want to be back on the page you started from, having now the permission to see it.

However, this is really the special case, not the norm for all forms: for most forms, if the form says "I want to redirect", the form should redirect.

We should probably make sure this has tests. I think dawehner's patch here made the user login form be a special case instead of the norm. (??).

jhodgdon’s picture

I've written a test for this. I created a little form that redirects on submit, and put it in a block. Went to both a 403 and a 404 page, submitted the form.

Without the patch here (current HEAD), if you submit from the 404 page, the redirect doesn't happen. But it works OK if you submit from the 403 page.

With the patch here, both tests pass, at least on my test site.

Attaching a test-only patch, and a patch that includes the code patch from #1.

By the way... This behavior that the test finds seems to be at odds with what I was told in IRC. The main reason you would want the user login form to have its normal redirect overridden, I would think, would be due to 403 errors, not 404 errors. ?!?

Anyway, the patch here does appear to fix the bug, and now we have a test. Let the reviews begin! I cannot begin to fathom the patch in #1...

The last submitted patch, 3: 2206909-test-only-FAIL.patch, failed testing.

The last submitted patch, 3: 2206909-test-only-FAIL.patch, failed testing.

jhodgdon’s picture

Setting back to NR because the FAIL patch failed the way it was supposed to. Oh, I guess the status wasn't updated by the bot anyway.

damiankloip’s picture

Status: Needs review » Needs work

Nice, this issue is making alot of sense.

  1. +++ b/core/modules/system/lib/Drupal/system/Tests/Form/RedirectTest.php
    @@ -19,12 +19,12 @@ class RedirectTest extends WebTestBase {
    +      'description' => 'Tests functionality of form redirection.',
    

    Sounds a bit weird, switch them round? i.e. "Tests form redirection functionality."

  2. +++ b/core/modules/system/lib/Drupal/system/Tests/Form/RedirectTest.php
    @@ -85,4 +85,32 @@ function testRedirect() {
    +  function testRedirectFromErrorPages() {
    

    Shouldn't we also have a test case using the destination parameter? As that is one of the things that has changed most in the patch.

  3. +++ b/core/modules/system/lib/Drupal/system/Tests/Form/RedirectTest.php
    @@ -85,4 +85,32 @@ function testRedirect() {
    +    $this->assertEqual($this->getUrl(), $expected, 'Redirected to correct url.');
    

    Does this also check the query string? I can't remember.

  4. +++ b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Form/RedirectBlockForm.php
    @@ -0,0 +1,45 @@
    +    $form['actions']['submit'] = array('#type' => 'submit', '#value' => $this->t('Submit'));
    

    Nitpick alert: separate onto different lines.

  5. +++ b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Plugin/Block/RedirectFormBlock.php
    @@ -0,0 +1,39 @@
    +    return drupal_get_form('Drupal\form_test\Form\RedirectBlockForm');
    

    Can we use form builder instead.

jhodgdon’s picture

Status: Needs work » Needs review
FileSize
1.89 KB
8.52 KB

Regarding comment #7...

1. Sure, either way is fine with me and perfectly good English I think. Made suggested change.

2. I have no idea. The test I wrote is for bug reported in this issue, plus a bonus of also testing it on 403 pages as well as 404 (which turned out not to be broken). If the parent issue needs more tests, then someone else needs to write them, because I was not even involved with the parent issue and I don't know what would need testing that wasn't in the original patch (which presumably should have included tests?).

3. I do not understand your question.... If you look up a few lines, you will see:

+    $expected = \Drupal::url('form_test.route1', array(), array('query' => array('test1' => 'test2'), 'absolute' => TRUE));

This is the expected full destination URL, with query params, whenever that form is being submitted, wherever it comes from, and that is what is used in the assertEqual() for both the 403 and 404 starting pages. Oh, I see maybe you are worried about the assert message? OK, updated that.

4. We have no standard saying "arrays must be on different lines", as far as I know. We have a standard that "if you separate them into different lines, each line must end in a comma", but not one mandating separating them.

5. What form builder? I don't see one on BlockBase, and on a 10-line class for testing purposes, I didn't feel like making a create() method etc. I guess you mean it could be:

return \Drupal::formBuilder()->getForm('Drupal\form_test\Form\RedirectBlockForm');

Sure. Apparently drupal_get_form(), which does just that, is deprecated, so that line should be changed. Did that.

So I (gasp!) edited the patch to address 1, 3, and 5, so those 4 lines changed and nothing else. I'll leave additional tests to someone else.

dawehner’s picture

Assigned: dawehner » Unassigned

I can't find anything, but yeah obviously also cannot RTBC it.

damiankloip’s picture

I do not understand your question.... If you look up a few lines, you will see...

I just meant, does the return value of getUrl() definitely contain the query string too. Which it does, so that's fine.

What form builder? I don't see one on BlockBase, and on a 10-line class for testing purposes,

Yes, I meant use formBuilder :) just not the old deprecated function. Also, there is no harm in injecting this properly even if it is a test class. This sets an example that people look at for how things are done.

So yes, I think someone should still add some coverage for the destination parameter whilst we are changing this code that touches it. Otherwise this is looking good.

jhodgdon’s picture

damiankloip: If you can provide "steps to reproduce" or some more details of what you would like tested, then maybe someone could write the test that you would like to see? I don't really know what you mean by "some coverage for the destination parameter" or where you want that added. It may also be that the existing RedirectTest (the other method that I didn't touch) might already test what you're looking for, did you check? What's missing?

damiankloip’s picture

did you check? What's missing?

Yes, of course.

+++ b/core/modules/user/lib/Drupal/user/Form/UserLoginForm.php
@@ -104,10 +104,17 @@ public function buildForm(array $form, array &$form_state) {
+    if (!$this->request->request->has('destination')) {
+      $form_state['redirect_route'] = array(
+        'route_name' => 'user.view',
+        'route_parameters' => array('user' => $account->id()),
+      );
+    }
+    else {
+      $this->request->query->set('destination', $this->request->request->get('destination'));
+    }

This. destination parameter. I thought that was pretty self explanatory.. For the UserLoginForm.

jhodgdon’s picture

FileSize
9.45 KB
947 bytes

Oh, so you are saying that we need a test for user login, where we verify if you go to something like
example.com/user?destination=foo
that after login, we end up on example.com/foo? That sounds like a good idea. Sorry for not getting it sooner. I grepped and there were no tests in user module space with 'destination' in their code.

Note that UserBlocksTests already verifies that if you use the user login block to log in from a page, you get redirected back to that page, so we do not need to add tests for that behavior.

So here's patch with this new test added.

damiankloip’s picture

Yes, exactly that! :)

This is looking pretty good. Let's see what the bot thinks - I think this is ready to fly though.

jhodgdon’s picture

Bot is happy... Anyone for RTBC?

tim.plunkett’s picture

  1. +++ b/core/modules/system/lib/Drupal/system/Tests/Form/RedirectTest.php
    @@ -85,4 +85,32 @@ function testRedirect() {
    +  function testRedirectFromErrorPages() {
    
    +++ b/core/modules/user/lib/Drupal/user/Tests/UserLoginTest.php
    @@ -23,6 +23,18 @@ public static function getInfo() {
    +  function testLoginDestination() {
    

    public function

  2. +++ b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Form/RedirectBlockForm.php
    @@ -0,0 +1,45 @@
    +    $form_state['redirect_route'] = array(
    +      'route_name' => 'form_test.route1',
    +      'options' => array('query' => array('test1' => 'test2')),
    +    );
    +  }
    +}
    

    Can this use a \Drupal\Core\Url object directly? One less thing to convert later.

    Also missing blank line before end of class

  3. +++ b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Plugin/Block/RedirectFormBlock.php
    @@ -0,0 +1,39 @@
    +  public function build() {
    +    return \Drupal::formBuilder()->getForm('Drupal\form_test\Form\RedirectBlockForm');
    +  }
    +}
    

    I guess it doesn't matter since its a test block, but this is injectable if we want. Also, missing blank line before end of class

  4. +++ b/core/modules/user/lib/Drupal/user/Form/UserLoginForm.php
    @@ -104,10 +104,17 @@ public function buildForm(array $form, array &$form_state) {
    +    // A destination was set, probably on an exception controller,
    +    if (!$this->request->request->has('destination')) {
    +      $form_state['redirect_route'] = array(
    +        'route_name' => 'user.view',
    +        'route_parameters' => array('user' => $account->id()),
    +      );
    +    }
    +    else {
    +      $this->request->query->set('destination', $this->request->request->get('destination'));
    +    }
    

    Is this something we should bake into redirectForm? I remember doing a similar dance in EntityFormController::delete().

dawehner’s picture

FileSize
10.71 KB
4.07 KB

Is this something we should bake into redirectForm? I remember doing a similar dance in EntityFormController::delete().

This is actually the full idea of the issue, we do remove the support for destination inside exception controllers and move that behavior to move back to the previous page into the login block.

tim.plunkett’s picture

Title: Regression: Form submit redirects from 404 pages are no longer possible » Regression: Form submit redirects from 403/404 pages are no longer possible
Status: Needs review » Reviewed & tested by the community

Ahh, the specific 404 in the issue title confused me, I now see why we're only changing the user login block (so you can log in from a 403 and get redirected).

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Committed 455840f and pushed to 8.x. Thanks!

  • Commit 455840f on 8.x by alexpott:
    Issue #2206909 by jhodgdon, dawehner: Regression: Form submit redirects...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.