function httprl_parse_data in HTTP Parallel Request & Threading Library 6
Same name and namespace in other branches
- 7 httprl.module \httprl_parse_data()
Extract the header and meta data from the http data stream.
@todo Send cookies in the redirect request if domain/path match.
Parameters
object $result: An object from httprl_send_request.
See also
1 call to httprl_parse_data()
- httprl_send_request in ./
httprl.module - Perform many HTTP requests.
File
- ./
httprl.module, line 1762 - HTTP Parallel Request Library module.
Code
function httprl_parse_data(&$result) {
// If in non blocking mode, skip.
if (empty($result->options['blocking'])) {
return;
}
// If the headers are already parsed, skip.
if (!empty($result->headers)) {
return;
}
// If the t function is not available use httprl_pr.
$t = function_exists('t') ? 't' : 'httprl_pr';
// Parse response headers from the response body.
// Be tolerant of malformed HTTP responses that separate header and body with
// \n\n or \r\r instead of \r\n\r\n.
$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);
// Parse the response status line.
$protocol_code_array = explode(' ', trim(array_shift($response)), 3);
$result->protocol = $protocol_code_array[0];
$code = (int) $protocol_code_array[1];
// If the response does not include a description, don't try to process it.
$result->status_message = isset($protocol_code_array[2]) ? $protocol_code_array[2] : '';
unset($protocol_code_array);
$result->headers = array();
// Parse the response headers.
$cookie_primary_counter = 0;
while ($line = trim(array_shift($response))) {
list($name, $value) = explode(':', $line, 2);
$name = strtolower($name);
// Parse cookies before they get added to the header.
if ($name == 'set-cookie') {
// Extract the key value pairs for this 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);
// The cookie name-value pair always comes first (RFC 2109 4.2.2).
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++;
}
// Add key value pairs to the header; including cookies.
if (isset($result->headers[$name]) && $name == 'set-cookie') {
// RFC 2109: the Set-Cookie response header comprises the token Set-
// Cookie:, followed by a comma-separated list of one or more cookies.
$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',
);
// 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;
}
$result->code = $code;
switch ($code) {
case 200:
// OK
case 201:
// Created
case 202:
// Accepted
case 206:
// Partial Content
case 304:
// Not modified
break;
case 301:
// Moved permanently
case 302:
// Moved temporarily
case 307:
// Moved temporarily
$location = @parse_url($result->headers['location']);
// If location isn't fully qualified URL (as per W3 RFC2616), build one.
if (empty($location['scheme']) || empty($location['host'])) {
$hostname = httprl_get_hostname();
// Get the important parts from the original request.
$original_location = @parse_url($result->url);
// Assume request is to self if none of this was setup correctly.
$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'];
}
// Set internal redirect states.
$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;
}
// Error out if we hit the max redirect.
if ($result->options['max_redirects'] <= 0) {
$result->code = HTTPRL_REQUEST_ALLOWED_REDIRECTS_EXHAUSTED;
$result->error = $t('Maximum allowed redirects exhausted.');
}
else {
// Redirect to the new location.
// TODO: Send cookies in the redirect request if domain/path match.
$result->options['max_redirects']--;
if (isset($result->options['headers']['Referer'])) {
$result->options['headers']['Referer'] = $result->url;
}
// Remove the host from the header.
unset($result->options['headers']['Host']);
// Pass along running time.
$result->options['internal_states']['running_time'] = $result->running_time;
// Send new request.
httprl_request($location, $result->options);
// Kill this request.
$result->options['internal_states']['kill'] = TRUE;
}
break;
default:
$result->error = $result->status_message;
}
}