20     const HISTORY_HEADER = 
'X-Guzzle-Redirect-History';
 
   22     const STATUS_HISTORY_HEADER = 
'X-Guzzle-Redirect-Status-History';
 
   24     public static $defaultSettings = [
 
   26         'protocols'       => [
'http', 
'https'],
 
   29         'track_redirects' => 
false,
 
   38     public function __construct(callable $nextHandler)
 
   40         $this->nextHandler = $nextHandler;
 
   51         $fn = $this->nextHandler;
 
   53         if (empty($options[
'allow_redirects'])) {
 
   54             return $fn($request, $options);
 
   57         if ($options[
'allow_redirects'] === 
true) {
 
   58             $options[
'allow_redirects'] = self::$defaultSettings;
 
   59         } elseif (!is_array($options[
'allow_redirects'])) {
 
   60             throw new \InvalidArgumentException(
'allow_redirects must be true, false, or array');
 
   63             $options[
'allow_redirects'] += self::$defaultSettings;
 
   66         if (empty($options[
'allow_redirects'][
'max'])) {
 
   67             return $fn($request, $options);
 
   70         return $fn($request, $options)
 
   71             ->then(
function (ResponseInterface $response) use ($request, $options) {
 
   72                 return $this->checkRedirect($request, $options, $response);
 
   83     public function checkRedirect(
 
   84         RequestInterface $request,
 
   88         if (substr($response->getStatusCode(), 0, 1) != 
'3' 
   89             || !$response->hasHeader(
'Location')
 
   94         $this->guardMax($request, $options);
 
   95         $nextRequest = $this->modifyRequest($request, $options, $response);
 
   97         if (isset($options[
'allow_redirects'][
'on_redirect'])) {
 
   99                 $options[
'allow_redirects'][
'on_redirect'],
 
  102                 $nextRequest->getUri()
 
  107         $promise = $this($nextRequest, $options);
 
  110         if (!empty($options[
'allow_redirects'][
'track_redirects'])) {
 
  111             return $this->withTracking(
 
  113                 (
string) $nextRequest->getUri(),
 
  114                 $response->getStatusCode()
 
  128         return $promise->
then(
 
  133                 $historyHeader = $response->getHeader(self::HISTORY_HEADER);
 
  134                 $statusHeader = $response->getHeader(self::STATUS_HISTORY_HEADER);
 
  135                 array_unshift($historyHeader, $uri);
 
  136                 array_unshift($statusHeader, $statusCode);
 
  137                 return $response->withHeader(self::HISTORY_HEADER, $historyHeader)
 
  138                                 ->withHeader(self::STATUS_HISTORY_HEADER, $statusHeader);
 
  150     private function guardMax(RequestInterface $request, array &$options)
 
  152         $current = isset($options[
'__redirect_count'])
 
  153             ? $options[
'__redirect_count']
 
  155         $options[
'__redirect_count'] = $current + 1;
 
  156         $max = $options[
'allow_redirects'][
'max'];
 
  158         if ($options[
'__redirect_count'] > $max) {
 
  159             throw new TooManyRedirectsException(
 
  160                 "Will not follow more than {$max} redirects",
 
  173     public function modifyRequest(
 
  174         RequestInterface $request,
 
  180         $protocols = $options[
'allow_redirects'][
'protocols'];
 
  185         $statusCode = $response->getStatusCode();
 
  186         if ($statusCode == 303 ||
 
  187             ($statusCode <= 302 && !$options[
'allow_redirects'][
'strict'])
 
  189             $modify[
'method'] = 
'GET';
 
  190             $modify[
'body'] = 
'';
 
  193         $uri = $this->redirectUri($request, $response, $protocols);
 
  194         if (isset($options[
'idn_conversion']) && ($options[
'idn_conversion'] !== 
false)) {
 
  195             $idnOptions = ($options[
'idn_conversion'] === 
true) ? IDNA_DEFAULT : $options[
'idn_conversion'];
 
  196             $uri = Utils::idnUriConvert($uri, $idnOptions);
 
  199         $modify[
'uri'] = $uri;
 
  200         Psr7\rewind_body($request);
 
  204         if ($options[
'allow_redirects'][
'referer']
 
  205             && $modify[
'uri']->getScheme() === $request->getUri()->getScheme()
 
  207             $uri = $request->getUri()->withUserInfo(
'');
 
  208             $modify[
'set_headers'][
'Referer'] = (string) $uri;
 
  210             $modify[
'remove_headers'][] = 
'Referer';
 
  214         if ($request->getUri()->getHost() !== $modify[
'uri']->getHost()) {
 
  215             $modify[
'remove_headers'][] = 
'Authorization';
 
  218         return Psr7\modify_request($request, $modify);
 
  230     private function redirectUri(
 
  235         $location = Psr7\UriResolver::resolve(
 
  237             new Psr7\
Uri($response->getHeaderLine(
'Location'))
 
  241         if (!in_array($location->getScheme(), $protocols)) {
 
  244                     'Redirect URI, %s, does not use one of the allowed redirect protocols: %s',
 
  246                     implode(
', ', $protocols)