You are here

function httprl_decode_data in HTTP Parallel Request & Threading Library 6

Same name and namespace in other branches
  1. 7 httprl.module \httprl_decode_data()

Will decode chunked transfer-encoding and gzip/deflate content-encoding.

Parameters

object $result: An object from httprl_send_request.

1 call to httprl_decode_data()
httprl_post_processing in ./httprl.module
Run post processing on the request if we are done reading.

File

./httprl.module, line 2413
HTTP Parallel Request Library module.

Code

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)) {

      // Get the number of bytes to read for this chunk.
      $rawnum = substr($data, $stream_position, strpos(substr($data, $stream_position), "\r\n") + 2);
      $num = hexdec(trim($rawnum));

      // Get the position to read from.
      $stream_position += httprl_strlen($rawnum);

      // Extract the chunk.
      $chunk = substr($data, $stream_position, $num);

      // Decompress if compressed.
      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;
        }
      }

      // Glue the chunks together.
      $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;
    }
  }

  // Cut up response for one sided Range requests.
  if (array_key_exists('max_data_size', $result->options)) {
    $result->code = 206;

    // Make the data conform to the range request.
    $new_data = array();
    foreach ($result->ranges as $range) {

      // Get only the last X number of bytes.
      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);

    // Fix content-length for fake 206s.
    if (isset($result->headers['content-length'])) {
      $result->headers['content-length'] = httprl_strlen($result->data);
    }
  }

  // Reassemble multipart/byteranges response.
  if (isset($result->headers['content-type']) && strpos($result->headers['content-type'], 'multipart/byteranges; boundary=') !== FALSE) {

    // Get boundary string.
    $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;
      }

      // Separate the data from the headers.
      list($response, $data) = $split;
      $response = array_filter(preg_split("/\r\n|\n|\r/", $response));

      // Parse the response headers.
      while ($line = trim(array_shift($response))) {
        list($name, $value) = explode(':', $line, 2);
        $name = strtolower($name);

        // Add key value pairs to the header.
        if ($name != 'content-range') {
          $result->headers[$name] = trim($value);
        }
      }
      $result->data .= $data;
    }

    // Fix content-length for multipart/byteranges.
    if (isset($result->headers['content-length'])) {
      $result->headers['content-length'] = httprl_strlen($result->data);
    }
  }
}