diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc
index 28c217b904ab4f98f3c7de6427de31fd041c8a28..ab53ca08b2ce2adaf911ce3ec945d72e3b761383 100644
--- a/includes/bootstrap.inc
+++ b/includes/bootstrap.inc
@@ -509,7 +509,7 @@ function drupal_settings_initialize() {
   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 @@ function drupal_settings_initialize() {
   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 @@ function drupal_settings_initialize() {
   }
   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 @@ function drupal_settings_initialize() {
       $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 @@ function drupal_settings_initialize() {
       $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 @@ function drupal_settings_initialize() {
   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));
 }
 
 /**
diff --git a/includes/common.inc b/includes/common.inc
index 848bd667c9bca989650db118f929b9f002543082..28897bdf87d99251a4f4ecc9b916036dad1bd8df 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -423,6 +423,14 @@ function drupal_goto($path = '', $query = NULL, $fragment = NULL, $http_response
     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.
@@ -2147,6 +2155,11 @@ function _format_date_callback(array $matches = NULL, $new_langcode = NULL) {
  *   - '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.
@@ -2166,6 +2179,7 @@ function url($path = NULL, array $options = array()) {
     'query' => '',
     'absolute' => FALSE,
     'alias' => FALSE,
+    'https' => FALSE,
     'prefix' => ''
   );
   if (!isset($options['external'])) {
@@ -2203,7 +2217,7 @@ function url($path = NULL, array $options = array()) {
     return $path . $options['fragment'];
   }
 
-  global $base_url;
+  global $base_url, $base_secure_url, $base_insecure_url;
   $script = &drupal_static(__FUNCTION__);
 
   if (!isset($script)) {
@@ -2213,9 +2227,21 @@ function url($path = NULL, array $options = array()) {
     $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.
diff --git a/includes/form.inc b/includes/form.inc
index 6bde787aad1c6be1c37c46e874f9c7e4d31b9427..55eb5e5fe6b0b31e49690c2e614b7328373780d4 100644
--- a/includes/form.inc
+++ b/includes/form.inc
@@ -979,6 +979,14 @@ function form_builder($form_id, $element, &$form_state) {
 
   // 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
diff --git a/includes/session.inc b/includes/session.inc
index 272ddc88de4d6a95eeceb1818618aaebf375b175..677963ae1ebee12b585f48c787de0e2439c829fc 100644
--- a/includes/session.inc
+++ b/includes/session.inc
@@ -66,7 +66,7 @@ function _drupal_session_close() {
  *   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 @@ function _drupal_session_read($sid) {
 
   // 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 @@ function _drupal_session_read($sid) {
  *   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 @@ function drupal_session_started($set = NULL) {
  * 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 @@ function drupal_session_regenerate() {
   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 @@ function drupal_session_count($timestamp = 0, $anonymous = TRUE) {
  *   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 @@ function _drupal_session_destroy($sid) {
   $_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]);
   }
 }
 
diff --git a/modules/simpletest/drupal_web_test_case.php b/modules/simpletest/drupal_web_test_case.php
index 41abb195c9108ca005107ae882236f6be384d2b9..f9789fe2fe37064e7b8f7a56157d109d8922afcb 100644
--- a/modules/simpletest/drupal_web_test_case.php
+++ b/modules/simpletest/drupal_web_test_case.php
@@ -1310,13 +1310,19 @@ protected function curlHeaderCallback($curlHandler, $header) {
       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;
+        }
       }
     }
 
diff --git a/modules/simpletest/tests/common.test b/modules/simpletest/tests/common.test
index ad565b1abd011417530cacd704e17ebab05a711e..dc6b0c7c8d2fd5a76a4b3ad00b074f4c138b58e4 100644
--- a/modules/simpletest/tests/common.test
+++ b/modules/simpletest/tests/common.test
@@ -600,6 +600,43 @@ class DrupalSetContentTestCase extends DrupalWebTestCase {
   }
 }
 
+/**
+ * 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.
  */
diff --git a/modules/simpletest/tests/common_test.module b/modules/simpletest/tests/common_test.module
index c1a8b7917499f0eb868743b9b9e4d741be57ed70..e94f72811ca64fca9b7c79e31d82f9f87aed3408 100644
--- a/modules/simpletest/tests/common_test.module
+++ b/modules/simpletest/tests/common_test.module
@@ -6,6 +6,70 @@
  * Helper module for the Common tests.
  */
 
+/**
+ * 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().
  */
diff --git a/modules/simpletest/tests/https.php b/modules/simpletest/tests/https.php
new file mode 100644
index 0000000000000000000000000000000000000000..bc473875dfa85a765ad3fbcba65db3d29dc5a3e2
--- /dev/null
+++ b/modules/simpletest/tests/https.php
@@ -0,0 +1,25 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Fake an https request, for use during testing.
+ */
+
+// Negated copy of the condition in _drupal_bootstrap(). If the user agent is
+// not from simpletest then disallow access.
+if (!(isset($_SERVER['HTTP_USER_AGENT']) && (strpos($_SERVER['HTTP_USER_AGENT'], "simpletest") !== FALSE))) {
+  exit;
+}
+
+// Change to https.
+$_SERVER['HTTPS'] = 'on';
+
+// Change to index.php.
+chdir('../../..');
+foreach ($_SERVER as $key => $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';
diff --git a/modules/simpletest/tests/session.test b/modules/simpletest/tests/session.test
index 6a2b4d32d36910225790aed56d16dce60bc25ca6..72648656cb988cf95a3efedc63288747dc3c9d21 100644
--- a/modules/simpletest/tests/session.test
+++ b/modules/simpletest/tests/session.test
@@ -250,3 +250,95 @@ class SessionTestCase extends DrupalWebTestCase {
     }
   }
 }
+
+/**
+ * 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;
+  }
+}
diff --git a/modules/simpletest/tests/session_test.module b/modules/simpletest/tests/session_test.module
index 48a65500117182f626f0bc514f30460e50471540..303c3c89a40afbb3b47321e17b9c7db1250d58b9 100644
--- a/modules/simpletest/tests/session_test.module
+++ b/modules/simpletest/tests/session_test.module
@@ -143,3 +143,20 @@ function session_test_user_login($edit = array(), $user = NULL) {
   }
 }
 
+/**
+ * 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'];
+}
diff --git a/modules/system/system.api.php b/modules/system/system.api.php
index a4ca25049dab1ebebe213c5d7ec364604c5d1d2b..4f2ec074b243ea54a531c128c4267db991f4f741 100644
--- a/modules/system/system.api.php
+++ b/modules/system/system.api.php
@@ -731,7 +731,7 @@ function hook_system_info_alter(&$info, $file) {
  * 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.
@@ -2189,7 +2189,27 @@ function hook_profile_tasks() {
     '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.
+ *   <code>
+ *     $args = array(
+ *       'path' => &$path,
+ *       'query' => &$query,
+ *       'fragment' => &$fragment,
+ *       'http_response_code' => &$http_response_code,
+ *     );
+ *   </code>
+ */
+function hook_drupal_goto_alter(array $args) {
+  // A good addition to misery module.
+  $args['http_response_code'] = 500;
 }
 
 /**
diff --git a/modules/system/system.install b/modules/system/system.install
index f22a6f2b5c9397cc468624260b212ef25d2d472d..4757d9b75f7d0a02b908c059963e99341afe813d 100644
--- a/modules/system/system.install
+++ b/modules/system/system.install
@@ -1316,6 +1316,13 @@ function system_schema() {
         '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',
@@ -1347,6 +1354,9 @@ function system_schema() {
       'timestamp' => array('timestamp'),
       'uid' => array('uid'),
     ),
+    'unique keys' => array(
+      'ssid' => array('ssid'),
+    ),
     'foreign keys' => array(
       'uid' => array('users' => 'uid'),
     ),