View source  
  <?php
define('HTTPRL_BACKGROUND_CALLBACK', TRUE);
define('HTTPRL_TIMEOUT', 30.0);
define('HTTPRL_DNS_TIMEOUT', 5.0);
define('HTTPRL_CONNECT_TIMEOUT', 5.0);
define('HTTPRL_TTFB_TIMEOUT', 20.0);
define('HTTPRL_GLOBAL_TIMEOUT', 120.0);
define('HTTPRL_REQUEST_ALLOWED_REDIRECTS_EXHAUSTED', -2);
define('HTTPRL_REQUEST_FWRITE_FAIL', -3);
define('HTTPRL_FUNCTION_TIMEOUT', -4);
define('HTTPRL_STREAM_SELECT_TIMEOUT', -5);
define('HTTPRL_URL_PARSE_ERROR', -1001);
define('HTTPRL_URL_MISSING_SCHEMA', -1002);
define('HTTPRL_URL_INVALID_SCHEMA', -1003);
define('HTTPRL_ERROR_INITIALIZING_STREAM', -1004);
define('HTTPRL_REQUEST_ABORTED', -10053);
define('HTTPRL_CONNECTION_RESET', -10054);
define('HTTPRL_REQUEST_TIMEOUT', -10060);
define('HTTPRL_CONNECTION_REFUSED', -10061);
define('HTTPRL_HOST_NOT_FOUND', -11001);
define('HTTPRL_MULTIPART_BOUNDARY', '---------------------------' . str_replace('.', '', microtime(TRUE)));
define('HTTPRL_PR_MAX_STRING_LENGTH', 262144);
define('HTTPRL_URL_INBOUND_ALTER', TRUE);
define('HTTPRL_SERVER_SCHEMA', 0);
define('HTTPRL_NON_BLOCKING_FCLOSE_DELAY', 0);
define('HTTPRL_SERVER_PORT', '');
function httprl_url_inbound_alter(&$path, $original_path, $path_language) {
  
  if (!variable_get('httprl_url_inbound_alter', HTTPRL_URL_INBOUND_ALTER)) {
    return;
  }
  
  $request_path = request_path();
  if ($path != $request_path && strpos($request_path, 'httprl_async_function_callback') !== FALSE) {
    $path = $request_path;
  }
}
function httprl_menu() {
  $items = array();
  
  if (defined('VERSION') && substr(VERSION, 0, 1) >= 7) {
    $config_url = 'admin/config/development/httprl';
  }
  else {
    $config_url = 'admin/settings/httprl';
  }
  $items[$config_url] = array(
    'title' => 'HTTPRL',
    'description' => 'Configure HTTPRL settings.',
    'access arguments' => array(
      'administer site configuration',
    ),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'httprl_admin_settings_form',
    ),
    'type' => MENU_NORMAL_ITEM,
    'file' => 'httprl.admin.inc',
  );
  
  $items['httprl_async_function_callback'] = array(
    'title' => 'HTTPRL',
    'page callback' => 'httprl_async_page',
    'access callback' => TRUE,
    'description' => 'URL for async function workers.',
    'type' => MENU_CALLBACK,
    'file' => 'httprl.async.inc',
  );
  return $items;
}
function httprl_cron() {
  
  $fuzz_factor = 300;
  
  if (defined('VERSION') && substr(VERSION, 0, 1) >= 7) {
    db_delete('semaphore')
      ->condition('value', 'httprl')
      ->condition('expire', REQUEST_TIME - $fuzz_factor, '<')
      ->execute();
  }
  else {
    db_query("DELETE FROM {semaphore} WHERE value = 'httprl' AND expire < %f", time() - $fuzz_factor);
  }
  
  $fuzz_factor = 3600;
  
  if (defined('VERSION') && substr(VERSION, 0, 1) >= 7) {
    db_delete('semaphore')
      ->condition('name', db_like('httprl_') . '%', 'LIKE')
      ->condition('expire', REQUEST_TIME - $fuzz_factor, '<')
      ->execute();
  }
  else {
    db_query("DELETE FROM {semaphore} WHERE name LIKE 'httprl_%' AND expire < %f", time() - $fuzz_factor);
  }
}
function httprl_override_core($url, $options = array()) {
  
  httprl_send_request();
  
  httprl_request($url, $options);
  
  $response = httprl_send_request();
  
  return is_array($response) && is_string($url) && array_key_exists($url, $response) ? $response[$url] : (is_array($response) ? array_pop($response) : $response);
}
function _httprl_build_drupal_root($level = 0, $hostname_mode = 0) {
  static $webroot;
  $root_path = '/';
  if ($level > 0) {
    
    if (!isset($webroot)) {
      $webroot = str_replace('\\', '/', dirname(__FILE__));
      while (!empty($webroot)) {
        if (file_exists($webroot . '/index.php') && strpos(file_get_contents($webroot . '/index.php'), 'menu_execute_active_handler();') !== FALSE) {
          break;
        }
        $new_webroot = str_replace('\\', '/', dirname($webroot));
        if ($new_webroot == $webroot) {
          $webroot = str_replace('\\', '/', getcwd());
          break;
        }
        $webroot = $new_webroot;
      }
    }
    $root_path = '';
    $webroot_array = explode('/', $webroot);
    while ($level > 0 && count($webroot_array) != 0) {
      $level--;
      $root_path = array_pop($webroot_array) . '/' . $root_path;
    }
    $root_path = '/' . $root_path;
    $root_path = str_replace('//', '/', $root_path);
  }
  else {
    if (!empty($GLOBALS['base_path'])) {
      $root_path = $GLOBALS['base_path'];
    }
  }
  
  $auth = '';
  if (module_exists('shield')) {
    $auth = variable_get('shield_user', '') . ':' . variable_get('shield_pass', '') . '@';
  }
  elseif (isset($_SERVER['AUTH_TYPE']) && $_SERVER['AUTH_TYPE'] == 'Basic' || isset($_SERVER['HTTP_AUTHORIZATION']) && preg_match('/Basic\\s+(.*)$/i', $_SERVER['HTTP_AUTHORIZATION'])) {
    $auth = $_SERVER['PHP_AUTH_USER'] . ':' . $_SERVER['PHP_AUTH_PW'] . '@';
  }
  
  static $dns_cache;
  $hostname = httprl_get_hostname();
  
  $ip = httprl_variable_get('httprl_server_addr', FALSE);
  if ($ip == -1 || $hostname_mode == 1) {
    $ip = $hostname;
    
    if (is_callable('drupal_is_cli') && drupal_is_cli() || !isset($_SERVER['SERVER_SOFTWARE']) && (php_sapi_name() == 'cli' || is_numeric($_SERVER['argc']) && $_SERVER['argc'] > 0)) {
      if (!isset($dns_cache[$hostname])) {
        $dns_cache[$hostname] = gethostbyname($hostname);
      }
      if ($dns_cache[$hostname] == $hostname) {
        $ip = '';
      }
    }
  }
  if (empty($ip) || $hostname_mode == 2) {
    $ip = empty($_SERVER['SERVER_ADDR']) ? '127.0.0.1' : $_SERVER['SERVER_ADDR'];
    
    if (strpos($ip, ':') !== FALSE) {
      if ($_SERVER['SERVER_ADDR'] == '::1') {
        $ip = "127.0.0.1";
      }
      elseif (preg_match('/^::\\d+.\\d+.\\d+.\\d+$/', $ip)) {
        $ip = substr($ip, 2);
      }
      elseif (!empty($hostname)) {
        
        if (!isset($dns_cache[$hostname])) {
          $dns_cache[$hostname] = gethostbyname($hostname);
        }
        $ip = $dns_cache[$hostname];
        if ($dns_cache[$hostname] == $hostname) {
          $ip = '';
        }
      }
    }
  }
  if ($hostname_mode == 3) {
    $ip = httprl_variable_get('httprl_server_hostname', FALSE);
  }
  if (empty($ip) || $hostname_mode == 4) {
    $ip = '127.0.0.1';
  }
  
  $port = httprl_variable_get('httprl_server_port', HTTPRL_SERVER_PORT);
  
  if (!empty($port)) {
    $port = ':' . $port;
  }
  elseif (isset($_SERVER['SERVER_PORT']) && is_numeric($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) {
    $port = ':' . $_SERVER['SERVER_PORT'];
  }
  
  $schema_var = httprl_variable_get('httprl_server_schema', HTTPRL_SERVER_SCHEMA);
  if ($schema_var == 0) {
    $schema = httprl_get_server_schema() . '://';
  }
  elseif ($schema_var == 1) {
    $schema = 'http://';
  }
  elseif ($schema_var == 2) {
    $schema = 'https://';
  }
  
  if (!variable_get('clean_url', 0)) {
    $path_parts = @parse_url('http://example.com/' . $path);
    if (!empty($path_parts)) {
      $path_parts_query = array();
      if (isset($path_parts['query'])) {
        parse_str($path_parts['query'], $path_parts_query);
      }
      $path_parts_query['q'] = ltrim($path_parts['path'], '/');
      $path = '?' . http_build_query($path_parts_query, '', '&');
    }
  }
  return $schema . $auth . $ip . $port . $root_path;
}
function httprl_build_url_self($path = '', $detect_schema = FALSE, $reset = FALSE) {
  static $drupal_root;
  if (!isset($drupal_root) || $reset) {
    $drupal_root = _httprl_build_drupal_root();
    
    if (is_callable('drupal_is_cli') && drupal_is_cli() || !isset($_SERVER['SERVER_SOFTWARE']) && (php_sapi_name() == 'cli' || is_numeric($_SERVER['argc']) && $_SERVER['argc'] > 0)) {
      $level = 0;
      $found = FALSE;
      $mode = 0;
      while (!$found) {
        
        $override_function = httprl_variable_get('drupal_http_request_function', FALSE);
        $GLOBALS['conf']['drupal_http_request_function'] = FALSE;
        $test_request = drupal_http_request($drupal_root . 'httprl_async_function_callback');
        $GLOBALS['conf']['drupal_http_request_function'] = $override_function;
        
        $headers = isset($test_request->headers) ? $test_request->headers : array();
        if (!empty($headers)) {
          foreach ($headers as $key => $value) {
            if (stripos($key, 'X-HTTPRL') !== FALSE || stripos($value, 'X-HTTPRL') !== FALSE) {
              $found = TRUE;
              break;
            }
          }
        }
        
        if (!$found) {
          $level++;
          $new_drupal_root = _httprl_build_drupal_root($level, $mode);
          if ($new_drupal_root == $drupal_root) {
            
            $mode++;
            $level = 0;
            if ($mode > 4) {
              
              $drupal_root = _httprl_build_drupal_root();
              break;
            }
          }
          $drupal_root = $new_drupal_root;
        }
      }
    }
  }
  return $drupal_root . $path;
}
function httprl_parse_url($url, &$result) {
  
  $uri = @parse_url($url);
  
  $t = function_exists('t') ? 't' : 'httprl_pr';
  if (empty($uri)) {
    
    $result->error = $t('Unable to parse URL.');
    $result->code = HTTPRL_URL_PARSE_ERROR;
  }
  elseif (!isset($uri['scheme'])) {
    
    $result->error = $t('Missing schema.');
    $result->code = HTTPRL_URL_MISSING_SCHEMA;
  }
  return $uri;
}
function httprl_set_default_options(array &$options) {
  global $base_root;
  
  $options += array(
    'headers' => array(),
    'method' => 'GET',
    'data' => NULL,
    'max_redirects' => 3,
    'timeout' => httprl_variable_get('httprl_timeout', HTTPRL_TIMEOUT),
    'dns_timeout' => httprl_variable_get('httprl_dns_timeout', HTTPRL_DNS_TIMEOUT),
    'connect_timeout' => httprl_variable_get('httprl_connect_timeout', HTTPRL_CONNECT_TIMEOUT),
    'ttfb_timeout' => httprl_variable_get('httprl_ttfb_timeout', HTTPRL_TTFB_TIMEOUT),
    'context' => NULL,
    'secure_socket_transport' => 'ssl',
    'blocking' => TRUE,
    'version' => '1.0',
    'referrer' => FALSE,
    'domain_connections' => 2,
    'global_connections' => 128,
    'global_timeout' => httprl_variable_get('httprl_global_timeout', HTTPRL_GLOBAL_TIMEOUT),
    'chunk_size_read' => 32768,
    'chunk_size_write' => 1024,
    'async_connect' => TRUE,
    'ping_db' => 20,
    'ignore_empty_chunk' => FALSE,
    'url_encoding' => array(),
  );
  
  if ($options['timeout'] > httprl_variable_get('httprl_timeout', HTTPRL_TIMEOUT) && $options['ttfb_timeout'] == httprl_variable_get('httprl_ttfb_timeout', HTTPRL_TTFB_TIMEOUT)) {
    $options['ttfb_timeout'] = $options['timeout'] - max(1, httprl_variable_get('httprl_timeout', HTTPRL_TIMEOUT) - httprl_variable_get('httprl_ttfb_timeout', HTTPRL_TTFB_TIMEOUT));
  }
  
  if ($options['timeout'] > httprl_variable_get('httprl_timeout', HTTPRL_TIMEOUT) && $options['global_timeout'] == httprl_variable_get('httprl_global_timeout', HTTPRL_GLOBAL_TIMEOUT)) {
    $options['global_timeout'] = $options['timeout'] + max(1, httprl_variable_get('httprl_global_timeout', HTTPRL_GLOBAL_TIMEOUT) - httprl_variable_get('httprl_timeout', HTTPRL_TIMEOUT));
  }
  
  $options['headers'] += array(
    'User-Agent' => 'Drupal (+http://drupal.org/)',
    'Connection' => 'close',
  );
  if (isset($options['headers']['User-Agent']) && $options['headers']['User-Agent'] === FALSE) {
    unset($options['headers']['User-Agent']);
  }
  if (isset($options['headers']['Connection']) && $options['headers']['Connection'] === FALSE) {
    unset($options['headers']['Connection']);
  }
  
  $options['url_encoding'] += array(
    'space' => array(),
  );
  $options['url_encoding']['space'] += array(
    'path' => '%20',
    'query' => '%20',
  );
  
  if (!isset($options['headers']['Referer']) && !empty($options['referrer'])) {
    if (function_exists('request_uri')) {
      $options['headers']['Referer'] = $base_root . request_uri();
      if (strpos($options['headers']['Referer'], 'httprl_async_function_callback') === TRUE) {
        $options['headers']['Referer'] = $_SERVER['HTTP_REFERER'];
      }
    }
  }
  
  $options['timeout'] = (double) $options['timeout'];
}
function httprl_setup_proxy(&$uri, &$options, $url) {
  
  $proxy_server = httprl_variable_get('proxy_server', '');
  
  if ($proxy_server && _httprl_use_proxy($uri['host'])) {
    
    $uri['scheme'] = 'proxy';
    
    $uri['path'] = $url;
    
    unset($uri['query']);
    
    if ($proxy_username = httprl_variable_get('proxy_username', '')) {
      $proxy_password = httprl_variable_get('proxy_password', '');
      $options['headers']['Proxy-Authorization'] = 'Basic ' . base64_encode($proxy_username . ':' . $proxy_password);
    }
    
    $proxy_user_agent = httprl_variable_get('proxy_user_agent', '');
    
    if (is_null($proxy_user_agent)) {
      unset($options['headers']['User-Agent']);
    }
    elseif ($proxy_user_agent) {
      $options['headers']['User-Agent'] = $proxy_user_agent;
    }
  }
  return $proxy_server;
}
function httprl_set_socket($uri, &$options, $proxy_server, &$result) {
  $socket = '';
  switch ($uri['scheme']) {
    case 'proxy':
      
      $socket = 'tcp://' . $proxy_server . ':' . httprl_variable_get('proxy_port', 8080);
      
      $options['headers']['Host'] = $uri['host'];
      $options['headers']['Host'] .= isset($uri['port']) && $uri['port'] != 80 ? ':' . $uri['port'] : '';
      break;
    case 'http':
    case 'feed':
      $port = isset($uri['port']) ? $uri['port'] : 80;
      $socket = 'tcp://' . $uri['host'] . ':' . $port;
      
      if (empty($options['headers']['Host'])) {
        $options['headers']['Host'] = $uri['host'];
      }
      if ($port != 80) {
        $options['headers']['Host'] .= ':' . $port;
      }
      break;
    case 'https':
      
      $port = isset($uri['port']) ? $uri['port'] : 443;
      $socket = $options['secure_socket_transport'] . '://' . $uri['host'] . ':' . $port;
      if (empty($options['headers']['Host'])) {
        $options['headers']['Host'] = $uri['host'];
      }
      if ($port != 443) {
        $options['headers']['Host'] .= ':' . $port;
      }
      
      if (empty($options['context'])) {
        $drupal_ssl_context_options = variable_get('drupal_ssl_context_options', array(
          'verify_peer' => TRUE,
        ));
        
        if (!defined('OPENSSL_VERSION_NUMBER') || OPENSSL_VERSION_NUMBER >= 0x1000009f && OPENSSL_VERSION_NUMBER <= 0x1000102f) {
          $drupal_ssl_context_options += array(
            'SNI_enabled' => FALSE,
          );
        }
        $options['context'] = stream_context_create(array(
          'ssl' => $drupal_ssl_context_options,
        ));
      }
      break;
    default:
      
      $t = function_exists('t') ? 't' : 'httprl_pr';
      $result->error = $t('Invalid schema @scheme.', array(
        '@scheme' => $uri['scheme'],
      ));
      $result->code = HTTPRL_URL_INVALID_SCHEMA;
  }
  return $socket;
}
function httprl_set_connection_flag(&$options, $uri) {
  $flags = STREAM_CLIENT_CONNECT;
  
  if ($options['async_connect']) {
    
    if ($uri['scheme'] == 'https' && (version_compare(PHP_VERSION, '5.2.11', '<') || version_compare(PHP_VERSION, '5.3.0', '='))) {
      $options['async_connect'] = FALSE;
    }
    else {
      $flags = STREAM_CLIENT_ASYNC_CONNECT | STREAM_CLIENT_CONNECT;
    }
  }
  return $flags;
}
function httprl_handle_data(&$options) {
  
  if (isset($options['data']) && !is_string($options['data'])) {
    
    $options['data-input'] = $options['data'];
    if (!empty($options['headers']['Content-Type']) && strpos($options['headers']['Content-Type'], 'multipart/related') === 0 && !empty($options['data'])) {
      
      $options['headers']['Content-Type'] = trim($options['headers']['Content-Type']);
      if (substr_compare($options['headers']['Content-Type'], ';', -1, 1) === 0) {
        $options['headers']['Content-Type'] = substr($options['headers']['Content-Type'], -1);
      }
      
      $options['headers']['Content-Type'] .= '; boundary=' . HTTPRL_MULTIPART_BOUNDARY;
      $data_stream = '';
      foreach ($options['data'] as $part) {
        $data_stream .= '--' . HTTPRL_MULTIPART_BOUNDARY . "\r\n";
        foreach ($part['headers'] as $key => $value) {
          $data_stream .= $key . ': ' . $value . "\r\n";
        }
        $data_stream .= "\r\n";
        if (isset($part['file'])) {
          $data_stream .= file_get_contents($part['file']) . "\r\n";
        }
        elseif (isset($part['string'])) {
          $data_stream .= $part['string'] . "\r\n";
        }
      }
      
      $data_stream .= '--' . HTTPRL_MULTIPART_BOUNDARY . "--\r\n";
      $options['data'] = $data_stream;
    }
    elseif (!empty($options['data']['file']) || !empty($options['data']['files'])) {
      $data_stream = '';
      $data_array = $options['data'];
      
      if (isset($options['data']['files'])) {
        foreach ($options['data']['files'] as $field_name => $info) {
          $multi_field = '[]';
          
          if (is_string($info)) {
            $multi_field = '';
            $temp = $info;
            unset($info);
            $info[] = $temp;
          }
          foreach ($info as $fullpath) {
            
            if (substr($fullpath, 0, 1) == "@") {
              $fullpath = substr($fullpath, 1);
            }
            $filename = basename($fullpath);
            
            $mimetype = 'application/octet-stream';
            
            $data_stream .= '--' . HTTPRL_MULTIPART_BOUNDARY . "\r\n";
            $data_stream .= 'Content-Disposition: form-data; name="files[' . $field_name . ']' . $multi_field . '"; filename="' . $filename . "\"\r\n";
            $data_stream .= 'Content-Transfer-Encoding: binary' . "\r\n";
            $data_stream .= 'Content-Type: ' . $mimetype . "\r\n\r\n";
            $data_stream .= file_get_contents($fullpath) . "\r\n";
          }
        }
        
        unset($data_array['files']);
      }
      elseif (isset($options['data']['file'])) {
        $fullpath = $options['data']['file'];
        
        if (substr($fullpath, 0, 1) == "@") {
          $fullpath = substr($fullpath, 1);
        }
        $filename = basename($fullpath);
        
        $mimetype = 'application/octet-stream';
        
        $data_stream .= '--' . HTTPRL_MULTIPART_BOUNDARY . "\r\n";
        $data_stream .= 'Content-Disposition: form-data; name="file"; filename="' . $filename . "\"\r\n";
        $data_stream .= 'Content-Transfer-Encoding: binary' . "\r\n";
        $data_stream .= 'Content-Type: ' . $mimetype . "\r\n\r\n";
        $data_stream .= file_get_contents($fullpath) . "\r\n";
        unset($data_array['file']);
      }
      
      httprl_multipart_encoder($data_stream, $data_array);
      
      $data_stream .= '--' . HTTPRL_MULTIPART_BOUNDARY . "--\r\n";
      $options['data'] = $data_stream;
      
      if (!empty($options['data']) && !isset($options['headers']['Content-Type']) && ($options['method'] == 'POST' || $options['method'] == 'PUT')) {
        $options['headers']['Content-Type'] = 'multipart/form-data; boundary=' . HTTPRL_MULTIPART_BOUNDARY;
      }
    }
    else {
      $options['data'] = http_build_query($options['data'], '', '&');
      
      if (!empty($options['data']) && !isset($options['headers']['Content-Type']) && ($options['method'] == 'POST' || $options['method'] == 'PUT')) {
        $options['headers']['Content-Type'] = 'application/x-www-form-urlencoded';
      }
    }
  }
  
  if (strlen($options['data']) > 0 || $options['method'] == 'POST' || $options['method'] == 'PUT') {
    $options['headers']['Content-Length'] = httprl_strlen($options['data']);
  }
}
function httprl_multipart_encoder(&$data_stream, $data_array, $prepend = array()) {
  foreach ($data_array as $key => $value) {
    $key_array = $prepend;
    $key_array[] = $key;
    if (is_array($value)) {
      httprl_multipart_encoder($data_stream, $value, $key_array);
    }
    elseif (is_scalar($value)) {
      $key_string = array_shift($key_array);
      if (!empty($key_array)) {
        $key_string .= '[' . implode('][', $key_array) . ']';
      }
      $data_stream .= '--' . HTTPRL_MULTIPART_BOUNDARY . "\r\n";
      $data_stream .= 'Content-Disposition: form-data; name="' . $key_string . "\"\r\n\r\n";
      $data_stream .= $value . "\r\n";
    }
  }
}
function httprl_basic_auth($uri, &$options) {
  
  if (isset($uri['user'])) {
    $options['headers']['Authorization'] = 'Basic ' . base64_encode($uri['user'] . ':' . (isset($uri['pass']) ? $uri['pass'] : ''));
  }
}
function httprl_build_request_string($uri, $options) {
  
  $path = isset($uri['path']) ? str_replace(' ', $options['url_encoding']['space']['path'], $uri['path']) : '/';
  if (isset($uri['query'])) {
    
    $path .= '?' . str_replace(' ', $options['url_encoding']['space']['query'], $uri['query']);
  }
  
  $request = $options['method'] . ' ' . $path . ' HTTP/' . sprintf("%.1F", $options['version']) . "\r\n";
  foreach ($options['headers'] as $name => $value) {
    $request .= $name . ': ' . trim($value) . "\r\n";
  }
  return $request . "\r\n" . $options['data'];
}
function httprl_stream_connection_error_formatter($errno, $errstr, &$result) {
  
  $t = function_exists('t') ? 't' : 'httprl_pr';
  if (function_exists('t')) {
    
    if (defined('VERSION') && substr(VERSION, 0, 1) >= 7) {
      require_once DRUPAL_ROOT . '/includes/unicode.inc';
    }
    else {
      require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/unicode.inc';
    }
    
    $errstr = trim(drupal_convert_to_utf8($errstr, 'ISO-8859-1'));
  }
  if (!$errno) {
    
    if (empty($errstr)) {
      
      $result->code = HTTPRL_ERROR_INITIALIZING_STREAM;
      $result->error = $t('Error initializing socket @socket.', array(
        '@socket' => $result->socket,
      ));
    }
    elseif (stripos($errstr, 'network_getaddresses: getaddrinfo failed:') !== FALSE) {
      
      $result->code = HTTPRL_HOST_NOT_FOUND;
      $result->error = $errstr;
    }
  }
  elseif ($errno == 110) {
    
    $result->code = HTTPRL_REQUEST_TIMEOUT;
    $result->error = !empty($errstr) ? $errstr : $t('Connection timed out. TCP.');
  }
  else {
    
    $result->code = (int) -$errno;
    $result->error = !empty($errstr) ? $errstr : $t('Error opening socket @socket.', array(
      '@socket' => $result->socket,
    ));
  }
}
function httprl_establish_stream_connection(&$result) {
  
  $start_time = microtime(TRUE);
  $result->fp = FALSE;
  
  $count = 0;
  while (!$result->fp && $count < 3) {
    
    if ($count > 0) {
      if ($result->flags === STREAM_CLIENT_ASYNC_CONNECT | STREAM_CLIENT_CONNECT && $result->uri['scheme'] == 'https') {
        $result->flags = STREAM_CLIENT_CONNECT;
        $result->options['async_connect'] = FALSE;
      }
      else {
        
        break;
      }
    }
    
    $timeout = $result->options['dns_timeout'];
    
    if (!$result->options['async_connect']) {
      $timeout += $result->options['connect_timeout'];
    }
    
    if (empty($result->options['context'])) {
      $result->fp = @stream_socket_client($result->socket, $errno, $errstr, $timeout, $result->flags);
    }
    else {
      
      $result->fp = @stream_socket_client($result->socket, $errno, $errstr, $timeout, $result->flags, $result->options['context']);
    }
    $count++;
  }
  
  if ($result->fp && !$result->options['async_connect'] && !stream_socket_get_name($result->fp, TRUE)) {
    $errno = HTTPRL_CONNECTION_REFUSED;
    $errstr = 'Connection refused. No connection could be made because the target machine actively refused it.';
    $result->fp = FALSE;
  }
  
  if (!$result->fp) {
    httprl_stream_connection_error_formatter($errno, $errstr, $result);
  }
  else {
    stream_set_blocking($result->fp, 0);
  }
  
  $end_time = microtime(TRUE);
  $extra = 0;
  if (isset($result->options['internal_states']['running_time'])) {
    $extra = $result->options['internal_states']['running_time'];
    unset($result->options['internal_states']['running_time']);
  }
  $result->running_time = $end_time - $start_time + $extra;
}
function httprl_request($urls, array $options = array()) {
  
  $full_bootstrap = httprl_drupal_full_bootstrap();
  
  if (!is_array($urls)) {
    $temp =& $urls;
    unset($urls);
    $urls = array(
      &$temp,
    );
    unset($temp);
  }
  if ($full_bootstrap) {
    
    $data = array(
      $urls,
      $options,
    );
    drupal_alter('pre_httprl_request', $data);
    list($urls, $options) = $data;
  }
  $connections = array();
  $return = array();
  
  foreach ($urls as &$url) {
    $result = new stdClass();
    $result->url =& $url;
    $result->status = 'Connecting.';
    $result->code = 0;
    $result->chunk_size = 1024;
    $result->data = '';
    
    $these_options = $options;
    
    httprl_set_default_options($these_options);
    
    $uri = httprl_parse_url($url, $result);
    if (isset($result->error)) {
      
      $connections[] = array(
        NULL,
        NULL,
        $uri,
        $url,
        $these_options,
        $result,
        NULL,
      );
      $return[$url] = FALSE;
      
      continue;
    }
    
    $proxy_server = httprl_setup_proxy($uri, $these_options, $url);
    
    $socket = httprl_set_socket($uri, $these_options, $proxy_server, $result, $return, $url);
    if (isset($result->error)) {
      
      $connections[] = array(
        $socket,
        NULL,
        $uri,
        $url,
        $these_options,
        $result,
        NULL,
      );
      $return[$url] = FALSE;
      
      continue;
    }
    
    $flags = httprl_set_connection_flag($these_options, $uri);
    
    httprl_basic_auth($uri, $these_options);
    
    httprl_handle_data($these_options);
    
    $response = httprl_build_request_string($uri, $these_options);
    
    $connections[] = array(
      $socket,
      $flags,
      $uri,
      $url,
      $these_options,
      $result,
      $response,
    );
    $return[$url] = TRUE;
  }
  $results = array();
  foreach ($connections as $connection) {
    list($socket, $flags, $uri, $url, $options, $result, $response) = $connection;
    $result->request = $response;
    $result->options = $options;
    $result->socket = $socket;
    $result->flags = $flags;
    $result->uri = $uri;
    $result->running_time = 0;
    $results[] = $result;
  }
  if ($full_bootstrap) {
    
    drupal_alter('httprl_request', $results);
  }
  if (httprl_send_request($results)) {
    return $return;
  }
  else {
    return FALSE;
  }
}
function httprl_send_request($results = NULL) {
  static $responses = array();
  static $counter = 0;
  static $output = array();
  static $static_stall_freads = FALSE;
  if (!is_null($results)) {
    if (empty($results)) {
      return FALSE;
    }
    
    foreach ($results as $result) {
      $responses[$counter] = $result;
      $counter++;
    }
    return TRUE;
  }
  
  if (empty($responses)) {
    return FALSE;
  }
  
  $t = function_exists('t') ? 't' : 'httprl_pr';
  
  $global_timeout = 1;
  $global_connection_limit = 1;
  $stall_freads = FALSE;
  foreach ($responses as $id => &$result) {
    if (!empty($result->error)) {
      $result->status = 'Connection not made.';
      
      httprl_post_processing($id, $responses, $output);
      continue;
    }
    if (!empty($result->cached)) {
      
      $output[$result->cached->url] = $result->cached;
      unset($responses[$id]);
      continue;
    }
    
    $global_connection_limit = max($global_connection_limit, $result->options['global_connections']);
    if (!isset($domain_connection_limit[$result->options['headers']['Host']])) {
      $domain_connection_limit[$result->options['headers']['Host']] = max(1, $result->options['domain_connections']);
    }
    else {
      $domain_connection_limit[$result->options['headers']['Host']] = max($domain_connection_limit[$result->options['headers']['Host']], $result->options['domain_connections']);
    }
    
    $global_timeout = max($global_timeout, $result->options['global_timeout']);
    
    if (!empty($result->options['stall_fread']) && !$static_stall_freads) {
      $static_stall_freads = TRUE;
      $stall_freads = TRUE;
    }
  }
  
  $start_time_this_run = $start_time_global = microtime(TRUE);
  
  $ping_db_counts = array();
  $full_bootstrap = httprl_drupal_full_bootstrap();
  
  $stream_select_timeout = 1;
  $stream_write_count = 0;
  while (!empty($responses)) {
    
    $this_run = array();
    $global_connection_count = 0;
    $domain_connection_count = array();
    $restart_timers = FALSE;
    
    $now = microtime(TRUE);
    
    $elapsed_time = $now - $start_time_this_run;
    $start_time_this_run = $now;
    $global_time = $global_timeout - ($start_time_this_run - $start_time_global);
    
    $rounded_time = floor($elapsed_time);
    if ($full_bootstrap && !empty($result->options['ping_db']) && $rounded_time >= $result->options['ping_db'] && $rounded_time % $result->options['ping_db'] == 0 && empty($ping_db_counts[$rounded_time])) {
      $empty_array = array();
      system_get_files_database($empty_array, 'ping_db');
      $ping_db_counts[$rounded_time] = 1;
    }
    
    foreach ($responses as $id => &$result) {
      
      if ($global_time <= 0) {
        
        if ($result->status == 'Connecting.') {
          $result->error = $t('Function timed out. TCP.');
          
          if (isset($result->fp)) {
            $stream_write_count--;
          }
        }
        elseif ($result->status == 'Writing to server.') {
          $result->error = $t('Function timed out. Write.');
          
          if (isset($result->fp)) {
            $stream_write_count--;
          }
        }
        else {
          $result->error = $t('Function timed out. Read');
        }
        $result->code = HTTPRL_FUNCTION_TIMEOUT;
        $result->status = 'Done.';
        
        httprl_post_processing($id, $responses, $output, $global_time);
        continue;
      }
      
      if (isset($result->fp)) {
        
        $result->running_time += $elapsed_time;
        
        $timeout = $result->options['timeout'] - $result->running_time;
        
        if ($timeout <= 0) {
          $result->error = $t('Connection timed out.');
          
          if ($result->status == 'Writing to server.') {
            $result->error .= ' ' . $t('Write.');
            
            $stream_write_count--;
          }
          else {
            $result->error .= ' ' . $t('Read.');
          }
          $result->code = HTTPRL_REQUEST_TIMEOUT;
          $result->status = 'Done.';
          
          httprl_post_processing($id, $responses, $output, $timeout);
          continue;
        }
        
        if ($result->status == 'Connecting.' && $result->running_time > $result->options['connect_timeout']) {
          $socket_name = stream_socket_get_name($result->fp, TRUE);
          if (empty($socket_name) || $result->running_time > $result->options['connect_timeout'] * 1.5) {
            $result->error = $t('Connection timed out.');
            
            if ($result->status == 'Connecting.') {
              $result->error .= ' ' . $t('TCP Connect Timeout.');
              
              $stream_write_count--;
            }
            $result->code = HTTPRL_REQUEST_TIMEOUT;
            $result->status = 'Done.';
            
            httprl_post_processing($id, $responses, $output, $timeout);
            continue;
          }
        }
        if (!isset($responses[$id]->time_to_first_byte) && $result->running_time > $result->options['ttfb_timeout']) {
          $result->error = $t('Connection timed out. Time to First Byte Timeout.');
          $result->code = HTTPRL_REQUEST_ABORTED;
          $result->status = 'Done.';
          
          httprl_post_processing($id, $responses, $output, $timeout);
          continue;
        }
      }
      
      if (!isset($result->fp) && $result->status != 'Connecting.') {
        
        httprl_post_processing($id, $responses, $output);
        continue;
      }
      
      $host = $result->options['headers']['Host'];
      
      if (!isset($domain_connection_limit[$host])) {
        $domain_connection_limit[$host] = max(1, $result->options['domain_connections']);
      }
      
      $global_connection_count++;
      if (empty($domain_connection_count[$host])) {
        $domain_connection_count[$host] = 1;
      }
      else {
        $domain_connection_count[$host]++;
      }
      
      if ($global_connection_limit >= $global_connection_count && $domain_connection_limit[$host] >= $domain_connection_count[$host]) {
        
        if (!isset($result->fp) && $result->status == 'Connecting.') {
          
          httprl_establish_stream_connection($result);
          
          $restart_timers = TRUE;
          
          if (!empty($result->options['lock_name'])) {
            httprl_acquire_lock($result);
          }
          
          if (!$result->fp) {
            
            httprl_post_processing($id, $responses, $output);
            $domain_connection_count[$host]--;
            $global_connection_count--;
            continue;
          }
          $stream_write_count++;
        }
        if (!empty($result->fp)) {
          $this_run[$id] = $result->fp;
        }
      }
    }
    
    if (empty($responses)) {
      break;
    }
    
    if ($restart_timers) {
      $start_time_this_run = microtime(TRUE);
    }
    
    if (empty($this_run)) {
      continue;
    }
    
    $read = $write = $this_run;
    $except = array();
    
    if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
      
      $n = @stream_select($read, $write, $except, $stream_select_timeout, 25000);
    }
    else {
      $n = stream_select($read, $write, $except, $stream_select_timeout, 25000);
    }
    $stream_select_timeout = 0;
    
    if ($n === FALSE) {
      $merged = array_unique(array_merge($read, $write, $except));
      foreach ($merged as $m) {
        $id = array_search($m, $this_run);
        @fclose($m);
        if ($id !== FALSE && isset($responses[$id])) {
          watchdog('httprl', 'The following url had a stream_select error and had to be terminated: %info', array(
            '%info' => $responses[$id]->url,
          ), WATCHDOG_ERROR);
          unset($responses[$id]);
        }
      }
    }
    
    $rw_done = FALSE;
    if (!empty($n)) {
      if (!empty($read) && is_array($read)) {
        
        foreach ($read as $r) {
          $id = array_search($r, $this_run);
          
          if ($id === FALSE) {
            @fclose($r);
            continue;
          }
          
          if (!array_key_exists($id, $responses)) {
            @fclose($r);
            continue;
          }
          
          if (empty($responses[$id]->options['blocking'])) {
            
            httprl_post_processing($id, $responses, $output);
            continue;
          }
          
          $chunk = fread($r, $responses[$id]->chunk_size);
          if (strlen($chunk) > 0) {
            $rw_done = TRUE;
            if (!isset($responses[$id]->time_to_first_byte)) {
              
              $responses[$id]->time_to_first_byte = $result->running_time + microtime(TRUE) - $start_time_this_run;
            }
          }
          $responses[$id]->data .= $chunk;
          
          if (!empty($responses[$id]->data) && empty($responses[$id]->headers) && (strpos($responses[$id]->data, "\r\n\r\n") || strpos($responses[$id]->data, "\n\n") || strpos($responses[$id]->data, "\r\r"))) {
            
            httprl_parse_data($responses[$id]);
            if (!empty($responses[$id]->headers)) {
              
              if (!empty($responses[$id]->options['internal_states']['kill'])) {
                fclose($r);
                unset($responses[$id]);
                continue;
              }
              
              $responses[$id]->chunk_size = $responses[$id]->options['chunk_size_read'];
              
              if (!empty($responses[$id]->options['headers']['Range']) && $responses[$id]->code == 200 && $responses[$id]->options['method'] == 'GET') {
                $responses[$id]->ranges = httprl_get_ranges($responses[$id]->options['headers']['Range']);
                $responses[$id]->options['max_data_size'] = httprl_get_last_byte_from_range($responses[$id]->ranges);
              }
            }
          }
          
          if (!empty($responses[$id]->options['max_data_size']) && is_numeric($responses[$id]->options['max_data_size']) && (!isset($result->headers['transfer-encoding']) || $result->headers['transfer-encoding'] != 'chunked') && (!isset($result->headers['content-encoding']) || $result->headers['content-encoding'] != 'gzip' && $result->headers['content-encoding'] != 'deflate') && $responses[$id]->options['max_data_size'] < httprl_strlen($responses[$id]->data)) {
            $responses[$id]->status = 'Done.';
            
            httprl_post_processing($id, $responses, $output);
            continue;
          }
          
          $info = stream_get_meta_data($r);
          $alive = !$info['eof'] && !feof($r) && !$info['timed_out'];
          
          if ($alive && !$responses[$id]->options['ignore_empty_chunk'] && !strlen($chunk)) {
            $alive = FALSE;
          }
          if (!$alive) {
            if ($responses[$id]->status == 'Connecting.') {
              $responses[$id]->error = $t('Connection refused by destination. TCP.');
              $responses[$id]->code = HTTPRL_CONNECTION_REFUSED;
            }
            if ($responses[$id]->status == 'Writing to server.') {
              $responses[$id]->error = $t('Connection refused by destination. Write.');
              $responses[$id]->code = HTTPRL_CONNECTION_REFUSED;
            }
            $responses[$id]->status = 'Done.';
            
            httprl_post_processing($id, $responses, $output);
            continue;
          }
          else {
            $responses[$id]->status = 'Reading data';
          }
        }
      }
      
      if ($stream_write_count > 0 && !empty($write) && is_array($write)) {
        foreach ($write as $w) {
          $id = array_search($w, $this_run);
          
          if ($id === FALSE || empty($responses[$id]->status) || $responses[$id]->status != 'Connecting.' && $responses[$id]->status != 'Writing to server.') {
            continue;
          }
          
          if (!isset($responses[$id]->bytes_sent)) {
            $responses[$id]->bytes_sent = 0;
          }
          
          $data_to_send = substr($responses[$id]->request, $responses[$id]->bytes_sent, 2 * $responses[$id]->options['chunk_size_write']);
          
          $len = httprl_strlen($data_to_send);
          if ($len > 0) {
            
            $bytes = fwrite($w, $data_to_send, min($responses[$id]->options['chunk_size_write'], $len));
          }
          else {
            
            $bytes = $len;
          }
          
          if ($bytes === FALSE) {
            
            $responses[$id]->error = $t('fwrite() failed.');
            $responses[$id]->code = HTTPRL_REQUEST_FWRITE_FAIL;
            $responses[$id]->status = 'Done.';
            $stream_write_count--;
            
            httprl_post_processing($id, $responses, $output);
            continue;
          }
          elseif ($bytes >= $len) {
            
            $stream_write_count--;
            
            if (empty($responses[$id]->options['blocking'])) {
              $responses[$id]->status = 'Non-Blocking request sent out. Not waiting for the response.';
              
              httprl_post_processing($id, $responses, $output);
              continue;
            }
            else {
              
              $responses[$id]->status = "Request sent, waiting for response.";
            }
            
            $responses[$id]->bytes_sent += $bytes;
            $rw_done = TRUE;
          }
          else {
            
            if ($responses[$id]->status = 'Connecting.') {
              $responses[$id]->status = 'Writing to server.';
            }
            
            $responses[$id]->bytes_sent += $bytes;
            $rw_done = TRUE;
          }
        }
      }
      elseif ($stall_freads) {
        return;
      }
    }
    if (!$rw_done) {
      
      usleep(5000);
    }
  }
  
  $return = $output;
  
  $responses = array();
  $counter = 0;
  $output = array();
  $static_stall_freads = FALSE;
  return $return;
}
function httprl_parse_data(&$result) {
  
  if (empty($result->options['blocking'])) {
    return;
  }
  
  if (!empty($result->headers)) {
    return;
  }
  
  $t = function_exists('t') ? 't' : 'httprl_pr';
  
  $response = $result->data;
  list($response, $result->data) = preg_split("/\r\n\r\n|\n\n|\r\r/", $response, 2);
  $response = preg_split("/\r\n|\n|\r/", $response);
  
  $protocol_code_array = explode(' ', trim(array_shift($response)), 3);
  $result->protocol = $protocol_code_array[0];
  $code = (int) $protocol_code_array[1];
  
  $result->status_message = isset($protocol_code_array[2]) ? $protocol_code_array[2] : '';
  unset($protocol_code_array);
  $result->headers = array();
  
  $cookie_primary_counter = 0;
  while ($line = trim(array_shift($response))) {
    list($name, $value) = explode(':', $line, 2);
    $name = strtolower($name);
    
    if ($name == 'set-cookie') {
      
      foreach (explode(';', $value) as $cookie_name_value) {
        $temp = explode('=', trim($cookie_name_value));
        $cookie_key = trim($temp[0]);
        $cookie_value = isset($temp[1]) ? trim($temp[1]) : '';
        unset($temp);
        
        if (!isset($result->cookies[$cookie_primary_counter])) {
          $result->cookies[$cookie_primary_counter] = array(
            'name' => $cookie_key,
            'value' => $cookie_value,
          );
        }
        else {
          $result->cookies[$cookie_primary_counter] += array(
            $cookie_key => $cookie_value,
          );
        }
      }
      $cookie_primary_counter++;
    }
    
    if (isset($result->headers[$name]) && $name == 'set-cookie') {
      
      $result->headers[$name] .= ',' . trim($value);
    }
    else {
      $result->headers[$name] = trim($value);
    }
  }
  $responses = array(
    100 => 'Continue',
    101 => 'Switching Protocols',
    200 => 'OK',
    201 => 'Created',
    202 => 'Accepted',
    203 => 'Non-Authoritative Information',
    204 => 'No Content',
    205 => 'Reset Content',
    206 => 'Partial Content',
    300 => 'Multiple Choices',
    301 => 'Moved Permanently',
    302 => 'Found',
    303 => 'See Other',
    304 => 'Not Modified',
    305 => 'Use Proxy',
    307 => 'Temporary Redirect',
    400 => 'Bad Request',
    401 => 'Unauthorized',
    402 => 'Payment Required',
    403 => 'Forbidden',
    404 => 'Not Found',
    405 => 'Method Not Allowed',
    406 => 'Not Acceptable',
    407 => 'Proxy Authentication Required',
    408 => 'Request Time-out',
    409 => 'Conflict',
    410 => 'Gone',
    411 => 'Length Required',
    412 => 'Precondition Failed',
    413 => 'Request Entity Too Large',
    414 => 'Request-URI Too Large',
    415 => 'Unsupported Media Type',
    416 => 'Requested range not satisfiable',
    417 => 'Expectation Failed',
    500 => 'Internal Server Error',
    501 => 'Not Implemented',
    502 => 'Bad Gateway',
    503 => 'Service Unavailable',
    504 => 'Gateway Time-out',
    505 => 'HTTP Version not supported',
  );
  
  if (!isset($responses[$code])) {
    $code = floor($code / 100) * 100;
  }
  $result->code = $code;
  switch ($code) {
    case 200:
    
    case 201:
    
    case 202:
    
    case 206:
    
    case 304:
      
      break;
    case 301:
    
    case 302:
    
    case 307:
      
      $location = @parse_url($result->headers['location']);
      
      if (empty($location['scheme']) || empty($location['host'])) {
        $hostname = httprl_get_hostname();
        
        $original_location = @parse_url($result->url);
        
        $location['scheme'] = !empty($location['scheme']) ? $location['scheme'] : $original_location['scheme'];
        $location['host'] = !empty($location['host']) ? $location['host'] : (!empty($original_location['host']) ? $original_location['host'] : $hostname);
        $location['port'] = !empty($location['port']) ? $location['port'] : (!empty($original_location['port']) ? $original_location['port'] : '');
        $location = httprl_glue_url($location);
      }
      else {
        $location = $result->headers['location'];
      }
      
      $result->options['internal_states']['redirect_code_array'][] = $code;
      $result->options['internal_states']['redirect_url_array'][] = $location;
      if (!isset($result->options['internal_states']['original_url'])) {
        $result->options['internal_states']['original_url'] = $result->url;
      }
      
      if ($result->options['max_redirects'] <= 0) {
        $result->code = HTTPRL_REQUEST_ALLOWED_REDIRECTS_EXHAUSTED;
        $result->error = $t('Maximum allowed redirects exhausted.');
      }
      else {
        
        $cookie_string = '';
        $parsed_location = parse_url($location);
        if (isset($result->cookies)) {
          foreach ($result->cookies as $cookie) {
            
            $cookie_domain = ltrim($cookie['domain'], '.');
            if (strpos($parsed_location['host'], $cookie_domain) !== FALSE) {
              if (!empty($cookie_string)) {
                $cookie_string .= ';';
              }
              $cookie_string .= $cookie['name'] . '=' . $cookie['value'];
            }
          }
          
          if (!empty($cookie_string)) {
            $result->options['headers']['Cookie'] = $cookie_string;
          }
        }
        
        $result->options['max_redirects']--;
        if (isset($result->options['headers']['Referer'])) {
          $result->options['headers']['Referer'] = $result->url;
        }
        
        unset($result->options['headers']['Host']);
        
        $result->options['internal_states']['running_time'] = $result->running_time;
        
        httprl_request($location, $result->options);
        
        $result->options['internal_states']['kill'] = TRUE;
      }
      break;
    default:
      $result->error = $result->status_message;
  }
}
function httprl_get_ranges($input) {
  $ranges = array();
  
  $string = preg_match('/^bytes=((\\d*-\\d*,? ?)+)$/', $input, $matches) ? $matches[1] : FALSE;
  if (!empty($string)) {
    
    foreach (explode(',', $string) as $range) {
      
      $values = explode('-', $range);
      if (count($values) != 2) {
        return FALSE;
      }
      $ranges[] = array(
        'start' => $values[0],
        'end' => $values[1],
      );
    }
  }
  return $ranges;
}
function httprl_get_last_byte_from_range($ranges) {
  $max = 0;
  if (empty($ranges)) {
    return NULL;
  }
  foreach ($ranges as $range) {
    if (!is_numeric($range['start']) || !is_numeric($range['end'])) {
      return NULL;
    }
    $max = max($range['end'] + 1, $max);
  }
  return $max;
}
function httprl_post_processing($id, &$responses, &$output, $time_left = NULL) {
  
  $result =& $responses[$id];
  
  if (isset($result->fp)) {
    if (empty($responses[$id]->options['blocking'])) {
      $ms_delay = httprl_variable_get('httprl_non_blocking_fclose_delay', HTTPRL_NON_BLOCKING_FCLOSE_DELAY);
      if (!empty($ms_delay)) {
        
        usleep($ms_delay * 1000);
      }
    }
    @fclose($result->fp);
    unset($result->fp);
  }
  
  if (is_null($time_left)) {
    $time_left = $result->options['timeout'] - $result->running_time;
  }
  $result->options['timeout'] = $time_left;
  
  httprl_reconstruct_redirects($result);
  
  httprl_decode_data($result);
  
  if (isset($result->options['internal_states']) && array_key_exists('background_function_return', $result->options['internal_states']) && isset($result->headers['content-type']) && strpos($result->headers['content-type'], 'application/x-www-form-urlencoded') !== FALSE) {
    httprl_extract_background_callback_data($result);
    unset($responses[$id]);
    return;
  }
  
  $full_bootstrap = httprl_drupal_full_bootstrap();
  
  if ($full_bootstrap && !empty($result->options['alter_all_streams_function']) && function_exists($result->options['alter_all_streams_function'])) {
    $result->options['alter_all_streams_function']($id, $responses);
  }
  unset($responses[$id]);
  
  if ($full_bootstrap) {
    
    drupal_alter('httprl_post_processing', $result);
  }
  
  if ($full_bootstrap && !empty($result->options['callback']) && is_array($result->options['callback']) && !empty($result->options['callback'][0]) && is_array($result->options['callback'][0]) && !empty($result->options['callback'][0]['function'])) {
    httprl_run_callback($result);
  }
  
  if (!empty($result->options['background_callback']) && is_array($result->options['background_callback']) && !empty($result->options['background_callback'][0]) && is_array($result->options['background_callback'][0]) && !empty($result->options['background_callback'][0]['function'])) {
    $call_is_queued = httprl_queue_background_callback($result->options['background_callback'], $result);
    if (is_null($call_is_queued)) {
      watchdog('httprl', 'Background callback attempted but it is disabled. Going to use a normal callback');
      unset($result->options['callback']);
      $result->options['callback'] = $result->options['background_callback'];
      unset($result->options['background_callback']);
      httprl_run_callback($result);
    }
  }
  
  if (isset($result->url)) {
    $output[$result->url] = $result;
  }
}
function httprl_extract_background_callback_data(&$result) {
  
  $data = array();
  parse_str($result->data, $data);
  
  $serialized_string = trim(base64_decode(strtr(current($data), array(
    '-' => '+',
    '_' => '/',
  ))));
  $data = @unserialize($serialized_string);
  if ($data !== 'b:0;' && $data === FALSE) {
    return;
  }
  
  if (isset($data['return'])) {
    $result->options['internal_states']['background_function_return'] = $data['return'];
  }
  if (isset($data['printed'])) {
    $result->options['internal_states']['background_function_printed'] = $data['printed'];
  }
  
  if (isset($data['args'])) {
    httprl_recursive_array_reference_extract($result->options['internal_states']['background_function_args'], $data['args']);
  }
}
function httprl_recursive_array_reference_extract(&$array, $data, $depth = 0) {
  $depth++;
  foreach ($array as $key => &$value) {
    if (isset($data[$key])) {
      if (is_array($data[$key]) && is_array($value) && $depth < 10) {
        $value = httprl_recursive_array_reference_extract($value, $data[$key], $depth);
      }
      else {
        $value = $data[$key];
      }
    }
    else {
      $value = NULL;
    }
  }
  
  foreach ($data as $key => $value) {
    if (isset($array[$key])) {
      continue;
    }
    $array[$key] = $value;
  }
}
function httprl_run_callback(&$result) {
  
  $callback_options = $result->options['callback'][0];
  
  $result->options['callback'][0] =& $result;
  
  ob_start();
  
  $callback_options['return'] = call_user_func_array($callback_options['function'], $result->options['callback']);
  if (array_key_exists('printed', $callback_options)) {
    
    $callback_options['printed'] = ob_get_contents();
  }
  ob_end_clean();
  
  if (isset($result->options['callback'])) {
    array_unshift($result->options['callback'], $callback_options);
  }
}
function httprl_queue_background_callback(&$args, &$result = NULL) {
  
  static $counter;
  if (!isset($counter)) {
    $counter = 0;
  }
  $counter++;
  if (!httprl_is_background_callback_capable()) {
    return NULL;
  }
  
  if (empty($callback_options['url'])) {
    $url = httprl_build_url_self('httprl_async_function_callback?count=' . $counter);
  }
  else {
    $url = $callback_options['url'];
  }
  
  $callback_options = $args[0];
  if (is_null($result)) {
    array_shift($args);
  }
  else {
    
    $args[0] =& $result;
  }
  
  if (isset($callback_options['return']) || isset($callback_options['printed'])) {
    $mode = TRUE;
  }
  else {
    $mode = FALSE;
  }
  
  if (!isset($callback_options['return'])) {
    $callback_options['return'] = '';
  }
  if (!isset($callback_options['function'])) {
    $callback_options['function'] = '';
  }
  
  $times = array(
    httprl_variable_get('httprl_timeout', HTTPRL_TIMEOUT),
    httprl_variable_get('httprl_global_timeout', HTTPRL_GLOBAL_TIMEOUT),
  );
  if (isset($callback_options['options']['timeout'])) {
    $times[] = $callback_options['options']['timeout'];
  }
  if (isset($callback_options['options']['global_timeout'])) {
    $times[] = $callback_options['options']['global_timeout'];
  }
  
  $available = FALSE;
  $lock_counter = 0;
  while (!$available && $lock_counter < 20) {
    
    if (function_exists('drupal_random_bytes')) {
      $name = 'httprl_' . hash('sha512', drupal_random_bytes(64));
    }
    elseif (function_exists('openssl_random_pseudo_bytes')) {
      $name = 'httprl_' . hash('sha512', openssl_random_pseudo_bytes(64));
    }
    else {
      $name = 'httprl_' . hash('sha512', mt_rand() . microtime(TRUE) . serialize($_SERVER));
    }
    $available = lock_may_be_available($name);
    $lock_counter++;
  }
  $callback_options['options']['lock_name'] = $name;
  
  $options = array(
    'data' => array(
      'master_key' => hash('sha512', httprl_drupal_get_private_key()),
      'temp_key' => $name,
      'mode' => $mode,
      'php_timeout' => max($times),
      'function' => $callback_options['function'],
      'context' => isset($callback_options['context']) ? $callback_options['context'] : array(),
      
      'args' => strtr(base64_encode(serialize($args)), array(
        '+' => '-',
        '/' => '_',
      )),
    ),
    'internal_states' => array(
      'background_function_return' => &$callback_options['return'],
      'background_function_args' => &$args,
    ),
    'blocking' => $mode,
    'method' => 'POST',
    'referrer' => 'TRUE',
  );
  if (isset($callback_options['printed'])) {
    $options['internal_states']['background_function_printed'] =& $callback_options['printed'];
  }
  if (isset($callback_options['options']) && is_array($callback_options['options'])) {
    $options += $callback_options['options'];
  }
  
  if (empty($options['headers']['Host'])) {
    $hostname = httprl_get_hostname();
    if (!empty($hostname)) {
      $options['headers']['Host'] = $hostname;
    }
  }
  
  if (!empty($callback_options['context']['session']) && !empty($_COOKIE[session_name()])) {
    if (!isset($options['headers']['Cookie'])) {
      $options['headers']['Cookie'] = '';
    }
    $options['headers']['Cookie'] = session_name() . '=' . $_COOKIE[session_name()] . ';';
  }
  
  return httprl_request($url, $options);
}
function httprl_acquire_lock(&$result) {
  if (empty($result->options['lock_name'])) {
    return FALSE;
  }
  
  $times = array(
    httprl_variable_get('httprl_timeout', HTTPRL_TIMEOUT),
    httprl_variable_get('httprl_global_timeout', HTTPRL_GLOBAL_TIMEOUT),
  );
  if (isset($result->options['timeout'])) {
    $times[] = $result->options['timeout'];
  }
  if (isset($result->options['global_timeout'])) {
    $times[] = $result->options['global_timeout'];
  }
  $time = max($times);
  $name = $result->options['lock_name'];
  return httprl_acquire_headless_lock($name, $time);
}
function httprl_acquire_headless_lock($name, $time = 60) {
  
  $locked = FALSE;
  $lock_counter = 0;
  while (!$locked && $lock_counter < 3) {
    
    $locked = lock_acquire($name, $time);
    $lock_counter++;
  }
  if (!$locked) {
    return FALSE;
  }
  
  unset($GLOBALS['locks'][$name]);
  
  $lock_inc = httprl_variable_get('lock_inc', './includes/lock.inc');
  if ($lock_inc === './includes/lock.inc') {
    if (defined('VERSION') && substr(VERSION, 0, 1) >= 7) {
      db_update('semaphore')
        ->fields(array(
        'value' => 'httprl',
      ))
        ->condition('name', $name)
        ->condition('value', _lock_id())
        ->execute();
    }
    else {
      db_query("UPDATE {semaphore} SET value = '%s' WHERE name = '%s' AND value = '%s'", 'httprl', $name, _lock_id());
    }
  }
  elseif (strpos($lock_inc, '/apdqc/apdqc.lock.inc') !== FALSE) {
    lock_change_lock_id($name, _lock_id(), 'httprl');
  }
  return TRUE;
}
function httprl_decode_data(&$result) {
  if (isset($result->headers['transfer-encoding']) && $result->headers['transfer-encoding'] == 'chunked') {
    $stream_position = 0;
    $output = '';
    $data = $result->data;
    while ($stream_position < httprl_strlen($data)) {
      
      $rawnum = substr($data, $stream_position, strpos(substr($data, $stream_position), "\r\n") + 2);
      $num = hexdec(trim($rawnum));
      
      $stream_position += httprl_strlen($rawnum);
      
      $chunk = substr($data, $stream_position, $num);
      
      if (isset($result->headers['content-encoding'])) {
        if ($result->headers['content-encoding'] === 'gzip') {
          $chunk = @gzinflate(substr($chunk, 10));
        }
        elseif ($result->headers['content-encoding'] === 'deflate') {
          $chunk = @gzinflate($chunk);
        }
        elseif ($result->headers['content-encoding'] === 'br' && is_callable('brotli_uncompress')) {
          $chunk = @brotli_uncompress($chunk);
        }
        if ($chunk === FALSE) {
          break;
        }
      }
      
      $output .= $chunk;
      $stream_position += httprl_strlen($chunk);
    }
    if ($chunk !== FALSE) {
      $result->data = $output;
    }
  }
  elseif (isset($result->headers['content-encoding'])) {
    if ($result->headers['content-encoding'] === 'gzip') {
      $chunk = @gzinflate(substr($result->data, 10));
    }
    elseif ($result->headers['content-encoding'] === 'deflate') {
      $chunk = @gzinflate($result->data);
    }
    elseif ($result->headers['content-encoding'] === 'br' && is_callable('brotli_uncompress')) {
      $chunk = @brotli_uncompress($result->data);
    }
    if (isset($chunk) && $chunk !== FALSE) {
      $result->data = $chunk;
    }
  }
  
  if (array_key_exists('max_data_size', $result->options)) {
    $result->code = 206;
    
    $new_data = array();
    foreach ($result->ranges as $range) {
      
      if (!is_numeric($range['start'])) {
        $new_data[] = substr($result->data, -$range['end']);
      }
      elseif (!is_numeric($range['end'])) {
        $new_data[] = substr($result->data, $range['start']);
      }
      else {
        $new_data[] = substr($result->data, $range['start'], $range['end'] + 1 - $range['start']);
      }
    }
    $result->data = implode('', $new_data);
    
    if (isset($result->headers['content-length'])) {
      $result->headers['content-length'] = httprl_strlen($result->data);
    }
  }
  
  if (isset($result->headers['content-type']) && strpos($result->headers['content-type'], 'multipart/byteranges; boundary=') !== FALSE) {
    
    $boundary = "\r\n--" . substr($result->headers['content-type'], 31);
    $datas = explode($boundary, $result->data);
    $result->data = '';
    foreach ($datas as $data) {
      $split = preg_split("/\r\n\r\n|\n\n|\r\r/", $data, 2);
      if (count($split) < 2) {
        continue;
      }
      
      list($response, $data) = $split;
      $response = array_filter(preg_split("/\r\n|\n|\r/", $response));
      
      while ($line = trim(array_shift($response))) {
        list($name, $value) = explode(':', $line, 2);
        $name = strtolower($name);
        
        if ($name != 'content-range') {
          $result->headers[$name] = trim($value);
        }
      }
      $result->data .= $data;
    }
    
    if (isset($result->headers['content-length'])) {
      $result->headers['content-length'] = httprl_strlen($result->data);
    }
  }
}
function httprl_reconstruct_redirects(&$result) {
  
  if (empty($result->options['internal_states']['original_url'])) {
    return;
  }
  
  $result->url = $result->options['internal_states']['original_url'];
  
  $result->redirect_code_array = $result->options['internal_states']['redirect_code_array'];
  $result->redirect_code = array_pop($result->options['internal_states']['redirect_code_array']);
  
  $result->redirect_url_array = $result->options['internal_states']['redirect_url_array'];
  $result->redirect_url = array_pop($result->options['internal_states']['redirect_url_array']);
  
  unset($result->options['internal_states']['original_url'], $result->options['internal_states']['redirect_code_array'], $result->options['internal_states']['redirect_url_array']);
  if (empty($result->options['internal_states'])) {
    unset($result->options['internal_states']);
  }
}
function httprl_background_processing($output, $wait = TRUE, $content_type = "text/html; charset=utf-8", $length = 0) {
  
  if (headers_sent()) {
    return FALSE;
  }
  
  @ob_end_clean();
  $loop = 0;
  while (ob_get_level() && $loop < 25) {
    @ob_end_clean();
    $loop++;
  }
  
  ignore_user_abort(TRUE);
  
  ob_start();
  header("HTTP/1.0 200 OK");
  header("Content-type: " . $content_type);
  header("Expires: Sun, 19 Nov 1978 05:00:00 GMT");
  header("Cache-Control: no-cache");
  header("Cache-Control: must-revalidate");
  header("Connection: close");
  header('Etag: "' . microtime(TRUE) . '"');
  print $output;
  $size = ob_get_length();
  header("Content-Length: " . $size);
  @ob_end_flush();
  @ob_flush();
  @flush();
  if (function_exists('fastcgi_finish_request')) {
    fastcgi_finish_request();
  }
  
  if ($wait) {
    sleep(1);
  }
  
  return TRUE;
}
function httprl_strlen($string) {
  static $mb_strlen;
  if (!isset($mb_strlen)) {
    $mb_strlen = function_exists('mb_strlen');
  }
  if ($mb_strlen) {
    return mb_strlen($string, '8bit');
  }
  else {
    return strlen($string);
  }
}
function httprl_glue_url($parsed) {
  if (!is_array($parsed)) {
    return FALSE;
  }
  $uri = isset($parsed['scheme']) ? $parsed['scheme'] . ':' . (strtolower($parsed['scheme']) == 'mailto' ? '' : '//') : '';
  $uri .= isset($parsed['user']) ? $parsed['user'] . (isset($parsed['pass']) ? ':' . $parsed['pass'] : '') . '@' : '';
  $uri .= isset($parsed['host']) ? $parsed['host'] : '';
  $uri .= !empty($parsed['port']) ? ':' . $parsed['port'] : '';
  if (isset($parsed['path'])) {
    $uri .= substr($parsed['path'], 0, 1) == '/' ? $parsed['path'] : (!empty($uri) ? '/' : '') . $parsed['path'];
  }
  $uri .= isset($parsed['query']) ? '?' . $parsed['query'] : '';
  $uri .= isset($parsed['fragment']) ? '#' . $parsed['fragment'] : '';
  return $uri;
}
function httprl_get_server_schema() {
  return isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' || isset($_SERVER['HTTP_HTTPS']) && $_SERVER['HTTP_HTTPS'] == 'on' ? 'https' : 'http';
}
function httprl_fast403($msg = '') {
  global $base_path;
  
  if (!headers_sent()) {
    header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
    header('X-HTTPRL: Forbidden.');
  }
  
  print '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">' . "\n";
  print '<html>';
  print '<head><title>403 Forbidden</title></head>';
  print '<body><h1>Forbidden</h1>';
  print '<p>You are not authorized to access this page.</p>';
  print '<p><a href="' . $base_path . '">Home</a></p>';
  print '<!-- httprl_fast403 ' . $msg . ' -->';
  print '</body></html>';
  
  httprl_call_exit();
}
function httprl_lock_release($name) {
  $lock_inc = httprl_variable_get('lock_inc', './includes/lock.inc');
  
  if ($lock_inc === './includes/lock.inc') {
    unset($GLOBALS['locks'][$name]);
    if (defined('VERSION') && substr(VERSION, 0, 1) >= 7) {
      db_delete('semaphore')
        ->condition('name', $name)
        ->execute();
    }
    else {
      db_query("DELETE FROM {semaphore} WHERE name = '%s'", $name);
    }
  }
  elseif (strpos($lock_inc, '/memcache_storage/includes/lock.inc') !== FALSE) {
    
    unset($GLOBALS['locks'][$name]);
    
    if (MemcacheStorageAPI::get($name, 'semaphore')) {
      MemcacheStorageAPI::delete($name, 'semaphore');
    }
  }
  elseif (strpos($lock_inc, '/memcache/memcache-lock.inc') !== FALSE) {
    
    unset($GLOBALS['locks'][$name]);
    if (dmemcache_get($name, 'semaphore')) {
      dmemcache_delete($name, 'semaphore');
    }
  }
  elseif (strpos($lock_inc, '/apdqc/apdqc.lock.inc') !== FALSE) {
    lock_release_fuzzy($name);
  }
  else {
    lock_release($name);
  }
}
function httprl_print_empty(&$data, $level = 0, $output_plain_text) {
  $level++;
  if ($level < 5) {
    if (is_object($data)) {
      $new_object = new stdClass();
      $new_object->__original_class_name__ = get_class($data);
      foreach ($data as $key => $values) {
        $new_object->{$key} = httprl_print_empty($values, $level, $output_plain_text);
      }
      $data = $new_object;
    }
    elseif (is_array($data)) {
      foreach ($data as &$values) {
        $values = httprl_print_empty($values, $level, $output_plain_text);
      }
    }
    elseif (is_bool($data) || strlen((string) $data) == 0) {
      $data = strtoupper(var_export($data, TRUE));
    }
    elseif (!$output_plain_text && is_string($data) && strlen($data) > HTTPRL_PR_MAX_STRING_LENGTH) {
      
      $data = substr($data, 0, HTTPRL_PR_MAX_STRING_LENGTH);
    }
  }
  return $data;
}
function httprl_pr($input) {
  $output_plain_text = FALSE;
  if (strpos(implode("\n", array_map('strtolower', headers_list())), 'content-type: text/plain') !== FALSE || function_exists('drupal_is_cli') && drupal_is_cli()) {
    $output_plain_text = TRUE;
  }
  $old_setting = ini_set('mbstring.substitute_character', '"none"');
  
  $input = func_get_args();
  
  $data = httprl_print_empty($input, 0, $output_plain_text);
  
  if (count($data) == 1) {
    $data = array_pop($data);
  }
  
  $output = print_r($data, TRUE);
  
  $encoded = FALSE;
  if (function_exists('mb_convert_encoding')) {
    $track_errors = ini_set('track_errors', '1');
    $php_errormsg = '';
    $translated = @mb_convert_encoding($output, 'UTF-8', 'auto');
    if (empty($php_errormsg)) {
      $encoded = TRUE;
    }
    $php_errormsg = '';
    ini_set('track_errors', $track_errors);
  }
  if (!$encoded) {
    $translated = @iconv('utf-8', 'utf-8//TRANSLIT//IGNORE', $output);
  }
  
  $options = ENT_QUOTES;
  if (defined('ENT_SUBSTITUTE')) {
    $options = ENT_QUOTES | ENT_SUBSTITUTE;
  }
  elseif (defined('ENT_IGNORE')) {
    $options = ENT_QUOTES | ENT_IGNORE;
  }
  $translated = htmlentities($translated, $options, 'UTF-8');
  
  $original_size = strlen($output);
  $translated_size = strlen($translated);
  $ratio = 0;
  if ($original_size != 0) {
    $ratio = ($original_size - $translated_size) / $original_size;
  }
  
  if (!empty($translated_size) && !empty($ratio) && $ratio < 0.5 && !$output_plain_text) {
    $html_output = TRUE;
    $output = $translated;
  }
  else {
    if (!$output_plain_text) {
      $output = str_replace(array(
        '<',
        '>',
      ), array(
        '<',
        '>',
      ), $output);
    }
    $output = "<pre>\n" . $output . "\n</pre>";
  }
  
  $output = array_filter(explode("\n", $output), 'strlen');
  
  foreach ($output as $key => $value) {
    if (str_replace('    ', '', $value) == "(") {
      $output[$key - 1] .= ' (';
      unset($output[$key]);
    }
  }
  
  $output = implode("\n", $output);
  if (!empty($html_output)) {
    $output = str_replace('    ', '    ', nl2br($output)) . '<br />';
  }
  else {
    $output .= "\n";
  }
  ini_set('mbstring.substitute_character', $old_setting);
  return $output;
}
function _httprl_use_proxy($host) {
  
  $proxy_exceptions = httprl_variable_get('proxy_exceptions', array(
    'localhost',
    '127\\.0\\.0\\.1',
  ));
  $use_proxy = TRUE;
  if (is_array($proxy_exceptions) && count($proxy_exceptions)) {
    foreach ($proxy_exceptions as $exception) {
      $match = preg_match("/{$exception}/is", $host);
      if ($match) {
        $use_proxy = FALSE;
        break;
      }
    }
  }
  return $use_proxy;
}
function httprl_variable_get($name, $default = NULL) {
  
  global $conf;
  if (isset($conf[$name])) {
    return $conf[$name];
  }
  
  if (function_exists('db_query') && !httprl_drupal_full_bootstrap()) {
    if (defined('VERSION') && substr(VERSION, 0, 1) >= 7) {
      $variables = array_map('unserialize', db_query('SELECT name, value FROM {variable} WHERE name = :name', array(
        ':name' => $name,
      ))
        ->fetchAllKeyed());
      
      return isset($variables[$name]) ? $variables[$name] : $default;
    }
    else {
      $result = db_query("SELECT value FROM {variable} WHERE name = '%s'", $name);
      if (!empty($result)) {
        $result = db_result($result);
        if (!empty($result)) {
          $value = @unserialize($result);
        }
      }
      
      return isset($value) ? $value : $default;
    }
  }
  else {
    
    return $default;
  }
}
function httprl_run_array(&$array) {
  $last = NULL;
  foreach ($array as &$data) {
    
    if (!isset($data['type'])) {
      continue;
    }
    
    if (isset($data['last'])) {
      $last = $data['last'];
    }
    
    if (isset($data['args']) && array_key_exists('last', $data['args'])) {
      $data['args']['last'] = $last;
      $data['args'] = array_values($data['args']);
    }
    
    if (array_key_exists('printed', $data)) {
      ob_start();
    }
    
    $args = array();
    if (isset($data['args']) && is_array($data['args'])) {
      foreach ($data['args'] as &$arg) {
        $args[] =& $arg;
      }
    }
    
    $track_errors = ini_set('track_errors', '1');
    $php_errormsg = '';
    
    switch ($data['type']) {
      case 'function':
        if (function_exists($data['call'])) {
          $last = call_user_func_array($data['call'], $args);
        }
        else {
          $php_errormsg = 'Recoverable Fatal error: Call to undefined function ' . $data['call'] . '()';
        }
        break;
      case 'method':
        if (method_exists($last, $data['call'])) {
          $last = call_user_func_array(array(
            $last,
            $data['call'],
          ), $args);
        }
        else {
          $php_errormsg = 'Recoverable Fatal error: Call to undefined method ' . get_class($last) . '::' . $data['call'] . '()';
        }
        break;
    }
    
    if (!empty($php_errormsg)) {
      $data['error'] = $php_errormsg;
      ini_set('track_errors', $track_errors);
      watchdog('httprl', 'Error thrown in httprl_run_array(). <br /> @error', array(
        '@error' => $php_errormsg,
      ), WATCHDOG_ERROR);
    }
    
    if (array_key_exists('printed', $data)) {
      $data['printed'] = ob_get_contents();
      ob_end_clean();
    }
    
    if (array_key_exists('return', $data)) {
      $data['return'] = $last;
    }
  }
  return array(
    'args' => array(
      $array,
    ),
  );
}
function httprl_run_function($function, &$input_args) {
  
  $args = array();
  foreach ($input_args as &$arg) {
    $args[] =& $arg;
  }
  
  ob_start();
  
  $track_errors = ini_set('track_errors', '1');
  $php_errormsg = '';
  
  $return = NULL;
  
  try {
    if (function_exists($function)) {
      $return = call_user_func_array($function, $args);
    }
    else {
      $php_errormsg = 'Recoverable Fatal error: Call to undefined function ' . $function . '()';
    }
  } catch (Exception $e) {
    $php_errormsg = $e;
  }
  $printed = ob_get_contents();
  ob_end_clean();
  
  $data = array(
    'return' => $return,
    'args' => $args,
    'printed' => $printed,
  );
  
  if (!empty($php_errormsg)) {
    $data['error'] = $php_errormsg;
    ini_set('track_errors', $track_errors);
    watchdog('httprl', 'Error thrown in httprl_run_function(). <br /> @error', array(
      '@error' => $php_errormsg,
    ), WATCHDOG_ERROR);
  }
  return $data;
}
function httprl_boot() {
  global $base_root;
  $full_url = $base_root . request_uri();
  
  if (strpos($full_url, '/httprl_async_function_callback') === FALSE || $_SERVER['REQUEST_METHOD'] !== 'POST' || empty($_POST['master_key']) || empty($_POST['temp_key']) || strpos($_POST['temp_key'], 'httprl_') !== 0 || !empty($_POST['function'])) {
    return NULL;
  }
  
  if (defined('DRUPAL_ROOT')) {
    require_once DRUPAL_ROOT . '/' . dirname(drupal_get_filename('module', 'httprl')) . '/httprl.async.inc';
  }
  else {
    require_once './' . dirname(drupal_get_filename('module', 'httprl')) . '/httprl.async.inc';
  }
  httprl_async_page();
}
function httprl_drupal_get_private_key() {
  $full_bootstrap = httprl_drupal_full_bootstrap();
  $private_key = $full_bootstrap ? drupal_get_private_key() : httprl_variable_get('drupal_private_key', 0);
  return $private_key;
}
function httprl_call_exit() {
  if (defined('VERSION') && substr(VERSION, 0, 1) >= 7 && drupal_get_bootstrap_phase() == DRUPAL_BOOTSTRAP_FULL) {
    
    drupal_save_session(FALSE);
    drupal_exit();
  }
  else {
    session_save_session(FALSE);
    exit;
  }
}
function httprl_drupal_full_bootstrap() {
  static $full_bootstrap;
  if (!isset($full_bootstrap)) {
    
    if (defined('VERSION') && substr(VERSION, 0, 1) >= 7) {
      $level = drupal_bootstrap();
      $full_bootstrap = $level == DRUPAL_BOOTSTRAP_FULL ? TRUE : FALSE;
    }
    else {
      $full_bootstrap = isset($GLOBALS['multibyte']) ? TRUE : FALSE;
    }
  }
  return $full_bootstrap;
}
function httprl_is_background_callback_capable() {
  
  if (defined('VERSION') && substr(VERSION, 0, 1) >= 7 && httprl_variable_get('maintenance_mode', 0) || httprl_variable_get('site_offline', 0)) {
    return FALSE;
  }
  
  if (!httprl_variable_get('httprl_background_callback', HTTPRL_BACKGROUND_CALLBACK)) {
    return FALSE;
  }
  
  if (httprl_drupal_full_bootstrap() && function_exists('menu_get_item') && !menu_get_item('httprl_async_function_callback')) {
    return FALSE;
  }
  
  return TRUE;
}
function httprl_set_user($uid) {
  $account = user_load($uid);
  if (!empty($account)) {
    $GLOBALS['user'] = $account;
    if (defined('VERSION') && substr(VERSION, 0, 1) >= 7) {
      drupal_save_session(FALSE);
    }
    else {
      session_save_session(FALSE);
    }
    return TRUE;
  }
}
function httprl_set_q($q) {
  $_GET['q'] = $q;
}
function &httprl_qcinp($callback, $param_arr = array(), $return = TRUE, $httprl_options = array()) {
  $return_var = NULL;
  
  $callback_options[0]['function'] = $callback;
  if ($return) {
    $return_var = '';
    $callback_options[0]['return'] =& $return_var;
  }
  if (isset($httprl_options['context'])) {
    $callback_options[0]['context'] = $httprl_options['context'];
    unset($httprl_options['context']);
  }
  $callback_options[0]['options'] = $httprl_options;
  
  $callback_options = array_merge($callback_options, $param_arr);
  
  httprl_queue_background_callback($callback_options);
  return $return_var;
}
function httprl_batch_callback($callback, $data, $options = array()) {
  
  $results = array();
  $unified_result = NULL;
  $number_of_items = count($data);
  $options += array(
    'max_batchsize' => 30,
    'threads' => 3,
    'timeout' => 120,
    'multiple_helper' => FALSE,
  );
  
  if ($number_of_items < $options['max_batchsize'] * $options['threads']) {
    $options['max_batchsize'] = ceil($number_of_items / $options['threads']);
  }
  
  $data = array_chunk($data, $options['max_batchsize'], TRUE);
  
  unset($options['max_batchsize']);
  $options['domain_connections'] = $options['threads'];
  unset($options['threads']);
  $multiple = $options['multiple_helper'];
  unset($options['multiple_helper']);
  
  if ($multiple) {
    foreach ($data as $key => $values) {
      $results[$key] =& httprl_qcinp('httprl_run_multiple', array(
        $callback,
        $values,
      ), TRUE, $options);
    }
  }
  else {
    foreach ($data as $key => $values) {
      $results[$key] =& httprl_qcinp($callback, array(
        $values,
      ), TRUE, $options);
    }
  }
  
  httprl_send_request();
  
  $unified = TRUE;
  $is_assoc = TRUE;
  foreach ($results as $key => $value) {
    if (is_null($unified_result)) {
      $unified_result = $results[$key];
    }
    elseif (is_string($results[$key]) && is_string($unified_result)) {
      $unified_result .= $results[$key];
    }
    elseif (is_array($results[$key]) && is_array($unified_result)) {
      if ($is_assoc && httprl_is_array_assoc($results[$key]) && httprl_is_array_assoc($unified_result)) {
        $unified_result = httprl_lossless_assoc_array_merge($unified_result, $results[$key]);
      }
      else {
        $is_assoc = FALSE;
        $unified_result += $results[$key];
      }
    }
    else {
      $unified = FALSE;
      break;
    }
  }
  
  if ($unified) {
    return $unified_result;
  }
  else {
    return $results;
  }
}
function httprl_is_array_assoc($array) {
  return ctype_digit(implode('', array_keys($array)));
}
function httprl_lossless_assoc_array_merge() {
  $arrays = func_get_args();
  $data = array();
  foreach ($arrays as $a) {
    foreach ($a as $k => $v) {
      if (isset($data[$k])) {
        $data[] = $v;
      }
      else {
        $data[$k] = $v;
      }
    }
  }
  return $data;
}
function httprl_run_multiple($callback, $data) {
  $results = array();
  foreach ($data as $key => $values) {
    $results[$key] = call_user_func_array($callback, array(
      $values,
    ));
  }
  return $results;
}
function httprl_call_user_func_array_async($callback, array $param_arr) {
  if (!httprl_is_background_callback_capable()) {
    call_user_func_array($callback, $param_arr);
  }
  else {
    
    $callback_options = array_merge(array(
      array(
        'function' => $callback,
      ),
    ), $param_arr);
    
    httprl_queue_background_callback($callback_options);
    
    httprl_send_request();
  }
}
function httprl_call_user_func_array_cache($callback, array $param_arr = array(), array $options = array()) {
  $options += array(
    
    'cache_lifetime_min' => 0,
    
    'cache_lifetime_max' => 3600,
    
    'bin' => 'cache',
    
    'lock_timeout' => 30.0,
    
    'return_null_cache_miss' => FALSE,
  );
  
  if (is_string($callback)) {
    $cid = __FUNCTION__ . ':' . $callback . ':' . drupal_hash_base64(serialize(array(
      $param_arr,
    )));
  }
  else {
    $cid = __FUNCTION__ . ':' . drupal_hash_base64(serialize(array(
      $callback,
      $param_arr,
    )));
  }
  $cache = cache_get($cid, $options['bin']);
  
  if (empty($options['return_null_cache_miss']) && (!isset($cache->data) || $cache->created < REQUEST_TIME - $options['cache_lifetime_max'])) {
    if (httprl_acquire_headless_lock($cid . ':run_function', $options['lock_timeout'])) {
      $cache = new stdClass();
      
      $cache->data = call_user_func_array($callback, $param_arr);
      
      cache_set($cid, $cache->data, $options['bin'], $options['cache_lifetime_max'] + time());
      
      httprl_lock_release($cid . ':run_function');
    }
    else {
      lock_wait($cid . ':run_function', $options['lock_timeout']);
      $cache = cache_get($cid);
      if (!isset($cache->data)) {
        $cache = new stdClass();
        
        $cache->data = call_user_func_array($callback, $param_arr);
        
        cache_set($cid, $cache->data, $options['bin'], $options['cache_lifetime_max'] + time());
      }
    }
    
    if ($options['cache_lifetime_max'] == 0) {
      httprl_lock_release($cid);
    }
  }
  else {
    
    if (empty($cache) || $cache->created < REQUEST_TIME - $options['cache_lifetime_min'] && lock_may_be_available($cid . ':run_function') && httprl_acquire_headless_lock($cid, $options['lock_timeout'])) {
      
      $options['cache_lifetime_max'] = 0;
      $options['return_null_cache_miss'] = FALSE;
      
      $args = array(
        $callback,
        $param_arr,
        $options,
      );
      if (!httprl_is_background_callback_capable()) {
        
        _httprl_run_functions_once_on_shutdown_array_cache($args);
      }
      else {
        
        httprl_call_user_func_array_async('httprl_call_user_func_array_cache', $args);
      }
    }
  }
  return isset($cache->data) ? $cache->data : NULL;
}
function _httprl_run_functions_once_on_shutdown_array_cache($args = array()) {
  $run_list =& drupal_static('_httprl_run_functions_once_on_shutdown_array_cache', array());
  if (!empty($args)) {
    if (empty($run_list)) {
      
      register_shutdown_function('_httprl_run_functions_once_on_shutdown_array_cache');
    }
    $run_list[] = $args;
  }
  else {
    unset($args);
    $will_run = array();
    $already_ran = array();
    foreach ($run_list as $key => $args) {
      if (empty($args)) {
        unset($run_list[$key]);
        continue;
      }
      if (is_string($args[0])) {
        $cid = __FUNCTION__ . ':' . $args[0] . ':' . drupal_hash_base64(serialize(array(
          $args[1],
        )));
      }
      else {
        $cid = __FUNCTION__ . ':' . drupal_hash_base64(serialize(array(
          $args[0],
          $args[1],
        )));
      }
      if (empty($already_ran[$cid])) {
        $already_ran[$cid] = TRUE;
        $will_run[] = $args;
      }
    }
    if (!empty($will_run)) {
      
      httprl_call_user_func_array_async('_httprl_run_cache_functions', array(
        $will_run,
      ));
    }
    unset($run_list[$key]);
  }
}
function _httprl_run_cache_functions($functions_to_cache) {
  
  @ob_end_flush();
  @ob_flush();
  @flush();
  sleep(1);
  if (function_exists('fastcgi_finish_request')) {
    fastcgi_finish_request();
  }
  foreach ($functions_to_cache as $args) {
    call_user_func_array('httprl_call_user_func_array_cache', $args);
  }
}
function httprl_get_hostname() {
  if (!empty($_SERVER['HTTP_HOST'])) {
    
    if (strpos($_SERVER['HTTP_HOST'], ':') !== FALSE) {
      return $_SERVER['SERVER_NAME'];
    }
    return $_SERVER['HTTP_HOST'];
  }
  elseif (!empty($_SERVER['SERVER_NAME'])) {
    return $_SERVER['SERVER_NAME'];
  }
  return '';
}