@@ -13,8 +13,7 @@ |
||
13 | 13 | * |
14 | 14 | * @see https://promisesaplus.com/ |
15 | 15 | */ |
16 | -interface PromiseInterface |
|
17 | -{ |
|
16 | +interface PromiseInterface { |
|
18 | 17 | public const PENDING = 'pending'; |
19 | 18 | public const FULFILLED = 'fulfilled'; |
20 | 19 | public const REJECTED = 'rejected'; |
@@ -1,6 +1,6 @@ |
||
1 | 1 | <?php |
2 | 2 | |
3 | -declare (strict_types=1); |
|
3 | +declare(strict_types=1); |
|
4 | 4 | namespace OCA\FullTextSearch_Elasticsearch\Vendor\GuzzleHttp\Promise; |
5 | 5 | |
6 | 6 | /** |
@@ -14,67 +14,67 @@ |
||
14 | 14 | */ |
15 | 15 | interface PromiseInterface |
16 | 16 | { |
17 | - public const PENDING = 'pending'; |
|
18 | - public const FULFILLED = 'fulfilled'; |
|
19 | - public const REJECTED = 'rejected'; |
|
20 | - /** |
|
21 | - * Appends fulfillment and rejection handlers to the promise, and returns |
|
22 | - * a new promise resolving to the return value of the called handler. |
|
23 | - * |
|
24 | - * @param callable $onFulfilled Invoked when the promise fulfills. |
|
25 | - * @param callable $onRejected Invoked when the promise is rejected. |
|
26 | - */ |
|
27 | - public function then(?callable $onFulfilled = null, ?callable $onRejected = null) : PromiseInterface; |
|
28 | - /** |
|
29 | - * Appends a rejection handler callback to the promise, and returns a new |
|
30 | - * promise resolving to the return value of the callback if it is called, |
|
31 | - * or to its original fulfillment value if the promise is instead |
|
32 | - * fulfilled. |
|
33 | - * |
|
34 | - * @param callable $onRejected Invoked when the promise is rejected. |
|
35 | - */ |
|
36 | - public function otherwise(callable $onRejected) : PromiseInterface; |
|
37 | - /** |
|
38 | - * Get the state of the promise ("pending", "rejected", or "fulfilled"). |
|
39 | - * |
|
40 | - * The three states can be checked against the constants defined on |
|
41 | - * PromiseInterface: PENDING, FULFILLED, and REJECTED. |
|
42 | - */ |
|
43 | - public function getState() : string; |
|
44 | - /** |
|
45 | - * Resolve the promise with the given value. |
|
46 | - * |
|
47 | - * @param mixed $value |
|
48 | - * |
|
49 | - * @throws \RuntimeException if the promise is already resolved. |
|
50 | - */ |
|
51 | - public function resolve($value) : void; |
|
52 | - /** |
|
53 | - * Reject the promise with the given reason. |
|
54 | - * |
|
55 | - * @param mixed $reason |
|
56 | - * |
|
57 | - * @throws \RuntimeException if the promise is already resolved. |
|
58 | - */ |
|
59 | - public function reject($reason) : void; |
|
60 | - /** |
|
61 | - * Cancels the promise if possible. |
|
62 | - * |
|
63 | - * @see https://github.com/promises-aplus/cancellation-spec/issues/7 |
|
64 | - */ |
|
65 | - public function cancel() : void; |
|
66 | - /** |
|
67 | - * Waits until the promise completes if possible. |
|
68 | - * |
|
69 | - * Pass $unwrap as true to unwrap the result of the promise, either |
|
70 | - * returning the resolved value or throwing the rejected exception. |
|
71 | - * |
|
72 | - * If the promise cannot be waited on, then the promise will be rejected. |
|
73 | - * |
|
74 | - * @return mixed |
|
75 | - * |
|
76 | - * @throws \LogicException if the promise has no wait function or if the |
|
77 | - * promise does not settle after waiting. |
|
78 | - */ |
|
79 | - public function wait(bool $unwrap = \true); |
|
17 | + public const PENDING = 'pending'; |
|
18 | + public const FULFILLED = 'fulfilled'; |
|
19 | + public const REJECTED = 'rejected'; |
|
20 | + /** |
|
21 | + * Appends fulfillment and rejection handlers to the promise, and returns |
|
22 | + * a new promise resolving to the return value of the called handler. |
|
23 | + * |
|
24 | + * @param callable $onFulfilled Invoked when the promise fulfills. |
|
25 | + * @param callable $onRejected Invoked when the promise is rejected. |
|
26 | + */ |
|
27 | + public function then(?callable $onFulfilled = null, ?callable $onRejected = null) : PromiseInterface; |
|
28 | + /** |
|
29 | + * Appends a rejection handler callback to the promise, and returns a new |
|
30 | + * promise resolving to the return value of the callback if it is called, |
|
31 | + * or to its original fulfillment value if the promise is instead |
|
32 | + * fulfilled. |
|
33 | + * |
|
34 | + * @param callable $onRejected Invoked when the promise is rejected. |
|
35 | + */ |
|
36 | + public function otherwise(callable $onRejected) : PromiseInterface; |
|
37 | + /** |
|
38 | + * Get the state of the promise ("pending", "rejected", or "fulfilled"). |
|
39 | + * |
|
40 | + * The three states can be checked against the constants defined on |
|
41 | + * PromiseInterface: PENDING, FULFILLED, and REJECTED. |
|
42 | + */ |
|
43 | + public function getState() : string; |
|
44 | + /** |
|
45 | + * Resolve the promise with the given value. |
|
46 | + * |
|
47 | + * @param mixed $value |
|
48 | + * |
|
49 | + * @throws \RuntimeException if the promise is already resolved. |
|
50 | + */ |
|
51 | + public function resolve($value) : void; |
|
52 | + /** |
|
53 | + * Reject the promise with the given reason. |
|
54 | + * |
|
55 | + * @param mixed $reason |
|
56 | + * |
|
57 | + * @throws \RuntimeException if the promise is already resolved. |
|
58 | + */ |
|
59 | + public function reject($reason) : void; |
|
60 | + /** |
|
61 | + * Cancels the promise if possible. |
|
62 | + * |
|
63 | + * @see https://github.com/promises-aplus/cancellation-spec/issues/7 |
|
64 | + */ |
|
65 | + public function cancel() : void; |
|
66 | + /** |
|
67 | + * Waits until the promise completes if possible. |
|
68 | + * |
|
69 | + * Pass $unwrap as true to unwrap the result of the promise, either |
|
70 | + * returning the resolved value or throwing the rejected exception. |
|
71 | + * |
|
72 | + * If the promise cannot be waited on, then the promise will be rejected. |
|
73 | + * |
|
74 | + * @return mixed |
|
75 | + * |
|
76 | + * @throws \LogicException if the promise has no wait function or if the |
|
77 | + * promise does not settle after waiting. |
|
78 | + */ |
|
79 | + public function wait(bool $unwrap = \true); |
|
80 | 80 | } |
@@ -7,6 +7,5 @@ |
||
7 | 7 | /** |
8 | 8 | * Exception that is set as the reason for a promise that has been cancelled. |
9 | 9 | */ |
10 | -class CancellationException extends RejectionException |
|
11 | -{ |
|
10 | +class CancellationException extends RejectionException { |
|
12 | 11 | } |
@@ -1,6 +1,6 @@ |
||
1 | 1 | <?php |
2 | 2 | |
3 | -declare (strict_types=1); |
|
3 | +declare(strict_types=1); |
|
4 | 4 | namespace OCA\FullTextSearch_Elasticsearch\Vendor\GuzzleHttp\Promise; |
5 | 5 | |
6 | 6 | /** |
@@ -11,8 +11,7 @@ |
||
11 | 11 | * |
12 | 12 | * @final |
13 | 13 | */ |
14 | -class Promise implements PromiseInterface |
|
15 | -{ |
|
14 | +class Promise implements PromiseInterface { |
|
16 | 15 | private $state = self::PENDING; |
17 | 16 | private $result; |
18 | 17 | private $cancelFn; |
@@ -1,6 +1,6 @@ discard block |
||
1 | 1 | <?php |
2 | 2 | |
3 | -declare (strict_types=1); |
|
3 | +declare(strict_types=1); |
|
4 | 4 | namespace OCA\FullTextSearch_Elasticsearch\Vendor\GuzzleHttp\Promise; |
5 | 5 | |
6 | 6 | /** |
@@ -124,7 +124,7 @@ discard block |
||
124 | 124 | if (!\is_object($value) || !\method_exists($value, 'then')) { |
125 | 125 | $id = $state === self::FULFILLED ? 1 : 2; |
126 | 126 | // It's a success, so resolve the handlers in the queue. |
127 | - Utils::queue()->add(static function () use($id, $value, $handlers) : void { |
|
127 | + Utils::queue()->add(static function() use($id, $value, $handlers) : void { |
|
128 | 128 | foreach ($handlers as $handler) { |
129 | 129 | self::callHandler($id, $value, $handler); |
130 | 130 | } |
@@ -134,11 +134,11 @@ discard block |
||
134 | 134 | $value->handlers = \array_merge($value->handlers, $handlers); |
135 | 135 | } else { |
136 | 136 | // Resolve the handlers when the forwarded promise is resolved. |
137 | - $value->then(static function ($value) use($handlers) : void { |
|
137 | + $value->then(static function($value) use($handlers) : void { |
|
138 | 138 | foreach ($handlers as $handler) { |
139 | 139 | self::callHandler(1, $value, $handler); |
140 | 140 | } |
141 | - }, static function ($reason) use($handlers) : void { |
|
141 | + }, static function($reason) use($handlers) : void { |
|
142 | 142 | foreach ($handlers as $handler) { |
143 | 143 | self::callHandler(2, $reason, $handler); |
144 | 144 | } |
@@ -193,7 +193,7 @@ discard block |
||
193 | 193 | $this->invokeWaitList(); |
194 | 194 | } else { |
195 | 195 | // If there's no wait function, then reject the promise. |
196 | - $this->reject('Cannot wait on a promise that has ' . 'no internal wait function. You must provide a wait ' . 'function when constructing the promise to be able to ' . 'wait on a promise.'); |
|
196 | + $this->reject('Cannot wait on a promise that has '.'no internal wait function. You must provide a wait '.'function when constructing the promise to be able to '.'wait on a promise.'); |
|
197 | 197 | } |
198 | 198 | Utils::queue()->run(); |
199 | 199 | /** @psalm-suppress RedundantCondition */ |
@@ -12,225 +12,225 @@ |
||
12 | 12 | */ |
13 | 13 | class Promise implements PromiseInterface |
14 | 14 | { |
15 | - private $state = self::PENDING; |
|
16 | - private $result; |
|
17 | - private $cancelFn; |
|
18 | - private $waitFn; |
|
19 | - private $waitList; |
|
20 | - private $handlers = []; |
|
21 | - /** |
|
22 | - * @param callable $waitFn Fn that when invoked resolves the promise. |
|
23 | - * @param callable $cancelFn Fn that when invoked cancels the promise. |
|
24 | - */ |
|
25 | - public function __construct(?callable $waitFn = null, ?callable $cancelFn = null) |
|
26 | - { |
|
27 | - $this->waitFn = $waitFn; |
|
28 | - $this->cancelFn = $cancelFn; |
|
29 | - } |
|
30 | - public function then(?callable $onFulfilled = null, ?callable $onRejected = null) : PromiseInterface |
|
31 | - { |
|
32 | - if ($this->state === self::PENDING) { |
|
33 | - $p = new Promise(null, [$this, 'cancel']); |
|
34 | - $this->handlers[] = [$p, $onFulfilled, $onRejected]; |
|
35 | - $p->waitList = $this->waitList; |
|
36 | - $p->waitList[] = $this; |
|
37 | - return $p; |
|
38 | - } |
|
39 | - // Return a fulfilled promise and immediately invoke any callbacks. |
|
40 | - if ($this->state === self::FULFILLED) { |
|
41 | - $promise = Create::promiseFor($this->result); |
|
42 | - return $onFulfilled ? $promise->then($onFulfilled) : $promise; |
|
43 | - } |
|
44 | - // It's either cancelled or rejected, so return a rejected promise |
|
45 | - // and immediately invoke any callbacks. |
|
46 | - $rejection = Create::rejectionFor($this->result); |
|
47 | - return $onRejected ? $rejection->then(null, $onRejected) : $rejection; |
|
48 | - } |
|
49 | - public function otherwise(callable $onRejected) : PromiseInterface |
|
50 | - { |
|
51 | - return $this->then(null, $onRejected); |
|
52 | - } |
|
53 | - public function wait(bool $unwrap = \true) |
|
54 | - { |
|
55 | - $this->waitIfPending(); |
|
56 | - if ($this->result instanceof PromiseInterface) { |
|
57 | - return $this->result->wait($unwrap); |
|
58 | - } |
|
59 | - if ($unwrap) { |
|
60 | - if ($this->state === self::FULFILLED) { |
|
61 | - return $this->result; |
|
62 | - } |
|
63 | - // It's rejected so "unwrap" and throw an exception. |
|
64 | - throw Create::exceptionFor($this->result); |
|
65 | - } |
|
66 | - } |
|
67 | - public function getState() : string |
|
68 | - { |
|
69 | - return $this->state; |
|
70 | - } |
|
71 | - public function cancel() : void |
|
72 | - { |
|
73 | - if ($this->state !== self::PENDING) { |
|
74 | - return; |
|
75 | - } |
|
76 | - $this->waitFn = $this->waitList = null; |
|
77 | - if ($this->cancelFn) { |
|
78 | - $fn = $this->cancelFn; |
|
79 | - $this->cancelFn = null; |
|
80 | - try { |
|
81 | - $fn(); |
|
82 | - } catch (\Throwable $e) { |
|
83 | - $this->reject($e); |
|
84 | - } |
|
85 | - } |
|
86 | - // Reject the promise only if it wasn't rejected in a then callback. |
|
87 | - /** @psalm-suppress RedundantCondition */ |
|
88 | - if ($this->state === self::PENDING) { |
|
89 | - $this->reject(new CancellationException('Promise has been cancelled')); |
|
90 | - } |
|
91 | - } |
|
92 | - public function resolve($value) : void |
|
93 | - { |
|
94 | - $this->settle(self::FULFILLED, $value); |
|
95 | - } |
|
96 | - public function reject($reason) : void |
|
97 | - { |
|
98 | - $this->settle(self::REJECTED, $reason); |
|
99 | - } |
|
100 | - private function settle(string $state, $value) : void |
|
101 | - { |
|
102 | - if ($this->state !== self::PENDING) { |
|
103 | - // Ignore calls with the same resolution. |
|
104 | - if ($state === $this->state && $value === $this->result) { |
|
105 | - return; |
|
106 | - } |
|
107 | - throw $this->state === $state ? new \LogicException("The promise is already {$state}.") : new \LogicException("Cannot change a {$this->state} promise to {$state}"); |
|
108 | - } |
|
109 | - if ($value === $this) { |
|
110 | - throw new \LogicException('Cannot fulfill or reject a promise with itself'); |
|
111 | - } |
|
112 | - // Clear out the state of the promise but stash the handlers. |
|
113 | - $this->state = $state; |
|
114 | - $this->result = $value; |
|
115 | - $handlers = $this->handlers; |
|
116 | - $this->handlers = null; |
|
117 | - $this->waitList = $this->waitFn = null; |
|
118 | - $this->cancelFn = null; |
|
119 | - if (!$handlers) { |
|
120 | - return; |
|
121 | - } |
|
122 | - // If the value was not a settled promise or a thenable, then resolve |
|
123 | - // it in the task queue using the correct ID. |
|
124 | - if (!\is_object($value) || !\method_exists($value, 'then')) { |
|
125 | - $id = $state === self::FULFILLED ? 1 : 2; |
|
126 | - // It's a success, so resolve the handlers in the queue. |
|
127 | - Utils::queue()->add(static function () use($id, $value, $handlers) : void { |
|
128 | - foreach ($handlers as $handler) { |
|
129 | - self::callHandler($id, $value, $handler); |
|
130 | - } |
|
131 | - }); |
|
132 | - } elseif ($value instanceof Promise && Is::pending($value)) { |
|
133 | - // We can just merge our handlers onto the next promise. |
|
134 | - $value->handlers = \array_merge($value->handlers, $handlers); |
|
135 | - } else { |
|
136 | - // Resolve the handlers when the forwarded promise is resolved. |
|
137 | - $value->then(static function ($value) use($handlers) : void { |
|
138 | - foreach ($handlers as $handler) { |
|
139 | - self::callHandler(1, $value, $handler); |
|
140 | - } |
|
141 | - }, static function ($reason) use($handlers) : void { |
|
142 | - foreach ($handlers as $handler) { |
|
143 | - self::callHandler(2, $reason, $handler); |
|
144 | - } |
|
145 | - }); |
|
146 | - } |
|
147 | - } |
|
148 | - /** |
|
149 | - * Call a stack of handlers using a specific callback index and value. |
|
150 | - * |
|
151 | - * @param int $index 1 (resolve) or 2 (reject). |
|
152 | - * @param mixed $value Value to pass to the callback. |
|
153 | - * @param array $handler Array of handler data (promise and callbacks). |
|
154 | - */ |
|
155 | - private static function callHandler(int $index, $value, array $handler) : void |
|
156 | - { |
|
157 | - /** @var PromiseInterface $promise */ |
|
158 | - $promise = $handler[0]; |
|
159 | - // The promise may have been cancelled or resolved before placing |
|
160 | - // this thunk in the queue. |
|
161 | - if (Is::settled($promise)) { |
|
162 | - return; |
|
163 | - } |
|
164 | - try { |
|
165 | - if (isset($handler[$index])) { |
|
166 | - /* |
|
15 | + private $state = self::PENDING; |
|
16 | + private $result; |
|
17 | + private $cancelFn; |
|
18 | + private $waitFn; |
|
19 | + private $waitList; |
|
20 | + private $handlers = []; |
|
21 | + /** |
|
22 | + * @param callable $waitFn Fn that when invoked resolves the promise. |
|
23 | + * @param callable $cancelFn Fn that when invoked cancels the promise. |
|
24 | + */ |
|
25 | + public function __construct(?callable $waitFn = null, ?callable $cancelFn = null) |
|
26 | + { |
|
27 | + $this->waitFn = $waitFn; |
|
28 | + $this->cancelFn = $cancelFn; |
|
29 | + } |
|
30 | + public function then(?callable $onFulfilled = null, ?callable $onRejected = null) : PromiseInterface |
|
31 | + { |
|
32 | + if ($this->state === self::PENDING) { |
|
33 | + $p = new Promise(null, [$this, 'cancel']); |
|
34 | + $this->handlers[] = [$p, $onFulfilled, $onRejected]; |
|
35 | + $p->waitList = $this->waitList; |
|
36 | + $p->waitList[] = $this; |
|
37 | + return $p; |
|
38 | + } |
|
39 | + // Return a fulfilled promise and immediately invoke any callbacks. |
|
40 | + if ($this->state === self::FULFILLED) { |
|
41 | + $promise = Create::promiseFor($this->result); |
|
42 | + return $onFulfilled ? $promise->then($onFulfilled) : $promise; |
|
43 | + } |
|
44 | + // It's either cancelled or rejected, so return a rejected promise |
|
45 | + // and immediately invoke any callbacks. |
|
46 | + $rejection = Create::rejectionFor($this->result); |
|
47 | + return $onRejected ? $rejection->then(null, $onRejected) : $rejection; |
|
48 | + } |
|
49 | + public function otherwise(callable $onRejected) : PromiseInterface |
|
50 | + { |
|
51 | + return $this->then(null, $onRejected); |
|
52 | + } |
|
53 | + public function wait(bool $unwrap = \true) |
|
54 | + { |
|
55 | + $this->waitIfPending(); |
|
56 | + if ($this->result instanceof PromiseInterface) { |
|
57 | + return $this->result->wait($unwrap); |
|
58 | + } |
|
59 | + if ($unwrap) { |
|
60 | + if ($this->state === self::FULFILLED) { |
|
61 | + return $this->result; |
|
62 | + } |
|
63 | + // It's rejected so "unwrap" and throw an exception. |
|
64 | + throw Create::exceptionFor($this->result); |
|
65 | + } |
|
66 | + } |
|
67 | + public function getState() : string |
|
68 | + { |
|
69 | + return $this->state; |
|
70 | + } |
|
71 | + public function cancel() : void |
|
72 | + { |
|
73 | + if ($this->state !== self::PENDING) { |
|
74 | + return; |
|
75 | + } |
|
76 | + $this->waitFn = $this->waitList = null; |
|
77 | + if ($this->cancelFn) { |
|
78 | + $fn = $this->cancelFn; |
|
79 | + $this->cancelFn = null; |
|
80 | + try { |
|
81 | + $fn(); |
|
82 | + } catch (\Throwable $e) { |
|
83 | + $this->reject($e); |
|
84 | + } |
|
85 | + } |
|
86 | + // Reject the promise only if it wasn't rejected in a then callback. |
|
87 | + /** @psalm-suppress RedundantCondition */ |
|
88 | + if ($this->state === self::PENDING) { |
|
89 | + $this->reject(new CancellationException('Promise has been cancelled')); |
|
90 | + } |
|
91 | + } |
|
92 | + public function resolve($value) : void |
|
93 | + { |
|
94 | + $this->settle(self::FULFILLED, $value); |
|
95 | + } |
|
96 | + public function reject($reason) : void |
|
97 | + { |
|
98 | + $this->settle(self::REJECTED, $reason); |
|
99 | + } |
|
100 | + private function settle(string $state, $value) : void |
|
101 | + { |
|
102 | + if ($this->state !== self::PENDING) { |
|
103 | + // Ignore calls with the same resolution. |
|
104 | + if ($state === $this->state && $value === $this->result) { |
|
105 | + return; |
|
106 | + } |
|
107 | + throw $this->state === $state ? new \LogicException("The promise is already {$state}.") : new \LogicException("Cannot change a {$this->state} promise to {$state}"); |
|
108 | + } |
|
109 | + if ($value === $this) { |
|
110 | + throw new \LogicException('Cannot fulfill or reject a promise with itself'); |
|
111 | + } |
|
112 | + // Clear out the state of the promise but stash the handlers. |
|
113 | + $this->state = $state; |
|
114 | + $this->result = $value; |
|
115 | + $handlers = $this->handlers; |
|
116 | + $this->handlers = null; |
|
117 | + $this->waitList = $this->waitFn = null; |
|
118 | + $this->cancelFn = null; |
|
119 | + if (!$handlers) { |
|
120 | + return; |
|
121 | + } |
|
122 | + // If the value was not a settled promise or a thenable, then resolve |
|
123 | + // it in the task queue using the correct ID. |
|
124 | + if (!\is_object($value) || !\method_exists($value, 'then')) { |
|
125 | + $id = $state === self::FULFILLED ? 1 : 2; |
|
126 | + // It's a success, so resolve the handlers in the queue. |
|
127 | + Utils::queue()->add(static function () use($id, $value, $handlers) : void { |
|
128 | + foreach ($handlers as $handler) { |
|
129 | + self::callHandler($id, $value, $handler); |
|
130 | + } |
|
131 | + }); |
|
132 | + } elseif ($value instanceof Promise && Is::pending($value)) { |
|
133 | + // We can just merge our handlers onto the next promise. |
|
134 | + $value->handlers = \array_merge($value->handlers, $handlers); |
|
135 | + } else { |
|
136 | + // Resolve the handlers when the forwarded promise is resolved. |
|
137 | + $value->then(static function ($value) use($handlers) : void { |
|
138 | + foreach ($handlers as $handler) { |
|
139 | + self::callHandler(1, $value, $handler); |
|
140 | + } |
|
141 | + }, static function ($reason) use($handlers) : void { |
|
142 | + foreach ($handlers as $handler) { |
|
143 | + self::callHandler(2, $reason, $handler); |
|
144 | + } |
|
145 | + }); |
|
146 | + } |
|
147 | + } |
|
148 | + /** |
|
149 | + * Call a stack of handlers using a specific callback index and value. |
|
150 | + * |
|
151 | + * @param int $index 1 (resolve) or 2 (reject). |
|
152 | + * @param mixed $value Value to pass to the callback. |
|
153 | + * @param array $handler Array of handler data (promise and callbacks). |
|
154 | + */ |
|
155 | + private static function callHandler(int $index, $value, array $handler) : void |
|
156 | + { |
|
157 | + /** @var PromiseInterface $promise */ |
|
158 | + $promise = $handler[0]; |
|
159 | + // The promise may have been cancelled or resolved before placing |
|
160 | + // this thunk in the queue. |
|
161 | + if (Is::settled($promise)) { |
|
162 | + return; |
|
163 | + } |
|
164 | + try { |
|
165 | + if (isset($handler[$index])) { |
|
166 | + /* |
|
167 | 167 | * If $f throws an exception, then $handler will be in the exception |
168 | 168 | * stack trace. Since $handler contains a reference to the callable |
169 | 169 | * itself we get a circular reference. We clear the $handler |
170 | 170 | * here to avoid that memory leak. |
171 | 171 | */ |
172 | - $f = $handler[$index]; |
|
173 | - unset($handler); |
|
174 | - $promise->resolve($f($value)); |
|
175 | - } elseif ($index === 1) { |
|
176 | - // Forward resolution values as-is. |
|
177 | - $promise->resolve($value); |
|
178 | - } else { |
|
179 | - // Forward rejections down the chain. |
|
180 | - $promise->reject($value); |
|
181 | - } |
|
182 | - } catch (\Throwable $reason) { |
|
183 | - $promise->reject($reason); |
|
184 | - } |
|
185 | - } |
|
186 | - private function waitIfPending() : void |
|
187 | - { |
|
188 | - if ($this->state !== self::PENDING) { |
|
189 | - return; |
|
190 | - } elseif ($this->waitFn) { |
|
191 | - $this->invokeWaitFn(); |
|
192 | - } elseif ($this->waitList) { |
|
193 | - $this->invokeWaitList(); |
|
194 | - } else { |
|
195 | - // If there's no wait function, then reject the promise. |
|
196 | - $this->reject('Cannot wait on a promise that has ' . 'no internal wait function. You must provide a wait ' . 'function when constructing the promise to be able to ' . 'wait on a promise.'); |
|
197 | - } |
|
198 | - Utils::queue()->run(); |
|
199 | - /** @psalm-suppress RedundantCondition */ |
|
200 | - if ($this->state === self::PENDING) { |
|
201 | - $this->reject('Invoking the wait callback did not resolve the promise'); |
|
202 | - } |
|
203 | - } |
|
204 | - private function invokeWaitFn() : void |
|
205 | - { |
|
206 | - try { |
|
207 | - $wfn = $this->waitFn; |
|
208 | - $this->waitFn = null; |
|
209 | - $wfn(\true); |
|
210 | - } catch (\Throwable $reason) { |
|
211 | - if ($this->state === self::PENDING) { |
|
212 | - // The promise has not been resolved yet, so reject the promise |
|
213 | - // with the exception. |
|
214 | - $this->reject($reason); |
|
215 | - } else { |
|
216 | - // The promise was already resolved, so there's a problem in |
|
217 | - // the application. |
|
218 | - throw $reason; |
|
219 | - } |
|
220 | - } |
|
221 | - } |
|
222 | - private function invokeWaitList() : void |
|
223 | - { |
|
224 | - $waitList = $this->waitList; |
|
225 | - $this->waitList = null; |
|
226 | - foreach ($waitList as $result) { |
|
227 | - do { |
|
228 | - $result->waitIfPending(); |
|
229 | - $result = $result->result; |
|
230 | - } while ($result instanceof Promise); |
|
231 | - if ($result instanceof PromiseInterface) { |
|
232 | - $result->wait(\false); |
|
233 | - } |
|
234 | - } |
|
235 | - } |
|
172 | + $f = $handler[$index]; |
|
173 | + unset($handler); |
|
174 | + $promise->resolve($f($value)); |
|
175 | + } elseif ($index === 1) { |
|
176 | + // Forward resolution values as-is. |
|
177 | + $promise->resolve($value); |
|
178 | + } else { |
|
179 | + // Forward rejections down the chain. |
|
180 | + $promise->reject($value); |
|
181 | + } |
|
182 | + } catch (\Throwable $reason) { |
|
183 | + $promise->reject($reason); |
|
184 | + } |
|
185 | + } |
|
186 | + private function waitIfPending() : void |
|
187 | + { |
|
188 | + if ($this->state !== self::PENDING) { |
|
189 | + return; |
|
190 | + } elseif ($this->waitFn) { |
|
191 | + $this->invokeWaitFn(); |
|
192 | + } elseif ($this->waitList) { |
|
193 | + $this->invokeWaitList(); |
|
194 | + } else { |
|
195 | + // If there's no wait function, then reject the promise. |
|
196 | + $this->reject('Cannot wait on a promise that has ' . 'no internal wait function. You must provide a wait ' . 'function when constructing the promise to be able to ' . 'wait on a promise.'); |
|
197 | + } |
|
198 | + Utils::queue()->run(); |
|
199 | + /** @psalm-suppress RedundantCondition */ |
|
200 | + if ($this->state === self::PENDING) { |
|
201 | + $this->reject('Invoking the wait callback did not resolve the promise'); |
|
202 | + } |
|
203 | + } |
|
204 | + private function invokeWaitFn() : void |
|
205 | + { |
|
206 | + try { |
|
207 | + $wfn = $this->waitFn; |
|
208 | + $this->waitFn = null; |
|
209 | + $wfn(\true); |
|
210 | + } catch (\Throwable $reason) { |
|
211 | + if ($this->state === self::PENDING) { |
|
212 | + // The promise has not been resolved yet, so reject the promise |
|
213 | + // with the exception. |
|
214 | + $this->reject($reason); |
|
215 | + } else { |
|
216 | + // The promise was already resolved, so there's a problem in |
|
217 | + // the application. |
|
218 | + throw $reason; |
|
219 | + } |
|
220 | + } |
|
221 | + } |
|
222 | + private function invokeWaitList() : void |
|
223 | + { |
|
224 | + $waitList = $this->waitList; |
|
225 | + $this->waitList = null; |
|
226 | + foreach ($waitList as $result) { |
|
227 | + do { |
|
228 | + $result->waitIfPending(); |
|
229 | + $result = $result->result; |
|
230 | + } while ($result instanceof Promise); |
|
231 | + if ($result instanceof PromiseInterface) { |
|
232 | + $result->wait(\false); |
|
233 | + } |
|
234 | + } |
|
235 | + } |
|
236 | 236 | } |
@@ -7,8 +7,7 @@ |
||
7 | 7 | /** |
8 | 8 | * Interface used with classes that return a promise. |
9 | 9 | */ |
10 | -interface PromisorInterface |
|
11 | -{ |
|
10 | +interface PromisorInterface { |
|
12 | 11 | /** |
13 | 12 | * Returns a promise. |
14 | 13 | */ |
@@ -8,8 +8,8 @@ |
||
8 | 8 | */ |
9 | 9 | interface PromisorInterface |
10 | 10 | { |
11 | - /** |
|
12 | - * Returns a promise. |
|
13 | - */ |
|
14 | - public function promise() : PromiseInterface; |
|
11 | + /** |
|
12 | + * Returns a promise. |
|
13 | + */ |
|
14 | + public function promise() : PromiseInterface; |
|
15 | 15 | } |
@@ -1,6 +1,6 @@ |
||
1 | 1 | <?php |
2 | 2 | |
3 | -declare (strict_types=1); |
|
3 | +declare(strict_types=1); |
|
4 | 4 | namespace OCA\FullTextSearch_Elasticsearch\Vendor\GuzzleHttp\Promise; |
5 | 5 | |
6 | 6 | /** |
@@ -13,8 +13,7 @@ |
||
13 | 13 | /** |
14 | 14 | * Functions used to create and wrap handlers with handler middleware. |
15 | 15 | */ |
16 | -final class Middleware |
|
17 | -{ |
|
16 | +final class Middleware { |
|
18 | 17 | /** |
19 | 18 | * Middleware that adds cookies to requests. |
20 | 19 | * |
@@ -14,214 +14,214 @@ |
||
14 | 14 | */ |
15 | 15 | final class Middleware |
16 | 16 | { |
17 | - /** |
|
18 | - * Middleware that adds cookies to requests. |
|
19 | - * |
|
20 | - * The options array must be set to a CookieJarInterface in order to use |
|
21 | - * cookies. This is typically handled for you by a client. |
|
22 | - * |
|
23 | - * @return callable Returns a function that accepts the next handler. |
|
24 | - */ |
|
25 | - public static function cookies() : callable |
|
26 | - { |
|
27 | - return static function (callable $handler) : callable { |
|
28 | - return static function ($request, array $options) use($handler) { |
|
29 | - if (empty($options['cookies'])) { |
|
30 | - return $handler($request, $options); |
|
31 | - } elseif (!$options['cookies'] instanceof CookieJarInterface) { |
|
32 | - throw new \InvalidArgumentException('OCA\\FullTextSearch_Elasticsearch\\Vendor\\cookies must be an instance of GuzzleHttp\\Cookie\\CookieJarInterface'); |
|
33 | - } |
|
34 | - $cookieJar = $options['cookies']; |
|
35 | - $request = $cookieJar->withCookieHeader($request); |
|
36 | - return $handler($request, $options)->then(static function (ResponseInterface $response) use($cookieJar, $request) : ResponseInterface { |
|
37 | - $cookieJar->extractCookies($request, $response); |
|
38 | - return $response; |
|
39 | - }); |
|
40 | - }; |
|
41 | - }; |
|
42 | - } |
|
43 | - /** |
|
44 | - * Middleware that throws exceptions for 4xx or 5xx responses when the |
|
45 | - * "http_errors" request option is set to true. |
|
46 | - * |
|
47 | - * @param BodySummarizerInterface|null $bodySummarizer The body summarizer to use in exception messages. |
|
48 | - * |
|
49 | - * @return callable(callable): callable Returns a function that accepts the next handler. |
|
50 | - */ |
|
51 | - public static function httpErrors(?BodySummarizerInterface $bodySummarizer = null) : callable |
|
52 | - { |
|
53 | - return static function (callable $handler) use($bodySummarizer) : callable { |
|
54 | - return static function ($request, array $options) use($handler, $bodySummarizer) { |
|
55 | - if (empty($options['http_errors'])) { |
|
56 | - return $handler($request, $options); |
|
57 | - } |
|
58 | - return $handler($request, $options)->then(static function (ResponseInterface $response) use($request, $bodySummarizer) { |
|
59 | - $code = $response->getStatusCode(); |
|
60 | - if ($code < 400) { |
|
61 | - return $response; |
|
62 | - } |
|
63 | - throw RequestException::create($request, $response, null, [], $bodySummarizer); |
|
64 | - }); |
|
65 | - }; |
|
66 | - }; |
|
67 | - } |
|
68 | - /** |
|
69 | - * Middleware that pushes history data to an ArrayAccess container. |
|
70 | - * |
|
71 | - * @param array|\ArrayAccess<int, array> $container Container to hold the history (by reference). |
|
72 | - * |
|
73 | - * @return callable(callable): callable Returns a function that accepts the next handler. |
|
74 | - * |
|
75 | - * @throws \InvalidArgumentException if container is not an array or ArrayAccess. |
|
76 | - */ |
|
77 | - public static function history(&$container) : callable |
|
78 | - { |
|
79 | - if (!\is_array($container) && !$container instanceof \ArrayAccess) { |
|
80 | - throw new \InvalidArgumentException('history container must be an array or object implementing ArrayAccess'); |
|
81 | - } |
|
82 | - return static function (callable $handler) use(&$container) : callable { |
|
83 | - return static function (RequestInterface $request, array $options) use($handler, &$container) { |
|
84 | - return $handler($request, $options)->then(static function ($value) use($request, &$container, $options) { |
|
85 | - $container[] = ['request' => $request, 'response' => $value, 'error' => null, 'options' => $options]; |
|
86 | - return $value; |
|
87 | - }, static function ($reason) use($request, &$container, $options) { |
|
88 | - $container[] = ['request' => $request, 'response' => null, 'error' => $reason, 'options' => $options]; |
|
89 | - return P\Create::rejectionFor($reason); |
|
90 | - }); |
|
91 | - }; |
|
92 | - }; |
|
93 | - } |
|
94 | - /** |
|
95 | - * Middleware that invokes a callback before and after sending a request. |
|
96 | - * |
|
97 | - * The provided listener cannot modify or alter the response. It simply |
|
98 | - * "taps" into the chain to be notified before returning the promise. The |
|
99 | - * before listener accepts a request and options array, and the after |
|
100 | - * listener accepts a request, options array, and response promise. |
|
101 | - * |
|
102 | - * @param callable $before Function to invoke before forwarding the request. |
|
103 | - * @param callable $after Function invoked after forwarding. |
|
104 | - * |
|
105 | - * @return callable Returns a function that accepts the next handler. |
|
106 | - */ |
|
107 | - public static function tap(?callable $before = null, ?callable $after = null) : callable |
|
108 | - { |
|
109 | - return static function (callable $handler) use($before, $after) : callable { |
|
110 | - return static function (RequestInterface $request, array $options) use($handler, $before, $after) { |
|
111 | - if ($before) { |
|
112 | - $before($request, $options); |
|
113 | - } |
|
114 | - $response = $handler($request, $options); |
|
115 | - if ($after) { |
|
116 | - $after($request, $options, $response); |
|
117 | - } |
|
118 | - return $response; |
|
119 | - }; |
|
120 | - }; |
|
121 | - } |
|
122 | - /** |
|
123 | - * Middleware that handles request redirects. |
|
124 | - * |
|
125 | - * @return callable Returns a function that accepts the next handler. |
|
126 | - */ |
|
127 | - public static function redirect() : callable |
|
128 | - { |
|
129 | - return static function (callable $handler) : RedirectMiddleware { |
|
130 | - return new RedirectMiddleware($handler); |
|
131 | - }; |
|
132 | - } |
|
133 | - /** |
|
134 | - * Middleware that retries requests based on the boolean result of |
|
135 | - * invoking the provided "decider" function. |
|
136 | - * |
|
137 | - * If no delay function is provided, a simple implementation of exponential |
|
138 | - * backoff will be utilized. |
|
139 | - * |
|
140 | - * @param callable $decider Function that accepts the number of retries, |
|
141 | - * a request, [response], and [exception] and |
|
142 | - * returns true if the request is to be retried. |
|
143 | - * @param callable $delay Function that accepts the number of retries and |
|
144 | - * returns the number of milliseconds to delay. |
|
145 | - * |
|
146 | - * @return callable Returns a function that accepts the next handler. |
|
147 | - */ |
|
148 | - public static function retry(callable $decider, ?callable $delay = null) : callable |
|
149 | - { |
|
150 | - return static function (callable $handler) use($decider, $delay) : RetryMiddleware { |
|
151 | - return new RetryMiddleware($decider, $handler, $delay); |
|
152 | - }; |
|
153 | - } |
|
154 | - /** |
|
155 | - * Middleware that logs requests, responses, and errors using a message |
|
156 | - * formatter. |
|
157 | - * |
|
158 | - * @phpstan-param \Psr\Log\LogLevel::* $logLevel Level at which to log requests. |
|
159 | - * |
|
160 | - * @param LoggerInterface $logger Logs messages. |
|
161 | - * @param MessageFormatterInterface|MessageFormatter $formatter Formatter used to create message strings. |
|
162 | - * @param string $logLevel Level at which to log requests. |
|
163 | - * |
|
164 | - * @return callable Returns a function that accepts the next handler. |
|
165 | - */ |
|
166 | - public static function log(LoggerInterface $logger, $formatter, string $logLevel = 'info') : callable |
|
167 | - { |
|
168 | - // To be compatible with Guzzle 7.1.x we need to allow users to pass a MessageFormatter |
|
169 | - if (!$formatter instanceof MessageFormatter && !$formatter instanceof MessageFormatterInterface) { |
|
170 | - throw new \LogicException(\sprintf('Argument 2 to %s::log() must be of type %s', self::class, MessageFormatterInterface::class)); |
|
171 | - } |
|
172 | - return static function (callable $handler) use($logger, $formatter, $logLevel) : callable { |
|
173 | - return static function (RequestInterface $request, array $options = []) use($handler, $logger, $formatter, $logLevel) { |
|
174 | - return $handler($request, $options)->then(static function ($response) use($logger, $request, $formatter, $logLevel) : ResponseInterface { |
|
175 | - $message = $formatter->format($request, $response); |
|
176 | - $logger->log($logLevel, $message); |
|
177 | - return $response; |
|
178 | - }, static function ($reason) use($logger, $request, $formatter) : PromiseInterface { |
|
179 | - $response = $reason instanceof RequestException ? $reason->getResponse() : null; |
|
180 | - $message = $formatter->format($request, $response, P\Create::exceptionFor($reason)); |
|
181 | - $logger->error($message); |
|
182 | - return P\Create::rejectionFor($reason); |
|
183 | - }); |
|
184 | - }; |
|
185 | - }; |
|
186 | - } |
|
187 | - /** |
|
188 | - * This middleware adds a default content-type if possible, a default |
|
189 | - * content-length or transfer-encoding header, and the expect header. |
|
190 | - */ |
|
191 | - public static function prepareBody() : callable |
|
192 | - { |
|
193 | - return static function (callable $handler) : PrepareBodyMiddleware { |
|
194 | - return new PrepareBodyMiddleware($handler); |
|
195 | - }; |
|
196 | - } |
|
197 | - /** |
|
198 | - * Middleware that applies a map function to the request before passing to |
|
199 | - * the next handler. |
|
200 | - * |
|
201 | - * @param callable $fn Function that accepts a RequestInterface and returns |
|
202 | - * a RequestInterface. |
|
203 | - */ |
|
204 | - public static function mapRequest(callable $fn) : callable |
|
205 | - { |
|
206 | - return static function (callable $handler) use($fn) : callable { |
|
207 | - return static function (RequestInterface $request, array $options) use($handler, $fn) { |
|
208 | - return $handler($fn($request), $options); |
|
209 | - }; |
|
210 | - }; |
|
211 | - } |
|
212 | - /** |
|
213 | - * Middleware that applies a map function to the resolved promise's |
|
214 | - * response. |
|
215 | - * |
|
216 | - * @param callable $fn Function that accepts a ResponseInterface and |
|
217 | - * returns a ResponseInterface. |
|
218 | - */ |
|
219 | - public static function mapResponse(callable $fn) : callable |
|
220 | - { |
|
221 | - return static function (callable $handler) use($fn) : callable { |
|
222 | - return static function (RequestInterface $request, array $options) use($handler, $fn) { |
|
223 | - return $handler($request, $options)->then($fn); |
|
224 | - }; |
|
225 | - }; |
|
226 | - } |
|
17 | + /** |
|
18 | + * Middleware that adds cookies to requests. |
|
19 | + * |
|
20 | + * The options array must be set to a CookieJarInterface in order to use |
|
21 | + * cookies. This is typically handled for you by a client. |
|
22 | + * |
|
23 | + * @return callable Returns a function that accepts the next handler. |
|
24 | + */ |
|
25 | + public static function cookies() : callable |
|
26 | + { |
|
27 | + return static function (callable $handler) : callable { |
|
28 | + return static function ($request, array $options) use($handler) { |
|
29 | + if (empty($options['cookies'])) { |
|
30 | + return $handler($request, $options); |
|
31 | + } elseif (!$options['cookies'] instanceof CookieJarInterface) { |
|
32 | + throw new \InvalidArgumentException('OCA\\FullTextSearch_Elasticsearch\\Vendor\\cookies must be an instance of GuzzleHttp\\Cookie\\CookieJarInterface'); |
|
33 | + } |
|
34 | + $cookieJar = $options['cookies']; |
|
35 | + $request = $cookieJar->withCookieHeader($request); |
|
36 | + return $handler($request, $options)->then(static function (ResponseInterface $response) use($cookieJar, $request) : ResponseInterface { |
|
37 | + $cookieJar->extractCookies($request, $response); |
|
38 | + return $response; |
|
39 | + }); |
|
40 | + }; |
|
41 | + }; |
|
42 | + } |
|
43 | + /** |
|
44 | + * Middleware that throws exceptions for 4xx or 5xx responses when the |
|
45 | + * "http_errors" request option is set to true. |
|
46 | + * |
|
47 | + * @param BodySummarizerInterface|null $bodySummarizer The body summarizer to use in exception messages. |
|
48 | + * |
|
49 | + * @return callable(callable): callable Returns a function that accepts the next handler. |
|
50 | + */ |
|
51 | + public static function httpErrors(?BodySummarizerInterface $bodySummarizer = null) : callable |
|
52 | + { |
|
53 | + return static function (callable $handler) use($bodySummarizer) : callable { |
|
54 | + return static function ($request, array $options) use($handler, $bodySummarizer) { |
|
55 | + if (empty($options['http_errors'])) { |
|
56 | + return $handler($request, $options); |
|
57 | + } |
|
58 | + return $handler($request, $options)->then(static function (ResponseInterface $response) use($request, $bodySummarizer) { |
|
59 | + $code = $response->getStatusCode(); |
|
60 | + if ($code < 400) { |
|
61 | + return $response; |
|
62 | + } |
|
63 | + throw RequestException::create($request, $response, null, [], $bodySummarizer); |
|
64 | + }); |
|
65 | + }; |
|
66 | + }; |
|
67 | + } |
|
68 | + /** |
|
69 | + * Middleware that pushes history data to an ArrayAccess container. |
|
70 | + * |
|
71 | + * @param array|\ArrayAccess<int, array> $container Container to hold the history (by reference). |
|
72 | + * |
|
73 | + * @return callable(callable): callable Returns a function that accepts the next handler. |
|
74 | + * |
|
75 | + * @throws \InvalidArgumentException if container is not an array or ArrayAccess. |
|
76 | + */ |
|
77 | + public static function history(&$container) : callable |
|
78 | + { |
|
79 | + if (!\is_array($container) && !$container instanceof \ArrayAccess) { |
|
80 | + throw new \InvalidArgumentException('history container must be an array or object implementing ArrayAccess'); |
|
81 | + } |
|
82 | + return static function (callable $handler) use(&$container) : callable { |
|
83 | + return static function (RequestInterface $request, array $options) use($handler, &$container) { |
|
84 | + return $handler($request, $options)->then(static function ($value) use($request, &$container, $options) { |
|
85 | + $container[] = ['request' => $request, 'response' => $value, 'error' => null, 'options' => $options]; |
|
86 | + return $value; |
|
87 | + }, static function ($reason) use($request, &$container, $options) { |
|
88 | + $container[] = ['request' => $request, 'response' => null, 'error' => $reason, 'options' => $options]; |
|
89 | + return P\Create::rejectionFor($reason); |
|
90 | + }); |
|
91 | + }; |
|
92 | + }; |
|
93 | + } |
|
94 | + /** |
|
95 | + * Middleware that invokes a callback before and after sending a request. |
|
96 | + * |
|
97 | + * The provided listener cannot modify or alter the response. It simply |
|
98 | + * "taps" into the chain to be notified before returning the promise. The |
|
99 | + * before listener accepts a request and options array, and the after |
|
100 | + * listener accepts a request, options array, and response promise. |
|
101 | + * |
|
102 | + * @param callable $before Function to invoke before forwarding the request. |
|
103 | + * @param callable $after Function invoked after forwarding. |
|
104 | + * |
|
105 | + * @return callable Returns a function that accepts the next handler. |
|
106 | + */ |
|
107 | + public static function tap(?callable $before = null, ?callable $after = null) : callable |
|
108 | + { |
|
109 | + return static function (callable $handler) use($before, $after) : callable { |
|
110 | + return static function (RequestInterface $request, array $options) use($handler, $before, $after) { |
|
111 | + if ($before) { |
|
112 | + $before($request, $options); |
|
113 | + } |
|
114 | + $response = $handler($request, $options); |
|
115 | + if ($after) { |
|
116 | + $after($request, $options, $response); |
|
117 | + } |
|
118 | + return $response; |
|
119 | + }; |
|
120 | + }; |
|
121 | + } |
|
122 | + /** |
|
123 | + * Middleware that handles request redirects. |
|
124 | + * |
|
125 | + * @return callable Returns a function that accepts the next handler. |
|
126 | + */ |
|
127 | + public static function redirect() : callable |
|
128 | + { |
|
129 | + return static function (callable $handler) : RedirectMiddleware { |
|
130 | + return new RedirectMiddleware($handler); |
|
131 | + }; |
|
132 | + } |
|
133 | + /** |
|
134 | + * Middleware that retries requests based on the boolean result of |
|
135 | + * invoking the provided "decider" function. |
|
136 | + * |
|
137 | + * If no delay function is provided, a simple implementation of exponential |
|
138 | + * backoff will be utilized. |
|
139 | + * |
|
140 | + * @param callable $decider Function that accepts the number of retries, |
|
141 | + * a request, [response], and [exception] and |
|
142 | + * returns true if the request is to be retried. |
|
143 | + * @param callable $delay Function that accepts the number of retries and |
|
144 | + * returns the number of milliseconds to delay. |
|
145 | + * |
|
146 | + * @return callable Returns a function that accepts the next handler. |
|
147 | + */ |
|
148 | + public static function retry(callable $decider, ?callable $delay = null) : callable |
|
149 | + { |
|
150 | + return static function (callable $handler) use($decider, $delay) : RetryMiddleware { |
|
151 | + return new RetryMiddleware($decider, $handler, $delay); |
|
152 | + }; |
|
153 | + } |
|
154 | + /** |
|
155 | + * Middleware that logs requests, responses, and errors using a message |
|
156 | + * formatter. |
|
157 | + * |
|
158 | + * @phpstan-param \Psr\Log\LogLevel::* $logLevel Level at which to log requests. |
|
159 | + * |
|
160 | + * @param LoggerInterface $logger Logs messages. |
|
161 | + * @param MessageFormatterInterface|MessageFormatter $formatter Formatter used to create message strings. |
|
162 | + * @param string $logLevel Level at which to log requests. |
|
163 | + * |
|
164 | + * @return callable Returns a function that accepts the next handler. |
|
165 | + */ |
|
166 | + public static function log(LoggerInterface $logger, $formatter, string $logLevel = 'info') : callable |
|
167 | + { |
|
168 | + // To be compatible with Guzzle 7.1.x we need to allow users to pass a MessageFormatter |
|
169 | + if (!$formatter instanceof MessageFormatter && !$formatter instanceof MessageFormatterInterface) { |
|
170 | + throw new \LogicException(\sprintf('Argument 2 to %s::log() must be of type %s', self::class, MessageFormatterInterface::class)); |
|
171 | + } |
|
172 | + return static function (callable $handler) use($logger, $formatter, $logLevel) : callable { |
|
173 | + return static function (RequestInterface $request, array $options = []) use($handler, $logger, $formatter, $logLevel) { |
|
174 | + return $handler($request, $options)->then(static function ($response) use($logger, $request, $formatter, $logLevel) : ResponseInterface { |
|
175 | + $message = $formatter->format($request, $response); |
|
176 | + $logger->log($logLevel, $message); |
|
177 | + return $response; |
|
178 | + }, static function ($reason) use($logger, $request, $formatter) : PromiseInterface { |
|
179 | + $response = $reason instanceof RequestException ? $reason->getResponse() : null; |
|
180 | + $message = $formatter->format($request, $response, P\Create::exceptionFor($reason)); |
|
181 | + $logger->error($message); |
|
182 | + return P\Create::rejectionFor($reason); |
|
183 | + }); |
|
184 | + }; |
|
185 | + }; |
|
186 | + } |
|
187 | + /** |
|
188 | + * This middleware adds a default content-type if possible, a default |
|
189 | + * content-length or transfer-encoding header, and the expect header. |
|
190 | + */ |
|
191 | + public static function prepareBody() : callable |
|
192 | + { |
|
193 | + return static function (callable $handler) : PrepareBodyMiddleware { |
|
194 | + return new PrepareBodyMiddleware($handler); |
|
195 | + }; |
|
196 | + } |
|
197 | + /** |
|
198 | + * Middleware that applies a map function to the request before passing to |
|
199 | + * the next handler. |
|
200 | + * |
|
201 | + * @param callable $fn Function that accepts a RequestInterface and returns |
|
202 | + * a RequestInterface. |
|
203 | + */ |
|
204 | + public static function mapRequest(callable $fn) : callable |
|
205 | + { |
|
206 | + return static function (callable $handler) use($fn) : callable { |
|
207 | + return static function (RequestInterface $request, array $options) use($handler, $fn) { |
|
208 | + return $handler($fn($request), $options); |
|
209 | + }; |
|
210 | + }; |
|
211 | + } |
|
212 | + /** |
|
213 | + * Middleware that applies a map function to the resolved promise's |
|
214 | + * response. |
|
215 | + * |
|
216 | + * @param callable $fn Function that accepts a ResponseInterface and |
|
217 | + * returns a ResponseInterface. |
|
218 | + */ |
|
219 | + public static function mapResponse(callable $fn) : callable |
|
220 | + { |
|
221 | + return static function (callable $handler) use($fn) : callable { |
|
222 | + return static function (RequestInterface $request, array $options) use($handler, $fn) { |
|
223 | + return $handler($request, $options)->then($fn); |
|
224 | + }; |
|
225 | + }; |
|
226 | + } |
|
227 | 227 | } |
@@ -24,8 +24,8 @@ discard block |
||
24 | 24 | */ |
25 | 25 | public static function cookies() : callable |
26 | 26 | { |
27 | - return static function (callable $handler) : callable { |
|
28 | - return static function ($request, array $options) use($handler) { |
|
27 | + return static function(callable $handler) : callable { |
|
28 | + return static function($request, array $options) use($handler) { |
|
29 | 29 | if (empty($options['cookies'])) { |
30 | 30 | return $handler($request, $options); |
31 | 31 | } elseif (!$options['cookies'] instanceof CookieJarInterface) { |
@@ -33,7 +33,7 @@ discard block |
||
33 | 33 | } |
34 | 34 | $cookieJar = $options['cookies']; |
35 | 35 | $request = $cookieJar->withCookieHeader($request); |
36 | - return $handler($request, $options)->then(static function (ResponseInterface $response) use($cookieJar, $request) : ResponseInterface { |
|
36 | + return $handler($request, $options)->then(static function(ResponseInterface $response) use($cookieJar, $request) : ResponseInterface { |
|
37 | 37 | $cookieJar->extractCookies($request, $response); |
38 | 38 | return $response; |
39 | 39 | }); |
@@ -50,12 +50,12 @@ discard block |
||
50 | 50 | */ |
51 | 51 | public static function httpErrors(?BodySummarizerInterface $bodySummarizer = null) : callable |
52 | 52 | { |
53 | - return static function (callable $handler) use($bodySummarizer) : callable { |
|
54 | - return static function ($request, array $options) use($handler, $bodySummarizer) { |
|
53 | + return static function(callable $handler) use($bodySummarizer) : callable { |
|
54 | + return static function($request, array $options) use($handler, $bodySummarizer) { |
|
55 | 55 | if (empty($options['http_errors'])) { |
56 | 56 | return $handler($request, $options); |
57 | 57 | } |
58 | - return $handler($request, $options)->then(static function (ResponseInterface $response) use($request, $bodySummarizer) { |
|
58 | + return $handler($request, $options)->then(static function(ResponseInterface $response) use($request, $bodySummarizer) { |
|
59 | 59 | $code = $response->getStatusCode(); |
60 | 60 | if ($code < 400) { |
61 | 61 | return $response; |
@@ -79,12 +79,12 @@ discard block |
||
79 | 79 | if (!\is_array($container) && !$container instanceof \ArrayAccess) { |
80 | 80 | throw new \InvalidArgumentException('history container must be an array or object implementing ArrayAccess'); |
81 | 81 | } |
82 | - return static function (callable $handler) use(&$container) : callable { |
|
83 | - return static function (RequestInterface $request, array $options) use($handler, &$container) { |
|
84 | - return $handler($request, $options)->then(static function ($value) use($request, &$container, $options) { |
|
82 | + return static function(callable $handler) use(&$container) : callable { |
|
83 | + return static function(RequestInterface $request, array $options) use($handler, &$container) { |
|
84 | + return $handler($request, $options)->then(static function($value) use($request, &$container, $options) { |
|
85 | 85 | $container[] = ['request' => $request, 'response' => $value, 'error' => null, 'options' => $options]; |
86 | 86 | return $value; |
87 | - }, static function ($reason) use($request, &$container, $options) { |
|
87 | + }, static function($reason) use($request, &$container, $options) { |
|
88 | 88 | $container[] = ['request' => $request, 'response' => null, 'error' => $reason, 'options' => $options]; |
89 | 89 | return P\Create::rejectionFor($reason); |
90 | 90 | }); |
@@ -106,8 +106,8 @@ discard block |
||
106 | 106 | */ |
107 | 107 | public static function tap(?callable $before = null, ?callable $after = null) : callable |
108 | 108 | { |
109 | - return static function (callable $handler) use($before, $after) : callable { |
|
110 | - return static function (RequestInterface $request, array $options) use($handler, $before, $after) { |
|
109 | + return static function(callable $handler) use($before, $after) : callable { |
|
110 | + return static function(RequestInterface $request, array $options) use($handler, $before, $after) { |
|
111 | 111 | if ($before) { |
112 | 112 | $before($request, $options); |
113 | 113 | } |
@@ -126,7 +126,7 @@ discard block |
||
126 | 126 | */ |
127 | 127 | public static function redirect() : callable |
128 | 128 | { |
129 | - return static function (callable $handler) : RedirectMiddleware { |
|
129 | + return static function(callable $handler) : RedirectMiddleware { |
|
130 | 130 | return new RedirectMiddleware($handler); |
131 | 131 | }; |
132 | 132 | } |
@@ -147,7 +147,7 @@ discard block |
||
147 | 147 | */ |
148 | 148 | public static function retry(callable $decider, ?callable $delay = null) : callable |
149 | 149 | { |
150 | - return static function (callable $handler) use($decider, $delay) : RetryMiddleware { |
|
150 | + return static function(callable $handler) use($decider, $delay) : RetryMiddleware { |
|
151 | 151 | return new RetryMiddleware($decider, $handler, $delay); |
152 | 152 | }; |
153 | 153 | } |
@@ -169,13 +169,13 @@ discard block |
||
169 | 169 | if (!$formatter instanceof MessageFormatter && !$formatter instanceof MessageFormatterInterface) { |
170 | 170 | throw new \LogicException(\sprintf('Argument 2 to %s::log() must be of type %s', self::class, MessageFormatterInterface::class)); |
171 | 171 | } |
172 | - return static function (callable $handler) use($logger, $formatter, $logLevel) : callable { |
|
173 | - return static function (RequestInterface $request, array $options = []) use($handler, $logger, $formatter, $logLevel) { |
|
174 | - return $handler($request, $options)->then(static function ($response) use($logger, $request, $formatter, $logLevel) : ResponseInterface { |
|
172 | + return static function(callable $handler) use($logger, $formatter, $logLevel) : callable { |
|
173 | + return static function(RequestInterface $request, array $options = []) use($handler, $logger, $formatter, $logLevel) { |
|
174 | + return $handler($request, $options)->then(static function($response) use($logger, $request, $formatter, $logLevel) : ResponseInterface { |
|
175 | 175 | $message = $formatter->format($request, $response); |
176 | 176 | $logger->log($logLevel, $message); |
177 | 177 | return $response; |
178 | - }, static function ($reason) use($logger, $request, $formatter) : PromiseInterface { |
|
178 | + }, static function($reason) use($logger, $request, $formatter) : PromiseInterface { |
|
179 | 179 | $response = $reason instanceof RequestException ? $reason->getResponse() : null; |
180 | 180 | $message = $formatter->format($request, $response, P\Create::exceptionFor($reason)); |
181 | 181 | $logger->error($message); |
@@ -190,7 +190,7 @@ discard block |
||
190 | 190 | */ |
191 | 191 | public static function prepareBody() : callable |
192 | 192 | { |
193 | - return static function (callable $handler) : PrepareBodyMiddleware { |
|
193 | + return static function(callable $handler) : PrepareBodyMiddleware { |
|
194 | 194 | return new PrepareBodyMiddleware($handler); |
195 | 195 | }; |
196 | 196 | } |
@@ -203,8 +203,8 @@ discard block |
||
203 | 203 | */ |
204 | 204 | public static function mapRequest(callable $fn) : callable |
205 | 205 | { |
206 | - return static function (callable $handler) use($fn) : callable { |
|
207 | - return static function (RequestInterface $request, array $options) use($handler, $fn) { |
|
206 | + return static function(callable $handler) use($fn) : callable { |
|
207 | + return static function(RequestInterface $request, array $options) use($handler, $fn) { |
|
208 | 208 | return $handler($fn($request), $options); |
209 | 209 | }; |
210 | 210 | }; |
@@ -218,8 +218,8 @@ discard block |
||
218 | 218 | */ |
219 | 219 | public static function mapResponse(callable $fn) : callable |
220 | 220 | { |
221 | - return static function (callable $handler) use($fn) : callable { |
|
222 | - return static function (RequestInterface $request, array $options) use($handler, $fn) { |
|
221 | + return static function(callable $handler) use($fn) : callable { |
|
222 | + return static function(RequestInterface $request, array $options) use($handler, $fn) { |
|
223 | 223 | return $handler($request, $options)->then($fn); |
224 | 224 | }; |
225 | 225 | }; |
@@ -12,8 +12,7 @@ |
||
12 | 12 | * |
13 | 13 | * @final |
14 | 14 | */ |
15 | -class HandlerStack |
|
16 | -{ |
|
15 | +class HandlerStack { |
|
17 | 16 | /** |
18 | 17 | * @var (callable(RequestInterface, array): PromiseInterface)|null |
19 | 18 | */ |
@@ -76,13 +76,13 @@ discard block |
||
76 | 76 | $depth = 0; |
77 | 77 | $stack = []; |
78 | 78 | if ($this->handler !== null) { |
79 | - $stack[] = '0) Handler: ' . $this->debugCallable($this->handler); |
|
79 | + $stack[] = '0) Handler: '.$this->debugCallable($this->handler); |
|
80 | 80 | } |
81 | 81 | $result = ''; |
82 | 82 | foreach (\array_reverse($this->stack) as $tuple) { |
83 | 83 | ++$depth; |
84 | 84 | $str = "{$depth}) Name: '{$tuple[1]}', "; |
85 | - $str .= 'Function: ' . $this->debugCallable($tuple[0]); |
|
85 | + $str .= 'Function: '.$this->debugCallable($tuple[0]); |
|
86 | 86 | $result = "> {$str}\n{$result}"; |
87 | 87 | $stack[] = $str; |
88 | 88 | } |
@@ -165,7 +165,7 @@ discard block |
||
165 | 165 | } |
166 | 166 | $this->cached = null; |
167 | 167 | $idx = \is_callable($remove) ? 0 : 1; |
168 | - $this->stack = \array_values(\array_filter($this->stack, static function ($tuple) use($idx, $remove) { |
|
168 | + $this->stack = \array_values(\array_filter($this->stack, static function($tuple) use($idx, $remove) { |
|
169 | 169 | return $tuple[$idx] !== $remove; |
170 | 170 | })); |
171 | 171 | } |
@@ -230,9 +230,9 @@ discard block |
||
230 | 230 | return "callable({$fn})"; |
231 | 231 | } |
232 | 232 | if (\is_array($fn)) { |
233 | - return \is_string($fn[0]) ? "callable({$fn[0]}::{$fn[1]})" : "callable(['" . \get_class($fn[0]) . "', '{$fn[1]}'])"; |
|
233 | + return \is_string($fn[0]) ? "callable({$fn[0]}::{$fn[1]})" : "callable(['".\get_class($fn[0])."', '{$fn[1]}'])"; |
|
234 | 234 | } |
235 | 235 | /** @var object $fn */ |
236 | - return 'callable(' . \spl_object_hash($fn) . ')'; |
|
236 | + return 'callable('.\spl_object_hash($fn).')'; |
|
237 | 237 | } |
238 | 238 | } |
@@ -13,226 +13,226 @@ |
||
13 | 13 | */ |
14 | 14 | class HandlerStack |
15 | 15 | { |
16 | - /** |
|
17 | - * @var (callable(RequestInterface, array): PromiseInterface)|null |
|
18 | - */ |
|
19 | - private $handler; |
|
20 | - /** |
|
21 | - * @var array{(callable(callable(RequestInterface, array): PromiseInterface): callable), (string|null)}[] |
|
22 | - */ |
|
23 | - private $stack = []; |
|
24 | - /** |
|
25 | - * @var (callable(RequestInterface, array): PromiseInterface)|null |
|
26 | - */ |
|
27 | - private $cached; |
|
28 | - /** |
|
29 | - * Creates a default handler stack that can be used by clients. |
|
30 | - * |
|
31 | - * The returned handler will wrap the provided handler or use the most |
|
32 | - * appropriate default handler for your system. The returned HandlerStack has |
|
33 | - * support for cookies, redirects, HTTP error exceptions, and preparing a body |
|
34 | - * before sending. |
|
35 | - * |
|
36 | - * The returned handler stack can be passed to a client in the "handler" |
|
37 | - * option. |
|
38 | - * |
|
39 | - * @param (callable(RequestInterface, array): PromiseInterface)|null $handler HTTP handler function to use with the stack. If no |
|
40 | - * handler is provided, the best handler for your |
|
41 | - * system will be utilized. |
|
42 | - */ |
|
43 | - public static function create(?callable $handler = null) : self |
|
44 | - { |
|
45 | - $stack = new self($handler ?: Utils::chooseHandler()); |
|
46 | - $stack->push(Middleware::httpErrors(), 'http_errors'); |
|
47 | - $stack->push(Middleware::redirect(), 'allow_redirects'); |
|
48 | - $stack->push(Middleware::cookies(), 'cookies'); |
|
49 | - $stack->push(Middleware::prepareBody(), 'prepare_body'); |
|
50 | - return $stack; |
|
51 | - } |
|
52 | - /** |
|
53 | - * @param (callable(RequestInterface, array): PromiseInterface)|null $handler Underlying HTTP handler. |
|
54 | - */ |
|
55 | - public function __construct(?callable $handler = null) |
|
56 | - { |
|
57 | - $this->handler = $handler; |
|
58 | - } |
|
59 | - /** |
|
60 | - * Invokes the handler stack as a composed handler |
|
61 | - * |
|
62 | - * @return ResponseInterface|PromiseInterface |
|
63 | - */ |
|
64 | - public function __invoke(RequestInterface $request, array $options) |
|
65 | - { |
|
66 | - $handler = $this->resolve(); |
|
67 | - return $handler($request, $options); |
|
68 | - } |
|
69 | - /** |
|
70 | - * Dumps a string representation of the stack. |
|
71 | - * |
|
72 | - * @return string |
|
73 | - */ |
|
74 | - public function __toString() |
|
75 | - { |
|
76 | - $depth = 0; |
|
77 | - $stack = []; |
|
78 | - if ($this->handler !== null) { |
|
79 | - $stack[] = '0) Handler: ' . $this->debugCallable($this->handler); |
|
80 | - } |
|
81 | - $result = ''; |
|
82 | - foreach (\array_reverse($this->stack) as $tuple) { |
|
83 | - ++$depth; |
|
84 | - $str = "{$depth}) Name: '{$tuple[1]}', "; |
|
85 | - $str .= 'Function: ' . $this->debugCallable($tuple[0]); |
|
86 | - $result = "> {$str}\n{$result}"; |
|
87 | - $stack[] = $str; |
|
88 | - } |
|
89 | - foreach (\array_keys($stack) as $k) { |
|
90 | - $result .= "< {$stack[$k]}\n"; |
|
91 | - } |
|
92 | - return $result; |
|
93 | - } |
|
94 | - /** |
|
95 | - * Set the HTTP handler that actually returns a promise. |
|
96 | - * |
|
97 | - * @param callable(RequestInterface, array): PromiseInterface $handler Accepts a request and array of options and |
|
98 | - * returns a Promise. |
|
99 | - */ |
|
100 | - public function setHandler(callable $handler) : void |
|
101 | - { |
|
102 | - $this->handler = $handler; |
|
103 | - $this->cached = null; |
|
104 | - } |
|
105 | - /** |
|
106 | - * Returns true if the builder has a handler. |
|
107 | - */ |
|
108 | - public function hasHandler() : bool |
|
109 | - { |
|
110 | - return $this->handler !== null; |
|
111 | - } |
|
112 | - /** |
|
113 | - * Unshift a middleware to the bottom of the stack. |
|
114 | - * |
|
115 | - * @param callable(callable): callable $middleware Middleware function |
|
116 | - * @param string $name Name to register for this middleware. |
|
117 | - */ |
|
118 | - public function unshift(callable $middleware, ?string $name = null) : void |
|
119 | - { |
|
120 | - \array_unshift($this->stack, [$middleware, $name]); |
|
121 | - $this->cached = null; |
|
122 | - } |
|
123 | - /** |
|
124 | - * Push a middleware to the top of the stack. |
|
125 | - * |
|
126 | - * @param callable(callable): callable $middleware Middleware function |
|
127 | - * @param string $name Name to register for this middleware. |
|
128 | - */ |
|
129 | - public function push(callable $middleware, string $name = '') : void |
|
130 | - { |
|
131 | - $this->stack[] = [$middleware, $name]; |
|
132 | - $this->cached = null; |
|
133 | - } |
|
134 | - /** |
|
135 | - * Add a middleware before another middleware by name. |
|
136 | - * |
|
137 | - * @param string $findName Middleware to find |
|
138 | - * @param callable(callable): callable $middleware Middleware function |
|
139 | - * @param string $withName Name to register for this middleware. |
|
140 | - */ |
|
141 | - public function before(string $findName, callable $middleware, string $withName = '') : void |
|
142 | - { |
|
143 | - $this->splice($findName, $withName, $middleware, \true); |
|
144 | - } |
|
145 | - /** |
|
146 | - * Add a middleware after another middleware by name. |
|
147 | - * |
|
148 | - * @param string $findName Middleware to find |
|
149 | - * @param callable(callable): callable $middleware Middleware function |
|
150 | - * @param string $withName Name to register for this middleware. |
|
151 | - */ |
|
152 | - public function after(string $findName, callable $middleware, string $withName = '') : void |
|
153 | - { |
|
154 | - $this->splice($findName, $withName, $middleware, \false); |
|
155 | - } |
|
156 | - /** |
|
157 | - * Remove a middleware by instance or name from the stack. |
|
158 | - * |
|
159 | - * @param callable|string $remove Middleware to remove by instance or name. |
|
160 | - */ |
|
161 | - public function remove($remove) : void |
|
162 | - { |
|
163 | - if (!\is_string($remove) && !\is_callable($remove)) { |
|
164 | - trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a callable or string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__); |
|
165 | - } |
|
166 | - $this->cached = null; |
|
167 | - $idx = \is_callable($remove) ? 0 : 1; |
|
168 | - $this->stack = \array_values(\array_filter($this->stack, static function ($tuple) use($idx, $remove) { |
|
169 | - return $tuple[$idx] !== $remove; |
|
170 | - })); |
|
171 | - } |
|
172 | - /** |
|
173 | - * Compose the middleware and handler into a single callable function. |
|
174 | - * |
|
175 | - * @return callable(RequestInterface, array): PromiseInterface |
|
176 | - */ |
|
177 | - public function resolve() : callable |
|
178 | - { |
|
179 | - if ($this->cached === null) { |
|
180 | - if (($prev = $this->handler) === null) { |
|
181 | - throw new \LogicException('No handler has been specified'); |
|
182 | - } |
|
183 | - foreach (\array_reverse($this->stack) as $fn) { |
|
184 | - /** @var callable(RequestInterface, array): PromiseInterface $prev */ |
|
185 | - $prev = $fn[0]($prev); |
|
186 | - } |
|
187 | - $this->cached = $prev; |
|
188 | - } |
|
189 | - return $this->cached; |
|
190 | - } |
|
191 | - private function findByName(string $name) : int |
|
192 | - { |
|
193 | - foreach ($this->stack as $k => $v) { |
|
194 | - if ($v[1] === $name) { |
|
195 | - return $k; |
|
196 | - } |
|
197 | - } |
|
198 | - throw new \InvalidArgumentException("Middleware not found: {$name}"); |
|
199 | - } |
|
200 | - /** |
|
201 | - * Splices a function into the middleware list at a specific position. |
|
202 | - */ |
|
203 | - private function splice(string $findName, string $withName, callable $middleware, bool $before) : void |
|
204 | - { |
|
205 | - $this->cached = null; |
|
206 | - $idx = $this->findByName($findName); |
|
207 | - $tuple = [$middleware, $withName]; |
|
208 | - if ($before) { |
|
209 | - if ($idx === 0) { |
|
210 | - \array_unshift($this->stack, $tuple); |
|
211 | - } else { |
|
212 | - $replacement = [$tuple, $this->stack[$idx]]; |
|
213 | - \array_splice($this->stack, $idx, 1, $replacement); |
|
214 | - } |
|
215 | - } elseif ($idx === \count($this->stack) - 1) { |
|
216 | - $this->stack[] = $tuple; |
|
217 | - } else { |
|
218 | - $replacement = [$this->stack[$idx], $tuple]; |
|
219 | - \array_splice($this->stack, $idx, 1, $replacement); |
|
220 | - } |
|
221 | - } |
|
222 | - /** |
|
223 | - * Provides a debug string for a given callable. |
|
224 | - * |
|
225 | - * @param callable|string $fn Function to write as a string. |
|
226 | - */ |
|
227 | - private function debugCallable($fn) : string |
|
228 | - { |
|
229 | - if (\is_string($fn)) { |
|
230 | - return "callable({$fn})"; |
|
231 | - } |
|
232 | - if (\is_array($fn)) { |
|
233 | - return \is_string($fn[0]) ? "callable({$fn[0]}::{$fn[1]})" : "callable(['" . \get_class($fn[0]) . "', '{$fn[1]}'])"; |
|
234 | - } |
|
235 | - /** @var object $fn */ |
|
236 | - return 'callable(' . \spl_object_hash($fn) . ')'; |
|
237 | - } |
|
16 | + /** |
|
17 | + * @var (callable(RequestInterface, array): PromiseInterface)|null |
|
18 | + */ |
|
19 | + private $handler; |
|
20 | + /** |
|
21 | + * @var array{(callable(callable(RequestInterface, array): PromiseInterface): callable), (string|null)}[] |
|
22 | + */ |
|
23 | + private $stack = []; |
|
24 | + /** |
|
25 | + * @var (callable(RequestInterface, array): PromiseInterface)|null |
|
26 | + */ |
|
27 | + private $cached; |
|
28 | + /** |
|
29 | + * Creates a default handler stack that can be used by clients. |
|
30 | + * |
|
31 | + * The returned handler will wrap the provided handler or use the most |
|
32 | + * appropriate default handler for your system. The returned HandlerStack has |
|
33 | + * support for cookies, redirects, HTTP error exceptions, and preparing a body |
|
34 | + * before sending. |
|
35 | + * |
|
36 | + * The returned handler stack can be passed to a client in the "handler" |
|
37 | + * option. |
|
38 | + * |
|
39 | + * @param (callable(RequestInterface, array): PromiseInterface)|null $handler HTTP handler function to use with the stack. If no |
|
40 | + * handler is provided, the best handler for your |
|
41 | + * system will be utilized. |
|
42 | + */ |
|
43 | + public static function create(?callable $handler = null) : self |
|
44 | + { |
|
45 | + $stack = new self($handler ?: Utils::chooseHandler()); |
|
46 | + $stack->push(Middleware::httpErrors(), 'http_errors'); |
|
47 | + $stack->push(Middleware::redirect(), 'allow_redirects'); |
|
48 | + $stack->push(Middleware::cookies(), 'cookies'); |
|
49 | + $stack->push(Middleware::prepareBody(), 'prepare_body'); |
|
50 | + return $stack; |
|
51 | + } |
|
52 | + /** |
|
53 | + * @param (callable(RequestInterface, array): PromiseInterface)|null $handler Underlying HTTP handler. |
|
54 | + */ |
|
55 | + public function __construct(?callable $handler = null) |
|
56 | + { |
|
57 | + $this->handler = $handler; |
|
58 | + } |
|
59 | + /** |
|
60 | + * Invokes the handler stack as a composed handler |
|
61 | + * |
|
62 | + * @return ResponseInterface|PromiseInterface |
|
63 | + */ |
|
64 | + public function __invoke(RequestInterface $request, array $options) |
|
65 | + { |
|
66 | + $handler = $this->resolve(); |
|
67 | + return $handler($request, $options); |
|
68 | + } |
|
69 | + /** |
|
70 | + * Dumps a string representation of the stack. |
|
71 | + * |
|
72 | + * @return string |
|
73 | + */ |
|
74 | + public function __toString() |
|
75 | + { |
|
76 | + $depth = 0; |
|
77 | + $stack = []; |
|
78 | + if ($this->handler !== null) { |
|
79 | + $stack[] = '0) Handler: ' . $this->debugCallable($this->handler); |
|
80 | + } |
|
81 | + $result = ''; |
|
82 | + foreach (\array_reverse($this->stack) as $tuple) { |
|
83 | + ++$depth; |
|
84 | + $str = "{$depth}) Name: '{$tuple[1]}', "; |
|
85 | + $str .= 'Function: ' . $this->debugCallable($tuple[0]); |
|
86 | + $result = "> {$str}\n{$result}"; |
|
87 | + $stack[] = $str; |
|
88 | + } |
|
89 | + foreach (\array_keys($stack) as $k) { |
|
90 | + $result .= "< {$stack[$k]}\n"; |
|
91 | + } |
|
92 | + return $result; |
|
93 | + } |
|
94 | + /** |
|
95 | + * Set the HTTP handler that actually returns a promise. |
|
96 | + * |
|
97 | + * @param callable(RequestInterface, array): PromiseInterface $handler Accepts a request and array of options and |
|
98 | + * returns a Promise. |
|
99 | + */ |
|
100 | + public function setHandler(callable $handler) : void |
|
101 | + { |
|
102 | + $this->handler = $handler; |
|
103 | + $this->cached = null; |
|
104 | + } |
|
105 | + /** |
|
106 | + * Returns true if the builder has a handler. |
|
107 | + */ |
|
108 | + public function hasHandler() : bool |
|
109 | + { |
|
110 | + return $this->handler !== null; |
|
111 | + } |
|
112 | + /** |
|
113 | + * Unshift a middleware to the bottom of the stack. |
|
114 | + * |
|
115 | + * @param callable(callable): callable $middleware Middleware function |
|
116 | + * @param string $name Name to register for this middleware. |
|
117 | + */ |
|
118 | + public function unshift(callable $middleware, ?string $name = null) : void |
|
119 | + { |
|
120 | + \array_unshift($this->stack, [$middleware, $name]); |
|
121 | + $this->cached = null; |
|
122 | + } |
|
123 | + /** |
|
124 | + * Push a middleware to the top of the stack. |
|
125 | + * |
|
126 | + * @param callable(callable): callable $middleware Middleware function |
|
127 | + * @param string $name Name to register for this middleware. |
|
128 | + */ |
|
129 | + public function push(callable $middleware, string $name = '') : void |
|
130 | + { |
|
131 | + $this->stack[] = [$middleware, $name]; |
|
132 | + $this->cached = null; |
|
133 | + } |
|
134 | + /** |
|
135 | + * Add a middleware before another middleware by name. |
|
136 | + * |
|
137 | + * @param string $findName Middleware to find |
|
138 | + * @param callable(callable): callable $middleware Middleware function |
|
139 | + * @param string $withName Name to register for this middleware. |
|
140 | + */ |
|
141 | + public function before(string $findName, callable $middleware, string $withName = '') : void |
|
142 | + { |
|
143 | + $this->splice($findName, $withName, $middleware, \true); |
|
144 | + } |
|
145 | + /** |
|
146 | + * Add a middleware after another middleware by name. |
|
147 | + * |
|
148 | + * @param string $findName Middleware to find |
|
149 | + * @param callable(callable): callable $middleware Middleware function |
|
150 | + * @param string $withName Name to register for this middleware. |
|
151 | + */ |
|
152 | + public function after(string $findName, callable $middleware, string $withName = '') : void |
|
153 | + { |
|
154 | + $this->splice($findName, $withName, $middleware, \false); |
|
155 | + } |
|
156 | + /** |
|
157 | + * Remove a middleware by instance or name from the stack. |
|
158 | + * |
|
159 | + * @param callable|string $remove Middleware to remove by instance or name. |
|
160 | + */ |
|
161 | + public function remove($remove) : void |
|
162 | + { |
|
163 | + if (!\is_string($remove) && !\is_callable($remove)) { |
|
164 | + trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a callable or string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__); |
|
165 | + } |
|
166 | + $this->cached = null; |
|
167 | + $idx = \is_callable($remove) ? 0 : 1; |
|
168 | + $this->stack = \array_values(\array_filter($this->stack, static function ($tuple) use($idx, $remove) { |
|
169 | + return $tuple[$idx] !== $remove; |
|
170 | + })); |
|
171 | + } |
|
172 | + /** |
|
173 | + * Compose the middleware and handler into a single callable function. |
|
174 | + * |
|
175 | + * @return callable(RequestInterface, array): PromiseInterface |
|
176 | + */ |
|
177 | + public function resolve() : callable |
|
178 | + { |
|
179 | + if ($this->cached === null) { |
|
180 | + if (($prev = $this->handler) === null) { |
|
181 | + throw new \LogicException('No handler has been specified'); |
|
182 | + } |
|
183 | + foreach (\array_reverse($this->stack) as $fn) { |
|
184 | + /** @var callable(RequestInterface, array): PromiseInterface $prev */ |
|
185 | + $prev = $fn[0]($prev); |
|
186 | + } |
|
187 | + $this->cached = $prev; |
|
188 | + } |
|
189 | + return $this->cached; |
|
190 | + } |
|
191 | + private function findByName(string $name) : int |
|
192 | + { |
|
193 | + foreach ($this->stack as $k => $v) { |
|
194 | + if ($v[1] === $name) { |
|
195 | + return $k; |
|
196 | + } |
|
197 | + } |
|
198 | + throw new \InvalidArgumentException("Middleware not found: {$name}"); |
|
199 | + } |
|
200 | + /** |
|
201 | + * Splices a function into the middleware list at a specific position. |
|
202 | + */ |
|
203 | + private function splice(string $findName, string $withName, callable $middleware, bool $before) : void |
|
204 | + { |
|
205 | + $this->cached = null; |
|
206 | + $idx = $this->findByName($findName); |
|
207 | + $tuple = [$middleware, $withName]; |
|
208 | + if ($before) { |
|
209 | + if ($idx === 0) { |
|
210 | + \array_unshift($this->stack, $tuple); |
|
211 | + } else { |
|
212 | + $replacement = [$tuple, $this->stack[$idx]]; |
|
213 | + \array_splice($this->stack, $idx, 1, $replacement); |
|
214 | + } |
|
215 | + } elseif ($idx === \count($this->stack) - 1) { |
|
216 | + $this->stack[] = $tuple; |
|
217 | + } else { |
|
218 | + $replacement = [$this->stack[$idx], $tuple]; |
|
219 | + \array_splice($this->stack, $idx, 1, $replacement); |
|
220 | + } |
|
221 | + } |
|
222 | + /** |
|
223 | + * Provides a debug string for a given callable. |
|
224 | + * |
|
225 | + * @param callable|string $fn Function to write as a string. |
|
226 | + */ |
|
227 | + private function debugCallable($fn) : string |
|
228 | + { |
|
229 | + if (\is_string($fn)) { |
|
230 | + return "callable({$fn})"; |
|
231 | + } |
|
232 | + if (\is_array($fn)) { |
|
233 | + return \is_string($fn[0]) ? "callable({$fn[0]}::{$fn[1]})" : "callable(['" . \get_class($fn[0]) . "', '{$fn[1]}'])"; |
|
234 | + } |
|
235 | + /** @var object $fn */ |
|
236 | + return 'callable(' . \spl_object_hash($fn) . ')'; |
|
237 | + } |
|
238 | 238 | } |
@@ -10,8 +10,7 @@ |
||
10 | 10 | * Represents data at the point after it was transferred either successfully |
11 | 11 | * or after a network error. |
12 | 12 | */ |
13 | -final class TransferStats |
|
14 | -{ |
|
13 | +final class TransferStats { |
|
15 | 14 | /** |
16 | 15 | * @var RequestInterface |
17 | 16 | */ |
@@ -11,104 +11,104 @@ |
||
11 | 11 | */ |
12 | 12 | final class TransferStats |
13 | 13 | { |
14 | - /** |
|
15 | - * @var RequestInterface |
|
16 | - */ |
|
17 | - private $request; |
|
18 | - /** |
|
19 | - * @var ResponseInterface|null |
|
20 | - */ |
|
21 | - private $response; |
|
22 | - /** |
|
23 | - * @var float|null |
|
24 | - */ |
|
25 | - private $transferTime; |
|
26 | - /** |
|
27 | - * @var array |
|
28 | - */ |
|
29 | - private $handlerStats; |
|
30 | - /** |
|
31 | - * @var mixed|null |
|
32 | - */ |
|
33 | - private $handlerErrorData; |
|
34 | - /** |
|
35 | - * @param RequestInterface $request Request that was sent. |
|
36 | - * @param ResponseInterface|null $response Response received (if any) |
|
37 | - * @param float|null $transferTime Total handler transfer time. |
|
38 | - * @param mixed $handlerErrorData Handler error data. |
|
39 | - * @param array $handlerStats Handler specific stats. |
|
40 | - */ |
|
41 | - public function __construct(RequestInterface $request, ?ResponseInterface $response = null, ?float $transferTime = null, $handlerErrorData = null, array $handlerStats = []) |
|
42 | - { |
|
43 | - $this->request = $request; |
|
44 | - $this->response = $response; |
|
45 | - $this->transferTime = $transferTime; |
|
46 | - $this->handlerErrorData = $handlerErrorData; |
|
47 | - $this->handlerStats = $handlerStats; |
|
48 | - } |
|
49 | - public function getRequest() : RequestInterface |
|
50 | - { |
|
51 | - return $this->request; |
|
52 | - } |
|
53 | - /** |
|
54 | - * Returns the response that was received (if any). |
|
55 | - */ |
|
56 | - public function getResponse() : ?ResponseInterface |
|
57 | - { |
|
58 | - return $this->response; |
|
59 | - } |
|
60 | - /** |
|
61 | - * Returns true if a response was received. |
|
62 | - */ |
|
63 | - public function hasResponse() : bool |
|
64 | - { |
|
65 | - return $this->response !== null; |
|
66 | - } |
|
67 | - /** |
|
68 | - * Gets handler specific error data. |
|
69 | - * |
|
70 | - * This might be an exception, a integer representing an error code, or |
|
71 | - * anything else. Relying on this value assumes that you know what handler |
|
72 | - * you are using. |
|
73 | - * |
|
74 | - * @return mixed |
|
75 | - */ |
|
76 | - public function getHandlerErrorData() |
|
77 | - { |
|
78 | - return $this->handlerErrorData; |
|
79 | - } |
|
80 | - /** |
|
81 | - * Get the effective URI the request was sent to. |
|
82 | - */ |
|
83 | - public function getEffectiveUri() : UriInterface |
|
84 | - { |
|
85 | - return $this->request->getUri(); |
|
86 | - } |
|
87 | - /** |
|
88 | - * Get the estimated time the request was being transferred by the handler. |
|
89 | - * |
|
90 | - * @return float|null Time in seconds. |
|
91 | - */ |
|
92 | - public function getTransferTime() : ?float |
|
93 | - { |
|
94 | - return $this->transferTime; |
|
95 | - } |
|
96 | - /** |
|
97 | - * Gets an array of all of the handler specific transfer data. |
|
98 | - */ |
|
99 | - public function getHandlerStats() : array |
|
100 | - { |
|
101 | - return $this->handlerStats; |
|
102 | - } |
|
103 | - /** |
|
104 | - * Get a specific handler statistic from the handler by name. |
|
105 | - * |
|
106 | - * @param string $stat Handler specific transfer stat to retrieve. |
|
107 | - * |
|
108 | - * @return mixed|null |
|
109 | - */ |
|
110 | - public function getHandlerStat(string $stat) |
|
111 | - { |
|
112 | - return $this->handlerStats[$stat] ?? null; |
|
113 | - } |
|
14 | + /** |
|
15 | + * @var RequestInterface |
|
16 | + */ |
|
17 | + private $request; |
|
18 | + /** |
|
19 | + * @var ResponseInterface|null |
|
20 | + */ |
|
21 | + private $response; |
|
22 | + /** |
|
23 | + * @var float|null |
|
24 | + */ |
|
25 | + private $transferTime; |
|
26 | + /** |
|
27 | + * @var array |
|
28 | + */ |
|
29 | + private $handlerStats; |
|
30 | + /** |
|
31 | + * @var mixed|null |
|
32 | + */ |
|
33 | + private $handlerErrorData; |
|
34 | + /** |
|
35 | + * @param RequestInterface $request Request that was sent. |
|
36 | + * @param ResponseInterface|null $response Response received (if any) |
|
37 | + * @param float|null $transferTime Total handler transfer time. |
|
38 | + * @param mixed $handlerErrorData Handler error data. |
|
39 | + * @param array $handlerStats Handler specific stats. |
|
40 | + */ |
|
41 | + public function __construct(RequestInterface $request, ?ResponseInterface $response = null, ?float $transferTime = null, $handlerErrorData = null, array $handlerStats = []) |
|
42 | + { |
|
43 | + $this->request = $request; |
|
44 | + $this->response = $response; |
|
45 | + $this->transferTime = $transferTime; |
|
46 | + $this->handlerErrorData = $handlerErrorData; |
|
47 | + $this->handlerStats = $handlerStats; |
|
48 | + } |
|
49 | + public function getRequest() : RequestInterface |
|
50 | + { |
|
51 | + return $this->request; |
|
52 | + } |
|
53 | + /** |
|
54 | + * Returns the response that was received (if any). |
|
55 | + */ |
|
56 | + public function getResponse() : ?ResponseInterface |
|
57 | + { |
|
58 | + return $this->response; |
|
59 | + } |
|
60 | + /** |
|
61 | + * Returns true if a response was received. |
|
62 | + */ |
|
63 | + public function hasResponse() : bool |
|
64 | + { |
|
65 | + return $this->response !== null; |
|
66 | + } |
|
67 | + /** |
|
68 | + * Gets handler specific error data. |
|
69 | + * |
|
70 | + * This might be an exception, a integer representing an error code, or |
|
71 | + * anything else. Relying on this value assumes that you know what handler |
|
72 | + * you are using. |
|
73 | + * |
|
74 | + * @return mixed |
|
75 | + */ |
|
76 | + public function getHandlerErrorData() |
|
77 | + { |
|
78 | + return $this->handlerErrorData; |
|
79 | + } |
|
80 | + /** |
|
81 | + * Get the effective URI the request was sent to. |
|
82 | + */ |
|
83 | + public function getEffectiveUri() : UriInterface |
|
84 | + { |
|
85 | + return $this->request->getUri(); |
|
86 | + } |
|
87 | + /** |
|
88 | + * Get the estimated time the request was being transferred by the handler. |
|
89 | + * |
|
90 | + * @return float|null Time in seconds. |
|
91 | + */ |
|
92 | + public function getTransferTime() : ?float |
|
93 | + { |
|
94 | + return $this->transferTime; |
|
95 | + } |
|
96 | + /** |
|
97 | + * Gets an array of all of the handler specific transfer data. |
|
98 | + */ |
|
99 | + public function getHandlerStats() : array |
|
100 | + { |
|
101 | + return $this->handlerStats; |
|
102 | + } |
|
103 | + /** |
|
104 | + * Get a specific handler statistic from the handler by name. |
|
105 | + * |
|
106 | + * @param string $stat Handler specific transfer stat to retrieve. |
|
107 | + * |
|
108 | + * @return mixed|null |
|
109 | + */ |
|
110 | + public function getHandlerStat(string $stat) |
|
111 | + { |
|
112 | + return $this->handlerStats[$stat] ?? null; |
|
113 | + } |
|
114 | 114 | } |
@@ -4,5 +4,5 @@ |
||
4 | 4 | |
5 | 5 | // Don't redefine the functions if included multiple times. |
6 | 6 | if (!\function_exists('OCA\\FullTextSearch_Elasticsearch\\Vendor\\GuzzleHttp\\describe_type')) { |
7 | - require __DIR__ . '/functions.php'; |
|
7 | + require __DIR__ . '/functions.php'; |
|
8 | 8 | } |
@@ -4,5 +4,5 @@ |
||
4 | 4 | |
5 | 5 | // Don't redefine the functions if included multiple times. |
6 | 6 | if (!\function_exists('OCA\\FullTextSearch_Elasticsearch\\Vendor\\GuzzleHttp\\describe_type')) { |
7 | - require __DIR__ . '/functions.php'; |
|
7 | + require __DIR__.'/functions.php'; |
|
8 | 8 | } |
@@ -18,145 +18,145 @@ |
||
18 | 18 | */ |
19 | 19 | class RedirectMiddleware |
20 | 20 | { |
21 | - public const HISTORY_HEADER = 'X-Guzzle-Redirect-History'; |
|
22 | - public const STATUS_HISTORY_HEADER = 'X-Guzzle-Redirect-Status-History'; |
|
23 | - /** |
|
24 | - * @var array |
|
25 | - */ |
|
26 | - public static $defaultSettings = ['max' => 5, 'protocols' => ['http', 'https'], 'strict' => \false, 'referer' => \false, 'track_redirects' => \false]; |
|
27 | - /** |
|
28 | - * @var callable(RequestInterface, array): PromiseInterface |
|
29 | - */ |
|
30 | - private $nextHandler; |
|
31 | - /** |
|
32 | - * @param callable(RequestInterface, array): PromiseInterface $nextHandler Next handler to invoke. |
|
33 | - */ |
|
34 | - public function __construct(callable $nextHandler) |
|
35 | - { |
|
36 | - $this->nextHandler = $nextHandler; |
|
37 | - } |
|
38 | - public function __invoke(RequestInterface $request, array $options) : PromiseInterface |
|
39 | - { |
|
40 | - $fn = $this->nextHandler; |
|
41 | - if (empty($options['allow_redirects'])) { |
|
42 | - return $fn($request, $options); |
|
43 | - } |
|
44 | - if ($options['allow_redirects'] === \true) { |
|
45 | - $options['allow_redirects'] = self::$defaultSettings; |
|
46 | - } elseif (!\is_array($options['allow_redirects'])) { |
|
47 | - throw new \InvalidArgumentException('allow_redirects must be true, false, or array'); |
|
48 | - } else { |
|
49 | - // Merge the default settings with the provided settings |
|
50 | - $options['allow_redirects'] += self::$defaultSettings; |
|
51 | - } |
|
52 | - if (empty($options['allow_redirects']['max'])) { |
|
53 | - return $fn($request, $options); |
|
54 | - } |
|
55 | - return $fn($request, $options)->then(function (ResponseInterface $response) use($request, $options) { |
|
56 | - return $this->checkRedirect($request, $options, $response); |
|
57 | - }); |
|
58 | - } |
|
59 | - /** |
|
60 | - * @return ResponseInterface|PromiseInterface |
|
61 | - */ |
|
62 | - public function checkRedirect(RequestInterface $request, array $options, ResponseInterface $response) |
|
63 | - { |
|
64 | - if (\strpos((string) $response->getStatusCode(), '3') !== 0 || !$response->hasHeader('Location')) { |
|
65 | - return $response; |
|
66 | - } |
|
67 | - $this->guardMax($request, $response, $options); |
|
68 | - $nextRequest = $this->modifyRequest($request, $options, $response); |
|
69 | - // If authorization is handled by curl, unset it if URI is cross-origin. |
|
70 | - if (Psr7\UriComparator::isCrossOrigin($request->getUri(), $nextRequest->getUri()) && \defined('\\CURLOPT_HTTPAUTH')) { |
|
71 | - unset($options['curl'][\CURLOPT_HTTPAUTH], $options['curl'][\CURLOPT_USERPWD]); |
|
72 | - } |
|
73 | - if (isset($options['allow_redirects']['on_redirect'])) { |
|
74 | - $options['allow_redirects']['on_redirect']($request, $response, $nextRequest->getUri()); |
|
75 | - } |
|
76 | - $promise = $this($nextRequest, $options); |
|
77 | - // Add headers to be able to track history of redirects. |
|
78 | - if (!empty($options['allow_redirects']['track_redirects'])) { |
|
79 | - return $this->withTracking($promise, (string) $nextRequest->getUri(), $response->getStatusCode()); |
|
80 | - } |
|
81 | - return $promise; |
|
82 | - } |
|
83 | - /** |
|
84 | - * Enable tracking on promise. |
|
85 | - */ |
|
86 | - private function withTracking(PromiseInterface $promise, string $uri, int $statusCode) : PromiseInterface |
|
87 | - { |
|
88 | - return $promise->then(static function (ResponseInterface $response) use($uri, $statusCode) { |
|
89 | - // Note that we are pushing to the front of the list as this |
|
90 | - // would be an earlier response than what is currently present |
|
91 | - // in the history header. |
|
92 | - $historyHeader = $response->getHeader(self::HISTORY_HEADER); |
|
93 | - $statusHeader = $response->getHeader(self::STATUS_HISTORY_HEADER); |
|
94 | - \array_unshift($historyHeader, $uri); |
|
95 | - \array_unshift($statusHeader, (string) $statusCode); |
|
96 | - return $response->withHeader(self::HISTORY_HEADER, $historyHeader)->withHeader(self::STATUS_HISTORY_HEADER, $statusHeader); |
|
97 | - }); |
|
98 | - } |
|
99 | - /** |
|
100 | - * Check for too many redirects. |
|
101 | - * |
|
102 | - * @throws TooManyRedirectsException Too many redirects. |
|
103 | - */ |
|
104 | - private function guardMax(RequestInterface $request, ResponseInterface $response, array &$options) : void |
|
105 | - { |
|
106 | - $current = $options['__redirect_count'] ?? 0; |
|
107 | - $options['__redirect_count'] = $current + 1; |
|
108 | - $max = $options['allow_redirects']['max']; |
|
109 | - if ($options['__redirect_count'] > $max) { |
|
110 | - throw new TooManyRedirectsException("Will not follow more than {$max} redirects", $request, $response); |
|
111 | - } |
|
112 | - } |
|
113 | - public function modifyRequest(RequestInterface $request, array $options, ResponseInterface $response) : RequestInterface |
|
114 | - { |
|
115 | - // Request modifications to apply. |
|
116 | - $modify = []; |
|
117 | - $protocols = $options['allow_redirects']['protocols']; |
|
118 | - // Use a GET request if this is an entity enclosing request and we are |
|
119 | - // not forcing RFC compliance, but rather emulating what all browsers |
|
120 | - // would do. |
|
121 | - $statusCode = $response->getStatusCode(); |
|
122 | - if ($statusCode == 303 || $statusCode <= 302 && !$options['allow_redirects']['strict']) { |
|
123 | - $safeMethods = ['GET', 'HEAD', 'OPTIONS']; |
|
124 | - $requestMethod = $request->getMethod(); |
|
125 | - $modify['method'] = \in_array($requestMethod, $safeMethods) ? $requestMethod : 'GET'; |
|
126 | - $modify['body'] = ''; |
|
127 | - } |
|
128 | - $uri = self::redirectUri($request, $response, $protocols); |
|
129 | - if (isset($options['idn_conversion']) && $options['idn_conversion'] !== \false) { |
|
130 | - $idnOptions = $options['idn_conversion'] === \true ? \IDNA_DEFAULT : $options['idn_conversion']; |
|
131 | - $uri = Utils::idnUriConvert($uri, $idnOptions); |
|
132 | - } |
|
133 | - $modify['uri'] = $uri; |
|
134 | - Psr7\Message::rewindBody($request); |
|
135 | - // Add the Referer header if it is told to do so and only |
|
136 | - // add the header if we are not redirecting from https to http. |
|
137 | - if ($options['allow_redirects']['referer'] && $modify['uri']->getScheme() === $request->getUri()->getScheme()) { |
|
138 | - $uri = $request->getUri()->withUserInfo(''); |
|
139 | - $modify['set_headers']['Referer'] = (string) $uri; |
|
140 | - } else { |
|
141 | - $modify['remove_headers'][] = 'Referer'; |
|
142 | - } |
|
143 | - // Remove Authorization and Cookie headers if URI is cross-origin. |
|
144 | - if (Psr7\UriComparator::isCrossOrigin($request->getUri(), $modify['uri'])) { |
|
145 | - $modify['remove_headers'][] = 'Authorization'; |
|
146 | - $modify['remove_headers'][] = 'Cookie'; |
|
147 | - } |
|
148 | - return Psr7\Utils::modifyRequest($request, $modify); |
|
149 | - } |
|
150 | - /** |
|
151 | - * Set the appropriate URL on the request based on the location header. |
|
152 | - */ |
|
153 | - private static function redirectUri(RequestInterface $request, ResponseInterface $response, array $protocols) : UriInterface |
|
154 | - { |
|
155 | - $location = Psr7\UriResolver::resolve($request->getUri(), new Psr7\Uri($response->getHeaderLine('Location'))); |
|
156 | - // Ensure that the redirect URI is allowed based on the protocols. |
|
157 | - if (!\in_array($location->getScheme(), $protocols)) { |
|
158 | - throw new BadResponseException(\sprintf('Redirect URI, %s, does not use one of the allowed redirect protocols: %s', $location, \implode(', ', $protocols)), $request, $response); |
|
159 | - } |
|
160 | - return $location; |
|
161 | - } |
|
21 | + public const HISTORY_HEADER = 'X-Guzzle-Redirect-History'; |
|
22 | + public const STATUS_HISTORY_HEADER = 'X-Guzzle-Redirect-Status-History'; |
|
23 | + /** |
|
24 | + * @var array |
|
25 | + */ |
|
26 | + public static $defaultSettings = ['max' => 5, 'protocols' => ['http', 'https'], 'strict' => \false, 'referer' => \false, 'track_redirects' => \false]; |
|
27 | + /** |
|
28 | + * @var callable(RequestInterface, array): PromiseInterface |
|
29 | + */ |
|
30 | + private $nextHandler; |
|
31 | + /** |
|
32 | + * @param callable(RequestInterface, array): PromiseInterface $nextHandler Next handler to invoke. |
|
33 | + */ |
|
34 | + public function __construct(callable $nextHandler) |
|
35 | + { |
|
36 | + $this->nextHandler = $nextHandler; |
|
37 | + } |
|
38 | + public function __invoke(RequestInterface $request, array $options) : PromiseInterface |
|
39 | + { |
|
40 | + $fn = $this->nextHandler; |
|
41 | + if (empty($options['allow_redirects'])) { |
|
42 | + return $fn($request, $options); |
|
43 | + } |
|
44 | + if ($options['allow_redirects'] === \true) { |
|
45 | + $options['allow_redirects'] = self::$defaultSettings; |
|
46 | + } elseif (!\is_array($options['allow_redirects'])) { |
|
47 | + throw new \InvalidArgumentException('allow_redirects must be true, false, or array'); |
|
48 | + } else { |
|
49 | + // Merge the default settings with the provided settings |
|
50 | + $options['allow_redirects'] += self::$defaultSettings; |
|
51 | + } |
|
52 | + if (empty($options['allow_redirects']['max'])) { |
|
53 | + return $fn($request, $options); |
|
54 | + } |
|
55 | + return $fn($request, $options)->then(function (ResponseInterface $response) use($request, $options) { |
|
56 | + return $this->checkRedirect($request, $options, $response); |
|
57 | + }); |
|
58 | + } |
|
59 | + /** |
|
60 | + * @return ResponseInterface|PromiseInterface |
|
61 | + */ |
|
62 | + public function checkRedirect(RequestInterface $request, array $options, ResponseInterface $response) |
|
63 | + { |
|
64 | + if (\strpos((string) $response->getStatusCode(), '3') !== 0 || !$response->hasHeader('Location')) { |
|
65 | + return $response; |
|
66 | + } |
|
67 | + $this->guardMax($request, $response, $options); |
|
68 | + $nextRequest = $this->modifyRequest($request, $options, $response); |
|
69 | + // If authorization is handled by curl, unset it if URI is cross-origin. |
|
70 | + if (Psr7\UriComparator::isCrossOrigin($request->getUri(), $nextRequest->getUri()) && \defined('\\CURLOPT_HTTPAUTH')) { |
|
71 | + unset($options['curl'][\CURLOPT_HTTPAUTH], $options['curl'][\CURLOPT_USERPWD]); |
|
72 | + } |
|
73 | + if (isset($options['allow_redirects']['on_redirect'])) { |
|
74 | + $options['allow_redirects']['on_redirect']($request, $response, $nextRequest->getUri()); |
|
75 | + } |
|
76 | + $promise = $this($nextRequest, $options); |
|
77 | + // Add headers to be able to track history of redirects. |
|
78 | + if (!empty($options['allow_redirects']['track_redirects'])) { |
|
79 | + return $this->withTracking($promise, (string) $nextRequest->getUri(), $response->getStatusCode()); |
|
80 | + } |
|
81 | + return $promise; |
|
82 | + } |
|
83 | + /** |
|
84 | + * Enable tracking on promise. |
|
85 | + */ |
|
86 | + private function withTracking(PromiseInterface $promise, string $uri, int $statusCode) : PromiseInterface |
|
87 | + { |
|
88 | + return $promise->then(static function (ResponseInterface $response) use($uri, $statusCode) { |
|
89 | + // Note that we are pushing to the front of the list as this |
|
90 | + // would be an earlier response than what is currently present |
|
91 | + // in the history header. |
|
92 | + $historyHeader = $response->getHeader(self::HISTORY_HEADER); |
|
93 | + $statusHeader = $response->getHeader(self::STATUS_HISTORY_HEADER); |
|
94 | + \array_unshift($historyHeader, $uri); |
|
95 | + \array_unshift($statusHeader, (string) $statusCode); |
|
96 | + return $response->withHeader(self::HISTORY_HEADER, $historyHeader)->withHeader(self::STATUS_HISTORY_HEADER, $statusHeader); |
|
97 | + }); |
|
98 | + } |
|
99 | + /** |
|
100 | + * Check for too many redirects. |
|
101 | + * |
|
102 | + * @throws TooManyRedirectsException Too many redirects. |
|
103 | + */ |
|
104 | + private function guardMax(RequestInterface $request, ResponseInterface $response, array &$options) : void |
|
105 | + { |
|
106 | + $current = $options['__redirect_count'] ?? 0; |
|
107 | + $options['__redirect_count'] = $current + 1; |
|
108 | + $max = $options['allow_redirects']['max']; |
|
109 | + if ($options['__redirect_count'] > $max) { |
|
110 | + throw new TooManyRedirectsException("Will not follow more than {$max} redirects", $request, $response); |
|
111 | + } |
|
112 | + } |
|
113 | + public function modifyRequest(RequestInterface $request, array $options, ResponseInterface $response) : RequestInterface |
|
114 | + { |
|
115 | + // Request modifications to apply. |
|
116 | + $modify = []; |
|
117 | + $protocols = $options['allow_redirects']['protocols']; |
|
118 | + // Use a GET request if this is an entity enclosing request and we are |
|
119 | + // not forcing RFC compliance, but rather emulating what all browsers |
|
120 | + // would do. |
|
121 | + $statusCode = $response->getStatusCode(); |
|
122 | + if ($statusCode == 303 || $statusCode <= 302 && !$options['allow_redirects']['strict']) { |
|
123 | + $safeMethods = ['GET', 'HEAD', 'OPTIONS']; |
|
124 | + $requestMethod = $request->getMethod(); |
|
125 | + $modify['method'] = \in_array($requestMethod, $safeMethods) ? $requestMethod : 'GET'; |
|
126 | + $modify['body'] = ''; |
|
127 | + } |
|
128 | + $uri = self::redirectUri($request, $response, $protocols); |
|
129 | + if (isset($options['idn_conversion']) && $options['idn_conversion'] !== \false) { |
|
130 | + $idnOptions = $options['idn_conversion'] === \true ? \IDNA_DEFAULT : $options['idn_conversion']; |
|
131 | + $uri = Utils::idnUriConvert($uri, $idnOptions); |
|
132 | + } |
|
133 | + $modify['uri'] = $uri; |
|
134 | + Psr7\Message::rewindBody($request); |
|
135 | + // Add the Referer header if it is told to do so and only |
|
136 | + // add the header if we are not redirecting from https to http. |
|
137 | + if ($options['allow_redirects']['referer'] && $modify['uri']->getScheme() === $request->getUri()->getScheme()) { |
|
138 | + $uri = $request->getUri()->withUserInfo(''); |
|
139 | + $modify['set_headers']['Referer'] = (string) $uri; |
|
140 | + } else { |
|
141 | + $modify['remove_headers'][] = 'Referer'; |
|
142 | + } |
|
143 | + // Remove Authorization and Cookie headers if URI is cross-origin. |
|
144 | + if (Psr7\UriComparator::isCrossOrigin($request->getUri(), $modify['uri'])) { |
|
145 | + $modify['remove_headers'][] = 'Authorization'; |
|
146 | + $modify['remove_headers'][] = 'Cookie'; |
|
147 | + } |
|
148 | + return Psr7\Utils::modifyRequest($request, $modify); |
|
149 | + } |
|
150 | + /** |
|
151 | + * Set the appropriate URL on the request based on the location header. |
|
152 | + */ |
|
153 | + private static function redirectUri(RequestInterface $request, ResponseInterface $response, array $protocols) : UriInterface |
|
154 | + { |
|
155 | + $location = Psr7\UriResolver::resolve($request->getUri(), new Psr7\Uri($response->getHeaderLine('Location'))); |
|
156 | + // Ensure that the redirect URI is allowed based on the protocols. |
|
157 | + if (!\in_array($location->getScheme(), $protocols)) { |
|
158 | + throw new BadResponseException(\sprintf('Redirect URI, %s, does not use one of the allowed redirect protocols: %s', $location, \implode(', ', $protocols)), $request, $response); |
|
159 | + } |
|
160 | + return $location; |
|
161 | + } |
|
162 | 162 | } |
@@ -52,7 +52,7 @@ discard block |
||
52 | 52 | if (empty($options['allow_redirects']['max'])) { |
53 | 53 | return $fn($request, $options); |
54 | 54 | } |
55 | - return $fn($request, $options)->then(function (ResponseInterface $response) use($request, $options) { |
|
55 | + return $fn($request, $options)->then(function(ResponseInterface $response) use($request, $options) { |
|
56 | 56 | return $this->checkRedirect($request, $options, $response); |
57 | 57 | }); |
58 | 58 | } |
@@ -61,7 +61,7 @@ discard block |
||
61 | 61 | */ |
62 | 62 | public function checkRedirect(RequestInterface $request, array $options, ResponseInterface $response) |
63 | 63 | { |
64 | - if (\strpos((string) $response->getStatusCode(), '3') !== 0 || !$response->hasHeader('Location')) { |
|
64 | + if (\strpos((string)$response->getStatusCode(), '3') !== 0 || !$response->hasHeader('Location')) { |
|
65 | 65 | return $response; |
66 | 66 | } |
67 | 67 | $this->guardMax($request, $response, $options); |
@@ -76,7 +76,7 @@ discard block |
||
76 | 76 | $promise = $this($nextRequest, $options); |
77 | 77 | // Add headers to be able to track history of redirects. |
78 | 78 | if (!empty($options['allow_redirects']['track_redirects'])) { |
79 | - return $this->withTracking($promise, (string) $nextRequest->getUri(), $response->getStatusCode()); |
|
79 | + return $this->withTracking($promise, (string)$nextRequest->getUri(), $response->getStatusCode()); |
|
80 | 80 | } |
81 | 81 | return $promise; |
82 | 82 | } |
@@ -85,14 +85,14 @@ discard block |
||
85 | 85 | */ |
86 | 86 | private function withTracking(PromiseInterface $promise, string $uri, int $statusCode) : PromiseInterface |
87 | 87 | { |
88 | - return $promise->then(static function (ResponseInterface $response) use($uri, $statusCode) { |
|
88 | + return $promise->then(static function(ResponseInterface $response) use($uri, $statusCode) { |
|
89 | 89 | // Note that we are pushing to the front of the list as this |
90 | 90 | // would be an earlier response than what is currently present |
91 | 91 | // in the history header. |
92 | 92 | $historyHeader = $response->getHeader(self::HISTORY_HEADER); |
93 | 93 | $statusHeader = $response->getHeader(self::STATUS_HISTORY_HEADER); |
94 | 94 | \array_unshift($historyHeader, $uri); |
95 | - \array_unshift($statusHeader, (string) $statusCode); |
|
95 | + \array_unshift($statusHeader, (string)$statusCode); |
|
96 | 96 | return $response->withHeader(self::HISTORY_HEADER, $historyHeader)->withHeader(self::STATUS_HISTORY_HEADER, $statusHeader); |
97 | 97 | }); |
98 | 98 | } |
@@ -136,7 +136,7 @@ discard block |
||
136 | 136 | // add the header if we are not redirecting from https to http. |
137 | 137 | if ($options['allow_redirects']['referer'] && $modify['uri']->getScheme() === $request->getUri()->getScheme()) { |
138 | 138 | $uri = $request->getUri()->withUserInfo(''); |
139 | - $modify['set_headers']['Referer'] = (string) $uri; |
|
139 | + $modify['set_headers']['Referer'] = (string)$uri; |
|
140 | 140 | } else { |
141 | 141 | $modify['remove_headers'][] = 'Referer'; |
142 | 142 | } |
@@ -16,8 +16,7 @@ |
||
16 | 16 | * |
17 | 17 | * @final |
18 | 18 | */ |
19 | -class RedirectMiddleware |
|
20 | -{ |
|
19 | +class RedirectMiddleware { |
|
21 | 20 | public const HISTORY_HEADER = 'X-Guzzle-Redirect-History'; |
22 | 21 | public const STATUS_HISTORY_HEADER = 'X-Guzzle-Redirect-Status-History'; |
23 | 22 | /** |