Viewing file: Batch.php (7.83 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php /* * Copyright 2012 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */
namespace Google\Http;
use Google\Client; use Google\Service\Exception as GoogleServiceException; use GuzzleHttp\Psr7; use GuzzleHttp\Psr7\Request; use GuzzleHttp\Psr7\Response; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface;
/** * Class to handle batched requests to the Google API service. * * Note that calls to `Google\Http\Batch::execute()` do not clear the queued * requests. To start a new batch, be sure to create a new instance of this * class. */ class Batch { const BATCH_PATH = 'batch';
private static $CONNECTION_ESTABLISHED_HEADERS = [ "HTTP/1.0 200 Connection established\r\n\r\n", "HTTP/1.1 200 Connection established\r\n\r\n", ];
/** @var string Multipart Boundary. */ private $boundary;
/** @var array service requests to be executed. */ private $requests = [];
/** @var Client */ private $client;
private $rootUrl;
private $batchPath;
public function __construct( Client $client, $boundary = false, $rootUrl = null, $batchPath = null ) { $this->client = $client; $this->boundary = $boundary ?: mt_rand(); $this->rootUrl = rtrim($rootUrl ?: $this->client->getConfig('base_path'), '/'); $this->batchPath = $batchPath ?: self::BATCH_PATH; }
public function add(RequestInterface $request, $key = false) { if (false == $key) { $key = mt_rand(); }
$this->requests[$key] = $request; }
public function execute() { $body = ''; $classes = []; $batchHttpTemplate = <<<EOF --%s Content-Type: application/http Content-Transfer-Encoding: binary MIME-Version: 1.0 Content-ID: %s
%s %s%s
EOF;
/** @var RequestInterface $request */ foreach ($this->requests as $key => $request) { $firstLine = sprintf( '%s %s HTTP/%s', $request->getMethod(), $request->getRequestTarget(), $request->getProtocolVersion() );
$content = (string) $request->getBody();
$headers = ''; foreach ($request->getHeaders() as $name => $values) { $headers .= sprintf("%s:%s\r\n", $name, implode(', ', $values)); }
$body .= sprintf( $batchHttpTemplate, $this->boundary, $key, $firstLine, $headers, $content ? "\n" . $content : '' );
$classes['response-' . $key] = $request->getHeaderLine('X-Php-Expected-Class'); }
$body .= "--{$this->boundary}--"; $body = trim($body); $url = $this->rootUrl . '/' . $this->batchPath; $headers = [ 'Content-Type' => sprintf('multipart/mixed; boundary=%s', $this->boundary), 'Content-Length' => (string) strlen($body), ];
$request = new Request( 'POST', $url, $headers, $body );
$response = $this->client->execute($request);
return $this->parseResponse($response, $classes); }
public function parseResponse(ResponseInterface $response, $classes = []) { $contentType = $response->getHeaderLine('content-type'); $contentType = explode(';', $contentType); $boundary = false; foreach ($contentType as $part) { $part = explode('=', $part, 2); if (isset($part[0]) && 'boundary' == trim($part[0])) { $boundary = $part[1]; } }
$body = (string) $response->getBody(); if (!empty($body)) { $body = str_replace("--$boundary--", "--$boundary", $body); $parts = explode("--$boundary", $body); $responses = []; $requests = array_values($this->requests);
foreach ($parts as $i => $part) { $part = trim($part); if (!empty($part)) { list($rawHeaders, $part) = explode("\r\n\r\n", $part, 2); $headers = $this->parseRawHeaders($rawHeaders);
$status = substr($part, 0, strpos($part, "\n")); $status = explode(" ", $status); $status = $status[1];
list($partHeaders, $partBody) = $this->parseHttpResponse($part, 0); $response = new Response( (int) $status, $partHeaders, Psr7\Utils::streamFor($partBody) );
// Need content id. $key = $headers['content-id'];
try { $response = REST::decodeHttpResponse($response, $requests[$i-1]); } catch (GoogleServiceException $e) { // Store the exception as the response, so successful responses // can be processed. $response = $e; }
$responses[$key] = $response; } }
return $responses; }
return null; }
private function parseRawHeaders($rawHeaders) { $headers = []; $responseHeaderLines = explode("\r\n", $rawHeaders); foreach ($responseHeaderLines as $headerLine) { if ($headerLine && strpos($headerLine, ':') !== false) { list($header, $value) = explode(': ', $headerLine, 2); $header = strtolower($header); if (isset($headers[$header])) { $headers[$header] = array_merge((array)$headers[$header], (array)$value); } else { $headers[$header] = $value; } } } return $headers; }
/** * Used by the IO lib and also the batch processing. * * @param string $respData * @param int $headerSize * @return array */ private function parseHttpResponse($respData, $headerSize) { // check proxy header foreach (self::$CONNECTION_ESTABLISHED_HEADERS as $established_header) { if (stripos($respData, $established_header) !== false) { // existed, remove it $respData = str_ireplace($established_header, '', $respData); // Subtract the proxy header size unless the cURL bug prior to 7.30.0 // is present which prevented the proxy header size from being taken into // account. // @TODO look into this // if (!$this->needsQuirk()) { // $headerSize -= strlen($established_header); // } break; } }
if ($headerSize) { $responseBody = substr($respData, $headerSize); $responseHeaders = substr($respData, 0, $headerSize); } else { $responseSegments = explode("\r\n\r\n", $respData, 2); $responseHeaders = $responseSegments[0]; $responseBody = isset($responseSegments[1]) ? $responseSegments[1] : null; }
$responseHeaders = $this->parseRawHeaders($responseHeaders);
return [$responseHeaders, $responseBody]; } }
|