1 <?php 2 3 namespace GuzzleHttp; 4 5 use GuzzleHttp\Cookie\CookieJarInterface; 6 use GuzzleHttp\Exception\RequestException; 7 use GuzzleHttp\Promise as P; 8 use GuzzleHttp\Promise\PromiseInterface; 9 use Psr\Http\Message\RequestInterface; 10 use Psr\Http\Message\ResponseInterface; 11 use Psr\Log\LoggerInterface; 12 13 /** 14 * Functions used to create and wrap handlers with handler middleware. 15 */ 16 final class Middleware 17 { 18 /** 19 * Middleware that adds cookies to requests. 20 * 21 * The options array must be set to a CookieJarInterface in order to use 22 * cookies. This is typically handled for you by a client. 23 * 24 * @return callable Returns a function that accepts the next handler. 25 */ 26 public static function cookies(): callable 27 { 28 return static function (callable $handler): callable { 29 return static function ($request, array $options) use ($handler) { 30 if (empty($options['cookies'])) { 31 return $handler($request, $options); 32 } elseif (!($options['cookies'] instanceof CookieJarInterface)) { 33 throw new \InvalidArgumentException('cookies must be an instance of GuzzleHttp\Cookie\CookieJarInterface'); 34 } 35 $cookieJar = $options['cookies']; 36 $request = $cookieJar->withCookieHeader($request); 37 return $handler($request, $options) 38 ->then( 39 static function (ResponseInterface $response) use ($cookieJar, $request): ResponseInterface { 40 $cookieJar->extractCookies($request, $response); 41 return $response; 42 } 43 ); 44 }; 45 }; 46 } 47 48 /** 49 * Middleware that throws exceptions for 4xx or 5xx responses when the 50 * "http_errors" request option is set to true. 51 * 52 * @param BodySummarizerInterface|null $bodySummarizer The body summarizer to use in exception messages. 53 * 54 * @return callable(callable): callable Returns a function that accepts the next handler. 55 */ 56 public static function httpErrors(BodySummarizerInterface $bodySummarizer = null): callable 57 { 58 return static function (callable $handler) use ($bodySummarizer): callable { 59 return static function ($request, array $options) use ($handler, $bodySummarizer) { 60 if (empty($options['http_errors'])) { 61 return $handler($request, $options); 62 } 63 return $handler($request, $options)->then( 64 static function (ResponseInterface $response) use ($request, $bodySummarizer) { 65 $code = $response->getStatusCode(); 66 if ($code < 400) { 67 return $response; 68 } 69 throw RequestException::create($request, $response, null, [], $bodySummarizer); 70 } 71 ); 72 }; 73 }; 74 } 75 76 /** 77 * Middleware that pushes history data to an ArrayAccess container. 78 * 79 * @param array|\ArrayAccess<int, array> $container Container to hold the history (by reference). 80 * 81 * @return callable(callable): callable Returns a function that accepts the next handler. 82 * 83 * @throws \InvalidArgumentException if container is not an array or ArrayAccess. 84 */ 85 public static function history(&$container): callable 86 { 87 if (!\is_array($container) && !$container instanceof \ArrayAccess) { 88 throw new \InvalidArgumentException('history container must be an array or object implementing ArrayAccess'); 89 } 90 91 return static function (callable $handler) use (&$container): callable { 92 return static function (RequestInterface $request, array $options) use ($handler, &$container) { 93 return $handler($request, $options)->then( 94 static function ($value) use ($request, &$container, $options) { 95 $container[] = [ 96 'request' => $request, 97 'response' => $value, 98 'error' => null, 99 'options' => $options 100 ]; 101 return $value; 102 }, 103 static function ($reason) use ($request, &$container, $options) { 104 $container[] = [ 105 'request' => $request, 106 'response' => null, 107 'error' => $reason, 108 'options' => $options 109 ]; 110 return P\Create::rejectionFor($reason); 111 } 112 ); 113 }; 114 }; 115 } 116 117 /** 118 * Middleware that invokes a callback before and after sending a request. 119 * 120 * The provided listener cannot modify or alter the response. It simply 121 * "taps" into the chain to be notified before returning the promise. The 122 * before listener accepts a request and options array, and the after 123 * listener accepts a request, options array, and response promise. 124 * 125 * @param callable $before Function to invoke before forwarding the request. 126 * @param callable $after Function invoked after forwarding. 127 * 128 * @return callable Returns a function that accepts the next handler. 129 */ 130 public static function tap(callable $before = null, callable $after = null): callable 131 { 132 return static function (callable $handler) use ($before, $after): callable { 133 return static function (RequestInterface $request, array $options) use ($handler, $before, $after) { 134 if ($before) { 135 $before($request, $options); 136 } 137 $response = $handler($request, $options); 138 if ($after) { 139 $after($request, $options, $response); 140 } 141 return $response; 142 }; 143 }; 144 } 145 146 /** 147 * Middleware that handles request redirects. 148 * 149 * @return callable Returns a function that accepts the next handler. 150 */ 151 public static function redirect(): callable 152 { 153 return static function (callable $handler): RedirectMiddleware { 154 return new RedirectMiddleware($handler); 155 }; 156 } 157 158 /** 159 * Middleware that retries requests based on the boolean result of 160 * invoking the provided "decider" function. 161 * 162 * If no delay function is provided, a simple implementation of exponential 163 * backoff will be utilized. 164 * 165 * @param callable $decider Function that accepts the number of retries, 166 * a request, [response], and [exception] and 167 * returns true if the request is to be retried. 168 * @param callable $delay Function that accepts the number of retries and 169 * returns the number of milliseconds to delay. 170 * 171 * @return callable Returns a function that accepts the next handler. 172 */ 173 public static function retry(callable $decider, callable $delay = null): callable 174 { 175 return static function (callable $handler) use ($decider, $delay): RetryMiddleware { 176 return new RetryMiddleware($decider, $handler, $delay); 177 }; 178 } 179 180 /** 181 * Middleware that logs requests, responses, and errors using a message 182 * formatter. 183 * 184 * @phpstan-param \Psr\Log\LogLevel::* $logLevel Level at which to log requests. 185 * 186 * @param LoggerInterface $logger Logs messages. 187 * @param MessageFormatterInterface|MessageFormatter $formatter Formatter used to create message strings. 188 * @param string $logLevel Level at which to log requests. 189 * 190 * @return callable Returns a function that accepts the next handler. 191 */ 192 public static function log(LoggerInterface $logger, $formatter, string $logLevel = 'info'): callable 193 { 194 // To be compatible with Guzzle 7.1.x we need to allow users to pass a MessageFormatter 195 if (!$formatter instanceof MessageFormatter && !$formatter instanceof MessageFormatterInterface) { 196 throw new \LogicException(sprintf('Argument 2 to %s::log() must be of type %s', self::class, MessageFormatterInterface::class)); 197 } 198 199 return static function (callable $handler) use ($logger, $formatter, $logLevel): callable { 200 return static function (RequestInterface $request, array $options = []) use ($handler, $logger, $formatter, $logLevel) { 201 return $handler($request, $options)->then( 202 static function ($response) use ($logger, $request, $formatter, $logLevel): ResponseInterface { 203 $message = $formatter->format($request, $response); 204 $logger->log($logLevel, $message); 205 return $response; 206 }, 207 static function ($reason) use ($logger, $request, $formatter): PromiseInterface { 208 $response = $reason instanceof RequestException ? $reason->getResponse() : null; 209 $message = $formatter->format($request, $response, P\Create::exceptionFor($reason)); 210 $logger->error($message); 211 return P\Create::rejectionFor($reason); 212 } 213 ); 214 }; 215 }; 216 } 217 218 /** 219 * This middleware adds a default content-type if possible, a default 220 * content-length or transfer-encoding header, and the expect header. 221 */ 222 public static function prepareBody(): callable 223 { 224 return static function (callable $handler): PrepareBodyMiddleware { 225 return new PrepareBodyMiddleware($handler); 226 }; 227 } 228 229 /** 230 * Middleware that applies a map function to the request before passing to 231 * the next handler. 232 * 233 * @param callable $fn Function that accepts a RequestInterface and returns 234 * a RequestInterface. 235 */ 236 public static function mapRequest(callable $fn): callable 237 { 238 return static function (callable $handler) use ($fn): callable { 239 return static function (RequestInterface $request, array $options) use ($handler, $fn) { 240 return $handler($fn($request), $options); 241 }; 242 }; 243 } 244 245 /** 246 * Middleware that applies a map function to the resolved promise's 247 * response. 248 * 249 * @param callable $fn Function that accepts a ResponseInterface and 250 * returns a ResponseInterface. 251 */ 252 public static function mapResponse(callable $fn): callable 253 { 254 return static function (callable $handler) use ($fn): callable { 255 return static function (RequestInterface $request, array $options) use ($handler, $fn) { 256 return $handler($request, $options)->then($fn); 257 }; 258 }; 259 } 260 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body