=== modified file 'includes/bootstrap.inc'
--- includes/bootstrap.inc	2009-07-28 12:13:46 +0000
+++ includes/bootstrap.inc	2009-08-02 08:39:25 +0000
@@ -518,7 +518,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;
   $conf = array();
 
   if (file_exists(DRUPAL_ROOT . '/' . conf_path() . '/settings.php')) {
@@ -528,6 +528,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'] = '';
     }
@@ -537,9 +538,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.
@@ -552,6 +554,8 @@
       $base_path = '/';
     }
   }
+  $is_https = $http_protocol == 'https';
+  $_SERVER['HTTPS'] = $is_https ? 'on' : NULL;
 
   if ($cookie_domain) {
     // If the user specifies the cookie domain, also use it for session name.
@@ -566,15 +570,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) {
@@ -587,7 +582,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));
 }
 
 /**

=== modified file 'includes/common.inc'
--- includes/common.inc	2009-07-31 19:56:09 +0000
+++ includes/common.inc	2009-08-02 08:36:35 +0000
@@ -338,7 +338,7 @@
     extract(parse_url(urldecode($_REQUEST['destination'])));
   }
 
-  $url = url($path, array('query' => $query, 'fragment' => $fragment, 'absolute' => TRUE));
+  $url = url($path, array('query' => $query, 'fragment' => $fragment, 'absolute' => TRUE, 'secure' => FALSE));
 
   // Allow modules to react to the end of the page request before redirecting.
   // We do not want this while running update.php.
@@ -2023,6 +2023,10 @@
  *   - 'language'
  *       An optional language object. Used to build the URL to link to and
  *       look up the proper alias for the link.
+ *   - 'secure'
+ *       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.
  *   - 'base_url'
  *       Only used internally, to modify the base URL when a language dependent
  *       URL requires so.
@@ -2042,6 +2046,7 @@
     'query' => '',
     'absolute' => FALSE,
     'alias' => FALSE,
+    'secure' => NULL,
     'prefix' => ''
   );
   if (!isset($options['external'])) {
@@ -2094,6 +2099,17 @@
     $options['base_url'] = $base_url;
   }
 
+  // Force an absolute URL when the URL scheme doesn't match the current one
+  // and rewrite the base URL.
+  if ($options['secure'] === TRUE && empty($_SERVER['HTTPS'])) {
+    $options['absolute'] = TRUE;
+    $options['base_url'] = str_replace('http://', 'https://', $options['base_url']);
+  }
+  else if ($options['secure'] === FALSE && !empty($_SERVER['HTTPS'])) {
+    $options['absolute'] = TRUE;
+    $options['base_url'] = str_replace('https://', 'http://', $options['base_url']);
+  }
+
   // Preserve the original path before aliasing.
   $original_path = $path;
 

=== modified file 'includes/session.inc'
--- includes/session.inc	2009-07-01 12:47:30 +0000
+++ includes/session.inc	2009-08-02 08:31:01 +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.
@@ -82,8 +82,23 @@
   }
 
   // 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) {
+      $unsecure_sid = substr(session_name(), 1);
+      if (isset($_COOKIE[$unsecure_sid])) {
+        $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[$unsecure_sid]))
+        ->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,28 @@
  *   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,
+  );
+  $unsecure_sid = substr(session_name(), 1);
+  watchdog('test', var_export($_COOKIE, TRUE). $unsecure_sid);
+  if ($is_https && isset($_COOKIE[$unsecure_sid])) {
+    $fields['sid'] = $_COOKIE[$unsecure_sid];
+  }
   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 +267,7 @@
  * Called when an anonymous user becomes authenticated or vice-versa.
  */
 function drupal_session_regenerate() {
-  global $user;
+  global $user, $is_https;
 
   if (drupal_session_started()) {
     $old_session_id = session_id();
@@ -259,12 +280,18 @@
     $account = $user;
     drupal_session_start();
     $user = $account;
+    if ($is_https) {
+      $insecure_sid = substr(session_name(), 1);
+      $params = session_get_cookie_params();
+      setcookie($insecure_sid, session_id(), REQUEST_TIME + $params['lifetime'], $params['path'], $params['domain'], FALSE, $params['httponly']);
+      $_COOKIE[$insecure_sid] = session_id();
+    }
   }
 
   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();

=== modified file 'modules/system/system.install'
--- modules/system/system.install	2009-08-01 20:31:50 +0000
+++ modules/system/system.install	2009-08-02 08:31:01 +0000
@@ -1273,6 +1273,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' => TRUE,
+        'default' => '',
+      ),
       'hostname' => array(
         'description' => 'The IP address that last used this session ID (sid).',
         'type' => 'varchar',
@@ -1304,6 +1311,9 @@
       'timestamp' => array('timestamp'),
       'uid' => array('uid'),
     ),
+    'unique keys' => array(
+      'ssid' => array('ssid'),
+    ),
     'foreign keys' => array(
       'uid' => array('users' => 'uid'),
     ),

=== modified file 'modules/user/user.module'
--- modules/user/user.module	2009-07-31 19:01:01 +0000
+++ modules/user/user.module	2009-08-02 08:33:49 +0000
@@ -985,7 +985,7 @@
 
 function user_login_block() {
   $form = array(
-    '#action' => url($_GET['q'], array('query' => drupal_get_destination())),
+    '#action' => url($_GET['q'], array('query' => drupal_get_destination(), 'secure' => TRUE)),
     '#id' => 'user-login-form',
     '#validate' => user_login_default_validators(),
     '#submit' => array('user_login_submit'),

