diff --git a/globalredirect.module b/globalredirect.module index 34f5310..903b21b 100644 --- a/globalredirect.module +++ b/globalredirect.module @@ -148,7 +148,7 @@ function globalredirect_init() { // If there is, go to the translation. if (!empty($node_translations[$language->language]) && $node_translations[$language->language] != $matches[0]) { - drupal_goto($node_translations[$language->language], $options, 301); + globalredirect_goto($node_translations[$language->language], $options); } // If there is no translation, change the language to fit the content else { @@ -160,7 +160,7 @@ function globalredirect_init() { // Change the global $language's prefix, to make drupal_goto() // follow the proper prefix $options['language'] = $language = $all_languages[$node->language]; - drupal_goto('node/' . $node->nid, $options, 301); + globalredirect_goto('node/' . $node->nid, $options); } } break; @@ -218,14 +218,14 @@ function globalredirect_init() { if ($request_path != $prefix . $alias) { // If it's not just a slash or user has deslash on, redirect if (str_replace($prefix . $alias, '', $request_path) != '/' || $settings['deslash']) { - drupal_goto($alias, $options, 301); + globalredirect_goto($alias, $options); } } // If no alias was returned, the final check is to direct non-clean to // clean - if clean is enabled if ($settings['nonclean_to_clean'] && ((bool)variable_get('clean_url', 0)) && strpos(request_uri(), '?q=')) { - drupal_goto($current_path, $options, 301); + globalredirect_goto($current_path, $options); } // Restore the destination from earlier so its available in other places. @@ -249,6 +249,28 @@ function globalredirect_init() { } /** + * A wrapper for drupal_goto() that does not pass through if $path is an + * external URL. + */ +function globalredirect_goto($path = '', array $options = array(), $http_response_code = 301) { + if (!globalredirect_url_is_external($path)) { + return drupal_goto($path, $options, $http_response_code); + } +} + +/** + * Check if a path is external (e.g. http://example.com). + * + * This is a simple copy of url_is_external() which if given an URL with an + * invalid protocal will return FALSE, an undesired value. This function will + * return TRUE given an URL with an invalid protocol. + */ +function globalredirect_url_is_external($path) { + $colonpos = strpos($path, ':'); + return $colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)); +} + +/** * Implements hook_menu(). */ function globalredirect_menu() { @@ -291,13 +313,6 @@ function _globalredirect_is_active($settings) { } /** - * Check if the request is an attempted url mask - */ - if (strpos(request_uri(), '://') !== FALSE) { - return FALSE; - } - - /** * If the site is in offline mode there is little point doing any of this as * you might end up redirecting to a 503. */ diff --git a/globalredirect.test b/globalredirect.test index c24b92a..82df645 100644 --- a/globalredirect.test +++ b/globalredirect.test @@ -133,11 +133,41 @@ class GlobalRedirectTestCase extends DrupalWebTestCase { 'expected-path' => $settings['nonclean_to_clean'] ? 'node/add/page' : '?q=node/add/page', ), + // Ensure that the NonClean to Clean with an external URL does not redirect. + array( + 'request' => url('', array('absolute' => TRUE)), + 'options' => array('query' => array('q' => 'http://www.example.com'), 'external' => TRUE), + 'return-code' => 404, + ), + array( + 'request' => url('', array('absolute' => TRUE)), + 'options' => array('query' => array('q' => 'http://www.example.com/'), 'external' => TRUE), + 'return-code' => 404, + ), + // Also test un-escaped query strings with external URLs. + array( + 'request' => url('', array('absolute' => TRUE)) . '?q=http://www.example.com', + 'options' => array('external' => TRUE), + 'return-code' => 404, + ), + array( + 'request' => url('', array('absolute' => TRUE)) . '?q=http://www.example.com/', + 'options' => array('external' => TRUE), + 'return-code' => 404, + ), + // Test with external URLs in the destination query string. + array( + 'request' => 'node/1', + 'options' => array('query' => array('destination' => 'http://www.example.com/')), + 'return-code' => 301, + 'expected-path' => url('test-node', array('absolute' => TRUE, 'query' => array('destination' => 'http://www.example.com/'))), + ), + // Case Sensitive URL Check --- This may or may not redirect, depending on the state of case_sensitive_urls as we're requesting an aliased path in the wrong case array( 'request' => 'Test-Node', 'options' => array('external' => TRUE), - 'return-code' => $settings['case_sensitive_urls'] ? 301 : 200, + 'return-code' => $settings['case_sensitive_urls'] ? 301 : (db_driver() == 'sqlite' ? 404 : 200), // SQLite cannot return case-insensitive rows. 'expected-path' => $settings['case_sensitive_urls'] ? 'test-node' : 'Test-Node', ),