Index: modules/simpletest/tests/session.test =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/tests/session.test,v retrieving revision 1.16 diff -u -r1.16 session.test --- modules/simpletest/tests/session.test 13 Jul 2009 21:51:41 -0000 1.16 +++ modules/simpletest/tests/session.test 16 Aug 2009 21:58:05 -0000 @@ -250,3 +250,95 @@ } } } + +/** + * Ensure that when running under https two session cookies are generated. + */ +class SessionHttpsTestCase extends DrupalWebTestCase { + + public static function getInfo() { + return array( + 'name' => 'Session https handling', + 'description' => 'Ensure that when running under https two session cookies are generated.', + 'group' => 'Session' + ); + } + + public function setUp() { + parent::setUp('session_test'); + } + + protected function testHttpsSession() { + global $is_https; + + if ($is_https) { + // The functionality does not make sense when running on https. + return; + } + + $insecure_session_name = session_name(); + $secure_session_name = "S$insecure_session_name"; + + // Enable secure pages. + variable_set('https', TRUE); + + $user = $this->drupalCreateUser(array('access administration pages')); + + $this->curlClose(); + $this->drupalGet('session-test/set/1'); + // Check secure cookie on insecure page. + $this->assertFalse(isset($this->cookies[$secure_session_name]), 'The secure cookie is not sent on insecure pages.'); + // Check insecure cookie on insecure page. + $this->assertFalse($this->cookies[$insecure_session_name]['secure'], 'The insecure cookie does not have the secure attribute'); + + // Check that password request form action is not secure. + $this->drupalGet('user/password'); + $form = $this->xpath('//form[@id="user-pass"]'); + $this->assertNotEqual(substr($form[0]['action'], 0, 6), 'https:', 'Password request form action is not secure'); + $form[0]['action'] = $this->httpsUrl('user'); + + // Check that user login form action is secure. + $this->drupalGet('user'); + $form = &$this->xpath('//form[@id="user-login"]'); + $this->assertEqual(substr($form[0]['action'], 0, 6), 'https:', 'Login form action is secure'); + $form[0]['action'] = $this->httpsUrl('user'); + + $edit = array( + 'name' => $user->name, + 'pass' => $user->pass_raw, + ); + $this->drupalPost(NULL, $edit, t('Log in')); + // Check secure cookie on secure page. + $this->assertTrue($this->cookies[$secure_session_name]['secure'], 'The secure cookie has the secure attribute'); + // Check insecure cookie on secure page. + $this->assertFalse($this->cookies[$insecure_session_name]['secure'], 'The insecure cookie does not have the secure attribute'); + $args = array( + ':sid' => $this->cookies[$insecure_session_name]['value'], + ':ssid' => $this->cookies[$secure_session_name]['value'], + ); + $this->assertTrue(db_query('SELECT sid FROM {sessions} WHERE sid = :sid AND ssid = :ssid', $args)->fetchField(), 'Session has both SIDs'); + $cookies = array( + $insecure_session_name . '=' . $args[':sid'], + $secure_session_name . '=' . $args[':ssid'], + ); + + foreach ($cookies as $cookie_key => $cookie) { + foreach (array('admin', $this->httpsUrl('admin')) as $url_key => $url) { + $this->curlClose(); + + $this->drupalGet($url, array(), array('Cookie: ' . $cookie)); + if ($cookie_key == $url_key) { + $this->assertText(t('Administer')); + } + else { + $this->assertNoText(t('Administer')); + } + } + } + } + + protected function httpsUrl($url) { + global $base_url; + return $base_url . '/modules/simpletest/tests/https.php?q=' . $url; + } +} Index: modules/simpletest/tests/session_test.module =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/tests/session_test.module,v retrieving revision 1.10 diff -u -r1.10 session_test.module --- modules/simpletest/tests/session_test.module 1 Jul 2009 12:47:30 -0000 1.10 +++ modules/simpletest/tests/session_test.module 16 Aug 2009 21:58:05 -0000 @@ -143,3 +143,20 @@ } } +/** + * Implement hook_form_FORM_ID_alter(). + */ +function session_test_form_user_login_alter(&$form) { + $form['#https'] = TRUE; +} + +/** + * Implement hook_drupal_goto_alter(). + * + * Force the redirection to go to a non-secure page after being on a secure + * page through https.php. + */ +function session_test_drupal_goto_alter(&$args) { + global $base_insecure_url; + $args['path'] = $base_insecure_url . '/' . $args['path']; +} Index: modules/simpletest/tests/common.test =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/tests/common.test,v retrieving revision 1.63 diff -u -r1.63 common.test --- modules/simpletest/tests/common.test 16 Aug 2009 17:37:06 -0000 1.63 +++ modules/simpletest/tests/common.test 16 Aug 2009 21:58:05 -0000 @@ -600,6 +600,43 @@ } /** + * Testing drupal_goto and hook_drupal_goto_alter(). + */ +class DrupalGotoTest extends DrupalWebTestCase { + public static function getInfo() { + return array( + 'name' => 'Drupal goto', + 'description' => 'Performs tests on the drupal_goto function and hook_drupal_goto_alter', + 'group' => 'System' + ); + } + + function setUp() { + parent::setUp('common_test'); + } + + /** + * Test setting and retrieving content for theme regions. + */ + function testDrupalGoto() { + $this->drupalGet('common-test/drupal_goto/redirect'); + + $this->assertNoText(t("Drupal goto failed to stop program"), t("Drupal goto stopped program.")); + $this->assertText('drupal_goto', t("Drupal goto redirect failed.")); + } + + /** + * Test setting and retrieving content for theme regions. + */ + function testDrupalGotoAlter() { + $this->drupalGet('common-test/drupal_goto/redirect_fail'); + + $this->assertNoText(t("Drupal goto failed to stop program"), t("Drupal goto stopped program.")); + $this->assertNoText('drupal_goto_fail', t("Drupal goto redirect failed.")); + } +} + +/** * Tests for the JavaScript system. */ class JavaScriptTestCase extends DrupalWebTestCase { Index: modules/simpletest/tests/common_test.module =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/tests/common_test.module,v retrieving revision 1.2 diff -u -r1.2 common_test.module --- modules/simpletest/tests/common_test.module 4 Jul 2009 18:26:42 -0000 1.2 +++ modules/simpletest/tests/common_test.module 16 Aug 2009 21:58:05 -0000 @@ -7,6 +7,70 @@ */ /** + * Implement hook_menu(). + */ +function common_test_menu() { + $items = array(); + $items['common-test/drupal_goto'] = array( + 'title' => 'Drupal Goto', + 'page callback' => 'common_test_drupal_goto_land', + 'access arguments' => array('access content'), + 'type' => MENU_CALLBACK, + ); + $items['common-test/drupal_goto/fail'] = array( + 'title' => 'Drupal Goto', + 'page callback' => 'common_test_drupal_goto_land_fail', + 'access arguments' => array('access content'), + 'type' => MENU_CALLBACK, + ); + $items['common-test/drupal_goto/redirect'] = array( + 'title' => 'Drupal Goto', + 'page callback' => 'common_test_drupal_goto_redirect', + 'access arguments' => array('access content'), + 'type' => MENU_CALLBACK, + ); + $items['common-test/drupal_goto/redirect_fail'] = array( + 'title' => 'Drupal Goto Failure', + 'page callback' => 'drupal_goto', + 'page arguments' => array('common-test/drupal_goto/fail'), + 'access arguments' => array('access content'), + 'type' => MENU_CALLBACK, + ); + return $items; +} + +/** + * Check that drupal_goto() exits once called. + */ +function common_test_drupal_goto_redirect() { + drupal_goto('common-test/drupal_goto'); + print t("Drupal goto failed to stop program"); +} + +/** + * Landing page for drupal_goto(). + */ +function common_test_drupal_goto_land() { + print "drupal_goto"; +} + +/** + * Fail landing page for drupal_goto(). + */ +function common_test_drupal_goto_land_fail() { + print "drupal_goto_fail"; +} + +/** + * Implement hook_drupal_goto_alter(). + */ +function common_test_drupal_goto_alter(&$args) { + if ($args['path'] == 'common-test/drupal_goto/fail') { + $args['path'] = 'common-test/drupal_goto/redirect'; + } +} + +/** * Implement hook_theme(). */ function common_test_theme() { Index: includes/session.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/session.inc,v retrieving revision 1.70 diff -u -r1.70 session.inc --- includes/session.inc 1 Jul 2009 12:47:30 -0000 1.70 +++ includes/session.inc 16 Aug 2009 21:58:04 -0000 @@ -66,7 +66,7 @@ * was found or the user is anonymous. */ function _drupal_session_read($sid) { - global $user; + global $user, $is_https; // Write and Close handlers are called after destructing objects // since PHP 5.0.5. @@ -76,14 +76,29 @@ // Handle the case of first time visitors and clients that don't store // cookies (eg. web crawlers). - if (!isset($_COOKIE[session_name()])) { + $insecure_session_name = substr(session_name(), 1); + if (!isset($_COOKIE[session_name()]) && !isset($_COOKIE[$insecure_session_name])) { $user = drupal_anonymous_user(); return ''; } // Otherwise, if the session is still active, we have a record of the - // client's session in the database. - $user = db_query("SELECT u.*, s.* FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.sid = :sid", array(':sid' => $sid))->fetchObject(); + // client's session in the database. If it's HTTPS then we are either have + // a HTTPS session or we are about to log in so we check the sessions table + // for an anonymous session wth the non-HTTPS-only cookie. + if ($is_https) { + $user = db_query("SELECT u.*, s.* FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.ssid = :ssid", array(':ssid' => $sid))->fetchObject(); + if (!$user) { + if (isset($_COOKIE[$insecure_session_name])) { + $user = db_query("SELECT u.*, s.* FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.sid = :sid AND s.uid = 0", array( + ':sid' => $_COOKIE[$insecure_session_name])) + ->fetchObject(); + } + } + } + else { + $user = db_query("SELECT u.*, s.* FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.sid = :sid", array(':sid' => $sid))->fetchObject(); + } // We found the client's session record and they are an authenticated user. if ($user && $user->uid > 0) { @@ -122,22 +137,27 @@ * This function will always return TRUE. */ function _drupal_session_write($sid, $value) { - global $user; + global $user, $is_https; if (!drupal_save_session()) { // We don't have anything to do if we are not allowed to save the session. return; } + $fields = array( + 'uid' => $user->uid, + 'cache' => isset($user->cache) ? $user->cache : 0, + 'hostname' => ip_address(), + 'session' => $value, + 'timestamp' => REQUEST_TIME, + ); + $insecure_session_name = substr(session_name(), 1); + if ($is_https && isset($_COOKIE[$insecure_session_name])) { + $fields['sid'] = $_COOKIE[$insecure_session_name]; + } db_merge('sessions') - ->key(array('sid' => $sid)) - ->fields(array( - 'uid' => $user->uid, - 'cache' => isset($user->cache) ? $user->cache : 0, - 'hostname' => ip_address(), - 'session' => $value, - 'timestamp' => REQUEST_TIME, - )) + ->key(array($is_https ? 'ssid' : 'sid' => $sid)) + ->fields($fields) ->execute(); // Last access time is updated no more frequently than once every 180 seconds. @@ -246,7 +266,14 @@ * Called when an anonymous user becomes authenticated or vice-versa. */ function drupal_session_regenerate() { - global $user; + global $user, $is_https; + if ($is_https && variable_get('https', FALSE)) { + $insecure_session_name = substr(session_name(), 1); + $params = session_get_cookie_params(); + $session_id = md5(uniqid(mt_rand(), TRUE)); + setcookie($insecure_session_name, $session_id, REQUEST_TIME + $params['lifetime'], $params['path'], $params['domain'], FALSE, $params['httponly']); + $_COOKIE[$insecure_session_name] = $session_id; + } if (drupal_session_started()) { $old_session_id = session_id(); @@ -264,7 +291,7 @@ if (isset($old_session_id)) { db_update('sessions') ->fields(array( - 'sid' => session_id() + $is_https ? 'ssid' : 'sid' => session_id() )) ->condition('sid', $old_session_id) ->execute(); @@ -304,11 +331,11 @@ * Session ID. */ function _drupal_session_destroy($sid) { - global $user; + global $user, $is_https; // Delete session data. db_delete('sessions') - ->condition('sid', $sid) + ->condition($is_https ? 'ssid' : 'sid', $sid) ->execute(); // Reset $_SESSION and $user to prevent a new session from being started @@ -316,11 +343,26 @@ $_SESSION = array(); $user = drupal_anonymous_user(); - // Unset the session cookie. - if (isset($_COOKIE[session_name()])) { + // Unset the session cookies. + _drupal_session_delete_cookie(session_name()); + if ($is_https) { + _drupal_session_delete_cookie(substr(session_name(), 1), TRUE); + } +} + +/** + * Deletes the session cookie. + * + * @param $name + * Name of session cookie to delete. + * @param $force_insecure + * Fornce cookie to be insecure. + */ +function _drupal_session_delete_cookie($name, $force_insecure = FALSE) { + if (isset($_COOKIE[$name])) { $params = session_get_cookie_params(); - setcookie(session_name(), '', REQUEST_TIME - 3600, $params['path'], $params['domain'], $params['secure'], $params['httponly']); - unset($_COOKIE[session_name()]); + setcookie($name, '', REQUEST_TIME - 3600, $params['path'], $params['domain'], !$force_insecure && $params['secure'], $params['httponly']); + unset($_COOKIE[$name]); } } Index: includes/bootstrap.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/bootstrap.inc,v retrieving revision 1.294 diff -u -r1.294 bootstrap.inc --- includes/bootstrap.inc 16 Aug 2009 18:39:45 -0000 1.294 +++ includes/bootstrap.inc 16 Aug 2009 21:58:04 -0000 @@ -509,7 +509,7 @@ global $base_url, $base_path, $base_root; // Export the following settings.php variables to the global namespace - global $databases, $db_prefix, $cookie_domain, $conf, $installed_profile, $update_free_access, $db_url; + global $databases, $db_prefix, $cookie_domain, $conf, $installed_profile, $update_free_access, $db_url, $is_https, $base_secure_url, $base_insecure_url; $conf = array(); if (file_exists(DRUPAL_ROOT . '/' . conf_path() . '/settings.php')) { @@ -519,6 +519,7 @@ if (isset($base_url)) { // Parse fixed base URL from settings.php. $parts = parse_url($base_url); + $http_protocol = $parts['scheme']; if (!isset($parts['path'])) { $parts['path'] = ''; } @@ -528,9 +529,10 @@ } else { // Create base URL - $base_root = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http'; + $http_protocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http'; + $base_root = $http_protocol . '://' . $_SERVER['HTTP_HOST']; - $base_url = $base_root .= '://' . $_SERVER['HTTP_HOST']; + $base_url = $base_root; // $_SERVER['SCRIPT_NAME'] can, in contrast to $_SERVER['PHP_SELF'], not // be modified by a visitor. @@ -543,6 +545,9 @@ $base_path = '/'; } } + $is_https = $http_protocol == 'https'; + $base_secure_url = str_replace('http://', 'https://', $base_url); + $base_insecure_url = str_replace('https://', 'http://', $base_url); if ($cookie_domain) { // If the user specifies the cookie domain, also use it for session name. @@ -557,15 +562,6 @@ $cookie_domain = check_plain($_SERVER['HTTP_HOST']); } } - // To prevent session cookies from being hijacked, a user can configure the - // SSL version of their website to only transfer session cookies via SSL by - // using PHP's session.cookie_secure setting. The browser will then use two - // separate session cookies for the HTTPS and HTTP versions of the site. So we - // must use different session identifiers for HTTPS and HTTP to prevent a - // cookie collision. - if (ini_get('session.cookie_secure')) { - $session_name .= 'SSL'; - } // Strip leading periods, www., and port numbers from cookie domain. $cookie_domain = ltrim($cookie_domain, '.'); if (strpos($cookie_domain, 'www.') === 0) { @@ -578,7 +574,17 @@ if (count(explode('.', $cookie_domain)) > 2 && !is_numeric(str_replace('.', '', $cookie_domain))) { ini_set('session.cookie_domain', $cookie_domain); } - session_name('SESS' . md5($session_name)); + // To prevent session cookies from being hijacked, a user can configure the + // SSL version of their website to only transfer session cookies via SSL by + // using PHP's session.cookie_secure setting. The browser will then use two + // separate session cookies for the HTTPS and HTTP versions of the site. So we + // must use different session identifiers for HTTPS and HTTP to prevent a + // cookie collision. + if ($is_https) { + ini_set('session.cookie_secure', TRUE); + } + $prefix = ini_get('session.cookie_secure') ? 'SSESS' : 'SESS'; + session_name($prefix . md5($session_name)); } /** Index: includes/form.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/form.inc,v retrieving revision 1.356 diff -u -r1.356 form.inc --- includes/form.inc 12 Aug 2009 11:45:14 -0000 1.356 +++ includes/form.inc 16 Aug 2009 21:58:04 -0000 @@ -946,6 +946,14 @@ // Special handling if we're on the top level form element. if (isset($element['#type']) && $element['#type'] == 'form') { + if (!empty($element['#https']) && variable_get('https', FALSE) && + !menu_path_is_external($element['#action'])) { + global $base_root; + + // Not an external URL so ensure that it is secure. + $element['#action'] = str_replace('http://', 'https://', $base_root) . $element['#action']; + } + // Store a complete copy of the form in form_state prior to building the form. $form_state['complete form'] = $element; // Set a flag if we have a correct form submission. This is always TRUE for Index: includes/common.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/common.inc,v retrieving revision 1.961 diff -u -r1.961 common.inc --- includes/common.inc 15 Aug 2009 06:20:20 -0000 1.961 +++ includes/common.inc 16 Aug 2009 21:58:04 -0000 @@ -338,6 +338,14 @@ extract(parse_url(urldecode($_REQUEST['destination']))); } + $args = array( + 'path' => &$path, + 'query' => &$query, + 'fragment' => &$fragment, + 'http_response_code' => &$http_response_code, + ); + drupal_alter('drupal_goto', $args); + $url = url($path, array('query' => $query, 'fragment' => $fragment, 'absolute' => TRUE)); // Allow modules to react to the end of the page request before redirecting. @@ -2065,6 +2073,11 @@ * - 'language' * An optional language object. Used to build the URL to link to and * look up the proper alias for the link. + * - 'https' + * Whether this URL should point to a secure location. If not specified, + * the current scheme is used, so the user stays on http or https + * respectively. TRUE enforces HTTPS and FALSE enforces HTTP, but HTTPS + * can only be enforced when the variable 'https' is set to TRUE. * - 'base_url' * Only used internally, to modify the base URL when a language dependent * URL requires so. @@ -2084,6 +2097,7 @@ 'query' => '', 'absolute' => FALSE, 'alias' => FALSE, + 'https' => FALSE, 'prefix' => '' ); if (!isset($options['external'])) { @@ -2121,7 +2135,7 @@ return $path . $options['fragment']; } - global $base_url; + global $base_url, $base_secure_url, $base_insecure_url; $script = &drupal_static(__FUNCTION__); if (!isset($script)) { @@ -2131,9 +2145,21 @@ $script = (strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') === FALSE) ? 'index.php' : ''; } + // The base_url might be rewritten from the language rewrite in domain mode. if (!isset($options['base_url'])) { - // The base_url might be rewritten from the language rewrite in domain mode. - $options['base_url'] = $base_url; + if (isset($options['https']) && variable_get('https', FALSE)) { + if ($options['https'] === TRUE) { + $options['base_url'] = $base_secure_url; + $options['absolute'] = TRUE; + } + elseif ($options['https'] === FALSE) { + $options['base_url'] = $base_insecure_url; + $options['absolute'] = TRUE; + } + } + else { + $options['base_url'] = $base_url; + } } // Preserve the original path before aliasing. @@ -2848,7 +2874,7 @@ * - 'file': Path to the file relative to base_path(). * - 'inline': The JavaScript code that should be placed in the given scope. * - 'external': The absolute path to an external JavaScript file that is not - * hosted on the local server. These files will not be aggregated if + * hosted on the local server. These files will not be aggregated if * JavaScript aggregation is enabled. * - 'setting': An array with configuration options as associative array. The * array is directly placed in Drupal.settings. All modules should wrap Index: modules/simpletest/drupal_web_test_case.php =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/drupal_web_test_case.php,v retrieving revision 1.136 diff -u -r1.136 drupal_web_test_case.php --- modules/simpletest/drupal_web_test_case.php 15 Aug 2009 17:52:53 -0000 1.136 +++ modules/simpletest/drupal_web_test_case.php 16 Aug 2009 21:58:04 -0000 @@ -1309,13 +1309,19 @@ call_user_func_array(array(&$this, 'error'), unserialize(urldecode($matches[1]))); } - // Save the session cookie, if set. - if (preg_match('/^Set-Cookie: ' . preg_quote($this->session_name) . '=([a-z90-9]+)/', $header, $matches)) { - if ($matches[1] != 'deleted') { - $this->session_id = $matches[1]; - } - else { - $this->session_id = NULL; + // Save cookies. + if (preg_match('/^Set-Cookie: ([^=]+)=(.+)/', $header, $matches)) { + $name = $matches[1]; + $parts = array_map('trim', explode(';', $matches[2])); + $value = array_shift($parts); + $this->cookies[$name] = array('value' => $value, 'secure' => in_array('secure', $parts)); + if ($name == $this->session_name) { + if ($value != 'deleted') { + $this->session_id = $value; + } + else { + $this->session_id = NULL; + } } } Index: modules/system/system.install =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.install,v retrieving revision 1.368 diff -u -r1.368 system.install --- modules/system/system.install 16 Aug 2009 18:39:45 -0000 1.368 +++ modules/system/system.install 16 Aug 2009 21:58:05 -0000 @@ -1272,6 +1272,13 @@ 'not null' => TRUE, 'default' => '', ), + 'ssid' => array( + 'description' => "Unique key: Secure session ID. The value is generated by PHP's Session API.", + 'type' => 'varchar', + 'length' => 64, + 'not null' => FALSE, + 'default' => NULL, + ), 'hostname' => array( 'description' => 'The IP address that last used this session ID (sid).', 'type' => 'varchar', @@ -1303,6 +1310,9 @@ 'timestamp' => array('timestamp'), 'uid' => array('uid'), ), + 'unique keys' => array( + 'ssid' => array('ssid'), + ), 'foreign keys' => array( 'uid' => array('users' => 'uid'), ), Index: modules/system/system.api.php =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.api.php,v retrieving revision 1.61 diff -u -r1.61 system.api.php --- modules/system/system.api.php 12 Aug 2009 12:36:04 -0000 1.61 +++ modules/system/system.api.php 16 Aug 2009 21:58:05 -0000 @@ -575,7 +575,7 @@ * Permissions are checked using user_access(). * * For a detailed usage example, see page_example.module. - * + * * @return * An array of which permission names are the keys and their corresponding * values are descriptions of each permission. @@ -1975,7 +1975,27 @@ 'myprofile_final_site_setup' => array( ), ); - return $tasks; + return $tasks; +} + +/** + * Change the page the user is sent to by drupal_goto(). + * + * @param $args + * The array keys are the same as drupal_goto() arguments and the array can + * be changed. + * + * $args = array( + * 'path' => &$path, + * 'query' => &$query, + * 'fragment' => &$fragment, + * 'http_response_code' => &$http_response_code, + * ); + * + */ +function hook_drupal_goto_alter(array $args) { + // A good addition to misery module. + $args['http_response_code'] = 500; } /** Index: modules/simpletest/tests/https.php =================================================================== RCS file: modules/simpletest/tests/https.php diff -N modules/simpletest/tests/https.php --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/simpletest/tests/https.php 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,25 @@ + $value) { + $_SERVER[$key] = str_replace('modules/simpletest/tests/https.php', 'index.php', $value); + $_SERVER[$key] = str_replace('http://', 'https://', $_SERVER[$key]); +} + +require_once 'index.php';