[e3d4e0a] | 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 | }
|
---|