PluginProbe
AutomatorWP – No-Code Workflow Automation, Integration & Webhooks Plugin, now with AI / 6.0.4
AutomatorWP – No-Code Workflow Automation, Integration & Webhooks Plugin, now with AI v6.0.4
6.0.4 6.0.3 6.0.2 6.0.1 6.0.0 5.8.6 5.8.5 5.8.4 5.8.3 5.8.2 5.8.1 5.8.0 5.7.9.2 5.7.9.1 5.7.8 5.7.9 5.7.6 5.7.7 5.7.5 5.7.4 5.7.3 5.7.2 5.7.1 trunk 5.6.0 All 35 releases
← All changes | integrations/mailchimp/vendor/guzzlehttp/guzzle/src/Client.php +483 -0 5.8.2 → 6.0.4 View file →
@@ -1,0 +1,483 @@
1 +<?php
2 +
3 +namespace GuzzleHttp;
4 +
5 +use GuzzleHttp\Cookie\CookieJar;
6 +use GuzzleHttp\Exception\GuzzleException;
7 +use GuzzleHttp\Exception\InvalidArgumentException;
8 +use GuzzleHttp\Promise as P;
9 +use GuzzleHttp\Promise\PromiseInterface;
10 +use Psr\Http\Message\RequestInterface;
11 +use Psr\Http\Message\ResponseInterface;
12 +use Psr\Http\Message\UriInterface;
13 +
14 +/**
15 + * @final
16 + */
17 +class Client implements ClientInterface, \Psr\Http\Client\ClientInterface
18 +{
19 + use ClientTrait;
20 +
21 + /**
22 + * @var array Default request options
23 + */
24 + private $config;
25 +
26 + /**
27 + * Clients accept an array of constructor parameters.
28 + *
29 + * Here's an example of creating a client using a base_uri and an array of
30 + * default request options to apply to each request:
31 + *
32 + * $client = new Client([
33 + * 'base_uri' => 'http://www.foo.com/1.0/',
34 + * 'timeout' => 0,
35 + * 'allow_redirects' => false,
36 + * 'proxy' => '192.168.16.1:10'
37 + * ]);
38 + *
39 + * Client configuration settings include the following options:
40 + *
41 + * - handler: (callable) Function that transfers HTTP requests over the
42 + * wire. The function is called with a Psr7\Http\Message\RequestInterface
43 + * and array of transfer options, and must return a
44 + * GuzzleHttp\Promise\PromiseInterface that is fulfilled with a
45 + * Psr7\Http\Message\ResponseInterface on success.
46 + * If no handler is provided, a default handler will be created
47 + * that enables all of the request options below by attaching all of the
48 + * default middleware to the handler.
49 + * - base_uri: (string|UriInterface) Base URI of the client that is merged
50 + * into relative URIs. Can be a string or instance of UriInterface.
51 + * - **: any request option
52 + *
53 + * @param array $config Client configuration settings.
54 + *
55 + * @see RequestOptions for a list of available request options.
56 + */
57 + public function __construct(array $config = [])
58 + {
59 + if (!isset($config['handler'])) {
60 + $config['handler'] = HandlerStack::create();
61 + } elseif (!\is_callable($config['handler'])) {
62 + throw new InvalidArgumentException('handler must be a callable');
63 + }
64 +
65 + // Convert the base_uri to a UriInterface
66 + if (isset($config['base_uri'])) {
67 + $config['base_uri'] = Psr7\Utils::uriFor($config['base_uri']);
68 + }
69 +
70 + $this->configureDefaults($config);
71 + }
72 +
73 + /**
74 + * @param string $method
75 + * @param array $args
76 + *
77 + * @return PromiseInterface|ResponseInterface
78 + *
79 + * @deprecated Client::__call will be removed in guzzlehttp/guzzle:8.0.
80 + */
81 + public function __call($method, $args)
82 + {
83 + if (\count($args) < 1) {
84 + throw new InvalidArgumentException('Magic request methods require a URI and optional options array');
85 + }
86 +
87 + $uri = $args[0];
88 + $opts = $args[1] ?? [];
89 +
90 + return \substr($method, -5) === 'Async'
91 + ? $this->requestAsync(\substr($method, 0, -5), $uri, $opts)
92 + : $this->request($method, $uri, $opts);
93 + }
94 +
95 + /**
96 + * Asynchronously send an HTTP request.
97 + *
98 + * @param array $options Request options to apply to the given
99 + * request and to the transfer. See \GuzzleHttp\RequestOptions.
100 + */
101 + public function sendAsync(RequestInterface $request, array $options = []): PromiseInterface
102 + {
103 + // Merge the base URI into the request URI if needed.
104 + $options = $this->prepareDefaults($options);
105 +
106 + return $this->transfer(
107 + $request->withUri($this->buildUri($request->getUri(), $options), $request->hasHeader('Host')),
108 + $options
109 + );
110 + }
111 +
112 + /**
113 + * Send an HTTP request.
114 + *
115 + * @param array $options Request options to apply to the given
116 + * request and to the transfer. See \GuzzleHttp\RequestOptions.
117 + *
118 + * @throws GuzzleException
119 + */
120 + public function send(RequestInterface $request, array $options = []): ResponseInterface
121 + {
122 + $options[RequestOptions::SYNCHRONOUS] = true;
123 +
124 + return $this->sendAsync($request, $options)->wait();
125 + }
126 +
127 + /**
128 + * The HttpClient PSR (PSR-18) specify this method.
129 + *
130 + * {@inheritDoc}
131 + */
132 + public function sendRequest(RequestInterface $request): ResponseInterface
133 + {
134 + $options[RequestOptions::SYNCHRONOUS] = true;
135 + $options[RequestOptions::ALLOW_REDIRECTS] = false;
136 + $options[RequestOptions::HTTP_ERRORS] = false;
137 +
138 + return $this->sendAsync($request, $options)->wait();
139 + }
140 +
141 + /**
142 + * Create and send an asynchronous HTTP request.
143 + *
144 + * Use an absolute path to override the base path of the client, or a
145 + * relative path to append to the base path of the client. The URL can
146 + * contain the query string as well. Use an array to provide a URL
147 + * template and additional variables to use in the URL template expansion.
148 + *
149 + * @param string $method HTTP method
150 + * @param string|UriInterface $uri URI object or string.
151 + * @param array $options Request options to apply. See \GuzzleHttp\RequestOptions.
152 + */
153 + public function requestAsync(string $method, $uri = '', array $options = []): PromiseInterface
154 + {
155 + $options = $this->prepareDefaults($options);
156 + // Remove request modifying parameter because it can be done up-front.
157 + $headers = $options['headers'] ?? [];
158 + $body = $options['body'] ?? null;
159 + $version = $options['version'] ?? '1.1';
160 + // Merge the URI into the base URI.
161 + $uri = $this->buildUri(Psr7\Utils::uriFor($uri), $options);
162 + if (\is_array($body)) {
163 + throw $this->invalidBody();
164 + }
165 + $request = new Psr7\Request($method, $uri, $headers, $body, $version);
166 + // Remove the option so that they are not doubly-applied.
167 + unset($options['headers'], $options['body'], $options['version']);
168 +
169 + return $this->transfer($request, $options);
170 + }
171 +
172 + /**
173 + * Create and send an HTTP request.
174 + *
175 + * Use an absolute path to override the base path of the client, or a
176 + * relative path to append to the base path of the client. The URL can
177 + * contain the query string as well.
178 + *
179 + * @param string $method HTTP method.
180 + * @param string|UriInterface $uri URI object or string.
181 + * @param array $options Request options to apply. See \GuzzleHttp\RequestOptions.
182 + *
183 + * @throws GuzzleException
184 + */
185 + public function request(string $method, $uri = '', array $options = []): ResponseInterface
186 + {
187 + $options[RequestOptions::SYNCHRONOUS] = true;
188 +
189 + return $this->requestAsync($method, $uri, $options)->wait();
190 + }
191 +
192 + /**
193 + * Get a client configuration option.
194 + *
195 + * These options include default request options of the client, a "handler"
196 + * (if utilized by the concrete client), and a "base_uri" if utilized by
197 + * the concrete client.
198 + *
199 + * @param string|null $option The config option to retrieve.
200 + *
201 + * @return mixed
202 + *
203 + * @deprecated Client::getConfig will be removed in guzzlehttp/guzzle:8.0.
204 + */
205 + public function getConfig(?string $option = null)
206 + {
207 + return $option === null
208 + ? $this->config
209 + : ($this->config[$option] ?? null);
210 + }
211 +
212 + private function buildUri(UriInterface $uri, array $config): UriInterface
213 + {
214 + if (isset($config['base_uri'])) {
215 + $uri = Psr7\UriResolver::resolve(Psr7\Utils::uriFor($config['base_uri']), $uri);
216 + }
217 +
218 + if (isset($config['idn_conversion']) && ($config['idn_conversion'] !== false)) {
219 + $idnOptions = ($config['idn_conversion'] === true) ? \IDNA_DEFAULT : $config['idn_conversion'];
220 + $uri = Utils::idnUriConvert($uri, $idnOptions);
221 + }
222 +
223 + return $uri->getScheme() === '' && $uri->getHost() !== '' ? $uri->withScheme('http') : $uri;
224 + }
225 +
226 + /**
227 + * Configures the default options for a client.
228 + */
229 + private function configureDefaults(array $config): void
230 + {
231 + $defaults = [
232 + 'allow_redirects' => RedirectMiddleware::$defaultSettings,
233 + 'http_errors' => true,
234 + 'decode_content' => true,
235 + 'verify' => true,
236 + 'cookies' => false,
237 + 'idn_conversion' => false,
238 + ];
239 +
240 + // Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set.
241 +
242 + // We can only trust the HTTP_PROXY environment variable in a CLI
243 + // process due to the fact that PHP has no reliable mechanism to
244 + // get environment variables that start with "HTTP_".
245 + if (\PHP_SAPI === 'cli' && ($proxy = Utils::getenv('HTTP_PROXY'))) {
246 + $defaults['proxy']['http'] = $proxy;
247 + }
248 +
249 + if ($proxy = Utils::getenv('HTTPS_PROXY')) {
250 + $defaults['proxy']['https'] = $proxy;
251 + }
252 +
253 + if ($noProxy = Utils::getenv('NO_PROXY')) {
254 + $cleanedNoProxy = \str_replace(' ', '', $noProxy);
255 + $defaults['proxy']['no'] = \explode(',', $cleanedNoProxy);
256 + }
257 +
258 + $this->config = $config + $defaults;
259 +
260 + if (!empty($config['cookies']) && $config['cookies'] === true) {
261 + $this->config['cookies'] = new CookieJar();
262 + }
263 +
264 + // Add the default user-agent header.
265 + if (!isset($this->config['headers'])) {
266 + $this->config['headers'] = ['User-Agent' => Utils::defaultUserAgent()];
267 + } else {
268 + // Add the User-Agent header if one was not already set.
269 + foreach (\array_keys($this->config['headers']) as $name) {
270 + if (\strtolower($name) === 'user-agent') {
271 + return;
272 + }
273 + }
274 + $this->config['headers']['User-Agent'] = Utils::defaultUserAgent();
275 + }
276 + }
277 +
278 + /**
279 + * Merges default options into the array.
280 + *
281 + * @param array $options Options to modify by reference
282 + */
283 + private function prepareDefaults(array $options): array
284 + {
285 + $defaults = $this->config;
286 +
287 + if (!empty($defaults['headers'])) {
288 + // Default headers are only added if they are not present.
289 + $defaults['_conditional'] = $defaults['headers'];
290 + unset($defaults['headers']);
291 + }
292 +
293 + // Special handling for headers is required as they are added as
294 + // conditional headers and as headers passed to a request ctor.
295 + if (\array_key_exists('headers', $options)) {
296 + // Allows default headers to be unset.
297 + if ($options['headers'] === null) {
298 + $defaults['_conditional'] = [];
299 + unset($options['headers']);
300 + } elseif (!\is_array($options['headers'])) {
301 + throw new InvalidArgumentException('headers must be an array');
302 + }
303 + }
304 +
305 + // Shallow merge defaults underneath options.
306 + $result = $options + $defaults;
307 +
308 + // Remove null values.
309 + foreach ($result as $k => $v) {
310 + if ($v === null) {
311 + unset($result[$k]);
312 + }
313 + }
314 +
315 + return $result;
316 + }
317 +
318 + /**
319 + * Transfers the given request and applies request options.
320 + *
321 + * The URI of the request is not modified and the request options are used
322 + * as-is without merging in default options.
323 + *
324 + * @param array $options See \GuzzleHttp\RequestOptions.
325 + */
326 + private function transfer(RequestInterface $request, array $options): PromiseInterface
327 + {
328 + $request = $this->applyOptions($request, $options);
329 + /** @var HandlerStack $handler */
330 + $handler = $options['handler'];
331 +
332 + try {
333 + return P\Create::promiseFor($handler($request, $options));
334 + } catch (\Exception $e) {
335 + return P\Create::rejectionFor($e);
336 + }
337 + }
338 +
339 + /**
340 + * Applies the array of request options to a request.
341 + */
342 + private function applyOptions(RequestInterface $request, array &$options): RequestInterface
343 + {
344 + $modify = [
345 + 'set_headers' => [],
346 + ];
347 +
348 + if (isset($options['headers'])) {
349 + if (array_keys($options['headers']) === range(0, count($options['headers']) - 1)) {
350 + throw new InvalidArgumentException('The headers array must have header name as keys.');
351 + }
352 + $modify['set_headers'] = $options['headers'];
353 + unset($options['headers']);
354 + }
355 +
356 + if (isset($options['form_params'])) {
357 + if (isset($options['multipart'])) {
358 + throw new InvalidArgumentException('You cannot use '
359 + .'form_params and multipart at the same time. Use the '
360 + .'form_params option if you want to send application/'
361 + .'x-www-form-urlencoded requests, and the multipart '
362 + .'option to send multipart/form-data requests.');
363 + }
364 + $options['body'] = \http_build_query($options['form_params'], '', '&');
365 + unset($options['form_params']);
366 + // Ensure that we don't have the header in different case and set the new value.
367 + $options['_conditional'] = Psr7\Utils::caselessRemove(['Content-Type'], $options['_conditional']);
368 + $options['_conditional']['Content-Type'] = 'application/x-www-form-urlencoded';
369 + }
370 +
371 + if (isset($options['multipart'])) {
372 + $options['body'] = new Psr7\MultipartStream($options['multipart']);
373 + unset($options['multipart']);
374 + }
375 +
376 + if (isset($options['json'])) {
377 + $options['body'] = Utils::jsonEncode($options['json']);
378 + unset($options['json']);
379 + // Ensure that we don't have the header in different case and set the new value.
380 + $options['_conditional'] = Psr7\Utils::caselessRemove(['Content-Type'], $options['_conditional']);
381 + $options['_conditional']['Content-Type'] = 'application/json';
382 + }
383 +
384 + if (!empty($options['decode_content'])
385 + && $options['decode_content'] !== true
386 + ) {
387 + // Ensure that we don't have the header in different case and set the new value.
388 + $options['_conditional'] = Psr7\Utils::caselessRemove(['Accept-Encoding'], $options['_conditional']);
389 + $modify['set_headers']['Accept-Encoding'] = $options['decode_content'];
390 + }
391 +
392 + if (isset($options['body'])) {
393 + if (\is_array($options['body'])) {
394 + throw $this->invalidBody();
395 + }
396 + $modify['body'] = Psr7\Utils::streamFor($options['body']);
397 + unset($options['body']);
398 + }
399 +
400 + if (!empty($options['auth']) && \is_array($options['auth'])) {
401 + $value = $options['auth'];
402 + $type = isset($value[2]) ? \strtolower($value[2]) : 'basic';
403 + switch ($type) {
404 + case 'basic':
405 + // Ensure that we don't have the header in different case and set the new value.
406 + $modify['set_headers'] = Psr7\Utils::caselessRemove(['Authorization'], $modify['set_headers']);
407 + $modify['set_headers']['Authorization'] = 'Basic '
408 + .\base64_encode("$value[0]:$value[1]");
409 + break;
410 + case 'digest':
411 + // @todo: Do not rely on curl
412 + $options['curl'][\CURLOPT_HTTPAUTH] = \CURLAUTH_DIGEST;
413 + $options['curl'][\CURLOPT_USERPWD] = "$value[0]:$value[1]";
414 + break;
415 + case 'ntlm':
416 + $options['curl'][\CURLOPT_HTTPAUTH] = \CURLAUTH_NTLM;
417 + $options['curl'][\CURLOPT_USERPWD] = "$value[0]:$value[1]";
418 + break;
419 + }
420 + }
421 +
422 + if (isset($options['query'])) {
423 + $value = $options['query'];
424 + if (\is_array($value)) {
425 + $value = \http_build_query($value, '', '&', \PHP_QUERY_RFC3986);
426 + }
427 + if (!\is_string($value)) {
428 + throw new InvalidArgumentException('query must be a string or array');
429 + }
430 + $modify['query'] = $value;
431 + unset($options['query']);
432 + }
433 +
434 + // Ensure that sink is not an invalid value.
435 + if (isset($options['sink'])) {
436 + // TODO: Add more sink validation?
437 + if (\is_bool($options['sink'])) {
438 + throw new InvalidArgumentException('sink must not be a boolean');
439 + }
440 + }
441 +
442 + if (isset($options['version'])) {
443 + $modify['version'] = $options['version'];
444 + }
445 +
446 + $request = Psr7\Utils::modifyRequest($request, $modify);
447 + if ($request->getBody() instanceof Psr7\MultipartStream) {
448 + // Use a multipart/form-data POST if a Content-Type is not set.
449 + // Ensure that we don't have the header in different case and set the new value.
450 + $options['_conditional'] = Psr7\Utils::caselessRemove(['Content-Type'], $options['_conditional']);
451 + $options['_conditional']['Content-Type'] = 'multipart/form-data; boundary='
452 + .$request->getBody()->getBoundary();
453 + }
454 +
455 + // Merge in conditional headers if they are not present.
456 + if (isset($options['_conditional'])) {
457 + // Build up the changes so it's in a single clone of the message.
458 + $modify = [];
459 + foreach ($options['_conditional'] as $k => $v) {
460 + if (!$request->hasHeader($k)) {
461 + $modify['set_headers'][$k] = $v;
462 + }
463 + }
464 + $request = Psr7\Utils::modifyRequest($request, $modify);
465 + // Don't pass this internal value along to middleware/handlers.
466 + unset($options['_conditional']);
467 + }
468 +
469 + return $request;
470 + }
471 +
472 + /**
473 + * Return an InvalidArgumentException with pre-set message.
474 + */
475 + private function invalidBody(): InvalidArgumentException
476 + {
477 + return new InvalidArgumentException('Passing in the "body" request '
478 + .'option as an array to send a request is not supported. '
479 + .'Please use the "form_params" request option to send a '
480 + .'application/x-www-form-urlencoded request, or the "multipart" '
481 + .'request option to send a multipart/form-data request.');
482 + }
483 +}