Problem/Motivation

Steps to reproduce the bug

  • basic page request (without a destination argument) that results in 403 or 404 response
  • default error page whose execution results in a call to drupal_goto()

Expected behavior: redirect to default error page
Actual behavior: redirect loop

This results in browser displaying something like the following:

The page isn't redirecting properly
Browser has detected that the server is redirecting the request for this address in a way that will never complete.

The code trail is as follows (for a 403 response):

menu_execute_active_handler()
- $router_item['access'] = FALSE;
- $page_callback_result = MENU_ACCESS_DENIED;
drupal_deliver_page()
drupal_deliver_html_page()
- case MENU_ACCESS_DENIED:
- $_GET['destination'] = $_GET['q'];
- above saves the invalid path to a key used later in drupal_goto()
- $path = drupal_get_normal_path(variable_get('site_403', ''));
- this $path is the default error page
- $return = menu_execute_active_handler($path, FALSE);
menu_execute_active_handler()
- drupal_alter('menu_site_status', $page_callback_result, $read_only_path);
- for the site that motivated this issue the error path is 'user/login'
user_menu_site_status_alter()
- because the user was logged in
- drupal_goto('user');
drupal_goto()
- if (isset($_GET['destination']) && !url_is_external($_GET['destination']))
- $destination = drupal_parse_url($_GET['destination']);
- $path = $destination['path'];
- and so we redirect to a known invalid path

Because drupal_deliver_html_page() set $_GET['destination'] to a page known to result in a 403 or 404 response, this causes a redirect loop. Why exactly would we want this code? Is there a use case for such? The comment on this statement reads:

Keep old path for reference, and to allow forms to redirect to it.

Why would a form want to redirect to a page known to result in a dead end? If we would like the path for reference, then put it in a different key in $_GET, not one that gets picked up by later code to hijack the whole error page handling process.

And lest someone question why the error path on a site is 'user/login' please do not let this interfere with understanding the bug in general sense (see "Steps to reproduce the bug" above).

Proposed resolution

Two choices:

  • Remove the conditional block in drupal_deliver_html_page() that sets $_GET['destination'] to the known bad path.
  • Set a different key in the $_GET array if the invalid path is truly needed for reference and let a contrib or custom module deal with it if desired in the call to drupal_alter('drupal_goto', $path);.

Remaining tasks

Review, a test could be written, but not clear it is necessary.

User interface changes

None.

API changes

None.

Comments

solotandem’s picture

Status: Active » Needs review
StatusFileSize
new2.24 KB

Attached patch adds conditional logic to drupal_goto() that checks for new key in $_GET which indicates the callback result of the destination path. If result is bad, then do not override goto path with destination path.

Status: Needs review » Needs work

The last submitted patch, 1: 2400511-1-check-destination_callback_result.patch, failed testing.

solotandem’s picture

Status: Needs work » Needs review
StatusFileSize
new2.87 KB

Unset the state variable when a valid menu callback is found.

solotandem’s picture

Updated patch for drupal 7.38.

solide-echt’s picture

I can confirm this patch works with - at least for me using passwordless login and email registration - no negative side effects.
eric

cilefen’s picture

Please can you expand the steps to reproduce in the issue summary. I think I understand them but not totally. An ordered list of instructions with examples would be great.

cilefen’s picture

Please check if this is an issue with Drupal 8. If so, it must be fixed there first according to the backport policy. If it is, move it to branch 8.0.x-dev and tag it “Needs backport to D7”.

michfuer’s picture

This is a related post https://drupal.stackexchange.com/questions/29384/direct-link-to-view-unp...

I verified this issues exists on 7.80 using https://simplytest.me/

Steps to reproduce are

  • Set the Default 403 path at /admin/config/system/site-information to /user/login
  • As an authenticated user view an unpublished node
  • Get the infinite redirect

The reason I think this is still considered a bug is that core is actually trying to redirect to /user via drupal_goto('user'); which the auth user does have access to. The outcome might not be ideal with a user served the /user page vs. a 403, but still that would be the behavior I would expect from the code.

Status: Needs review » Closed (outdated)

Automatically closed because Drupal 7 security and bugfix support has ended as of 5 January 2025. If the issue verifiably applies to later versions, please reopen with details and update the version.