diff --git a/includes/common.inc b/includes/common.inc
index 8276576..7452dc4 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -753,38 +753,51 @@ function drupal_access_denied() {
  *
  * @param $url
  *   A string containing a fully qualified URI.
- * @param array $options
- *   (optional) An array that can have one or more of the following elements:
- *   - headers: An array containing request headers to send as name/value pairs.
- *   - method: A string containing the request method. Defaults to 'GET'.
- *   - data: A string containing the request body, formatted as
- *     'param=value&param=value&...'. Defaults to NULL.
- *   - max_redirects: An integer representing how many times a redirect
- *     may be followed. Defaults to 3.
- *   - timeout: A float representing the maximum number of seconds the function
- *     call may take. The default is 30 seconds. If a timeout occurs, the error
- *     code is set to the HTTP_REQUEST_TIMEOUT constant.
- *   - context: A context resource created with stream_context_create().
- *
- * @return object
- *   An object that can have one or more of the following components:
- *   - request: A string containing the request body that was sent.
- *   - code: An integer containing the response status code, or the error code
- *     if an error occurred.
- *   - protocol: The response protocol (e.g. HTTP/1.1 or HTTP/1.0).
- *   - status_message: The status message from the response, if a response was
- *     received.
- *   - redirect_code: If redirected, an integer containing the initial response
- *     status code.
- *   - redirect_url: If redirected, a string containing the URL of the redirect
- *     target.
- *   - error: If an error occurred, the error message. Otherwise not set.
- *   - headers: An array containing the response headers as name/value pairs.
- *     HTTP header names are case-insensitive (RFC 2616, section 4.2), so for
- *     easy access the array keys are returned in lower case.
- *   - data: A string containing the response body that was received.
- */
-function drupal_http_request($url, array $options = array()) {
+ * @param $options
+ *   (optional) An array which can have one or more of following keys:
+ *   - headers
+ *       An array containing request headers to send as name/value pairs.
+ *   - method
+ *       A string containing the request method. Defaults to 'GET'.
+ *   - data
+ *       A string containing the request body. Defaults to NULL.
+ *   - max_redirects
+ *       An integer representing how many times a redirect may be followed.
+ *       Defaults to 3.
+ *   - timeout
+ *       A float representing the maximum number of seconds the function call
+ *       may take. The default is 30 seconds. If a timeout occurs, the error
+ *       code is set to the HTTP_REQUEST_TIMEOUT constant.
+ *   - context
+ *       A context resource created with stream_context_create().
+ * @param fp_in
+ *   An optional file pointer, if the socket is provided externally
+ * @return
+ *   An object which can have one or more of the following parameters:
+ *   - request
+ *       A string containing the request body that was sent.
+ *   - code
+ *       An integer containing the response status code, or the error code if
+ *       an error occurred.
+ *   - protocol
+ *       The response protocol (e.g. HTTP/1.1 or HTTP/1.0).
+ *   - status_message
+ *       The status message from the response, if a response was received.
+ *   - redirect_code
+ *       If redirected, an integer containing the initial response status code.
+ *   - redirect_url
+ *       If redirected, a string containing the redirection location.
+ *   - error
+ *       If an error occurred, the error message. Otherwise not set.
+ *   - headers
+ *       An array containing the response headers as name/value pairs. HTTP
+ *       header names are case-insensitive (RFC 2616, section 4.2), so for easy
+ *       access the array keys are returned in lower case.
+ *   - data
+ *       A string containing the response body that was received.
+ */
+
+function drupal_http_request($url, array $options = array(), $fp_in = NULL) {
   $result = new stdClass();
 
   // Parse the URL and make sure we can handle the schema.
@@ -802,25 +815,61 @@ function drupal_http_request($url, array $options = array()) {
     return $result;
   }
 
-  timer_start(__FUNCTION__);
-
   // Merge the default options.
   $options += array(
-    'headers' => array(),
-    'method' => 'GET',
-    'data' => NULL,
+    'headers'       => array(),
+    'method'        => 'GET',
+    'protocol'      => 'HTTP/1.0',
+    'data'          => NULL,
     'max_redirects' => 3,
-    'timeout' => 30.0,
-    'context' => NULL,
+    'timeout'       => 30.0,
+    'context'       => NULL,
   );
 
+  $timeout = (float) $options['timeout'];
+
   // Merge the default headers.
+  //
+  // RFC 2616: "... non-standard ports MUST, default ports MAY be included ...".
+  // When port is implicit (standard port), allow Header Host without information
+  // for port, else some rewrite rules could be broken when checking the host
+  // that do not take into account the port number.
   $options['headers'] += array(
     'User-Agent' => 'Drupal (+http://drupal.org/)',
+    'Host'       => isset($uri['port']) ? (":" . $uri['port']) : $uri['host'],
   );
 
-  // stream_socket_client() requires timeout to be a float.
-  $options['timeout'] = (float) $options['timeout'];
+  // Proxy setup - normal sites don't need a proxy.
+  $proxy_server = ($options['method'] == 'CONNECT')
+                ? '': variable_get('proxy_server', '');
+  if ($proxy_server && __drupal_http_use_proxy($uri['host'])) {
+    // Since the url is passed as the path, we won't use the parsed query.
+    unset($uri['query']);
+    $uri['path'] = $url;
+
+    // Set the scheme so we open a socket to the proxy server.
+    $uri['scheme'] = ($uri['scheme'] == 'https') ? 'proxy_https' : 'proxy_http';
+
+    $proxy_username = variable_get('proxy_username', '');
+    $proxy_password = variable_get('proxy_password', '');
+    
+    // As described by RFC-2617 for Basic Authentication Scheme.
+    // Digest Access Authentication Scheme is not supported (by now)
+    $options['headers']['Proxy-Authorization'] = 'Basic ' . base64_encode($proxy_username . ":" . $proxy_password);
+
+    // Some proxies reject requests with any User-Agent headers, while others
+    // require a specific one.
+    $proxy_user_agent = variable_get('proxy_user_agent', '');
+    // The default value matches neither condition.
+    if ($proxy_user_agent === NULL) {
+      unset($options['headers']['User-Agent']);
+    }
+    elseif ($proxy_user_agent) {
+      $options['headers']['User-Agent'] = $proxy_user_agent;
+    }
+  }
+
+  timer_start(__FUNCTION__);
 
   // Use a proxy if one is defined and the host is not on the excluded list.
   $proxy_server = variable_get('proxy_server', '');
@@ -851,6 +900,7 @@ function drupal_http_request($url, array $options = array()) {
 
   switch ($uri['scheme']) {
     case 'proxy':
+    case 'proxy_http':
       // Make the socket connection to a proxy server.
       $socket = 'tcp://' . $proxy_server . ':' . variable_get('proxy_port', 8080);
       // The Host header still needs to match the real request.
@@ -881,13 +931,11 @@ function drupal_http_request($url, array $options = array()) {
       return $result;
   }
 
-  if (empty($options['context'])) {
-    $fp = @stream_socket_client($socket, $errno, $errstr, $options['timeout']);
-  }
-  else {
-    // Create a stream with context. Allows verification of a SSL certificate.
-    $fp = @stream_socket_client($socket, $errno, $errstr, $options['timeout'], STREAM_CLIENT_CONNECT, $options['context']);
-  }
+  // Use of a context in the stream allows verification of a SSL certificate.
+  if (!($fp = $fp_in))
+      $fp = empty($options['context'])
+          ? @stream_socket_client ($socket, $errno, $errstr, $timeout)
+          : @stream_socket_client ($socket, $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $options['context']);
 
   // Make sure the socket opened properly.
   if (!$fp) {
@@ -905,6 +953,29 @@ function drupal_http_request($url, array $options = array()) {
     return $result;
   }
 
+  // As described by RFC-2817
+  switch ($uri['scheme']) {
+    case 'proxy_https':
+        $options_connect = array(
+            'headers'  => array(),
+            'method'   => 'CONNECT',
+            'protocol' => 'HTTP/1.0'
+        );
+        $options_connect['headers']['Host']
+              = $options['headers']['Host'];
+        $options_connect['headers']['User-Agent']
+              = $options['headers']['User-Agent'];
+        $options_connect['headers']['Proxy-Authorization']
+              = $options['headers']['Proxy-Authorization'];
+        if (!($result_connect = drupal_http_request($url, $options_connect, $fp))) {
+            ($fp_in) ? TRUE : fclose($fp);
+            return $result_connect;
+        }
+
+        stream_socket_enable_crypto($fp, TRUE, STREAM_CRYPTO_METHOD_SSLv23_CLIENT);
+      break;
+  }
+
   // Construct the path to act on.
   $path = isset($uri['path']) ? $uri['path'] : '/';
   if (isset($uri['query'])) {
@@ -1047,12 +1118,11 @@ function drupal_http_request($url, array $options = array()) {
   );
   // RFC 2616 states that all unknown HTTP codes must be treated the same as the
   // base code in their class.
-  if (!isset($responses[$code])) {
-    $code = floor($code / 100) * 100;
+  if (!isset($responses[$result->code])) {
+    $result->code = floor($result->code / 100) * 100;
   }
-  $result->code = $code;
 
-  switch ($code) {
+  switch ($result->code) {
     case 200: // OK
     case 304: // Not modified
       break;
