Completed
Pull Request — master (#421)
by Maxence
03:59
created
lib/Vendor/GuzzleHttp/ClientInterface.php 2 patches
Braces   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -11,8 +11,7 @@
 block discarded – undo
11 11
 /**
12 12
  * Client interface for sending HTTP requests.
13 13
  */
14
-interface ClientInterface
15
-{
14
+interface ClientInterface {
16 15
     /**
17 16
      * The Guzzle major version.
18 17
      */
Please login to merge, or discard this patch.
Indentation   +63 added lines, -63 removed lines patch added patch discarded remove patch
@@ -12,67 +12,67 @@
 block discarded – undo
12 12
  */
13 13
 interface ClientInterface
14 14
 {
15
-    /**
16
-     * The Guzzle major version.
17
-     */
18
-    public const MAJOR_VERSION = 7;
19
-    /**
20
-     * Send an HTTP request.
21
-     *
22
-     * @param RequestInterface $request Request to send
23
-     * @param array            $options Request options to apply to the given
24
-     *                                  request and to the transfer.
25
-     *
26
-     * @throws GuzzleException
27
-     */
28
-    public function send(RequestInterface $request, array $options = []) : ResponseInterface;
29
-    /**
30
-     * Asynchronously send an HTTP request.
31
-     *
32
-     * @param RequestInterface $request Request to send
33
-     * @param array            $options Request options to apply to the given
34
-     *                                  request and to the transfer.
35
-     */
36
-    public function sendAsync(RequestInterface $request, array $options = []) : PromiseInterface;
37
-    /**
38
-     * Create and send an HTTP request.
39
-     *
40
-     * Use an absolute path to override the base path of the client, or a
41
-     * relative path to append to the base path of the client. The URL can
42
-     * contain the query string as well.
43
-     *
44
-     * @param string              $method  HTTP method.
45
-     * @param string|UriInterface $uri     URI object or string.
46
-     * @param array               $options Request options to apply.
47
-     *
48
-     * @throws GuzzleException
49
-     */
50
-    public function request(string $method, $uri, array $options = []) : ResponseInterface;
51
-    /**
52
-     * Create and send an asynchronous HTTP request.
53
-     *
54
-     * Use an absolute path to override the base path of the client, or a
55
-     * relative path to append to the base path of the client. The URL can
56
-     * contain the query string as well. Use an array to provide a URL
57
-     * template and additional variables to use in the URL template expansion.
58
-     *
59
-     * @param string              $method  HTTP method
60
-     * @param string|UriInterface $uri     URI object or string.
61
-     * @param array               $options Request options to apply.
62
-     */
63
-    public function requestAsync(string $method, $uri, array $options = []) : PromiseInterface;
64
-    /**
65
-     * Get a client configuration option.
66
-     *
67
-     * These options include default request options of the client, a "handler"
68
-     * (if utilized by the concrete client), and a "base_uri" if utilized by
69
-     * the concrete client.
70
-     *
71
-     * @param string|null $option The config option to retrieve.
72
-     *
73
-     * @return mixed
74
-     *
75
-     * @deprecated ClientInterface::getConfig will be removed in guzzlehttp/guzzle:8.0.
76
-     */
77
-    public function getConfig(?string $option = null);
15
+	/**
16
+	 * The Guzzle major version.
17
+	 */
18
+	public const MAJOR_VERSION = 7;
19
+	/**
20
+	 * Send an HTTP request.
21
+	 *
22
+	 * @param RequestInterface $request Request to send
23
+	 * @param array            $options Request options to apply to the given
24
+	 *                                  request and to the transfer.
25
+	 *
26
+	 * @throws GuzzleException
27
+	 */
28
+	public function send(RequestInterface $request, array $options = []) : ResponseInterface;
29
+	/**
30
+	 * Asynchronously send an HTTP request.
31
+	 *
32
+	 * @param RequestInterface $request Request to send
33
+	 * @param array            $options Request options to apply to the given
34
+	 *                                  request and to the transfer.
35
+	 */
36
+	public function sendAsync(RequestInterface $request, array $options = []) : PromiseInterface;
37
+	/**
38
+	 * Create and send an HTTP request.
39
+	 *
40
+	 * Use an absolute path to override the base path of the client, or a
41
+	 * relative path to append to the base path of the client. The URL can
42
+	 * contain the query string as well.
43
+	 *
44
+	 * @param string              $method  HTTP method.
45
+	 * @param string|UriInterface $uri     URI object or string.
46
+	 * @param array               $options Request options to apply.
47
+	 *
48
+	 * @throws GuzzleException
49
+	 */
50
+	public function request(string $method, $uri, array $options = []) : ResponseInterface;
51
+	/**
52
+	 * Create and send an asynchronous HTTP request.
53
+	 *
54
+	 * Use an absolute path to override the base path of the client, or a
55
+	 * relative path to append to the base path of the client. The URL can
56
+	 * contain the query string as well. Use an array to provide a URL
57
+	 * template and additional variables to use in the URL template expansion.
58
+	 *
59
+	 * @param string              $method  HTTP method
60
+	 * @param string|UriInterface $uri     URI object or string.
61
+	 * @param array               $options Request options to apply.
62
+	 */
63
+	public function requestAsync(string $method, $uri, array $options = []) : PromiseInterface;
64
+	/**
65
+	 * Get a client configuration option.
66
+	 *
67
+	 * These options include default request options of the client, a "handler"
68
+	 * (if utilized by the concrete client), and a "base_uri" if utilized by
69
+	 * the concrete client.
70
+	 *
71
+	 * @param string|null $option The config option to retrieve.
72
+	 *
73
+	 * @return mixed
74
+	 *
75
+	 * @deprecated ClientInterface::getConfig will be removed in guzzlehttp/guzzle:8.0.
76
+	 */
77
+	public function getConfig(?string $option = null);
78 78
 }
Please login to merge, or discard this patch.
lib/Vendor/GuzzleHttp/Handler/StreamHandler.php 3 patches
Braces   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -20,8 +20,7 @@
 block discarded – undo
20 20
  *
21 21
  * @final
22 22
  */
23
-class StreamHandler
24
-{
23
+class StreamHandler {
25 24
     /**
26 25
      * @var array
27 26
      */
Please login to merge, or discard this patch.
Spacing   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -133,7 +133,7 @@  discard block
 block discarded – undo
133 133
                     // Fix content-length header
134 134
                     if (isset($normalizedKeys['content-length'])) {
135 135
                         $headers['x-encoded-content-length'] = $headers[$normalizedKeys['content-length']];
136
-                        $length = (int) $stream->getSize();
136
+                        $length = (int)$stream->getSize();
137 137
                         if ($length === 0) {
138 138
                             unset($headers[$normalizedKeys['content-length']]);
139 139
                         } else {
@@ -159,7 +159,7 @@  discard block
 block discarded – undo
159 159
         // that number of bytes has been read. This can prevent infinitely
160 160
         // reading from a stream when dealing with servers that do not honor
161 161
         // Connection: Close headers.
162
-        Psr7\Utils::copyToStream($source, $sink, \strlen($contentLength) > 0 && (int) $contentLength > 0 ? (int) $contentLength : -1);
162
+        Psr7\Utils::copyToStream($source, $sink, \strlen($contentLength) > 0 && (int)$contentLength > 0 ? (int)$contentLength : -1);
163 163
         $sink->seek(0);
164 164
         $source->close();
165 165
         return $sink;
@@ -176,7 +176,7 @@  discard block
 block discarded – undo
176 176
     private function createResource(callable $callback)
177 177
     {
178 178
         $errors = [];
179
-        \set_error_handler(static function ($_, $msg, $file, $line) use(&$errors) : bool {
179
+        \set_error_handler(static function($_, $msg, $file, $line) use(&$errors) : bool {
180 180
             $errors[] = ['message' => $msg, 'file' => $file, 'line' => $line];
181 181
             return \true;
182 182
         });
@@ -189,7 +189,7 @@  discard block
 block discarded – undo
189 189
             $message = 'Error creating resource: ';
190 190
             foreach ($errors as $err) {
191 191
                 foreach ($err as $key => $value) {
192
-                    $message .= "[{$key}] {$value}" . \PHP_EOL;
192
+                    $message .= "[{$key}] {$value}".\PHP_EOL;
193 193
                 }
194 194
             }
195 195
             throw new \RuntimeException(\trim($message));
@@ -241,18 +241,18 @@  discard block
 block discarded – undo
241 241
             throw new \InvalidArgumentException('Microsoft NTLM authentication only supported with curl handler');
242 242
         }
243 243
         $uri = $this->resolveHost($request, $options);
244
-        $contextResource = $this->createResource(static function () use($context, $params) {
244
+        $contextResource = $this->createResource(static function() use($context, $params) {
245 245
             return \stream_context_create($context, $params);
246 246
         });
247
-        return $this->createResource(function () use($uri, &$http_response_header, $contextResource, $context, $options, $request) {
248
-            $resource = @\fopen((string) $uri, 'r', \false, $contextResource);
247
+        return $this->createResource(function() use($uri, &$http_response_header, $contextResource, $context, $options, $request) {
248
+            $resource = @\fopen((string)$uri, 'r', \false, $contextResource);
249 249
             $this->lastHeaders = $http_response_header ?? [];
250 250
             if (\false === $resource) {
251 251
                 throw new ConnectException(\sprintf('Connection refused for URI %s', $uri), $request, null, $context);
252 252
             }
253 253
             if (isset($options['read_timeout'])) {
254 254
                 $readTimeout = $options['read_timeout'];
255
-                $sec = (int) $readTimeout;
255
+                $sec = (int)$readTimeout;
256 256
                 $usec = ($readTimeout - $sec) * 100000;
257 257
                 \stream_set_timeout($resource, $sec, $usec);
258 258
             }
@@ -275,7 +275,7 @@  discard block
 block discarded – undo
275 275
                 if (\false === $records || !isset($records[0]['ipv6'])) {
276 276
                     throw new ConnectException(\sprintf("Could not resolve IPv6 address for host '%s'", $uri->getHost()), $request);
277 277
                 }
278
-                return $uri->withHost('[' . $records[0]['ipv6'] . ']');
278
+                return $uri->withHost('['.$records[0]['ipv6'].']');
279 279
             }
280 280
         }
281 281
         return $uri;
@@ -289,7 +289,7 @@  discard block
 block discarded – undo
289 289
             }
290 290
         }
291 291
         $context = ['http' => ['method' => $request->getMethod(), 'header' => $headers, 'protocol_version' => $request->getProtocolVersion(), 'ignore_errors' => \true, 'follow_location' => 0], 'ssl' => ['peer_name' => $request->getUri()->getHost()]];
292
-        $body = (string) $request->getBody();
292
+        $body = (string)$request->getBody();
293 293
         if ('' !== $body) {
294 294
             $context['http']['content'] = $body;
295 295
             // Prevent the HTTP handler from adding a Content-Type header.
@@ -407,7 +407,7 @@  discard block
 block discarded – undo
407 407
      */
408 408
     private function add_progress(RequestInterface $request, array &$options, $value, array &$params) : void
409 409
     {
410
-        self::addNotification($params, static function ($code, $a, $b, $c, $transferred, $total) use($value) {
410
+        self::addNotification($params, static function($code, $a, $b, $c, $transferred, $total) use($value) {
411 411
             if ($code == \STREAM_NOTIFY_PROGRESS) {
412 412
                 // The upload progress cannot be determined. Use 0 for cURL compatibility:
413 413
                 // https://curl.se/libcurl/c/CURLOPT_PROGRESSFUNCTION.html
@@ -426,11 +426,11 @@  discard block
 block discarded – undo
426 426
         static $map = [\STREAM_NOTIFY_CONNECT => 'CONNECT', \STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED', \STREAM_NOTIFY_AUTH_RESULT => 'AUTH_RESULT', \STREAM_NOTIFY_MIME_TYPE_IS => 'MIME_TYPE_IS', \STREAM_NOTIFY_FILE_SIZE_IS => 'FILE_SIZE_IS', \STREAM_NOTIFY_REDIRECTED => 'REDIRECTED', \STREAM_NOTIFY_PROGRESS => 'PROGRESS', \STREAM_NOTIFY_FAILURE => 'FAILURE', \STREAM_NOTIFY_COMPLETED => 'COMPLETED', \STREAM_NOTIFY_RESOLVE => 'RESOLVE'];
427 427
         static $args = ['severity', 'message', 'message_code', 'bytes_transferred', 'bytes_max'];
428 428
         $value = Utils::debugResource($value);
429
-        $ident = $request->getMethod() . ' ' . $request->getUri()->withFragment('');
430
-        self::addNotification($params, static function (int $code, ...$passed) use($ident, $value, $map, $args) : void {
429
+        $ident = $request->getMethod().' '.$request->getUri()->withFragment('');
430
+        self::addNotification($params, static function(int $code, ...$passed) use($ident, $value, $map, $args) : void {
431 431
             \fprintf($value, '<%s> [%s] ', $ident, $map[$code]);
432 432
             foreach (\array_filter($passed) as $i => $v) {
433
-                \fwrite($value, $args[$i] . ': "' . $v . '" ');
433
+                \fwrite($value, $args[$i].': "'.$v.'" ');
434 434
             }
435 435
             \fwrite($value, "\n");
436 436
         });
@@ -446,7 +446,7 @@  discard block
 block discarded – undo
446 446
     }
447 447
     private static function callArray(array $functions) : callable
448 448
     {
449
-        return static function (...$args) use($functions) {
449
+        return static function(...$args) use($functions) {
450 450
             foreach ($functions as $fn) {
451 451
                 $fn(...$args);
452 452
             }
Please login to merge, or discard this patch.
Indentation   +435 added lines, -435 removed lines patch added patch discarded remove patch
@@ -21,439 +21,439 @@
 block discarded – undo
21 21
  */
22 22
 class StreamHandler
23 23
 {
24
-    /**
25
-     * @var array
26
-     */
27
-    private $lastHeaders = [];
28
-    /**
29
-     * Sends an HTTP request.
30
-     *
31
-     * @param RequestInterface $request Request to send.
32
-     * @param array            $options Request transfer options.
33
-     */
34
-    public function __invoke(RequestInterface $request, array $options) : PromiseInterface
35
-    {
36
-        // Sleep if there is a delay specified.
37
-        if (isset($options['delay'])) {
38
-            \usleep($options['delay'] * 1000);
39
-        }
40
-        $protocolVersion = $request->getProtocolVersion();
41
-        if ('1.0' !== $protocolVersion && '1.1' !== $protocolVersion) {
42
-            throw new ConnectException(\sprintf('HTTP/%s is not supported by the stream handler.', $protocolVersion), $request);
43
-        }
44
-        $startTime = isset($options['on_stats']) ? Utils::currentTime() : null;
45
-        try {
46
-            // Does not support the expect header.
47
-            $request = $request->withoutHeader('Expect');
48
-            // Append a content-length header if body size is zero to match
49
-            // cURL's behavior.
50
-            if (0 === $request->getBody()->getSize()) {
51
-                $request = $request->withHeader('Content-Length', '0');
52
-            }
53
-            return $this->createResponse($request, $options, $this->createStream($request, $options), $startTime);
54
-        } catch (\InvalidArgumentException $e) {
55
-            throw $e;
56
-        } catch (\Exception $e) {
57
-            // Determine if the error was a networking error.
58
-            $message = $e->getMessage();
59
-            // This list can probably get more comprehensive.
60
-            if (\false !== \strpos($message, 'getaddrinfo') || \false !== \strpos($message, 'Connection refused') || \false !== \strpos($message, "couldn't connect to host") || \false !== \strpos($message, 'connection attempt failed')) {
61
-                $e = new ConnectException($e->getMessage(), $request, $e);
62
-            } else {
63
-                $e = RequestException::wrapException($request, $e);
64
-            }
65
-            $this->invokeStats($options, $request, $startTime, null, $e);
66
-            return P\Create::rejectionFor($e);
67
-        }
68
-    }
69
-    private function invokeStats(array $options, RequestInterface $request, ?float $startTime, ?ResponseInterface $response = null, ?\Throwable $error = null) : void
70
-    {
71
-        if (isset($options['on_stats'])) {
72
-            $stats = new TransferStats($request, $response, Utils::currentTime() - $startTime, $error, []);
73
-            $options['on_stats']($stats);
74
-        }
75
-    }
76
-    /**
77
-     * @param resource $stream
78
-     */
79
-    private function createResponse(RequestInterface $request, array $options, $stream, ?float $startTime) : PromiseInterface
80
-    {
81
-        $hdrs = $this->lastHeaders;
82
-        $this->lastHeaders = [];
83
-        try {
84
-            [$ver, $status, $reason, $headers] = HeaderProcessor::parseHeaders($hdrs);
85
-        } catch (\Exception $e) {
86
-            return P\Create::rejectionFor(new RequestException('An error was encountered while creating the response', $request, null, $e));
87
-        }
88
-        [$stream, $headers] = $this->checkDecode($options, $headers, $stream);
89
-        $stream = Psr7\Utils::streamFor($stream);
90
-        $sink = $stream;
91
-        if (\strcasecmp('HEAD', $request->getMethod())) {
92
-            $sink = $this->createSink($stream, $options);
93
-        }
94
-        try {
95
-            $response = new Psr7\Response($status, $headers, $sink, $ver, $reason);
96
-        } catch (\Exception $e) {
97
-            return P\Create::rejectionFor(new RequestException('An error was encountered while creating the response', $request, null, $e));
98
-        }
99
-        if (isset($options['on_headers'])) {
100
-            try {
101
-                $options['on_headers']($response);
102
-            } catch (\Exception $e) {
103
-                return P\Create::rejectionFor(new RequestException('An error was encountered during the on_headers event', $request, $response, $e));
104
-            }
105
-        }
106
-        // Do not drain when the request is a HEAD request because they have
107
-        // no body.
108
-        if ($sink !== $stream) {
109
-            $this->drain($stream, $sink, $response->getHeaderLine('Content-Length'));
110
-        }
111
-        $this->invokeStats($options, $request, $startTime, $response, null);
112
-        return new FulfilledPromise($response);
113
-    }
114
-    private function createSink(StreamInterface $stream, array $options) : StreamInterface
115
-    {
116
-        if (!empty($options['stream'])) {
117
-            return $stream;
118
-        }
119
-        $sink = $options['sink'] ?? Psr7\Utils::tryFopen('php://temp', 'r+');
120
-        return \is_string($sink) ? new Psr7\LazyOpenStream($sink, 'w+') : Psr7\Utils::streamFor($sink);
121
-    }
122
-    /**
123
-     * @param resource $stream
124
-     */
125
-    private function checkDecode(array $options, array $headers, $stream) : array
126
-    {
127
-        // Automatically decode responses when instructed.
128
-        if (!empty($options['decode_content'])) {
129
-            $normalizedKeys = Utils::normalizeHeaderKeys($headers);
130
-            if (isset($normalizedKeys['content-encoding'])) {
131
-                $encoding = $headers[$normalizedKeys['content-encoding']];
132
-                if ($encoding[0] === 'gzip' || $encoding[0] === 'deflate') {
133
-                    $stream = new Psr7\InflateStream(Psr7\Utils::streamFor($stream));
134
-                    $headers['x-encoded-content-encoding'] = $headers[$normalizedKeys['content-encoding']];
135
-                    // Remove content-encoding header
136
-                    unset($headers[$normalizedKeys['content-encoding']]);
137
-                    // Fix content-length header
138
-                    if (isset($normalizedKeys['content-length'])) {
139
-                        $headers['x-encoded-content-length'] = $headers[$normalizedKeys['content-length']];
140
-                        $length = (int) $stream->getSize();
141
-                        if ($length === 0) {
142
-                            unset($headers[$normalizedKeys['content-length']]);
143
-                        } else {
144
-                            $headers[$normalizedKeys['content-length']] = [$length];
145
-                        }
146
-                    }
147
-                }
148
-            }
149
-        }
150
-        return [$stream, $headers];
151
-    }
152
-    /**
153
-     * Drains the source stream into the "sink" client option.
154
-     *
155
-     * @param string $contentLength Header specifying the amount of
156
-     *                              data to read.
157
-     *
158
-     * @throws \RuntimeException when the sink option is invalid.
159
-     */
160
-    private function drain(StreamInterface $source, StreamInterface $sink, string $contentLength) : StreamInterface
161
-    {
162
-        // If a content-length header is provided, then stop reading once
163
-        // that number of bytes has been read. This can prevent infinitely
164
-        // reading from a stream when dealing with servers that do not honor
165
-        // Connection: Close headers.
166
-        Psr7\Utils::copyToStream($source, $sink, \strlen($contentLength) > 0 && (int) $contentLength > 0 ? (int) $contentLength : -1);
167
-        $sink->seek(0);
168
-        $source->close();
169
-        return $sink;
170
-    }
171
-    /**
172
-     * Create a resource and check to ensure it was created successfully
173
-     *
174
-     * @param callable $callback Callable that returns stream resource
175
-     *
176
-     * @return resource
177
-     *
178
-     * @throws \RuntimeException on error
179
-     */
180
-    private function createResource(callable $callback)
181
-    {
182
-        $errors = [];
183
-        \set_error_handler(static function ($_, $msg, $file, $line) use(&$errors) : bool {
184
-            $errors[] = ['message' => $msg, 'file' => $file, 'line' => $line];
185
-            return \true;
186
-        });
187
-        try {
188
-            $resource = $callback();
189
-        } finally {
190
-            \restore_error_handler();
191
-        }
192
-        if (!$resource) {
193
-            $message = 'Error creating resource: ';
194
-            foreach ($errors as $err) {
195
-                foreach ($err as $key => $value) {
196
-                    $message .= "[{$key}] {$value}" . \PHP_EOL;
197
-                }
198
-            }
199
-            throw new \RuntimeException(\trim($message));
200
-        }
201
-        return $resource;
202
-    }
203
-    /**
204
-     * @return resource
205
-     */
206
-    private function createStream(RequestInterface $request, array $options)
207
-    {
208
-        static $methods;
209
-        if (!$methods) {
210
-            $methods = \array_flip(\get_class_methods(__CLASS__));
211
-        }
212
-        if (!\in_array($request->getUri()->getScheme(), ['http', 'https'])) {
213
-            throw new RequestException(\sprintf("The scheme '%s' is not supported.", $request->getUri()->getScheme()), $request);
214
-        }
215
-        // HTTP/1.1 streams using the PHP stream wrapper require a
216
-        // Connection: close header
217
-        if ($request->getProtocolVersion() === '1.1' && !$request->hasHeader('Connection')) {
218
-            $request = $request->withHeader('Connection', 'close');
219
-        }
220
-        // Ensure SSL is verified by default
221
-        if (!isset($options['verify'])) {
222
-            $options['verify'] = \true;
223
-        }
224
-        $params = [];
225
-        $context = $this->getDefaultContext($request);
226
-        if (isset($options['on_headers']) && !\is_callable($options['on_headers'])) {
227
-            throw new \InvalidArgumentException('on_headers must be callable');
228
-        }
229
-        if (!empty($options)) {
230
-            foreach ($options as $key => $value) {
231
-                $method = "add_{$key}";
232
-                if (isset($methods[$method])) {
233
-                    $this->{$method}($request, $context, $value, $params);
234
-                }
235
-            }
236
-        }
237
-        if (isset($options['stream_context'])) {
238
-            if (!\is_array($options['stream_context'])) {
239
-                throw new \InvalidArgumentException('stream_context must be an array');
240
-            }
241
-            $context = \array_replace_recursive($context, $options['stream_context']);
242
-        }
243
-        // Microsoft NTLM authentication only supported with curl handler
244
-        if (isset($options['auth'][2]) && 'ntlm' === $options['auth'][2]) {
245
-            throw new \InvalidArgumentException('Microsoft NTLM authentication only supported with curl handler');
246
-        }
247
-        $uri = $this->resolveHost($request, $options);
248
-        $contextResource = $this->createResource(static function () use($context, $params) {
249
-            return \stream_context_create($context, $params);
250
-        });
251
-        return $this->createResource(function () use($uri, &$http_response_header, $contextResource, $context, $options, $request) {
252
-            $resource = @\fopen((string) $uri, 'r', \false, $contextResource);
253
-            $this->lastHeaders = $http_response_header ?? [];
254
-            if (\false === $resource) {
255
-                throw new ConnectException(\sprintf('Connection refused for URI %s', $uri), $request, null, $context);
256
-            }
257
-            if (isset($options['read_timeout'])) {
258
-                $readTimeout = $options['read_timeout'];
259
-                $sec = (int) $readTimeout;
260
-                $usec = ($readTimeout - $sec) * 100000;
261
-                \stream_set_timeout($resource, $sec, $usec);
262
-            }
263
-            return $resource;
264
-        });
265
-    }
266
-    private function resolveHost(RequestInterface $request, array $options) : UriInterface
267
-    {
268
-        $uri = $request->getUri();
269
-        if (isset($options['force_ip_resolve']) && !\filter_var($uri->getHost(), \FILTER_VALIDATE_IP)) {
270
-            if ('v4' === $options['force_ip_resolve']) {
271
-                $records = \dns_get_record($uri->getHost(), \DNS_A);
272
-                if (\false === $records || !isset($records[0]['ip'])) {
273
-                    throw new ConnectException(\sprintf("Could not resolve IPv4 address for host '%s'", $uri->getHost()), $request);
274
-                }
275
-                return $uri->withHost($records[0]['ip']);
276
-            }
277
-            if ('v6' === $options['force_ip_resolve']) {
278
-                $records = \dns_get_record($uri->getHost(), \DNS_AAAA);
279
-                if (\false === $records || !isset($records[0]['ipv6'])) {
280
-                    throw new ConnectException(\sprintf("Could not resolve IPv6 address for host '%s'", $uri->getHost()), $request);
281
-                }
282
-                return $uri->withHost('[' . $records[0]['ipv6'] . ']');
283
-            }
284
-        }
285
-        return $uri;
286
-    }
287
-    private function getDefaultContext(RequestInterface $request) : array
288
-    {
289
-        $headers = '';
290
-        foreach ($request->getHeaders() as $name => $value) {
291
-            foreach ($value as $val) {
292
-                $headers .= "{$name}: {$val}\r\n";
293
-            }
294
-        }
295
-        $context = ['http' => ['method' => $request->getMethod(), 'header' => $headers, 'protocol_version' => $request->getProtocolVersion(), 'ignore_errors' => \true, 'follow_location' => 0], 'ssl' => ['peer_name' => $request->getUri()->getHost()]];
296
-        $body = (string) $request->getBody();
297
-        if ('' !== $body) {
298
-            $context['http']['content'] = $body;
299
-            // Prevent the HTTP handler from adding a Content-Type header.
300
-            if (!$request->hasHeader('Content-Type')) {
301
-                $context['http']['header'] .= "Content-Type:\r\n";
302
-            }
303
-        }
304
-        $context['http']['header'] = \rtrim($context['http']['header']);
305
-        return $context;
306
-    }
307
-    /**
308
-     * @param mixed $value as passed via Request transfer options.
309
-     */
310
-    private function add_proxy(RequestInterface $request, array &$options, $value, array &$params) : void
311
-    {
312
-        $uri = null;
313
-        if (!\is_array($value)) {
314
-            $uri = $value;
315
-        } else {
316
-            $scheme = $request->getUri()->getScheme();
317
-            if (isset($value[$scheme])) {
318
-                if (!isset($value['no']) || !Utils::isHostInNoProxy($request->getUri()->getHost(), $value['no'])) {
319
-                    $uri = $value[$scheme];
320
-                }
321
-            }
322
-        }
323
-        if (!$uri) {
324
-            return;
325
-        }
326
-        $parsed = $this->parse_proxy($uri);
327
-        $options['http']['proxy'] = $parsed['proxy'];
328
-        if ($parsed['auth']) {
329
-            if (!isset($options['http']['header'])) {
330
-                $options['http']['header'] = [];
331
-            }
332
-            $options['http']['header'] .= "\r\nProxy-Authorization: {$parsed['auth']}";
333
-        }
334
-    }
335
-    /**
336
-     * Parses the given proxy URL to make it compatible with the format PHP's stream context expects.
337
-     */
338
-    private function parse_proxy(string $url) : array
339
-    {
340
-        $parsed = \parse_url($url);
341
-        if ($parsed !== \false && isset($parsed['scheme']) && $parsed['scheme'] === 'http') {
342
-            if (isset($parsed['host']) && isset($parsed['port'])) {
343
-                $auth = null;
344
-                if (isset($parsed['user']) && isset($parsed['pass'])) {
345
-                    $auth = \base64_encode("{$parsed['user']}:{$parsed['pass']}");
346
-                }
347
-                return ['proxy' => "tcp://{$parsed['host']}:{$parsed['port']}", 'auth' => $auth ? "Basic {$auth}" : null];
348
-            }
349
-        }
350
-        // Return proxy as-is.
351
-        return ['proxy' => $url, 'auth' => null];
352
-    }
353
-    /**
354
-     * @param mixed $value as passed via Request transfer options.
355
-     */
356
-    private function add_timeout(RequestInterface $request, array &$options, $value, array &$params) : void
357
-    {
358
-        if ($value > 0) {
359
-            $options['http']['timeout'] = $value;
360
-        }
361
-    }
362
-    /**
363
-     * @param mixed $value as passed via Request transfer options.
364
-     */
365
-    private function add_crypto_method(RequestInterface $request, array &$options, $value, array &$params) : void
366
-    {
367
-        if ($value === \STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT || $value === \STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT || $value === \STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT || \defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT') && $value === \STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT) {
368
-            $options['http']['crypto_method'] = $value;
369
-            return;
370
-        }
371
-        throw new \InvalidArgumentException('Invalid crypto_method request option: unknown version provided');
372
-    }
373
-    /**
374
-     * @param mixed $value as passed via Request transfer options.
375
-     */
376
-    private function add_verify(RequestInterface $request, array &$options, $value, array &$params) : void
377
-    {
378
-        if ($value === \false) {
379
-            $options['ssl']['verify_peer'] = \false;
380
-            $options['ssl']['verify_peer_name'] = \false;
381
-            return;
382
-        }
383
-        if (\is_string($value)) {
384
-            $options['ssl']['cafile'] = $value;
385
-            if (!\file_exists($value)) {
386
-                throw new \RuntimeException("SSL CA bundle not found: {$value}");
387
-            }
388
-        } elseif ($value !== \true) {
389
-            throw new \InvalidArgumentException('Invalid verify request option');
390
-        }
391
-        $options['ssl']['verify_peer'] = \true;
392
-        $options['ssl']['verify_peer_name'] = \true;
393
-        $options['ssl']['allow_self_signed'] = \false;
394
-    }
395
-    /**
396
-     * @param mixed $value as passed via Request transfer options.
397
-     */
398
-    private function add_cert(RequestInterface $request, array &$options, $value, array &$params) : void
399
-    {
400
-        if (\is_array($value)) {
401
-            $options['ssl']['passphrase'] = $value[1];
402
-            $value = $value[0];
403
-        }
404
-        if (!\file_exists($value)) {
405
-            throw new \RuntimeException("SSL certificate not found: {$value}");
406
-        }
407
-        $options['ssl']['local_cert'] = $value;
408
-    }
409
-    /**
410
-     * @param mixed $value as passed via Request transfer options.
411
-     */
412
-    private function add_progress(RequestInterface $request, array &$options, $value, array &$params) : void
413
-    {
414
-        self::addNotification($params, static function ($code, $a, $b, $c, $transferred, $total) use($value) {
415
-            if ($code == \STREAM_NOTIFY_PROGRESS) {
416
-                // The upload progress cannot be determined. Use 0 for cURL compatibility:
417
-                // https://curl.se/libcurl/c/CURLOPT_PROGRESSFUNCTION.html
418
-                $value($total, $transferred, 0, 0);
419
-            }
420
-        });
421
-    }
422
-    /**
423
-     * @param mixed $value as passed via Request transfer options.
424
-     */
425
-    private function add_debug(RequestInterface $request, array &$options, $value, array &$params) : void
426
-    {
427
-        if ($value === \false) {
428
-            return;
429
-        }
430
-        static $map = [\STREAM_NOTIFY_CONNECT => 'CONNECT', \STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED', \STREAM_NOTIFY_AUTH_RESULT => 'AUTH_RESULT', \STREAM_NOTIFY_MIME_TYPE_IS => 'MIME_TYPE_IS', \STREAM_NOTIFY_FILE_SIZE_IS => 'FILE_SIZE_IS', \STREAM_NOTIFY_REDIRECTED => 'REDIRECTED', \STREAM_NOTIFY_PROGRESS => 'PROGRESS', \STREAM_NOTIFY_FAILURE => 'FAILURE', \STREAM_NOTIFY_COMPLETED => 'COMPLETED', \STREAM_NOTIFY_RESOLVE => 'RESOLVE'];
431
-        static $args = ['severity', 'message', 'message_code', 'bytes_transferred', 'bytes_max'];
432
-        $value = Utils::debugResource($value);
433
-        $ident = $request->getMethod() . ' ' . $request->getUri()->withFragment('');
434
-        self::addNotification($params, static function (int $code, ...$passed) use($ident, $value, $map, $args) : void {
435
-            \fprintf($value, '<%s> [%s] ', $ident, $map[$code]);
436
-            foreach (\array_filter($passed) as $i => $v) {
437
-                \fwrite($value, $args[$i] . ': "' . $v . '" ');
438
-            }
439
-            \fwrite($value, "\n");
440
-        });
441
-    }
442
-    private static function addNotification(array &$params, callable $notify) : void
443
-    {
444
-        // Wrap the existing function if needed.
445
-        if (!isset($params['notification'])) {
446
-            $params['notification'] = $notify;
447
-        } else {
448
-            $params['notification'] = self::callArray([$params['notification'], $notify]);
449
-        }
450
-    }
451
-    private static function callArray(array $functions) : callable
452
-    {
453
-        return static function (...$args) use($functions) {
454
-            foreach ($functions as $fn) {
455
-                $fn(...$args);
456
-            }
457
-        };
458
-    }
24
+	/**
25
+	 * @var array
26
+	 */
27
+	private $lastHeaders = [];
28
+	/**
29
+	 * Sends an HTTP request.
30
+	 *
31
+	 * @param RequestInterface $request Request to send.
32
+	 * @param array            $options Request transfer options.
33
+	 */
34
+	public function __invoke(RequestInterface $request, array $options) : PromiseInterface
35
+	{
36
+		// Sleep if there is a delay specified.
37
+		if (isset($options['delay'])) {
38
+			\usleep($options['delay'] * 1000);
39
+		}
40
+		$protocolVersion = $request->getProtocolVersion();
41
+		if ('1.0' !== $protocolVersion && '1.1' !== $protocolVersion) {
42
+			throw new ConnectException(\sprintf('HTTP/%s is not supported by the stream handler.', $protocolVersion), $request);
43
+		}
44
+		$startTime = isset($options['on_stats']) ? Utils::currentTime() : null;
45
+		try {
46
+			// Does not support the expect header.
47
+			$request = $request->withoutHeader('Expect');
48
+			// Append a content-length header if body size is zero to match
49
+			// cURL's behavior.
50
+			if (0 === $request->getBody()->getSize()) {
51
+				$request = $request->withHeader('Content-Length', '0');
52
+			}
53
+			return $this->createResponse($request, $options, $this->createStream($request, $options), $startTime);
54
+		} catch (\InvalidArgumentException $e) {
55
+			throw $e;
56
+		} catch (\Exception $e) {
57
+			// Determine if the error was a networking error.
58
+			$message = $e->getMessage();
59
+			// This list can probably get more comprehensive.
60
+			if (\false !== \strpos($message, 'getaddrinfo') || \false !== \strpos($message, 'Connection refused') || \false !== \strpos($message, "couldn't connect to host") || \false !== \strpos($message, 'connection attempt failed')) {
61
+				$e = new ConnectException($e->getMessage(), $request, $e);
62
+			} else {
63
+				$e = RequestException::wrapException($request, $e);
64
+			}
65
+			$this->invokeStats($options, $request, $startTime, null, $e);
66
+			return P\Create::rejectionFor($e);
67
+		}
68
+	}
69
+	private function invokeStats(array $options, RequestInterface $request, ?float $startTime, ?ResponseInterface $response = null, ?\Throwable $error = null) : void
70
+	{
71
+		if (isset($options['on_stats'])) {
72
+			$stats = new TransferStats($request, $response, Utils::currentTime() - $startTime, $error, []);
73
+			$options['on_stats']($stats);
74
+		}
75
+	}
76
+	/**
77
+	 * @param resource $stream
78
+	 */
79
+	private function createResponse(RequestInterface $request, array $options, $stream, ?float $startTime) : PromiseInterface
80
+	{
81
+		$hdrs = $this->lastHeaders;
82
+		$this->lastHeaders = [];
83
+		try {
84
+			[$ver, $status, $reason, $headers] = HeaderProcessor::parseHeaders($hdrs);
85
+		} catch (\Exception $e) {
86
+			return P\Create::rejectionFor(new RequestException('An error was encountered while creating the response', $request, null, $e));
87
+		}
88
+		[$stream, $headers] = $this->checkDecode($options, $headers, $stream);
89
+		$stream = Psr7\Utils::streamFor($stream);
90
+		$sink = $stream;
91
+		if (\strcasecmp('HEAD', $request->getMethod())) {
92
+			$sink = $this->createSink($stream, $options);
93
+		}
94
+		try {
95
+			$response = new Psr7\Response($status, $headers, $sink, $ver, $reason);
96
+		} catch (\Exception $e) {
97
+			return P\Create::rejectionFor(new RequestException('An error was encountered while creating the response', $request, null, $e));
98
+		}
99
+		if (isset($options['on_headers'])) {
100
+			try {
101
+				$options['on_headers']($response);
102
+			} catch (\Exception $e) {
103
+				return P\Create::rejectionFor(new RequestException('An error was encountered during the on_headers event', $request, $response, $e));
104
+			}
105
+		}
106
+		// Do not drain when the request is a HEAD request because they have
107
+		// no body.
108
+		if ($sink !== $stream) {
109
+			$this->drain($stream, $sink, $response->getHeaderLine('Content-Length'));
110
+		}
111
+		$this->invokeStats($options, $request, $startTime, $response, null);
112
+		return new FulfilledPromise($response);
113
+	}
114
+	private function createSink(StreamInterface $stream, array $options) : StreamInterface
115
+	{
116
+		if (!empty($options['stream'])) {
117
+			return $stream;
118
+		}
119
+		$sink = $options['sink'] ?? Psr7\Utils::tryFopen('php://temp', 'r+');
120
+		return \is_string($sink) ? new Psr7\LazyOpenStream($sink, 'w+') : Psr7\Utils::streamFor($sink);
121
+	}
122
+	/**
123
+	 * @param resource $stream
124
+	 */
125
+	private function checkDecode(array $options, array $headers, $stream) : array
126
+	{
127
+		// Automatically decode responses when instructed.
128
+		if (!empty($options['decode_content'])) {
129
+			$normalizedKeys = Utils::normalizeHeaderKeys($headers);
130
+			if (isset($normalizedKeys['content-encoding'])) {
131
+				$encoding = $headers[$normalizedKeys['content-encoding']];
132
+				if ($encoding[0] === 'gzip' || $encoding[0] === 'deflate') {
133
+					$stream = new Psr7\InflateStream(Psr7\Utils::streamFor($stream));
134
+					$headers['x-encoded-content-encoding'] = $headers[$normalizedKeys['content-encoding']];
135
+					// Remove content-encoding header
136
+					unset($headers[$normalizedKeys['content-encoding']]);
137
+					// Fix content-length header
138
+					if (isset($normalizedKeys['content-length'])) {
139
+						$headers['x-encoded-content-length'] = $headers[$normalizedKeys['content-length']];
140
+						$length = (int) $stream->getSize();
141
+						if ($length === 0) {
142
+							unset($headers[$normalizedKeys['content-length']]);
143
+						} else {
144
+							$headers[$normalizedKeys['content-length']] = [$length];
145
+						}
146
+					}
147
+				}
148
+			}
149
+		}
150
+		return [$stream, $headers];
151
+	}
152
+	/**
153
+	 * Drains the source stream into the "sink" client option.
154
+	 *
155
+	 * @param string $contentLength Header specifying the amount of
156
+	 *                              data to read.
157
+	 *
158
+	 * @throws \RuntimeException when the sink option is invalid.
159
+	 */
160
+	private function drain(StreamInterface $source, StreamInterface $sink, string $contentLength) : StreamInterface
161
+	{
162
+		// If a content-length header is provided, then stop reading once
163
+		// that number of bytes has been read. This can prevent infinitely
164
+		// reading from a stream when dealing with servers that do not honor
165
+		// Connection: Close headers.
166
+		Psr7\Utils::copyToStream($source, $sink, \strlen($contentLength) > 0 && (int) $contentLength > 0 ? (int) $contentLength : -1);
167
+		$sink->seek(0);
168
+		$source->close();
169
+		return $sink;
170
+	}
171
+	/**
172
+	 * Create a resource and check to ensure it was created successfully
173
+	 *
174
+	 * @param callable $callback Callable that returns stream resource
175
+	 *
176
+	 * @return resource
177
+	 *
178
+	 * @throws \RuntimeException on error
179
+	 */
180
+	private function createResource(callable $callback)
181
+	{
182
+		$errors = [];
183
+		\set_error_handler(static function ($_, $msg, $file, $line) use(&$errors) : bool {
184
+			$errors[] = ['message' => $msg, 'file' => $file, 'line' => $line];
185
+			return \true;
186
+		});
187
+		try {
188
+			$resource = $callback();
189
+		} finally {
190
+			\restore_error_handler();
191
+		}
192
+		if (!$resource) {
193
+			$message = 'Error creating resource: ';
194
+			foreach ($errors as $err) {
195
+				foreach ($err as $key => $value) {
196
+					$message .= "[{$key}] {$value}" . \PHP_EOL;
197
+				}
198
+			}
199
+			throw new \RuntimeException(\trim($message));
200
+		}
201
+		return $resource;
202
+	}
203
+	/**
204
+	 * @return resource
205
+	 */
206
+	private function createStream(RequestInterface $request, array $options)
207
+	{
208
+		static $methods;
209
+		if (!$methods) {
210
+			$methods = \array_flip(\get_class_methods(__CLASS__));
211
+		}
212
+		if (!\in_array($request->getUri()->getScheme(), ['http', 'https'])) {
213
+			throw new RequestException(\sprintf("The scheme '%s' is not supported.", $request->getUri()->getScheme()), $request);
214
+		}
215
+		// HTTP/1.1 streams using the PHP stream wrapper require a
216
+		// Connection: close header
217
+		if ($request->getProtocolVersion() === '1.1' && !$request->hasHeader('Connection')) {
218
+			$request = $request->withHeader('Connection', 'close');
219
+		}
220
+		// Ensure SSL is verified by default
221
+		if (!isset($options['verify'])) {
222
+			$options['verify'] = \true;
223
+		}
224
+		$params = [];
225
+		$context = $this->getDefaultContext($request);
226
+		if (isset($options['on_headers']) && !\is_callable($options['on_headers'])) {
227
+			throw new \InvalidArgumentException('on_headers must be callable');
228
+		}
229
+		if (!empty($options)) {
230
+			foreach ($options as $key => $value) {
231
+				$method = "add_{$key}";
232
+				if (isset($methods[$method])) {
233
+					$this->{$method}($request, $context, $value, $params);
234
+				}
235
+			}
236
+		}
237
+		if (isset($options['stream_context'])) {
238
+			if (!\is_array($options['stream_context'])) {
239
+				throw new \InvalidArgumentException('stream_context must be an array');
240
+			}
241
+			$context = \array_replace_recursive($context, $options['stream_context']);
242
+		}
243
+		// Microsoft NTLM authentication only supported with curl handler
244
+		if (isset($options['auth'][2]) && 'ntlm' === $options['auth'][2]) {
245
+			throw new \InvalidArgumentException('Microsoft NTLM authentication only supported with curl handler');
246
+		}
247
+		$uri = $this->resolveHost($request, $options);
248
+		$contextResource = $this->createResource(static function () use($context, $params) {
249
+			return \stream_context_create($context, $params);
250
+		});
251
+		return $this->createResource(function () use($uri, &$http_response_header, $contextResource, $context, $options, $request) {
252
+			$resource = @\fopen((string) $uri, 'r', \false, $contextResource);
253
+			$this->lastHeaders = $http_response_header ?? [];
254
+			if (\false === $resource) {
255
+				throw new ConnectException(\sprintf('Connection refused for URI %s', $uri), $request, null, $context);
256
+			}
257
+			if (isset($options['read_timeout'])) {
258
+				$readTimeout = $options['read_timeout'];
259
+				$sec = (int) $readTimeout;
260
+				$usec = ($readTimeout - $sec) * 100000;
261
+				\stream_set_timeout($resource, $sec, $usec);
262
+			}
263
+			return $resource;
264
+		});
265
+	}
266
+	private function resolveHost(RequestInterface $request, array $options) : UriInterface
267
+	{
268
+		$uri = $request->getUri();
269
+		if (isset($options['force_ip_resolve']) && !\filter_var($uri->getHost(), \FILTER_VALIDATE_IP)) {
270
+			if ('v4' === $options['force_ip_resolve']) {
271
+				$records = \dns_get_record($uri->getHost(), \DNS_A);
272
+				if (\false === $records || !isset($records[0]['ip'])) {
273
+					throw new ConnectException(\sprintf("Could not resolve IPv4 address for host '%s'", $uri->getHost()), $request);
274
+				}
275
+				return $uri->withHost($records[0]['ip']);
276
+			}
277
+			if ('v6' === $options['force_ip_resolve']) {
278
+				$records = \dns_get_record($uri->getHost(), \DNS_AAAA);
279
+				if (\false === $records || !isset($records[0]['ipv6'])) {
280
+					throw new ConnectException(\sprintf("Could not resolve IPv6 address for host '%s'", $uri->getHost()), $request);
281
+				}
282
+				return $uri->withHost('[' . $records[0]['ipv6'] . ']');
283
+			}
284
+		}
285
+		return $uri;
286
+	}
287
+	private function getDefaultContext(RequestInterface $request) : array
288
+	{
289
+		$headers = '';
290
+		foreach ($request->getHeaders() as $name => $value) {
291
+			foreach ($value as $val) {
292
+				$headers .= "{$name}: {$val}\r\n";
293
+			}
294
+		}
295
+		$context = ['http' => ['method' => $request->getMethod(), 'header' => $headers, 'protocol_version' => $request->getProtocolVersion(), 'ignore_errors' => \true, 'follow_location' => 0], 'ssl' => ['peer_name' => $request->getUri()->getHost()]];
296
+		$body = (string) $request->getBody();
297
+		if ('' !== $body) {
298
+			$context['http']['content'] = $body;
299
+			// Prevent the HTTP handler from adding a Content-Type header.
300
+			if (!$request->hasHeader('Content-Type')) {
301
+				$context['http']['header'] .= "Content-Type:\r\n";
302
+			}
303
+		}
304
+		$context['http']['header'] = \rtrim($context['http']['header']);
305
+		return $context;
306
+	}
307
+	/**
308
+	 * @param mixed $value as passed via Request transfer options.
309
+	 */
310
+	private function add_proxy(RequestInterface $request, array &$options, $value, array &$params) : void
311
+	{
312
+		$uri = null;
313
+		if (!\is_array($value)) {
314
+			$uri = $value;
315
+		} else {
316
+			$scheme = $request->getUri()->getScheme();
317
+			if (isset($value[$scheme])) {
318
+				if (!isset($value['no']) || !Utils::isHostInNoProxy($request->getUri()->getHost(), $value['no'])) {
319
+					$uri = $value[$scheme];
320
+				}
321
+			}
322
+		}
323
+		if (!$uri) {
324
+			return;
325
+		}
326
+		$parsed = $this->parse_proxy($uri);
327
+		$options['http']['proxy'] = $parsed['proxy'];
328
+		if ($parsed['auth']) {
329
+			if (!isset($options['http']['header'])) {
330
+				$options['http']['header'] = [];
331
+			}
332
+			$options['http']['header'] .= "\r\nProxy-Authorization: {$parsed['auth']}";
333
+		}
334
+	}
335
+	/**
336
+	 * Parses the given proxy URL to make it compatible with the format PHP's stream context expects.
337
+	 */
338
+	private function parse_proxy(string $url) : array
339
+	{
340
+		$parsed = \parse_url($url);
341
+		if ($parsed !== \false && isset($parsed['scheme']) && $parsed['scheme'] === 'http') {
342
+			if (isset($parsed['host']) && isset($parsed['port'])) {
343
+				$auth = null;
344
+				if (isset($parsed['user']) && isset($parsed['pass'])) {
345
+					$auth = \base64_encode("{$parsed['user']}:{$parsed['pass']}");
346
+				}
347
+				return ['proxy' => "tcp://{$parsed['host']}:{$parsed['port']}", 'auth' => $auth ? "Basic {$auth}" : null];
348
+			}
349
+		}
350
+		// Return proxy as-is.
351
+		return ['proxy' => $url, 'auth' => null];
352
+	}
353
+	/**
354
+	 * @param mixed $value as passed via Request transfer options.
355
+	 */
356
+	private function add_timeout(RequestInterface $request, array &$options, $value, array &$params) : void
357
+	{
358
+		if ($value > 0) {
359
+			$options['http']['timeout'] = $value;
360
+		}
361
+	}
362
+	/**
363
+	 * @param mixed $value as passed via Request transfer options.
364
+	 */
365
+	private function add_crypto_method(RequestInterface $request, array &$options, $value, array &$params) : void
366
+	{
367
+		if ($value === \STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT || $value === \STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT || $value === \STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT || \defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT') && $value === \STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT) {
368
+			$options['http']['crypto_method'] = $value;
369
+			return;
370
+		}
371
+		throw new \InvalidArgumentException('Invalid crypto_method request option: unknown version provided');
372
+	}
373
+	/**
374
+	 * @param mixed $value as passed via Request transfer options.
375
+	 */
376
+	private function add_verify(RequestInterface $request, array &$options, $value, array &$params) : void
377
+	{
378
+		if ($value === \false) {
379
+			$options['ssl']['verify_peer'] = \false;
380
+			$options['ssl']['verify_peer_name'] = \false;
381
+			return;
382
+		}
383
+		if (\is_string($value)) {
384
+			$options['ssl']['cafile'] = $value;
385
+			if (!\file_exists($value)) {
386
+				throw new \RuntimeException("SSL CA bundle not found: {$value}");
387
+			}
388
+		} elseif ($value !== \true) {
389
+			throw new \InvalidArgumentException('Invalid verify request option');
390
+		}
391
+		$options['ssl']['verify_peer'] = \true;
392
+		$options['ssl']['verify_peer_name'] = \true;
393
+		$options['ssl']['allow_self_signed'] = \false;
394
+	}
395
+	/**
396
+	 * @param mixed $value as passed via Request transfer options.
397
+	 */
398
+	private function add_cert(RequestInterface $request, array &$options, $value, array &$params) : void
399
+	{
400
+		if (\is_array($value)) {
401
+			$options['ssl']['passphrase'] = $value[1];
402
+			$value = $value[0];
403
+		}
404
+		if (!\file_exists($value)) {
405
+			throw new \RuntimeException("SSL certificate not found: {$value}");
406
+		}
407
+		$options['ssl']['local_cert'] = $value;
408
+	}
409
+	/**
410
+	 * @param mixed $value as passed via Request transfer options.
411
+	 */
412
+	private function add_progress(RequestInterface $request, array &$options, $value, array &$params) : void
413
+	{
414
+		self::addNotification($params, static function ($code, $a, $b, $c, $transferred, $total) use($value) {
415
+			if ($code == \STREAM_NOTIFY_PROGRESS) {
416
+				// The upload progress cannot be determined. Use 0 for cURL compatibility:
417
+				// https://curl.se/libcurl/c/CURLOPT_PROGRESSFUNCTION.html
418
+				$value($total, $transferred, 0, 0);
419
+			}
420
+		});
421
+	}
422
+	/**
423
+	 * @param mixed $value as passed via Request transfer options.
424
+	 */
425
+	private function add_debug(RequestInterface $request, array &$options, $value, array &$params) : void
426
+	{
427
+		if ($value === \false) {
428
+			return;
429
+		}
430
+		static $map = [\STREAM_NOTIFY_CONNECT => 'CONNECT', \STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED', \STREAM_NOTIFY_AUTH_RESULT => 'AUTH_RESULT', \STREAM_NOTIFY_MIME_TYPE_IS => 'MIME_TYPE_IS', \STREAM_NOTIFY_FILE_SIZE_IS => 'FILE_SIZE_IS', \STREAM_NOTIFY_REDIRECTED => 'REDIRECTED', \STREAM_NOTIFY_PROGRESS => 'PROGRESS', \STREAM_NOTIFY_FAILURE => 'FAILURE', \STREAM_NOTIFY_COMPLETED => 'COMPLETED', \STREAM_NOTIFY_RESOLVE => 'RESOLVE'];
431
+		static $args = ['severity', 'message', 'message_code', 'bytes_transferred', 'bytes_max'];
432
+		$value = Utils::debugResource($value);
433
+		$ident = $request->getMethod() . ' ' . $request->getUri()->withFragment('');
434
+		self::addNotification($params, static function (int $code, ...$passed) use($ident, $value, $map, $args) : void {
435
+			\fprintf($value, '<%s> [%s] ', $ident, $map[$code]);
436
+			foreach (\array_filter($passed) as $i => $v) {
437
+				\fwrite($value, $args[$i] . ': "' . $v . '" ');
438
+			}
439
+			\fwrite($value, "\n");
440
+		});
441
+	}
442
+	private static function addNotification(array &$params, callable $notify) : void
443
+	{
444
+		// Wrap the existing function if needed.
445
+		if (!isset($params['notification'])) {
446
+			$params['notification'] = $notify;
447
+		} else {
448
+			$params['notification'] = self::callArray([$params['notification'], $notify]);
449
+		}
450
+	}
451
+	private static function callArray(array $functions) : callable
452
+	{
453
+		return static function (...$args) use($functions) {
454
+			foreach ($functions as $fn) {
455
+				$fn(...$args);
456
+			}
457
+		};
458
+	}
459 459
 }
Please login to merge, or discard this patch.
lib/Vendor/GuzzleHttp/Handler/CurlMultiHandler.php 3 patches
Braces   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -17,8 +17,7 @@
 block discarded – undo
17 17
  *
18 18
  * @final
19 19
  */
20
-class CurlMultiHandler
21
-{
20
+class CurlMultiHandler {
22 21
     /**
23 22
      * @var CurlFactoryInterface
24 23
      */
Please login to merge, or discard this patch.
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -64,7 +64,7 @@  discard block
 block discarded – undo
64 64
             $this->selectTimeout = $options['select_timeout'];
65 65
         } elseif ($selectTimeout = Utils::getenv('GUZZLE_CURL_SELECT_TIMEOUT')) {
66 66
             @\trigger_error('Since guzzlehttp/guzzle 7.2.0: Using environment variable GUZZLE_CURL_SELECT_TIMEOUT is deprecated. Use option "select_timeout" instead.', \E_USER_DEPRECATED);
67
-            $this->selectTimeout = (int) $selectTimeout;
67
+            $this->selectTimeout = (int)$selectTimeout;
68 68
         } else {
69 69
             $this->selectTimeout = 1;
70 70
         }
@@ -107,8 +107,8 @@  discard block
 block discarded – undo
107 107
     public function __invoke(RequestInterface $request, array $options) : PromiseInterface
108 108
     {
109 109
         $easy = $this->factory->create($request, $options);
110
-        $id = (int) $easy->handle;
111
-        $promise = new Promise([$this, 'execute'], function () use($id) {
110
+        $id = (int)$easy->handle;
111
+        $promise = new Promise([$this, 'execute'], function() use($id) {
112 112
             return $this->cancel($id);
113 113
         });
114 114
         $this->addRequest(['easy' => $easy, 'deferred' => $promise]);
@@ -157,7 +157,7 @@  discard block
 block discarded – undo
157 157
     private function addRequest(array $entry) : void
158 158
     {
159 159
         $easy = $entry['easy'];
160
-        $id = (int) $easy->handle;
160
+        $id = (int)$easy->handle;
161 161
         $this->handles[$id] = $entry;
162 162
         if (empty($easy->options['delay'])) {
163 163
             \curl_multi_add_handle($this->_mh, $easy->handle);
@@ -194,7 +194,7 @@  discard block
 block discarded – undo
194 194
                 // if it's not done, then it would be premature to remove the handle. ref https://github.com/guzzle/guzzle/pull/2892#issuecomment-945150216
195 195
                 continue;
196 196
             }
197
-            $id = (int) $done['handle'];
197
+            $id = (int)$done['handle'];
198 198
             \curl_multi_remove_handle($this->_mh, $done['handle']);
199 199
             if (!isset($this->handles[$id])) {
200 200
                 // Probably was cancelled.
@@ -215,6 +215,6 @@  discard block
 block discarded – undo
215 215
                 $nextTime = $time;
216 216
             }
217 217
         }
218
-        return (int) \max(0, $nextTime - $currentTime) * 1000000;
218
+        return (int)\max(0, $nextTime - $currentTime) * 1000000;
219 219
     }
220 220
 }
Please login to merge, or discard this patch.
Indentation   +213 added lines, -213 removed lines patch added patch discarded remove patch
@@ -19,217 +19,217 @@
 block discarded – undo
19 19
  */
20 20
 class CurlMultiHandler
21 21
 {
22
-    /**
23
-     * @var CurlFactoryInterface
24
-     */
25
-    private $factory;
26
-    /**
27
-     * @var int
28
-     */
29
-    private $selectTimeout;
30
-    /**
31
-     * @var int Will be higher than 0 when `curl_multi_exec` is still running.
32
-     */
33
-    private $active = 0;
34
-    /**
35
-     * @var array Request entry handles, indexed by handle id in `addRequest`.
36
-     *
37
-     * @see CurlMultiHandler::addRequest
38
-     */
39
-    private $handles = [];
40
-    /**
41
-     * @var array<int, float> An array of delay times, indexed by handle id in `addRequest`.
42
-     *
43
-     * @see CurlMultiHandler::addRequest
44
-     */
45
-    private $delays = [];
46
-    /**
47
-     * @var array<mixed> An associative array of CURLMOPT_* options and corresponding values for curl_multi_setopt()
48
-     */
49
-    private $options = [];
50
-    /** @var resource|\CurlMultiHandle */
51
-    private $_mh;
52
-    /**
53
-     * This handler accepts the following options:
54
-     *
55
-     * - handle_factory: An optional factory  used to create curl handles
56
-     * - select_timeout: Optional timeout (in seconds) to block before timing
57
-     *   out while selecting curl handles. Defaults to 1 second.
58
-     * - options: An associative array of CURLMOPT_* options and
59
-     *   corresponding values for curl_multi_setopt()
60
-     */
61
-    public function __construct(array $options = [])
62
-    {
63
-        $this->factory = $options['handle_factory'] ?? new CurlFactory(50);
64
-        if (isset($options['select_timeout'])) {
65
-            $this->selectTimeout = $options['select_timeout'];
66
-        } elseif ($selectTimeout = Utils::getenv('GUZZLE_CURL_SELECT_TIMEOUT')) {
67
-            @\trigger_error('Since guzzlehttp/guzzle 7.2.0: Using environment variable GUZZLE_CURL_SELECT_TIMEOUT is deprecated. Use option "select_timeout" instead.', \E_USER_DEPRECATED);
68
-            $this->selectTimeout = (int) $selectTimeout;
69
-        } else {
70
-            $this->selectTimeout = 1;
71
-        }
72
-        $this->options = $options['options'] ?? [];
73
-        // unsetting the property forces the first access to go through
74
-        // __get().
75
-        unset($this->_mh);
76
-    }
77
-    /**
78
-     * @param string $name
79
-     *
80
-     * @return resource|\CurlMultiHandle
81
-     *
82
-     * @throws \BadMethodCallException when another field as `_mh` will be gotten
83
-     * @throws \RuntimeException       when curl can not initialize a multi handle
84
-     */
85
-    public function __get($name)
86
-    {
87
-        if ($name !== '_mh') {
88
-            throw new \BadMethodCallException("Can not get other property as '_mh'.");
89
-        }
90
-        $multiHandle = \curl_multi_init();
91
-        if (\false === $multiHandle) {
92
-            throw new \RuntimeException('Can not initialize curl multi handle.');
93
-        }
94
-        $this->_mh = $multiHandle;
95
-        foreach ($this->options as $option => $value) {
96
-            // A warning is raised in case of a wrong option.
97
-            \curl_multi_setopt($this->_mh, $option, $value);
98
-        }
99
-        return $this->_mh;
100
-    }
101
-    public function __destruct()
102
-    {
103
-        if (isset($this->_mh)) {
104
-            \curl_multi_close($this->_mh);
105
-            unset($this->_mh);
106
-        }
107
-    }
108
-    public function __invoke(RequestInterface $request, array $options) : PromiseInterface
109
-    {
110
-        $easy = $this->factory->create($request, $options);
111
-        $id = (int) $easy->handle;
112
-        $promise = new Promise([$this, 'execute'], function () use($id) {
113
-            return $this->cancel($id);
114
-        });
115
-        $this->addRequest(['easy' => $easy, 'deferred' => $promise]);
116
-        return $promise;
117
-    }
118
-    /**
119
-     * Ticks the curl event loop.
120
-     */
121
-    public function tick() : void
122
-    {
123
-        // Add any delayed handles if needed.
124
-        if ($this->delays) {
125
-            $currentTime = Utils::currentTime();
126
-            foreach ($this->delays as $id => $delay) {
127
-                if ($currentTime >= $delay) {
128
-                    unset($this->delays[$id]);
129
-                    \curl_multi_add_handle($this->_mh, $this->handles[$id]['easy']->handle);
130
-                }
131
-            }
132
-        }
133
-        // Run curl_multi_exec in the queue to enable other async tasks to run
134
-        P\Utils::queue()->add(Closure::fromCallable([$this, 'tickInQueue']));
135
-        // Step through the task queue which may add additional requests.
136
-        P\Utils::queue()->run();
137
-        if ($this->active && \curl_multi_select($this->_mh, $this->selectTimeout) === -1) {
138
-            // Perform a usleep if a select returns -1.
139
-            // See: https://bugs.php.net/bug.php?id=61141
140
-            \usleep(250);
141
-        }
142
-        while (\curl_multi_exec($this->_mh, $this->active) === \CURLM_CALL_MULTI_PERFORM) {
143
-            // Prevent busy looping for slow HTTP requests.
144
-            \curl_multi_select($this->_mh, $this->selectTimeout);
145
-        }
146
-        $this->processMessages();
147
-    }
148
-    /**
149
-     * Runs \curl_multi_exec() inside the event loop, to prevent busy looping
150
-     */
151
-    private function tickInQueue() : void
152
-    {
153
-        if (\curl_multi_exec($this->_mh, $this->active) === \CURLM_CALL_MULTI_PERFORM) {
154
-            \curl_multi_select($this->_mh, 0);
155
-            P\Utils::queue()->add(Closure::fromCallable([$this, 'tickInQueue']));
156
-        }
157
-    }
158
-    /**
159
-     * Runs until all outstanding connections have completed.
160
-     */
161
-    public function execute() : void
162
-    {
163
-        $queue = P\Utils::queue();
164
-        while ($this->handles || !$queue->isEmpty()) {
165
-            // If there are no transfers, then sleep for the next delay
166
-            if (!$this->active && $this->delays) {
167
-                \usleep($this->timeToNext());
168
-            }
169
-            $this->tick();
170
-        }
171
-    }
172
-    private function addRequest(array $entry) : void
173
-    {
174
-        $easy = $entry['easy'];
175
-        $id = (int) $easy->handle;
176
-        $this->handles[$id] = $entry;
177
-        if (empty($easy->options['delay'])) {
178
-            \curl_multi_add_handle($this->_mh, $easy->handle);
179
-        } else {
180
-            $this->delays[$id] = Utils::currentTime() + $easy->options['delay'] / 1000;
181
-        }
182
-    }
183
-    /**
184
-     * Cancels a handle from sending and removes references to it.
185
-     *
186
-     * @param int $id Handle ID to cancel and remove.
187
-     *
188
-     * @return bool True on success, false on failure.
189
-     */
190
-    private function cancel($id) : bool
191
-    {
192
-        if (!\is_int($id)) {
193
-            trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing an integer to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
194
-        }
195
-        // Cannot cancel if it has been processed.
196
-        if (!isset($this->handles[$id])) {
197
-            return \false;
198
-        }
199
-        $handle = $this->handles[$id]['easy']->handle;
200
-        unset($this->delays[$id], $this->handles[$id]);
201
-        \curl_multi_remove_handle($this->_mh, $handle);
202
-        \curl_close($handle);
203
-        return \true;
204
-    }
205
-    private function processMessages() : void
206
-    {
207
-        while ($done = \curl_multi_info_read($this->_mh)) {
208
-            if ($done['msg'] !== \CURLMSG_DONE) {
209
-                // if it's not done, then it would be premature to remove the handle. ref https://github.com/guzzle/guzzle/pull/2892#issuecomment-945150216
210
-                continue;
211
-            }
212
-            $id = (int) $done['handle'];
213
-            \curl_multi_remove_handle($this->_mh, $done['handle']);
214
-            if (!isset($this->handles[$id])) {
215
-                // Probably was cancelled.
216
-                continue;
217
-            }
218
-            $entry = $this->handles[$id];
219
-            unset($this->handles[$id], $this->delays[$id]);
220
-            $entry['easy']->errno = $done['result'];
221
-            $entry['deferred']->resolve(CurlFactory::finish($this, $entry['easy'], $this->factory));
222
-        }
223
-    }
224
-    private function timeToNext() : int
225
-    {
226
-        $currentTime = Utils::currentTime();
227
-        $nextTime = \PHP_INT_MAX;
228
-        foreach ($this->delays as $time) {
229
-            if ($time < $nextTime) {
230
-                $nextTime = $time;
231
-            }
232
-        }
233
-        return (int) \max(0, $nextTime - $currentTime) * 1000000;
234
-    }
22
+	/**
23
+	 * @var CurlFactoryInterface
24
+	 */
25
+	private $factory;
26
+	/**
27
+	 * @var int
28
+	 */
29
+	private $selectTimeout;
30
+	/**
31
+	 * @var int Will be higher than 0 when `curl_multi_exec` is still running.
32
+	 */
33
+	private $active = 0;
34
+	/**
35
+	 * @var array Request entry handles, indexed by handle id in `addRequest`.
36
+	 *
37
+	 * @see CurlMultiHandler::addRequest
38
+	 */
39
+	private $handles = [];
40
+	/**
41
+	 * @var array<int, float> An array of delay times, indexed by handle id in `addRequest`.
42
+	 *
43
+	 * @see CurlMultiHandler::addRequest
44
+	 */
45
+	private $delays = [];
46
+	/**
47
+	 * @var array<mixed> An associative array of CURLMOPT_* options and corresponding values for curl_multi_setopt()
48
+	 */
49
+	private $options = [];
50
+	/** @var resource|\CurlMultiHandle */
51
+	private $_mh;
52
+	/**
53
+	 * This handler accepts the following options:
54
+	 *
55
+	 * - handle_factory: An optional factory  used to create curl handles
56
+	 * - select_timeout: Optional timeout (in seconds) to block before timing
57
+	 *   out while selecting curl handles. Defaults to 1 second.
58
+	 * - options: An associative array of CURLMOPT_* options and
59
+	 *   corresponding values for curl_multi_setopt()
60
+	 */
61
+	public function __construct(array $options = [])
62
+	{
63
+		$this->factory = $options['handle_factory'] ?? new CurlFactory(50);
64
+		if (isset($options['select_timeout'])) {
65
+			$this->selectTimeout = $options['select_timeout'];
66
+		} elseif ($selectTimeout = Utils::getenv('GUZZLE_CURL_SELECT_TIMEOUT')) {
67
+			@\trigger_error('Since guzzlehttp/guzzle 7.2.0: Using environment variable GUZZLE_CURL_SELECT_TIMEOUT is deprecated. Use option "select_timeout" instead.', \E_USER_DEPRECATED);
68
+			$this->selectTimeout = (int) $selectTimeout;
69
+		} else {
70
+			$this->selectTimeout = 1;
71
+		}
72
+		$this->options = $options['options'] ?? [];
73
+		// unsetting the property forces the first access to go through
74
+		// __get().
75
+		unset($this->_mh);
76
+	}
77
+	/**
78
+	 * @param string $name
79
+	 *
80
+	 * @return resource|\CurlMultiHandle
81
+	 *
82
+	 * @throws \BadMethodCallException when another field as `_mh` will be gotten
83
+	 * @throws \RuntimeException       when curl can not initialize a multi handle
84
+	 */
85
+	public function __get($name)
86
+	{
87
+		if ($name !== '_mh') {
88
+			throw new \BadMethodCallException("Can not get other property as '_mh'.");
89
+		}
90
+		$multiHandle = \curl_multi_init();
91
+		if (\false === $multiHandle) {
92
+			throw new \RuntimeException('Can not initialize curl multi handle.');
93
+		}
94
+		$this->_mh = $multiHandle;
95
+		foreach ($this->options as $option => $value) {
96
+			// A warning is raised in case of a wrong option.
97
+			\curl_multi_setopt($this->_mh, $option, $value);
98
+		}
99
+		return $this->_mh;
100
+	}
101
+	public function __destruct()
102
+	{
103
+		if (isset($this->_mh)) {
104
+			\curl_multi_close($this->_mh);
105
+			unset($this->_mh);
106
+		}
107
+	}
108
+	public function __invoke(RequestInterface $request, array $options) : PromiseInterface
109
+	{
110
+		$easy = $this->factory->create($request, $options);
111
+		$id = (int) $easy->handle;
112
+		$promise = new Promise([$this, 'execute'], function () use($id) {
113
+			return $this->cancel($id);
114
+		});
115
+		$this->addRequest(['easy' => $easy, 'deferred' => $promise]);
116
+		return $promise;
117
+	}
118
+	/**
119
+	 * Ticks the curl event loop.
120
+	 */
121
+	public function tick() : void
122
+	{
123
+		// Add any delayed handles if needed.
124
+		if ($this->delays) {
125
+			$currentTime = Utils::currentTime();
126
+			foreach ($this->delays as $id => $delay) {
127
+				if ($currentTime >= $delay) {
128
+					unset($this->delays[$id]);
129
+					\curl_multi_add_handle($this->_mh, $this->handles[$id]['easy']->handle);
130
+				}
131
+			}
132
+		}
133
+		// Run curl_multi_exec in the queue to enable other async tasks to run
134
+		P\Utils::queue()->add(Closure::fromCallable([$this, 'tickInQueue']));
135
+		// Step through the task queue which may add additional requests.
136
+		P\Utils::queue()->run();
137
+		if ($this->active && \curl_multi_select($this->_mh, $this->selectTimeout) === -1) {
138
+			// Perform a usleep if a select returns -1.
139
+			// See: https://bugs.php.net/bug.php?id=61141
140
+			\usleep(250);
141
+		}
142
+		while (\curl_multi_exec($this->_mh, $this->active) === \CURLM_CALL_MULTI_PERFORM) {
143
+			// Prevent busy looping for slow HTTP requests.
144
+			\curl_multi_select($this->_mh, $this->selectTimeout);
145
+		}
146
+		$this->processMessages();
147
+	}
148
+	/**
149
+	 * Runs \curl_multi_exec() inside the event loop, to prevent busy looping
150
+	 */
151
+	private function tickInQueue() : void
152
+	{
153
+		if (\curl_multi_exec($this->_mh, $this->active) === \CURLM_CALL_MULTI_PERFORM) {
154
+			\curl_multi_select($this->_mh, 0);
155
+			P\Utils::queue()->add(Closure::fromCallable([$this, 'tickInQueue']));
156
+		}
157
+	}
158
+	/**
159
+	 * Runs until all outstanding connections have completed.
160
+	 */
161
+	public function execute() : void
162
+	{
163
+		$queue = P\Utils::queue();
164
+		while ($this->handles || !$queue->isEmpty()) {
165
+			// If there are no transfers, then sleep for the next delay
166
+			if (!$this->active && $this->delays) {
167
+				\usleep($this->timeToNext());
168
+			}
169
+			$this->tick();
170
+		}
171
+	}
172
+	private function addRequest(array $entry) : void
173
+	{
174
+		$easy = $entry['easy'];
175
+		$id = (int) $easy->handle;
176
+		$this->handles[$id] = $entry;
177
+		if (empty($easy->options['delay'])) {
178
+			\curl_multi_add_handle($this->_mh, $easy->handle);
179
+		} else {
180
+			$this->delays[$id] = Utils::currentTime() + $easy->options['delay'] / 1000;
181
+		}
182
+	}
183
+	/**
184
+	 * Cancels a handle from sending and removes references to it.
185
+	 *
186
+	 * @param int $id Handle ID to cancel and remove.
187
+	 *
188
+	 * @return bool True on success, false on failure.
189
+	 */
190
+	private function cancel($id) : bool
191
+	{
192
+		if (!\is_int($id)) {
193
+			trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing an integer to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
194
+		}
195
+		// Cannot cancel if it has been processed.
196
+		if (!isset($this->handles[$id])) {
197
+			return \false;
198
+		}
199
+		$handle = $this->handles[$id]['easy']->handle;
200
+		unset($this->delays[$id], $this->handles[$id]);
201
+		\curl_multi_remove_handle($this->_mh, $handle);
202
+		\curl_close($handle);
203
+		return \true;
204
+	}
205
+	private function processMessages() : void
206
+	{
207
+		while ($done = \curl_multi_info_read($this->_mh)) {
208
+			if ($done['msg'] !== \CURLMSG_DONE) {
209
+				// if it's not done, then it would be premature to remove the handle. ref https://github.com/guzzle/guzzle/pull/2892#issuecomment-945150216
210
+				continue;
211
+			}
212
+			$id = (int) $done['handle'];
213
+			\curl_multi_remove_handle($this->_mh, $done['handle']);
214
+			if (!isset($this->handles[$id])) {
215
+				// Probably was cancelled.
216
+				continue;
217
+			}
218
+			$entry = $this->handles[$id];
219
+			unset($this->handles[$id], $this->delays[$id]);
220
+			$entry['easy']->errno = $done['result'];
221
+			$entry['deferred']->resolve(CurlFactory::finish($this, $entry['easy'], $this->factory));
222
+		}
223
+	}
224
+	private function timeToNext() : int
225
+	{
226
+		$currentTime = Utils::currentTime();
227
+		$nextTime = \PHP_INT_MAX;
228
+		foreach ($this->delays as $time) {
229
+			if ($time < $nextTime) {
230
+				$nextTime = $time;
231
+			}
232
+		}
233
+		return (int) \max(0, $nextTime - $currentTime) * 1000000;
234
+	}
235 235
 }
Please login to merge, or discard this patch.
lib/Vendor/GuzzleHttp/Handler/HeaderProcessor.php 3 patches
Braces   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -7,8 +7,7 @@
 block discarded – undo
7 7
 /**
8 8
  * @internal
9 9
  */
10
-final class HeaderProcessor
11
-{
10
+final class HeaderProcessor {
12 11
     /**
13 12
      * Returns the HTTP version, status code, reason phrase, and headers.
14 13
      *
Please login to merge, or discard this patch.
Indentation   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -8,29 +8,29 @@
 block discarded – undo
8 8
  */
9 9
 final class HeaderProcessor
10 10
 {
11
-    /**
12
-     * Returns the HTTP version, status code, reason phrase, and headers.
13
-     *
14
-     * @param string[] $headers
15
-     *
16
-     * @return array{0:string, 1:int, 2:?string, 3:array}
17
-     *
18
-     * @throws \RuntimeException
19
-     */
20
-    public static function parseHeaders(array $headers) : array
21
-    {
22
-        if ($headers === []) {
23
-            throw new \RuntimeException('Expected a non-empty array of header data');
24
-        }
25
-        $parts = \explode(' ', \array_shift($headers), 3);
26
-        $version = \explode('/', $parts[0])[1] ?? null;
27
-        if ($version === null) {
28
-            throw new \RuntimeException('HTTP version missing from header data');
29
-        }
30
-        $status = $parts[1] ?? null;
31
-        if ($status === null) {
32
-            throw new \RuntimeException('HTTP status code missing from header data');
33
-        }
34
-        return [$version, (int) $status, $parts[2] ?? null, Utils::headersFromLines($headers)];
35
-    }
11
+	/**
12
+	 * Returns the HTTP version, status code, reason phrase, and headers.
13
+	 *
14
+	 * @param string[] $headers
15
+	 *
16
+	 * @return array{0:string, 1:int, 2:?string, 3:array}
17
+	 *
18
+	 * @throws \RuntimeException
19
+	 */
20
+	public static function parseHeaders(array $headers) : array
21
+	{
22
+		if ($headers === []) {
23
+			throw new \RuntimeException('Expected a non-empty array of header data');
24
+		}
25
+		$parts = \explode(' ', \array_shift($headers), 3);
26
+		$version = \explode('/', $parts[0])[1] ?? null;
27
+		if ($version === null) {
28
+			throw new \RuntimeException('HTTP version missing from header data');
29
+		}
30
+		$status = $parts[1] ?? null;
31
+		if ($status === null) {
32
+			throw new \RuntimeException('HTTP status code missing from header data');
33
+		}
34
+		return [$version, (int) $status, $parts[2] ?? null, Utils::headersFromLines($headers)];
35
+	}
36 36
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -31,6 +31,6 @@
 block discarded – undo
31 31
         if ($status === null) {
32 32
             throw new \RuntimeException('HTTP status code missing from header data');
33 33
         }
34
-        return [$version, (int) $status, $parts[2] ?? null, Utils::headersFromLines($headers)];
34
+        return [$version, (int)$status, $parts[2] ?? null, Utils::headersFromLines($headers)];
35 35
     }
36 36
 }
Please login to merge, or discard this patch.
lib/Vendor/GuzzleHttp/Handler/EasyHandle.php 3 patches
Braces   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -13,8 +13,7 @@
 block discarded – undo
13 13
  *
14 14
  * @internal
15 15
  */
16
-final class EasyHandle
17
-{
16
+final class EasyHandle {
18 17
     /**
19 18
      * @var resource|\CurlHandle cURL resource
20 19
      */
Please login to merge, or discard this patch.
Indentation   +74 added lines, -74 removed lines patch added patch discarded remove patch
@@ -14,78 +14,78 @@
 block discarded – undo
14 14
  */
15 15
 final class EasyHandle
16 16
 {
17
-    /**
18
-     * @var resource|\CurlHandle cURL resource
19
-     */
20
-    public $handle;
21
-    /**
22
-     * @var StreamInterface Where data is being written
23
-     */
24
-    public $sink;
25
-    /**
26
-     * @var array Received HTTP headers so far
27
-     */
28
-    public $headers = [];
29
-    /**
30
-     * @var ResponseInterface|null Received response (if any)
31
-     */
32
-    public $response;
33
-    /**
34
-     * @var RequestInterface Request being sent
35
-     */
36
-    public $request;
37
-    /**
38
-     * @var array Request options
39
-     */
40
-    public $options = [];
41
-    /**
42
-     * @var int cURL error number (if any)
43
-     */
44
-    public $errno = 0;
45
-    /**
46
-     * @var \Throwable|null Exception during on_headers (if any)
47
-     */
48
-    public $onHeadersException;
49
-    /**
50
-     * @var \Exception|null Exception during createResponse (if any)
51
-     */
52
-    public $createResponseException;
53
-    /**
54
-     * Attach a response to the easy handle based on the received headers.
55
-     *
56
-     * @throws \RuntimeException if no headers have been received or the first
57
-     *                           header line is invalid.
58
-     */
59
-    public function createResponse() : void
60
-    {
61
-        [$ver, $status, $reason, $headers] = HeaderProcessor::parseHeaders($this->headers);
62
-        $normalizedKeys = Utils::normalizeHeaderKeys($headers);
63
-        if (!empty($this->options['decode_content']) && isset($normalizedKeys['content-encoding'])) {
64
-            $headers['x-encoded-content-encoding'] = $headers[$normalizedKeys['content-encoding']];
65
-            unset($headers[$normalizedKeys['content-encoding']]);
66
-            if (isset($normalizedKeys['content-length'])) {
67
-                $headers['x-encoded-content-length'] = $headers[$normalizedKeys['content-length']];
68
-                $bodyLength = (int) $this->sink->getSize();
69
-                if ($bodyLength) {
70
-                    $headers[$normalizedKeys['content-length']] = $bodyLength;
71
-                } else {
72
-                    unset($headers[$normalizedKeys['content-length']]);
73
-                }
74
-            }
75
-        }
76
-        // Attach a response to the easy handle with the parsed headers.
77
-        $this->response = new Response($status, $headers, $this->sink, $ver, $reason);
78
-    }
79
-    /**
80
-     * @param string $name
81
-     *
82
-     * @return void
83
-     *
84
-     * @throws \BadMethodCallException
85
-     */
86
-    public function __get($name)
87
-    {
88
-        $msg = $name === 'handle' ? 'The EasyHandle has been released' : 'Invalid property: ' . $name;
89
-        throw new \BadMethodCallException($msg);
90
-    }
17
+	/**
18
+	 * @var resource|\CurlHandle cURL resource
19
+	 */
20
+	public $handle;
21
+	/**
22
+	 * @var StreamInterface Where data is being written
23
+	 */
24
+	public $sink;
25
+	/**
26
+	 * @var array Received HTTP headers so far
27
+	 */
28
+	public $headers = [];
29
+	/**
30
+	 * @var ResponseInterface|null Received response (if any)
31
+	 */
32
+	public $response;
33
+	/**
34
+	 * @var RequestInterface Request being sent
35
+	 */
36
+	public $request;
37
+	/**
38
+	 * @var array Request options
39
+	 */
40
+	public $options = [];
41
+	/**
42
+	 * @var int cURL error number (if any)
43
+	 */
44
+	public $errno = 0;
45
+	/**
46
+	 * @var \Throwable|null Exception during on_headers (if any)
47
+	 */
48
+	public $onHeadersException;
49
+	/**
50
+	 * @var \Exception|null Exception during createResponse (if any)
51
+	 */
52
+	public $createResponseException;
53
+	/**
54
+	 * Attach a response to the easy handle based on the received headers.
55
+	 *
56
+	 * @throws \RuntimeException if no headers have been received or the first
57
+	 *                           header line is invalid.
58
+	 */
59
+	public function createResponse() : void
60
+	{
61
+		[$ver, $status, $reason, $headers] = HeaderProcessor::parseHeaders($this->headers);
62
+		$normalizedKeys = Utils::normalizeHeaderKeys($headers);
63
+		if (!empty($this->options['decode_content']) && isset($normalizedKeys['content-encoding'])) {
64
+			$headers['x-encoded-content-encoding'] = $headers[$normalizedKeys['content-encoding']];
65
+			unset($headers[$normalizedKeys['content-encoding']]);
66
+			if (isset($normalizedKeys['content-length'])) {
67
+				$headers['x-encoded-content-length'] = $headers[$normalizedKeys['content-length']];
68
+				$bodyLength = (int) $this->sink->getSize();
69
+				if ($bodyLength) {
70
+					$headers[$normalizedKeys['content-length']] = $bodyLength;
71
+				} else {
72
+					unset($headers[$normalizedKeys['content-length']]);
73
+				}
74
+			}
75
+		}
76
+		// Attach a response to the easy handle with the parsed headers.
77
+		$this->response = new Response($status, $headers, $this->sink, $ver, $reason);
78
+	}
79
+	/**
80
+	 * @param string $name
81
+	 *
82
+	 * @return void
83
+	 *
84
+	 * @throws \BadMethodCallException
85
+	 */
86
+	public function __get($name)
87
+	{
88
+		$msg = $name === 'handle' ? 'The EasyHandle has been released' : 'Invalid property: ' . $name;
89
+		throw new \BadMethodCallException($msg);
90
+	}
91 91
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -65,7 +65,7 @@  discard block
 block discarded – undo
65 65
             unset($headers[$normalizedKeys['content-encoding']]);
66 66
             if (isset($normalizedKeys['content-length'])) {
67 67
                 $headers['x-encoded-content-length'] = $headers[$normalizedKeys['content-length']];
68
-                $bodyLength = (int) $this->sink->getSize();
68
+                $bodyLength = (int)$this->sink->getSize();
69 69
                 if ($bodyLength) {
70 70
                     $headers[$normalizedKeys['content-length']] = $bodyLength;
71 71
                 } else {
@@ -85,7 +85,7 @@  discard block
 block discarded – undo
85 85
      */
86 86
     public function __get($name)
87 87
     {
88
-        $msg = $name === 'handle' ? 'The EasyHandle has been released' : 'Invalid property: ' . $name;
88
+        $msg = $name === 'handle' ? 'The EasyHandle has been released' : 'Invalid property: '.$name;
89 89
         throw new \BadMethodCallException($msg);
90 90
     }
91 91
 }
Please login to merge, or discard this patch.
lib/Vendor/GuzzleHttp/Handler/Proxy.php 3 patches
Braces   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -11,8 +11,7 @@
 block discarded – undo
11 11
  *
12 12
  * @final
13 13
  */
14
-class Proxy
15
-{
14
+class Proxy {
16 15
     /**
17 16
      * Sends synchronous requests to a specific handler while sending all other
18 17
      * requests to another handler.
Please login to merge, or discard this patch.
Indentation   +34 added lines, -34 removed lines patch added patch discarded remove patch
@@ -12,38 +12,38 @@
 block discarded – undo
12 12
  */
13 13
 class Proxy
14 14
 {
15
-    /**
16
-     * Sends synchronous requests to a specific handler while sending all other
17
-     * requests to another handler.
18
-     *
19
-     * @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $default Handler used for normal responses
20
-     * @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $sync    Handler used for synchronous responses.
21
-     *
22
-     * @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the composed handler.
23
-     */
24
-    public static function wrapSync(callable $default, callable $sync) : callable
25
-    {
26
-        return static function (RequestInterface $request, array $options) use($default, $sync) : PromiseInterface {
27
-            return empty($options[RequestOptions::SYNCHRONOUS]) ? $default($request, $options) : $sync($request, $options);
28
-        };
29
-    }
30
-    /**
31
-     * Sends streaming requests to a streaming compatible handler while sending
32
-     * all other requests to a default handler.
33
-     *
34
-     * This, for example, could be useful for taking advantage of the
35
-     * performance benefits of curl while still supporting true streaming
36
-     * through the StreamHandler.
37
-     *
38
-     * @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $default   Handler used for non-streaming responses
39
-     * @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $streaming Handler used for streaming responses
40
-     *
41
-     * @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the composed handler.
42
-     */
43
-    public static function wrapStreaming(callable $default, callable $streaming) : callable
44
-    {
45
-        return static function (RequestInterface $request, array $options) use($default, $streaming) : PromiseInterface {
46
-            return empty($options['stream']) ? $default($request, $options) : $streaming($request, $options);
47
-        };
48
-    }
15
+	/**
16
+	 * Sends synchronous requests to a specific handler while sending all other
17
+	 * requests to another handler.
18
+	 *
19
+	 * @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $default Handler used for normal responses
20
+	 * @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $sync    Handler used for synchronous responses.
21
+	 *
22
+	 * @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the composed handler.
23
+	 */
24
+	public static function wrapSync(callable $default, callable $sync) : callable
25
+	{
26
+		return static function (RequestInterface $request, array $options) use($default, $sync) : PromiseInterface {
27
+			return empty($options[RequestOptions::SYNCHRONOUS]) ? $default($request, $options) : $sync($request, $options);
28
+		};
29
+	}
30
+	/**
31
+	 * Sends streaming requests to a streaming compatible handler while sending
32
+	 * all other requests to a default handler.
33
+	 *
34
+	 * This, for example, could be useful for taking advantage of the
35
+	 * performance benefits of curl while still supporting true streaming
36
+	 * through the StreamHandler.
37
+	 *
38
+	 * @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $default   Handler used for non-streaming responses
39
+	 * @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $streaming Handler used for streaming responses
40
+	 *
41
+	 * @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the composed handler.
42
+	 */
43
+	public static function wrapStreaming(callable $default, callable $streaming) : callable
44
+	{
45
+		return static function (RequestInterface $request, array $options) use($default, $streaming) : PromiseInterface {
46
+			return empty($options['stream']) ? $default($request, $options) : $streaming($request, $options);
47
+		};
48
+	}
49 49
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -23,7 +23,7 @@  discard block
 block discarded – undo
23 23
      */
24 24
     public static function wrapSync(callable $default, callable $sync) : callable
25 25
     {
26
-        return static function (RequestInterface $request, array $options) use($default, $sync) : PromiseInterface {
26
+        return static function(RequestInterface $request, array $options) use($default, $sync) : PromiseInterface {
27 27
             return empty($options[RequestOptions::SYNCHRONOUS]) ? $default($request, $options) : $sync($request, $options);
28 28
         };
29 29
     }
@@ -42,7 +42,7 @@  discard block
 block discarded – undo
42 42
      */
43 43
     public static function wrapStreaming(callable $default, callable $streaming) : callable
44 44
     {
45
-        return static function (RequestInterface $request, array $options) use($default, $streaming) : PromiseInterface {
45
+        return static function(RequestInterface $request, array $options) use($default, $streaming) : PromiseInterface {
46 46
             return empty($options['stream']) ? $default($request, $options) : $streaming($request, $options);
47 47
         };
48 48
     }
Please login to merge, or discard this patch.
lib/Vendor/GuzzleHttp/Handler/CurlHandler.php 2 patches
Braces   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -14,8 +14,7 @@
 block discarded – undo
14 14
  *
15 15
  * @final
16 16
  */
17
-class CurlHandler
18
-{
17
+class CurlHandler {
19 18
     /**
20 19
      * @var CurlFactoryInterface
21 20
      */
Please login to merge, or discard this patch.
Indentation   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -15,29 +15,29 @@
 block discarded – undo
15 15
  */
16 16
 class CurlHandler
17 17
 {
18
-    /**
19
-     * @var CurlFactoryInterface
20
-     */
21
-    private $factory;
22
-    /**
23
-     * Accepts an associative array of options:
24
-     *
25
-     * - handle_factory: Optional curl factory used to create cURL handles.
26
-     *
27
-     * @param array{handle_factory?: ?CurlFactoryInterface} $options Array of options to use with the handler
28
-     */
29
-    public function __construct(array $options = [])
30
-    {
31
-        $this->factory = $options['handle_factory'] ?? new CurlFactory(3);
32
-    }
33
-    public function __invoke(RequestInterface $request, array $options) : PromiseInterface
34
-    {
35
-        if (isset($options['delay'])) {
36
-            \usleep($options['delay'] * 1000);
37
-        }
38
-        $easy = $this->factory->create($request, $options);
39
-        \curl_exec($easy->handle);
40
-        $easy->errno = \curl_errno($easy->handle);
41
-        return CurlFactory::finish($this, $easy, $this->factory);
42
-    }
18
+	/**
19
+	 * @var CurlFactoryInterface
20
+	 */
21
+	private $factory;
22
+	/**
23
+	 * Accepts an associative array of options:
24
+	 *
25
+	 * - handle_factory: Optional curl factory used to create cURL handles.
26
+	 *
27
+	 * @param array{handle_factory?: ?CurlFactoryInterface} $options Array of options to use with the handler
28
+	 */
29
+	public function __construct(array $options = [])
30
+	{
31
+		$this->factory = $options['handle_factory'] ?? new CurlFactory(3);
32
+	}
33
+	public function __invoke(RequestInterface $request, array $options) : PromiseInterface
34
+	{
35
+		if (isset($options['delay'])) {
36
+			\usleep($options['delay'] * 1000);
37
+		}
38
+		$easy = $this->factory->create($request, $options);
39
+		\curl_exec($easy->handle);
40
+		$easy->errno = \curl_errno($easy->handle);
41
+		return CurlFactory::finish($this, $easy, $this->factory);
42
+	}
43 43
 }
Please login to merge, or discard this patch.
lib/Vendor/GuzzleHttp/RequestOptions.php 2 patches
Braces   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -7,8 +7,7 @@
 block discarded – undo
7 7
  *
8 8
  * @see https://docs.guzzlephp.org/en/latest/request-options.html
9 9
  */
10
-final class RequestOptions
11
-{
10
+final class RequestOptions {
12 11
     /**
13 12
      * allow_redirects: (bool|array) Controls redirect behavior. Pass false
14 13
      * to disable redirects, pass true to enable redirects, pass an
Please login to merge, or discard this patch.
Indentation   +232 added lines, -232 removed lines patch added patch discarded remove patch
@@ -9,236 +9,236 @@
 block discarded – undo
9 9
  */
10 10
 final class RequestOptions
11 11
 {
12
-    /**
13
-     * allow_redirects: (bool|array) Controls redirect behavior. Pass false
14
-     * to disable redirects, pass true to enable redirects, pass an
15
-     * associative to provide custom redirect settings. Defaults to "false".
16
-     * This option only works if your handler has the RedirectMiddleware. When
17
-     * passing an associative array, you can provide the following key value
18
-     * pairs:
19
-     *
20
-     * - max: (int, default=5) maximum number of allowed redirects.
21
-     * - strict: (bool, default=false) Set to true to use strict redirects
22
-     *   meaning redirect POST requests with POST requests vs. doing what most
23
-     *   browsers do which is redirect POST requests with GET requests
24
-     * - referer: (bool, default=false) Set to true to enable the Referer
25
-     *   header.
26
-     * - protocols: (array, default=['http', 'https']) Allowed redirect
27
-     *   protocols.
28
-     * - on_redirect: (callable) PHP callable that is invoked when a redirect
29
-     *   is encountered. The callable is invoked with the request, the redirect
30
-     *   response that was received, and the effective URI. Any return value
31
-     *   from the on_redirect function is ignored.
32
-     */
33
-    public const ALLOW_REDIRECTS = 'allow_redirects';
34
-    /**
35
-     * auth: (array) Pass an array of HTTP authentication parameters to use
36
-     * with the request. The array must contain the username in index [0],
37
-     * the password in index [1], and you can optionally provide a built-in
38
-     * authentication type in index [2]. Pass null to disable authentication
39
-     * for a request.
40
-     */
41
-    public const AUTH = 'auth';
42
-    /**
43
-     * body: (resource|string|null|int|float|StreamInterface|callable|\Iterator)
44
-     * Body to send in the request.
45
-     */
46
-    public const BODY = 'body';
47
-    /**
48
-     * cert: (string|array) Set to a string to specify the path to a file
49
-     * containing a PEM formatted SSL client side certificate. If a password
50
-     * is required, then set cert to an array containing the path to the PEM
51
-     * file in the first array element followed by the certificate password
52
-     * in the second array element.
53
-     */
54
-    public const CERT = 'cert';
55
-    /**
56
-     * cookies: (bool|GuzzleHttp\Cookie\CookieJarInterface, default=false)
57
-     * Specifies whether or not cookies are used in a request or what cookie
58
-     * jar to use or what cookies to send. This option only works if your
59
-     * handler has the `cookie` middleware. Valid values are `false` and
60
-     * an instance of {@see Cookie\CookieJarInterface}.
61
-     */
62
-    public const COOKIES = 'cookies';
63
-    /**
64
-     * connect_timeout: (float, default=0) Float describing the number of
65
-     * seconds to wait while trying to connect to a server. Use 0 to wait
66
-     * 300 seconds (the default behavior).
67
-     */
68
-    public const CONNECT_TIMEOUT = 'connect_timeout';
69
-    /**
70
-     * crypto_method: (int) A value describing the minimum TLS protocol
71
-     * version to use.
72
-     *
73
-     * This setting must be set to one of the
74
-     * ``STREAM_CRYPTO_METHOD_TLS*_CLIENT`` constants. PHP 7.4 or higher is
75
-     * required in order to use TLS 1.3, and cURL 7.34.0 or higher is required
76
-     * in order to specify a crypto method, with cURL 7.52.0 or higher being
77
-     * required to use TLS 1.3.
78
-     */
79
-    public const CRYPTO_METHOD = 'crypto_method';
80
-    /**
81
-     * debug: (bool|resource) Set to true or set to a PHP stream returned by
82
-     * fopen()  enable debug output with the HTTP handler used to send a
83
-     * request.
84
-     */
85
-    public const DEBUG = 'debug';
86
-    /**
87
-     * decode_content: (bool, default=true) Specify whether or not
88
-     * Content-Encoding responses (gzip, deflate, etc.) are automatically
89
-     * decoded.
90
-     */
91
-    public const DECODE_CONTENT = 'decode_content';
92
-    /**
93
-     * delay: (int) The amount of time to delay before sending in milliseconds.
94
-     */
95
-    public const DELAY = 'delay';
96
-    /**
97
-     * expect: (bool|integer) Controls the behavior of the
98
-     * "Expect: 100-Continue" header.
99
-     *
100
-     * Set to `true` to enable the "Expect: 100-Continue" header for all
101
-     * requests that sends a body. Set to `false` to disable the
102
-     * "Expect: 100-Continue" header for all requests. Set to a number so that
103
-     * the size of the payload must be greater than the number in order to send
104
-     * the Expect header. Setting to a number will send the Expect header for
105
-     * all requests in which the size of the payload cannot be determined or
106
-     * where the body is not rewindable.
107
-     *
108
-     * By default, Guzzle will add the "Expect: 100-Continue" header when the
109
-     * size of the body of a request is greater than 1 MB and a request is
110
-     * using HTTP/1.1.
111
-     */
112
-    public const EXPECT = 'expect';
113
-    /**
114
-     * form_params: (array) Associative array of form field names to values
115
-     * where each value is a string or array of strings. Sets the Content-Type
116
-     * header to application/x-www-form-urlencoded when no Content-Type header
117
-     * is already present.
118
-     */
119
-    public const FORM_PARAMS = 'form_params';
120
-    /**
121
-     * headers: (array) Associative array of HTTP headers. Each value MUST be
122
-     * a string or array of strings.
123
-     */
124
-    public const HEADERS = 'headers';
125
-    /**
126
-     * http_errors: (bool, default=true) Set to false to disable exceptions
127
-     * when a non- successful HTTP response is received. By default,
128
-     * exceptions will be thrown for 4xx and 5xx responses. This option only
129
-     * works if your handler has the `httpErrors` middleware.
130
-     */
131
-    public const HTTP_ERRORS = 'http_errors';
132
-    /**
133
-     * idn: (bool|int, default=true) A combination of IDNA_* constants for
134
-     * idn_to_ascii() PHP's function (see "options" parameter). Set to false to
135
-     * disable IDN support completely, or to true to use the default
136
-     * configuration (IDNA_DEFAULT constant).
137
-     */
138
-    public const IDN_CONVERSION = 'idn_conversion';
139
-    /**
140
-     * json: (mixed) Adds JSON data to a request. The provided value is JSON
141
-     * encoded and a Content-Type header of application/json will be added to
142
-     * the request if no Content-Type header is already present.
143
-     */
144
-    public const JSON = 'json';
145
-    /**
146
-     * multipart: (array) Array of associative arrays, each containing a
147
-     * required "name" key mapping to the form field, name, a required
148
-     * "contents" key mapping to a StreamInterface|resource|string, an
149
-     * optional "headers" associative array of custom headers, and an
150
-     * optional "filename" key mapping to a string to send as the filename in
151
-     * the part. If no "filename" key is present, then no "filename" attribute
152
-     * will be added to the part.
153
-     */
154
-    public const MULTIPART = 'multipart';
155
-    /**
156
-     * on_headers: (callable) A callable that is invoked when the HTTP headers
157
-     * of the response have been received but the body has not yet begun to
158
-     * download.
159
-     */
160
-    public const ON_HEADERS = 'on_headers';
161
-    /**
162
-     * on_stats: (callable) allows you to get access to transfer statistics of
163
-     * a request and access the lower level transfer details of the handler
164
-     * associated with your client. ``on_stats`` is a callable that is invoked
165
-     * when a handler has finished sending a request. The callback is invoked
166
-     * with transfer statistics about the request, the response received, or
167
-     * the error encountered. Included in the data is the total amount of time
168
-     * taken to send the request.
169
-     */
170
-    public const ON_STATS = 'on_stats';
171
-    /**
172
-     * progress: (callable) Defines a function to invoke when transfer
173
-     * progress is made. The function accepts the following positional
174
-     * arguments: the total number of bytes expected to be downloaded, the
175
-     * number of bytes downloaded so far, the number of bytes expected to be
176
-     * uploaded, the number of bytes uploaded so far.
177
-     */
178
-    public const PROGRESS = 'progress';
179
-    /**
180
-     * proxy: (string|array) Pass a string to specify an HTTP proxy, or an
181
-     * array to specify different proxies for different protocols (where the
182
-     * key is the protocol and the value is a proxy string).
183
-     */
184
-    public const PROXY = 'proxy';
185
-    /**
186
-     * query: (array|string) Associative array of query string values to add
187
-     * to the request. This option uses PHP's http_build_query() to create
188
-     * the string representation. Pass a string value if you need more
189
-     * control than what this method provides
190
-     */
191
-    public const QUERY = 'query';
192
-    /**
193
-     * sink: (resource|string|StreamInterface) Where the data of the
194
-     * response is written to. Defaults to a PHP temp stream. Providing a
195
-     * string will write data to a file by the given name.
196
-     */
197
-    public const SINK = 'sink';
198
-    /**
199
-     * synchronous: (bool) Set to true to inform HTTP handlers that you intend
200
-     * on waiting on the response. This can be useful for optimizations. Note
201
-     * that a promise is still returned if you are using one of the async
202
-     * client methods.
203
-     */
204
-    public const SYNCHRONOUS = 'synchronous';
205
-    /**
206
-     * ssl_key: (array|string) Specify the path to a file containing a private
207
-     * SSL key in PEM format. If a password is required, then set to an array
208
-     * containing the path to the SSL key in the first array element followed
209
-     * by the password required for the certificate in the second element.
210
-     */
211
-    public const SSL_KEY = 'ssl_key';
212
-    /**
213
-     * stream: Set to true to attempt to stream a response rather than
214
-     * download it all up-front.
215
-     */
216
-    public const STREAM = 'stream';
217
-    /**
218
-     * verify: (bool|string, default=true) Describes the SSL certificate
219
-     * verification behavior of a request. Set to true to enable SSL
220
-     * certificate verification using the system CA bundle when available
221
-     * (the default). Set to false to disable certificate verification (this
222
-     * is insecure!). Set to a string to provide the path to a CA bundle on
223
-     * disk to enable verification using a custom certificate.
224
-     */
225
-    public const VERIFY = 'verify';
226
-    /**
227
-     * timeout: (float, default=0) Float describing the timeout of the
228
-     * request in seconds. Use 0 to wait indefinitely (the default behavior).
229
-     */
230
-    public const TIMEOUT = 'timeout';
231
-    /**
232
-     * read_timeout: (float, default=default_socket_timeout ini setting) Float describing
233
-     * the body read timeout, for stream requests.
234
-     */
235
-    public const READ_TIMEOUT = 'read_timeout';
236
-    /**
237
-     * version: (float) Specifies the HTTP protocol version to attempt to use.
238
-     */
239
-    public const VERSION = 'version';
240
-    /**
241
-     * force_ip_resolve: (bool) Force client to use only ipv4 or ipv6 protocol
242
-     */
243
-    public const FORCE_IP_RESOLVE = 'force_ip_resolve';
12
+	/**
13
+	 * allow_redirects: (bool|array) Controls redirect behavior. Pass false
14
+	 * to disable redirects, pass true to enable redirects, pass an
15
+	 * associative to provide custom redirect settings. Defaults to "false".
16
+	 * This option only works if your handler has the RedirectMiddleware. When
17
+	 * passing an associative array, you can provide the following key value
18
+	 * pairs:
19
+	 *
20
+	 * - max: (int, default=5) maximum number of allowed redirects.
21
+	 * - strict: (bool, default=false) Set to true to use strict redirects
22
+	 *   meaning redirect POST requests with POST requests vs. doing what most
23
+	 *   browsers do which is redirect POST requests with GET requests
24
+	 * - referer: (bool, default=false) Set to true to enable the Referer
25
+	 *   header.
26
+	 * - protocols: (array, default=['http', 'https']) Allowed redirect
27
+	 *   protocols.
28
+	 * - on_redirect: (callable) PHP callable that is invoked when a redirect
29
+	 *   is encountered. The callable is invoked with the request, the redirect
30
+	 *   response that was received, and the effective URI. Any return value
31
+	 *   from the on_redirect function is ignored.
32
+	 */
33
+	public const ALLOW_REDIRECTS = 'allow_redirects';
34
+	/**
35
+	 * auth: (array) Pass an array of HTTP authentication parameters to use
36
+	 * with the request. The array must contain the username in index [0],
37
+	 * the password in index [1], and you can optionally provide a built-in
38
+	 * authentication type in index [2]. Pass null to disable authentication
39
+	 * for a request.
40
+	 */
41
+	public const AUTH = 'auth';
42
+	/**
43
+	 * body: (resource|string|null|int|float|StreamInterface|callable|\Iterator)
44
+	 * Body to send in the request.
45
+	 */
46
+	public const BODY = 'body';
47
+	/**
48
+	 * cert: (string|array) Set to a string to specify the path to a file
49
+	 * containing a PEM formatted SSL client side certificate. If a password
50
+	 * is required, then set cert to an array containing the path to the PEM
51
+	 * file in the first array element followed by the certificate password
52
+	 * in the second array element.
53
+	 */
54
+	public const CERT = 'cert';
55
+	/**
56
+	 * cookies: (bool|GuzzleHttp\Cookie\CookieJarInterface, default=false)
57
+	 * Specifies whether or not cookies are used in a request or what cookie
58
+	 * jar to use or what cookies to send. This option only works if your
59
+	 * handler has the `cookie` middleware. Valid values are `false` and
60
+	 * an instance of {@see Cookie\CookieJarInterface}.
61
+	 */
62
+	public const COOKIES = 'cookies';
63
+	/**
64
+	 * connect_timeout: (float, default=0) Float describing the number of
65
+	 * seconds to wait while trying to connect to a server. Use 0 to wait
66
+	 * 300 seconds (the default behavior).
67
+	 */
68
+	public const CONNECT_TIMEOUT = 'connect_timeout';
69
+	/**
70
+	 * crypto_method: (int) A value describing the minimum TLS protocol
71
+	 * version to use.
72
+	 *
73
+	 * This setting must be set to one of the
74
+	 * ``STREAM_CRYPTO_METHOD_TLS*_CLIENT`` constants. PHP 7.4 or higher is
75
+	 * required in order to use TLS 1.3, and cURL 7.34.0 or higher is required
76
+	 * in order to specify a crypto method, with cURL 7.52.0 or higher being
77
+	 * required to use TLS 1.3.
78
+	 */
79
+	public const CRYPTO_METHOD = 'crypto_method';
80
+	/**
81
+	 * debug: (bool|resource) Set to true or set to a PHP stream returned by
82
+	 * fopen()  enable debug output with the HTTP handler used to send a
83
+	 * request.
84
+	 */
85
+	public const DEBUG = 'debug';
86
+	/**
87
+	 * decode_content: (bool, default=true) Specify whether or not
88
+	 * Content-Encoding responses (gzip, deflate, etc.) are automatically
89
+	 * decoded.
90
+	 */
91
+	public const DECODE_CONTENT = 'decode_content';
92
+	/**
93
+	 * delay: (int) The amount of time to delay before sending in milliseconds.
94
+	 */
95
+	public const DELAY = 'delay';
96
+	/**
97
+	 * expect: (bool|integer) Controls the behavior of the
98
+	 * "Expect: 100-Continue" header.
99
+	 *
100
+	 * Set to `true` to enable the "Expect: 100-Continue" header for all
101
+	 * requests that sends a body. Set to `false` to disable the
102
+	 * "Expect: 100-Continue" header for all requests. Set to a number so that
103
+	 * the size of the payload must be greater than the number in order to send
104
+	 * the Expect header. Setting to a number will send the Expect header for
105
+	 * all requests in which the size of the payload cannot be determined or
106
+	 * where the body is not rewindable.
107
+	 *
108
+	 * By default, Guzzle will add the "Expect: 100-Continue" header when the
109
+	 * size of the body of a request is greater than 1 MB and a request is
110
+	 * using HTTP/1.1.
111
+	 */
112
+	public const EXPECT = 'expect';
113
+	/**
114
+	 * form_params: (array) Associative array of form field names to values
115
+	 * where each value is a string or array of strings. Sets the Content-Type
116
+	 * header to application/x-www-form-urlencoded when no Content-Type header
117
+	 * is already present.
118
+	 */
119
+	public const FORM_PARAMS = 'form_params';
120
+	/**
121
+	 * headers: (array) Associative array of HTTP headers. Each value MUST be
122
+	 * a string or array of strings.
123
+	 */
124
+	public const HEADERS = 'headers';
125
+	/**
126
+	 * http_errors: (bool, default=true) Set to false to disable exceptions
127
+	 * when a non- successful HTTP response is received. By default,
128
+	 * exceptions will be thrown for 4xx and 5xx responses. This option only
129
+	 * works if your handler has the `httpErrors` middleware.
130
+	 */
131
+	public const HTTP_ERRORS = 'http_errors';
132
+	/**
133
+	 * idn: (bool|int, default=true) A combination of IDNA_* constants for
134
+	 * idn_to_ascii() PHP's function (see "options" parameter). Set to false to
135
+	 * disable IDN support completely, or to true to use the default
136
+	 * configuration (IDNA_DEFAULT constant).
137
+	 */
138
+	public const IDN_CONVERSION = 'idn_conversion';
139
+	/**
140
+	 * json: (mixed) Adds JSON data to a request. The provided value is JSON
141
+	 * encoded and a Content-Type header of application/json will be added to
142
+	 * the request if no Content-Type header is already present.
143
+	 */
144
+	public const JSON = 'json';
145
+	/**
146
+	 * multipart: (array) Array of associative arrays, each containing a
147
+	 * required "name" key mapping to the form field, name, a required
148
+	 * "contents" key mapping to a StreamInterface|resource|string, an
149
+	 * optional "headers" associative array of custom headers, and an
150
+	 * optional "filename" key mapping to a string to send as the filename in
151
+	 * the part. If no "filename" key is present, then no "filename" attribute
152
+	 * will be added to the part.
153
+	 */
154
+	public const MULTIPART = 'multipart';
155
+	/**
156
+	 * on_headers: (callable) A callable that is invoked when the HTTP headers
157
+	 * of the response have been received but the body has not yet begun to
158
+	 * download.
159
+	 */
160
+	public const ON_HEADERS = 'on_headers';
161
+	/**
162
+	 * on_stats: (callable) allows you to get access to transfer statistics of
163
+	 * a request and access the lower level transfer details of the handler
164
+	 * associated with your client. ``on_stats`` is a callable that is invoked
165
+	 * when a handler has finished sending a request. The callback is invoked
166
+	 * with transfer statistics about the request, the response received, or
167
+	 * the error encountered. Included in the data is the total amount of time
168
+	 * taken to send the request.
169
+	 */
170
+	public const ON_STATS = 'on_stats';
171
+	/**
172
+	 * progress: (callable) Defines a function to invoke when transfer
173
+	 * progress is made. The function accepts the following positional
174
+	 * arguments: the total number of bytes expected to be downloaded, the
175
+	 * number of bytes downloaded so far, the number of bytes expected to be
176
+	 * uploaded, the number of bytes uploaded so far.
177
+	 */
178
+	public const PROGRESS = 'progress';
179
+	/**
180
+	 * proxy: (string|array) Pass a string to specify an HTTP proxy, or an
181
+	 * array to specify different proxies for different protocols (where the
182
+	 * key is the protocol and the value is a proxy string).
183
+	 */
184
+	public const PROXY = 'proxy';
185
+	/**
186
+	 * query: (array|string) Associative array of query string values to add
187
+	 * to the request. This option uses PHP's http_build_query() to create
188
+	 * the string representation. Pass a string value if you need more
189
+	 * control than what this method provides
190
+	 */
191
+	public const QUERY = 'query';
192
+	/**
193
+	 * sink: (resource|string|StreamInterface) Where the data of the
194
+	 * response is written to. Defaults to a PHP temp stream. Providing a
195
+	 * string will write data to a file by the given name.
196
+	 */
197
+	public const SINK = 'sink';
198
+	/**
199
+	 * synchronous: (bool) Set to true to inform HTTP handlers that you intend
200
+	 * on waiting on the response. This can be useful for optimizations. Note
201
+	 * that a promise is still returned if you are using one of the async
202
+	 * client methods.
203
+	 */
204
+	public const SYNCHRONOUS = 'synchronous';
205
+	/**
206
+	 * ssl_key: (array|string) Specify the path to a file containing a private
207
+	 * SSL key in PEM format. If a password is required, then set to an array
208
+	 * containing the path to the SSL key in the first array element followed
209
+	 * by the password required for the certificate in the second element.
210
+	 */
211
+	public const SSL_KEY = 'ssl_key';
212
+	/**
213
+	 * stream: Set to true to attempt to stream a response rather than
214
+	 * download it all up-front.
215
+	 */
216
+	public const STREAM = 'stream';
217
+	/**
218
+	 * verify: (bool|string, default=true) Describes the SSL certificate
219
+	 * verification behavior of a request. Set to true to enable SSL
220
+	 * certificate verification using the system CA bundle when available
221
+	 * (the default). Set to false to disable certificate verification (this
222
+	 * is insecure!). Set to a string to provide the path to a CA bundle on
223
+	 * disk to enable verification using a custom certificate.
224
+	 */
225
+	public const VERIFY = 'verify';
226
+	/**
227
+	 * timeout: (float, default=0) Float describing the timeout of the
228
+	 * request in seconds. Use 0 to wait indefinitely (the default behavior).
229
+	 */
230
+	public const TIMEOUT = 'timeout';
231
+	/**
232
+	 * read_timeout: (float, default=default_socket_timeout ini setting) Float describing
233
+	 * the body read timeout, for stream requests.
234
+	 */
235
+	public const READ_TIMEOUT = 'read_timeout';
236
+	/**
237
+	 * version: (float) Specifies the HTTP protocol version to attempt to use.
238
+	 */
239
+	public const VERSION = 'version';
240
+	/**
241
+	 * force_ip_resolve: (bool) Force client to use only ipv4 or ipv6 protocol
242
+	 */
243
+	public const FORCE_IP_RESOLVE = 'force_ip_resolve';
244 244
 }
Please login to merge, or discard this patch.
lib/Vendor/GuzzleHttp/Cookie/SetCookie.php 3 patches
Braces   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -5,8 +5,7 @@
 block discarded – undo
5 5
 /**
6 6
  * Set-Cookie object
7 7
  */
8
-class SetCookie
9
-{
8
+class SetCookie {
10 9
     /**
11 10
      * @var array
12 11
      */
Please login to merge, or discard this patch.
Indentation   +397 added lines, -397 removed lines patch added patch discarded remove patch
@@ -7,401 +7,401 @@
 block discarded – undo
7 7
  */
8 8
 class SetCookie
9 9
 {
10
-    /**
11
-     * @var array
12
-     */
13
-    private static $defaults = ['Name' => null, 'Value' => null, 'Domain' => null, 'Path' => '/', 'Max-Age' => null, 'Expires' => null, 'Secure' => \false, 'Discard' => \false, 'HttpOnly' => \false];
14
-    /**
15
-     * @var array Cookie data
16
-     */
17
-    private $data;
18
-    /**
19
-     * Create a new SetCookie object from a string.
20
-     *
21
-     * @param string $cookie Set-Cookie header string
22
-     */
23
-    public static function fromString(string $cookie) : self
24
-    {
25
-        // Create the default return array
26
-        $data = self::$defaults;
27
-        // Explode the cookie string using a series of semicolons
28
-        $pieces = \array_filter(\array_map('trim', \explode(';', $cookie)));
29
-        // The name of the cookie (first kvp) must exist and include an equal sign.
30
-        if (!isset($pieces[0]) || \strpos($pieces[0], '=') === \false) {
31
-            return new self($data);
32
-        }
33
-        // Add the cookie pieces into the parsed data array
34
-        foreach ($pieces as $part) {
35
-            $cookieParts = \explode('=', $part, 2);
36
-            $key = \trim($cookieParts[0]);
37
-            $value = isset($cookieParts[1]) ? \trim($cookieParts[1], " \n\r\t\x00\v") : \true;
38
-            // Only check for non-cookies when cookies have been found
39
-            if (!isset($data['Name'])) {
40
-                $data['Name'] = $key;
41
-                $data['Value'] = $value;
42
-            } else {
43
-                foreach (\array_keys(self::$defaults) as $search) {
44
-                    if (!\strcasecmp($search, $key)) {
45
-                        if ($search === 'Max-Age') {
46
-                            if (\is_numeric($value)) {
47
-                                $data[$search] = (int) $value;
48
-                            }
49
-                        } else {
50
-                            $data[$search] = $value;
51
-                        }
52
-                        continue 2;
53
-                    }
54
-                }
55
-                $data[$key] = $value;
56
-            }
57
-        }
58
-        return new self($data);
59
-    }
60
-    /**
61
-     * @param array $data Array of cookie data provided by a Cookie parser
62
-     */
63
-    public function __construct(array $data = [])
64
-    {
65
-        $this->data = self::$defaults;
66
-        if (isset($data['Name'])) {
67
-            $this->setName($data['Name']);
68
-        }
69
-        if (isset($data['Value'])) {
70
-            $this->setValue($data['Value']);
71
-        }
72
-        if (isset($data['Domain'])) {
73
-            $this->setDomain($data['Domain']);
74
-        }
75
-        if (isset($data['Path'])) {
76
-            $this->setPath($data['Path']);
77
-        }
78
-        if (isset($data['Max-Age'])) {
79
-            $this->setMaxAge($data['Max-Age']);
80
-        }
81
-        if (isset($data['Expires'])) {
82
-            $this->setExpires($data['Expires']);
83
-        }
84
-        if (isset($data['Secure'])) {
85
-            $this->setSecure($data['Secure']);
86
-        }
87
-        if (isset($data['Discard'])) {
88
-            $this->setDiscard($data['Discard']);
89
-        }
90
-        if (isset($data['HttpOnly'])) {
91
-            $this->setHttpOnly($data['HttpOnly']);
92
-        }
93
-        // Set the remaining values that don't have extra validation logic
94
-        foreach (\array_diff(\array_keys($data), \array_keys(self::$defaults)) as $key) {
95
-            $this->data[$key] = $data[$key];
96
-        }
97
-        // Extract the Expires value and turn it into a UNIX timestamp if needed
98
-        if (!$this->getExpires() && $this->getMaxAge()) {
99
-            // Calculate the Expires date
100
-            $this->setExpires(\time() + $this->getMaxAge());
101
-        } elseif (null !== ($expires = $this->getExpires()) && !\is_numeric($expires)) {
102
-            $this->setExpires($expires);
103
-        }
104
-    }
105
-    public function __toString()
106
-    {
107
-        $str = $this->data['Name'] . '=' . ($this->data['Value'] ?? '') . '; ';
108
-        foreach ($this->data as $k => $v) {
109
-            if ($k !== 'Name' && $k !== 'Value' && $v !== null && $v !== \false) {
110
-                if ($k === 'Expires') {
111
-                    $str .= 'Expires=' . \gmdate('D, d M Y H:i:s \\G\\M\\T', $v) . '; ';
112
-                } else {
113
-                    $str .= ($v === \true ? $k : "{$k}={$v}") . '; ';
114
-                }
115
-            }
116
-        }
117
-        return \rtrim($str, '; ');
118
-    }
119
-    public function toArray() : array
120
-    {
121
-        return $this->data;
122
-    }
123
-    /**
124
-     * Get the cookie name.
125
-     *
126
-     * @return string
127
-     */
128
-    public function getName()
129
-    {
130
-        return $this->data['Name'];
131
-    }
132
-    /**
133
-     * Set the cookie name.
134
-     *
135
-     * @param string $name Cookie name
136
-     */
137
-    public function setName($name) : void
138
-    {
139
-        if (!\is_string($name)) {
140
-            trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
141
-        }
142
-        $this->data['Name'] = (string) $name;
143
-    }
144
-    /**
145
-     * Get the cookie value.
146
-     *
147
-     * @return string|null
148
-     */
149
-    public function getValue()
150
-    {
151
-        return $this->data['Value'];
152
-    }
153
-    /**
154
-     * Set the cookie value.
155
-     *
156
-     * @param string $value Cookie value
157
-     */
158
-    public function setValue($value) : void
159
-    {
160
-        if (!\is_string($value)) {
161
-            trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
162
-        }
163
-        $this->data['Value'] = (string) $value;
164
-    }
165
-    /**
166
-     * Get the domain.
167
-     *
168
-     * @return string|null
169
-     */
170
-    public function getDomain()
171
-    {
172
-        return $this->data['Domain'];
173
-    }
174
-    /**
175
-     * Set the domain of the cookie.
176
-     *
177
-     * @param string|null $domain
178
-     */
179
-    public function setDomain($domain) : void
180
-    {
181
-        if (!\is_string($domain) && null !== $domain) {
182
-            trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string or null to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
183
-        }
184
-        $this->data['Domain'] = null === $domain ? null : (string) $domain;
185
-    }
186
-    /**
187
-     * Get the path.
188
-     *
189
-     * @return string
190
-     */
191
-    public function getPath()
192
-    {
193
-        return $this->data['Path'];
194
-    }
195
-    /**
196
-     * Set the path of the cookie.
197
-     *
198
-     * @param string $path Path of the cookie
199
-     */
200
-    public function setPath($path) : void
201
-    {
202
-        if (!\is_string($path)) {
203
-            trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
204
-        }
205
-        $this->data['Path'] = (string) $path;
206
-    }
207
-    /**
208
-     * Maximum lifetime of the cookie in seconds.
209
-     *
210
-     * @return int|null
211
-     */
212
-    public function getMaxAge()
213
-    {
214
-        return null === $this->data['Max-Age'] ? null : (int) $this->data['Max-Age'];
215
-    }
216
-    /**
217
-     * Set the max-age of the cookie.
218
-     *
219
-     * @param int|null $maxAge Max age of the cookie in seconds
220
-     */
221
-    public function setMaxAge($maxAge) : void
222
-    {
223
-        if (!\is_int($maxAge) && null !== $maxAge) {
224
-            trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing an int or null to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
225
-        }
226
-        $this->data['Max-Age'] = $maxAge === null ? null : (int) $maxAge;
227
-    }
228
-    /**
229
-     * The UNIX timestamp when the cookie Expires.
230
-     *
231
-     * @return string|int|null
232
-     */
233
-    public function getExpires()
234
-    {
235
-        return $this->data['Expires'];
236
-    }
237
-    /**
238
-     * Set the unix timestamp for which the cookie will expire.
239
-     *
240
-     * @param int|string|null $timestamp Unix timestamp or any English textual datetime description.
241
-     */
242
-    public function setExpires($timestamp) : void
243
-    {
244
-        if (!\is_int($timestamp) && !\is_string($timestamp) && null !== $timestamp) {
245
-            trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing an int, string or null to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
246
-        }
247
-        $this->data['Expires'] = null === $timestamp ? null : (\is_numeric($timestamp) ? (int) $timestamp : \strtotime((string) $timestamp));
248
-    }
249
-    /**
250
-     * Get whether or not this is a secure cookie.
251
-     *
252
-     * @return bool
253
-     */
254
-    public function getSecure()
255
-    {
256
-        return $this->data['Secure'];
257
-    }
258
-    /**
259
-     * Set whether or not the cookie is secure.
260
-     *
261
-     * @param bool $secure Set to true or false if secure
262
-     */
263
-    public function setSecure($secure) : void
264
-    {
265
-        if (!\is_bool($secure)) {
266
-            trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a bool to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
267
-        }
268
-        $this->data['Secure'] = (bool) $secure;
269
-    }
270
-    /**
271
-     * Get whether or not this is a session cookie.
272
-     *
273
-     * @return bool|null
274
-     */
275
-    public function getDiscard()
276
-    {
277
-        return $this->data['Discard'];
278
-    }
279
-    /**
280
-     * Set whether or not this is a session cookie.
281
-     *
282
-     * @param bool $discard Set to true or false if this is a session cookie
283
-     */
284
-    public function setDiscard($discard) : void
285
-    {
286
-        if (!\is_bool($discard)) {
287
-            trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a bool to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
288
-        }
289
-        $this->data['Discard'] = (bool) $discard;
290
-    }
291
-    /**
292
-     * Get whether or not this is an HTTP only cookie.
293
-     *
294
-     * @return bool
295
-     */
296
-    public function getHttpOnly()
297
-    {
298
-        return $this->data['HttpOnly'];
299
-    }
300
-    /**
301
-     * Set whether or not this is an HTTP only cookie.
302
-     *
303
-     * @param bool $httpOnly Set to true or false if this is HTTP only
304
-     */
305
-    public function setHttpOnly($httpOnly) : void
306
-    {
307
-        if (!\is_bool($httpOnly)) {
308
-            trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a bool to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
309
-        }
310
-        $this->data['HttpOnly'] = (bool) $httpOnly;
311
-    }
312
-    /**
313
-     * Check if the cookie matches a path value.
314
-     *
315
-     * A request-path path-matches a given cookie-path if at least one of
316
-     * the following conditions holds:
317
-     *
318
-     * - The cookie-path and the request-path are identical.
319
-     * - The cookie-path is a prefix of the request-path, and the last
320
-     *   character of the cookie-path is %x2F ("/").
321
-     * - The cookie-path is a prefix of the request-path, and the first
322
-     *   character of the request-path that is not included in the cookie-
323
-     *   path is a %x2F ("/") character.
324
-     *
325
-     * @param string $requestPath Path to check against
326
-     */
327
-    public function matchesPath(string $requestPath) : bool
328
-    {
329
-        $cookiePath = $this->getPath();
330
-        // Match on exact matches or when path is the default empty "/"
331
-        if ($cookiePath === '/' || $cookiePath == $requestPath) {
332
-            return \true;
333
-        }
334
-        // Ensure that the cookie-path is a prefix of the request path.
335
-        if (0 !== \strpos($requestPath, $cookiePath)) {
336
-            return \false;
337
-        }
338
-        // Match if the last character of the cookie-path is "/"
339
-        if (\substr($cookiePath, -1, 1) === '/') {
340
-            return \true;
341
-        }
342
-        // Match if the first character not included in cookie path is "/"
343
-        return \substr($requestPath, \strlen($cookiePath), 1) === '/';
344
-    }
345
-    /**
346
-     * Check if the cookie matches a domain value.
347
-     *
348
-     * @param string $domain Domain to check against
349
-     */
350
-    public function matchesDomain(string $domain) : bool
351
-    {
352
-        $cookieDomain = $this->getDomain();
353
-        if (null === $cookieDomain) {
354
-            return \true;
355
-        }
356
-        // Remove the leading '.' as per spec in RFC 6265.
357
-        // https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.3
358
-        $cookieDomain = \ltrim(\strtolower($cookieDomain), '.');
359
-        $domain = \strtolower($domain);
360
-        // Domain not set or exact match.
361
-        if ('' === $cookieDomain || $domain === $cookieDomain) {
362
-            return \true;
363
-        }
364
-        // Matching the subdomain according to RFC 6265.
365
-        // https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.3
366
-        if (\filter_var($domain, \FILTER_VALIDATE_IP)) {
367
-            return \false;
368
-        }
369
-        return (bool) \preg_match('/\\.' . \preg_quote($cookieDomain, '/') . '$/', $domain);
370
-    }
371
-    /**
372
-     * Check if the cookie is expired.
373
-     */
374
-    public function isExpired() : bool
375
-    {
376
-        return $this->getExpires() !== null && \time() > $this->getExpires();
377
-    }
378
-    /**
379
-     * Check if the cookie is valid according to RFC 6265.
380
-     *
381
-     * @return bool|string Returns true if valid or an error message if invalid
382
-     */
383
-    public function validate()
384
-    {
385
-        $name = $this->getName();
386
-        if ($name === '') {
387
-            return 'The cookie name must not be empty';
388
-        }
389
-        // Check if any of the invalid characters are present in the cookie name
390
-        if (\preg_match('/[\\x00-\\x20\\x22\\x28-\\x29\\x2c\\x2f\\x3a-\\x40\\x5c\\x7b\\x7d\\x7f]/', $name)) {
391
-            return 'Cookie name must not contain invalid characters: ASCII ' . 'Control characters (0-31;127), space, tab and the ' . 'following characters: ()<>@,;:\\"/?={}';
392
-        }
393
-        // Value must not be null. 0 and empty string are valid. Empty strings
394
-        // are technically against RFC 6265, but known to happen in the wild.
395
-        $value = $this->getValue();
396
-        if ($value === null) {
397
-            return 'The cookie value must not be empty';
398
-        }
399
-        // Domains must not be empty, but can be 0. "0" is not a valid internet
400
-        // domain, but may be used as server name in a private network.
401
-        $domain = $this->getDomain();
402
-        if ($domain === null || $domain === '') {
403
-            return 'The cookie domain must not be empty';
404
-        }
405
-        return \true;
406
-    }
10
+	/**
11
+	 * @var array
12
+	 */
13
+	private static $defaults = ['Name' => null, 'Value' => null, 'Domain' => null, 'Path' => '/', 'Max-Age' => null, 'Expires' => null, 'Secure' => \false, 'Discard' => \false, 'HttpOnly' => \false];
14
+	/**
15
+	 * @var array Cookie data
16
+	 */
17
+	private $data;
18
+	/**
19
+	 * Create a new SetCookie object from a string.
20
+	 *
21
+	 * @param string $cookie Set-Cookie header string
22
+	 */
23
+	public static function fromString(string $cookie) : self
24
+	{
25
+		// Create the default return array
26
+		$data = self::$defaults;
27
+		// Explode the cookie string using a series of semicolons
28
+		$pieces = \array_filter(\array_map('trim', \explode(';', $cookie)));
29
+		// The name of the cookie (first kvp) must exist and include an equal sign.
30
+		if (!isset($pieces[0]) || \strpos($pieces[0], '=') === \false) {
31
+			return new self($data);
32
+		}
33
+		// Add the cookie pieces into the parsed data array
34
+		foreach ($pieces as $part) {
35
+			$cookieParts = \explode('=', $part, 2);
36
+			$key = \trim($cookieParts[0]);
37
+			$value = isset($cookieParts[1]) ? \trim($cookieParts[1], " \n\r\t\x00\v") : \true;
38
+			// Only check for non-cookies when cookies have been found
39
+			if (!isset($data['Name'])) {
40
+				$data['Name'] = $key;
41
+				$data['Value'] = $value;
42
+			} else {
43
+				foreach (\array_keys(self::$defaults) as $search) {
44
+					if (!\strcasecmp($search, $key)) {
45
+						if ($search === 'Max-Age') {
46
+							if (\is_numeric($value)) {
47
+								$data[$search] = (int) $value;
48
+							}
49
+						} else {
50
+							$data[$search] = $value;
51
+						}
52
+						continue 2;
53
+					}
54
+				}
55
+				$data[$key] = $value;
56
+			}
57
+		}
58
+		return new self($data);
59
+	}
60
+	/**
61
+	 * @param array $data Array of cookie data provided by a Cookie parser
62
+	 */
63
+	public function __construct(array $data = [])
64
+	{
65
+		$this->data = self::$defaults;
66
+		if (isset($data['Name'])) {
67
+			$this->setName($data['Name']);
68
+		}
69
+		if (isset($data['Value'])) {
70
+			$this->setValue($data['Value']);
71
+		}
72
+		if (isset($data['Domain'])) {
73
+			$this->setDomain($data['Domain']);
74
+		}
75
+		if (isset($data['Path'])) {
76
+			$this->setPath($data['Path']);
77
+		}
78
+		if (isset($data['Max-Age'])) {
79
+			$this->setMaxAge($data['Max-Age']);
80
+		}
81
+		if (isset($data['Expires'])) {
82
+			$this->setExpires($data['Expires']);
83
+		}
84
+		if (isset($data['Secure'])) {
85
+			$this->setSecure($data['Secure']);
86
+		}
87
+		if (isset($data['Discard'])) {
88
+			$this->setDiscard($data['Discard']);
89
+		}
90
+		if (isset($data['HttpOnly'])) {
91
+			$this->setHttpOnly($data['HttpOnly']);
92
+		}
93
+		// Set the remaining values that don't have extra validation logic
94
+		foreach (\array_diff(\array_keys($data), \array_keys(self::$defaults)) as $key) {
95
+			$this->data[$key] = $data[$key];
96
+		}
97
+		// Extract the Expires value and turn it into a UNIX timestamp if needed
98
+		if (!$this->getExpires() && $this->getMaxAge()) {
99
+			// Calculate the Expires date
100
+			$this->setExpires(\time() + $this->getMaxAge());
101
+		} elseif (null !== ($expires = $this->getExpires()) && !\is_numeric($expires)) {
102
+			$this->setExpires($expires);
103
+		}
104
+	}
105
+	public function __toString()
106
+	{
107
+		$str = $this->data['Name'] . '=' . ($this->data['Value'] ?? '') . '; ';
108
+		foreach ($this->data as $k => $v) {
109
+			if ($k !== 'Name' && $k !== 'Value' && $v !== null && $v !== \false) {
110
+				if ($k === 'Expires') {
111
+					$str .= 'Expires=' . \gmdate('D, d M Y H:i:s \\G\\M\\T', $v) . '; ';
112
+				} else {
113
+					$str .= ($v === \true ? $k : "{$k}={$v}") . '; ';
114
+				}
115
+			}
116
+		}
117
+		return \rtrim($str, '; ');
118
+	}
119
+	public function toArray() : array
120
+	{
121
+		return $this->data;
122
+	}
123
+	/**
124
+	 * Get the cookie name.
125
+	 *
126
+	 * @return string
127
+	 */
128
+	public function getName()
129
+	{
130
+		return $this->data['Name'];
131
+	}
132
+	/**
133
+	 * Set the cookie name.
134
+	 *
135
+	 * @param string $name Cookie name
136
+	 */
137
+	public function setName($name) : void
138
+	{
139
+		if (!\is_string($name)) {
140
+			trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
141
+		}
142
+		$this->data['Name'] = (string) $name;
143
+	}
144
+	/**
145
+	 * Get the cookie value.
146
+	 *
147
+	 * @return string|null
148
+	 */
149
+	public function getValue()
150
+	{
151
+		return $this->data['Value'];
152
+	}
153
+	/**
154
+	 * Set the cookie value.
155
+	 *
156
+	 * @param string $value Cookie value
157
+	 */
158
+	public function setValue($value) : void
159
+	{
160
+		if (!\is_string($value)) {
161
+			trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
162
+		}
163
+		$this->data['Value'] = (string) $value;
164
+	}
165
+	/**
166
+	 * Get the domain.
167
+	 *
168
+	 * @return string|null
169
+	 */
170
+	public function getDomain()
171
+	{
172
+		return $this->data['Domain'];
173
+	}
174
+	/**
175
+	 * Set the domain of the cookie.
176
+	 *
177
+	 * @param string|null $domain
178
+	 */
179
+	public function setDomain($domain) : void
180
+	{
181
+		if (!\is_string($domain) && null !== $domain) {
182
+			trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string or null to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
183
+		}
184
+		$this->data['Domain'] = null === $domain ? null : (string) $domain;
185
+	}
186
+	/**
187
+	 * Get the path.
188
+	 *
189
+	 * @return string
190
+	 */
191
+	public function getPath()
192
+	{
193
+		return $this->data['Path'];
194
+	}
195
+	/**
196
+	 * Set the path of the cookie.
197
+	 *
198
+	 * @param string $path Path of the cookie
199
+	 */
200
+	public function setPath($path) : void
201
+	{
202
+		if (!\is_string($path)) {
203
+			trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
204
+		}
205
+		$this->data['Path'] = (string) $path;
206
+	}
207
+	/**
208
+	 * Maximum lifetime of the cookie in seconds.
209
+	 *
210
+	 * @return int|null
211
+	 */
212
+	public function getMaxAge()
213
+	{
214
+		return null === $this->data['Max-Age'] ? null : (int) $this->data['Max-Age'];
215
+	}
216
+	/**
217
+	 * Set the max-age of the cookie.
218
+	 *
219
+	 * @param int|null $maxAge Max age of the cookie in seconds
220
+	 */
221
+	public function setMaxAge($maxAge) : void
222
+	{
223
+		if (!\is_int($maxAge) && null !== $maxAge) {
224
+			trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing an int or null to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
225
+		}
226
+		$this->data['Max-Age'] = $maxAge === null ? null : (int) $maxAge;
227
+	}
228
+	/**
229
+	 * The UNIX timestamp when the cookie Expires.
230
+	 *
231
+	 * @return string|int|null
232
+	 */
233
+	public function getExpires()
234
+	{
235
+		return $this->data['Expires'];
236
+	}
237
+	/**
238
+	 * Set the unix timestamp for which the cookie will expire.
239
+	 *
240
+	 * @param int|string|null $timestamp Unix timestamp or any English textual datetime description.
241
+	 */
242
+	public function setExpires($timestamp) : void
243
+	{
244
+		if (!\is_int($timestamp) && !\is_string($timestamp) && null !== $timestamp) {
245
+			trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing an int, string or null to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
246
+		}
247
+		$this->data['Expires'] = null === $timestamp ? null : (\is_numeric($timestamp) ? (int) $timestamp : \strtotime((string) $timestamp));
248
+	}
249
+	/**
250
+	 * Get whether or not this is a secure cookie.
251
+	 *
252
+	 * @return bool
253
+	 */
254
+	public function getSecure()
255
+	{
256
+		return $this->data['Secure'];
257
+	}
258
+	/**
259
+	 * Set whether or not the cookie is secure.
260
+	 *
261
+	 * @param bool $secure Set to true or false if secure
262
+	 */
263
+	public function setSecure($secure) : void
264
+	{
265
+		if (!\is_bool($secure)) {
266
+			trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a bool to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
267
+		}
268
+		$this->data['Secure'] = (bool) $secure;
269
+	}
270
+	/**
271
+	 * Get whether or not this is a session cookie.
272
+	 *
273
+	 * @return bool|null
274
+	 */
275
+	public function getDiscard()
276
+	{
277
+		return $this->data['Discard'];
278
+	}
279
+	/**
280
+	 * Set whether or not this is a session cookie.
281
+	 *
282
+	 * @param bool $discard Set to true or false if this is a session cookie
283
+	 */
284
+	public function setDiscard($discard) : void
285
+	{
286
+		if (!\is_bool($discard)) {
287
+			trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a bool to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
288
+		}
289
+		$this->data['Discard'] = (bool) $discard;
290
+	}
291
+	/**
292
+	 * Get whether or not this is an HTTP only cookie.
293
+	 *
294
+	 * @return bool
295
+	 */
296
+	public function getHttpOnly()
297
+	{
298
+		return $this->data['HttpOnly'];
299
+	}
300
+	/**
301
+	 * Set whether or not this is an HTTP only cookie.
302
+	 *
303
+	 * @param bool $httpOnly Set to true or false if this is HTTP only
304
+	 */
305
+	public function setHttpOnly($httpOnly) : void
306
+	{
307
+		if (!\is_bool($httpOnly)) {
308
+			trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a bool to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
309
+		}
310
+		$this->data['HttpOnly'] = (bool) $httpOnly;
311
+	}
312
+	/**
313
+	 * Check if the cookie matches a path value.
314
+	 *
315
+	 * A request-path path-matches a given cookie-path if at least one of
316
+	 * the following conditions holds:
317
+	 *
318
+	 * - The cookie-path and the request-path are identical.
319
+	 * - The cookie-path is a prefix of the request-path, and the last
320
+	 *   character of the cookie-path is %x2F ("/").
321
+	 * - The cookie-path is a prefix of the request-path, and the first
322
+	 *   character of the request-path that is not included in the cookie-
323
+	 *   path is a %x2F ("/") character.
324
+	 *
325
+	 * @param string $requestPath Path to check against
326
+	 */
327
+	public function matchesPath(string $requestPath) : bool
328
+	{
329
+		$cookiePath = $this->getPath();
330
+		// Match on exact matches or when path is the default empty "/"
331
+		if ($cookiePath === '/' || $cookiePath == $requestPath) {
332
+			return \true;
333
+		}
334
+		// Ensure that the cookie-path is a prefix of the request path.
335
+		if (0 !== \strpos($requestPath, $cookiePath)) {
336
+			return \false;
337
+		}
338
+		// Match if the last character of the cookie-path is "/"
339
+		if (\substr($cookiePath, -1, 1) === '/') {
340
+			return \true;
341
+		}
342
+		// Match if the first character not included in cookie path is "/"
343
+		return \substr($requestPath, \strlen($cookiePath), 1) === '/';
344
+	}
345
+	/**
346
+	 * Check if the cookie matches a domain value.
347
+	 *
348
+	 * @param string $domain Domain to check against
349
+	 */
350
+	public function matchesDomain(string $domain) : bool
351
+	{
352
+		$cookieDomain = $this->getDomain();
353
+		if (null === $cookieDomain) {
354
+			return \true;
355
+		}
356
+		// Remove the leading '.' as per spec in RFC 6265.
357
+		// https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.3
358
+		$cookieDomain = \ltrim(\strtolower($cookieDomain), '.');
359
+		$domain = \strtolower($domain);
360
+		// Domain not set or exact match.
361
+		if ('' === $cookieDomain || $domain === $cookieDomain) {
362
+			return \true;
363
+		}
364
+		// Matching the subdomain according to RFC 6265.
365
+		// https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.3
366
+		if (\filter_var($domain, \FILTER_VALIDATE_IP)) {
367
+			return \false;
368
+		}
369
+		return (bool) \preg_match('/\\.' . \preg_quote($cookieDomain, '/') . '$/', $domain);
370
+	}
371
+	/**
372
+	 * Check if the cookie is expired.
373
+	 */
374
+	public function isExpired() : bool
375
+	{
376
+		return $this->getExpires() !== null && \time() > $this->getExpires();
377
+	}
378
+	/**
379
+	 * Check if the cookie is valid according to RFC 6265.
380
+	 *
381
+	 * @return bool|string Returns true if valid or an error message if invalid
382
+	 */
383
+	public function validate()
384
+	{
385
+		$name = $this->getName();
386
+		if ($name === '') {
387
+			return 'The cookie name must not be empty';
388
+		}
389
+		// Check if any of the invalid characters are present in the cookie name
390
+		if (\preg_match('/[\\x00-\\x20\\x22\\x28-\\x29\\x2c\\x2f\\x3a-\\x40\\x5c\\x7b\\x7d\\x7f]/', $name)) {
391
+			return 'Cookie name must not contain invalid characters: ASCII ' . 'Control characters (0-31;127), space, tab and the ' . 'following characters: ()<>@,;:\\"/?={}';
392
+		}
393
+		// Value must not be null. 0 and empty string are valid. Empty strings
394
+		// are technically against RFC 6265, but known to happen in the wild.
395
+		$value = $this->getValue();
396
+		if ($value === null) {
397
+			return 'The cookie value must not be empty';
398
+		}
399
+		// Domains must not be empty, but can be 0. "0" is not a valid internet
400
+		// domain, but may be used as server name in a private network.
401
+		$domain = $this->getDomain();
402
+		if ($domain === null || $domain === '') {
403
+			return 'The cookie domain must not be empty';
404
+		}
405
+		return \true;
406
+	}
407 407
 }
Please login to merge, or discard this patch.
Spacing   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -44,7 +44,7 @@  discard block
 block discarded – undo
44 44
                     if (!\strcasecmp($search, $key)) {
45 45
                         if ($search === 'Max-Age') {
46 46
                             if (\is_numeric($value)) {
47
-                                $data[$search] = (int) $value;
47
+                                $data[$search] = (int)$value;
48 48
                             }
49 49
                         } else {
50 50
                             $data[$search] = $value;
@@ -104,13 +104,13 @@  discard block
 block discarded – undo
104 104
     }
105 105
     public function __toString()
106 106
     {
107
-        $str = $this->data['Name'] . '=' . ($this->data['Value'] ?? '') . '; ';
107
+        $str = $this->data['Name'].'='.($this->data['Value'] ?? '').'; ';
108 108
         foreach ($this->data as $k => $v) {
109 109
             if ($k !== 'Name' && $k !== 'Value' && $v !== null && $v !== \false) {
110 110
                 if ($k === 'Expires') {
111
-                    $str .= 'Expires=' . \gmdate('D, d M Y H:i:s \\G\\M\\T', $v) . '; ';
111
+                    $str .= 'Expires='.\gmdate('D, d M Y H:i:s \\G\\M\\T', $v).'; ';
112 112
                 } else {
113
-                    $str .= ($v === \true ? $k : "{$k}={$v}") . '; ';
113
+                    $str .= ($v === \true ? $k : "{$k}={$v}").'; ';
114 114
                 }
115 115
             }
116 116
         }
@@ -139,7 +139,7 @@  discard block
 block discarded – undo
139 139
         if (!\is_string($name)) {
140 140
             trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
141 141
         }
142
-        $this->data['Name'] = (string) $name;
142
+        $this->data['Name'] = (string)$name;
143 143
     }
144 144
     /**
145 145
      * Get the cookie value.
@@ -160,7 +160,7 @@  discard block
 block discarded – undo
160 160
         if (!\is_string($value)) {
161 161
             trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
162 162
         }
163
-        $this->data['Value'] = (string) $value;
163
+        $this->data['Value'] = (string)$value;
164 164
     }
165 165
     /**
166 166
      * Get the domain.
@@ -181,7 +181,7 @@  discard block
 block discarded – undo
181 181
         if (!\is_string($domain) && null !== $domain) {
182 182
             trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string or null to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
183 183
         }
184
-        $this->data['Domain'] = null === $domain ? null : (string) $domain;
184
+        $this->data['Domain'] = null === $domain ? null : (string)$domain;
185 185
     }
186 186
     /**
187 187
      * Get the path.
@@ -202,7 +202,7 @@  discard block
 block discarded – undo
202 202
         if (!\is_string($path)) {
203 203
             trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
204 204
         }
205
-        $this->data['Path'] = (string) $path;
205
+        $this->data['Path'] = (string)$path;
206 206
     }
207 207
     /**
208 208
      * Maximum lifetime of the cookie in seconds.
@@ -211,7 +211,7 @@  discard block
 block discarded – undo
211 211
      */
212 212
     public function getMaxAge()
213 213
     {
214
-        return null === $this->data['Max-Age'] ? null : (int) $this->data['Max-Age'];
214
+        return null === $this->data['Max-Age'] ? null : (int)$this->data['Max-Age'];
215 215
     }
216 216
     /**
217 217
      * Set the max-age of the cookie.
@@ -223,7 +223,7 @@  discard block
 block discarded – undo
223 223
         if (!\is_int($maxAge) && null !== $maxAge) {
224 224
             trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing an int or null to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
225 225
         }
226
-        $this->data['Max-Age'] = $maxAge === null ? null : (int) $maxAge;
226
+        $this->data['Max-Age'] = $maxAge === null ? null : (int)$maxAge;
227 227
     }
228 228
     /**
229 229
      * The UNIX timestamp when the cookie Expires.
@@ -244,7 +244,7 @@  discard block
 block discarded – undo
244 244
         if (!\is_int($timestamp) && !\is_string($timestamp) && null !== $timestamp) {
245 245
             trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing an int, string or null to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
246 246
         }
247
-        $this->data['Expires'] = null === $timestamp ? null : (\is_numeric($timestamp) ? (int) $timestamp : \strtotime((string) $timestamp));
247
+        $this->data['Expires'] = null === $timestamp ? null : (\is_numeric($timestamp) ? (int)$timestamp : \strtotime((string)$timestamp));
248 248
     }
249 249
     /**
250 250
      * Get whether or not this is a secure cookie.
@@ -265,7 +265,7 @@  discard block
 block discarded – undo
265 265
         if (!\is_bool($secure)) {
266 266
             trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a bool to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
267 267
         }
268
-        $this->data['Secure'] = (bool) $secure;
268
+        $this->data['Secure'] = (bool)$secure;
269 269
     }
270 270
     /**
271 271
      * Get whether or not this is a session cookie.
@@ -286,7 +286,7 @@  discard block
 block discarded – undo
286 286
         if (!\is_bool($discard)) {
287 287
             trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a bool to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
288 288
         }
289
-        $this->data['Discard'] = (bool) $discard;
289
+        $this->data['Discard'] = (bool)$discard;
290 290
     }
291 291
     /**
292 292
      * Get whether or not this is an HTTP only cookie.
@@ -307,7 +307,7 @@  discard block
 block discarded – undo
307 307
         if (!\is_bool($httpOnly)) {
308 308
             trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a bool to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
309 309
         }
310
-        $this->data['HttpOnly'] = (bool) $httpOnly;
310
+        $this->data['HttpOnly'] = (bool)$httpOnly;
311 311
     }
312 312
     /**
313 313
      * Check if the cookie matches a path value.
@@ -366,7 +366,7 @@  discard block
 block discarded – undo
366 366
         if (\filter_var($domain, \FILTER_VALIDATE_IP)) {
367 367
             return \false;
368 368
         }
369
-        return (bool) \preg_match('/\\.' . \preg_quote($cookieDomain, '/') . '$/', $domain);
369
+        return (bool)\preg_match('/\\.'.\preg_quote($cookieDomain, '/').'$/', $domain);
370 370
     }
371 371
     /**
372 372
      * Check if the cookie is expired.
@@ -388,7 +388,7 @@  discard block
 block discarded – undo
388 388
         }
389 389
         // Check if any of the invalid characters are present in the cookie name
390 390
         if (\preg_match('/[\\x00-\\x20\\x22\\x28-\\x29\\x2c\\x2f\\x3a-\\x40\\x5c\\x7b\\x7d\\x7f]/', $name)) {
391
-            return 'Cookie name must not contain invalid characters: ASCII ' . 'Control characters (0-31;127), space, tab and the ' . 'following characters: ()<>@,;:\\"/?={}';
391
+            return 'Cookie name must not contain invalid characters: ASCII '.'Control characters (0-31;127), space, tab and the '.'following characters: ()<>@,;:\\"/?={}';
392 392
         }
393 393
         // Value must not be null. 0 and empty string are valid. Empty strings
394 394
         // are technically against RFC 6265, but known to happen in the wild.
Please login to merge, or discard this patch.