source: vendor/google/apiclient/src/Http/Batch.php@ f9c482b

Last change on this file since f9c482b was f9c482b, checked in by Vlado 222039 <vlado.popovski@…>, 7 days ago

Upload new project files

  • Property mode set to 100644
File size: 8.0 KB
RevLine 
[f9c482b]1<?php
2/*
3 * Copyright 2012 Google Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18namespace Google\Http;
19
20use Google\Client;
21use Google\Service\Exception as GoogleServiceException;
22use GuzzleHttp\Psr7;
23use GuzzleHttp\Psr7\Request;
24use GuzzleHttp\Psr7\Response;
25use Psr\Http\Message\RequestInterface;
26use Psr\Http\Message\ResponseInterface;
27
28/**
29 * Class to handle batched requests to the Google API service.
30 *
31 * Note that calls to `Google\Http\Batch::execute()` do not clear the queued
32 * requests. To start a new batch, be sure to create a new instance of this
33 * class.
34 */
35class Batch
36{
37 const BATCH_PATH = 'batch';
38
39 private static $CONNECTION_ESTABLISHED_HEADERS = [
40 "HTTP/1.0 200 Connection established\r\n\r\n",
41 "HTTP/1.1 200 Connection established\r\n\r\n",
42 ];
43
44 /** @var string Multipart Boundary. */
45 private $boundary;
46
47 /** @var array service requests to be executed. */
48 private $requests = [];
49
50 /** @var Client */
51 private $client;
52
53 private $rootUrl;
54
55 private $batchPath;
56
57 public function __construct(
58 Client $client,
59 $boundary = false,
60 $rootUrl = null,
61 $batchPath = null
62 ) {
63 $this->client = $client;
64 $this->boundary = $boundary ?: mt_rand();
65 $rootUrl = rtrim($rootUrl ?: $this->client->getConfig('base_path'), '/');
66 $this->rootUrl = str_replace(
67 'UNIVERSE_DOMAIN',
68 $this->client->getUniverseDomain(),
69 $rootUrl
70 );
71 $this->batchPath = $batchPath ?: self::BATCH_PATH;
72 }
73
74 public function add(RequestInterface $request, $key = false)
75 {
76 if (false == $key) {
77 $key = mt_rand();
78 }
79
80 $this->requests[$key] = $request;
81 }
82
83 public function execute()
84 {
85 $body = '';
86 $classes = [];
87 $batchHttpTemplate = <<<EOF
88--%s
89Content-Type: application/http
90Content-Transfer-Encoding: binary
91MIME-Version: 1.0
92Content-ID: %s
93
94%s
95%s%s
96
97
98EOF;
99
100 /** @var RequestInterface $request */
101 foreach ($this->requests as $key => $request) {
102 $firstLine = sprintf(
103 '%s %s HTTP/%s',
104 $request->getMethod(),
105 $request->getRequestTarget(),
106 $request->getProtocolVersion()
107 );
108
109 $content = (string) $request->getBody();
110
111 $headers = '';
112 foreach ($request->getHeaders() as $name => $values) {
113 $headers .= sprintf("%s:%s\r\n", $name, implode(', ', $values));
114 }
115
116 $body .= sprintf(
117 $batchHttpTemplate,
118 $this->boundary,
119 $key,
120 $firstLine,
121 $headers,
122 $content ? "\n" . $content : ''
123 );
124
125 $classes['response-' . $key] = $request->getHeaderLine('X-Php-Expected-Class');
126 }
127
128 $body .= "--{$this->boundary}--";
129 $body = trim($body);
130 $url = $this->rootUrl . '/' . $this->batchPath;
131 $headers = [
132 'Content-Type' => sprintf('multipart/mixed; boundary=%s', $this->boundary),
133 'Content-Length' => (string) strlen($body),
134 ];
135
136 $request = new Request(
137 'POST',
138 $url,
139 $headers,
140 $body
141 );
142
143 $response = $this->client->execute($request);
144
145 return $this->parseResponse($response, $classes);
146 }
147
148 public function parseResponse(ResponseInterface $response, $classes = [])
149 {
150 $contentType = $response->getHeaderLine('content-type');
151 $contentType = explode(';', $contentType);
152 $boundary = false;
153 foreach ($contentType as $part) {
154 $part = explode('=', $part, 2);
155 if (isset($part[0]) && 'boundary' == trim($part[0])) {
156 $boundary = $part[1];
157 }
158 }
159
160 $body = (string) $response->getBody();
161 if (!empty($body)) {
162 $body = str_replace("--$boundary--", "--$boundary", $body);
163 $parts = explode("--$boundary", $body);
164 $responses = [];
165 $requests = array_values($this->requests);
166
167 foreach ($parts as $i => $part) {
168 $part = trim($part);
169 if (!empty($part)) {
170 list($rawHeaders, $part) = explode("\r\n\r\n", $part, 2);
171 $headers = $this->parseRawHeaders($rawHeaders);
172
173 $status = substr($part, 0, strpos($part, "\n"));
174 $status = explode(" ", $status);
175 $status = $status[1];
176
177 list($partHeaders, $partBody) = $this->parseHttpResponse($part, 0);
178 $response = new Response(
179 (int) $status,
180 $partHeaders,
181 Psr7\Utils::streamFor($partBody)
182 );
183
184 // Need content id.
185 $key = $headers['content-id'];
186
187 try {
188 $response = REST::decodeHttpResponse($response, $requests[$i-1]);
189 } catch (GoogleServiceException $e) {
190 // Store the exception as the response, so successful responses
191 // can be processed.
192 $response = $e;
193 }
194
195 $responses[$key] = $response;
196 }
197 }
198
199 return $responses;
200 }
201
202 return null;
203 }
204
205 private function parseRawHeaders($rawHeaders)
206 {
207 $headers = [];
208 $responseHeaderLines = explode("\r\n", $rawHeaders);
209 foreach ($responseHeaderLines as $headerLine) {
210 if ($headerLine && strpos($headerLine, ':') !== false) {
211 list($header, $value) = explode(': ', $headerLine, 2);
212 $header = strtolower($header);
213 if (isset($headers[$header])) {
214 $headers[$header] = array_merge((array)$headers[$header], (array)$value);
215 } else {
216 $headers[$header] = $value;
217 }
218 }
219 }
220 return $headers;
221 }
222
223 /**
224 * Used by the IO lib and also the batch processing.
225 *
226 * @param string $respData
227 * @param int $headerSize
228 * @return array
229 */
230 private function parseHttpResponse($respData, $headerSize)
231 {
232 // check proxy header
233 foreach (self::$CONNECTION_ESTABLISHED_HEADERS as $established_header) {
234 if (stripos($respData, $established_header) !== false) {
235 // existed, remove it
236 $respData = str_ireplace($established_header, '', $respData);
237 // Subtract the proxy header size unless the cURL bug prior to 7.30.0
238 // is present which prevented the proxy header size from being taken into
239 // account.
240 // @TODO look into this
241 // if (!$this->needsQuirk()) {
242 // $headerSize -= strlen($established_header);
243 // }
244 break;
245 }
246 }
247
248 if ($headerSize) {
249 $responseBody = substr($respData, $headerSize);
250 $responseHeaders = substr($respData, 0, $headerSize);
251 } else {
252 $responseSegments = explode("\r\n\r\n", $respData, 2);
253 $responseHeaders = $responseSegments[0];
254 $responseBody = isset($responseSegments[1]) ? $responseSegments[1] : null;
255 }
256
257 $responseHeaders = $this->parseRawHeaders($responseHeaders);
258
259 return [$responseHeaders, $responseBody];
260 }
261}
Note: See TracBrowser for help on using the repository browser.