[ Index ]

PHP Cross Reference of phpBB-3.3.3-deutsch

title

Body

[close]

/vendor/guzzlehttp/guzzle/src/ -> RedirectMiddleware.php (source)

   1  <?php
   2  namespace GuzzleHttp;
   3  
   4  use GuzzleHttp\Exception\BadResponseException;
   5  use GuzzleHttp\Exception\TooManyRedirectsException;
   6  use GuzzleHttp\Promise\PromiseInterface;
   7  use GuzzleHttp\Psr7;
   8  use Psr\Http\Message\RequestInterface;
   9  use Psr\Http\Message\ResponseInterface;
  10  use Psr\Http\Message\UriInterface;
  11  
  12  /**
  13   * Request redirect middleware.
  14   *
  15   * Apply this middleware like other middleware using
  16   * {@see \GuzzleHttp\Middleware::redirect()}.
  17   */
  18  class RedirectMiddleware
  19  {
  20      const HISTORY_HEADER = 'X-Guzzle-Redirect-History';
  21  
  22      const STATUS_HISTORY_HEADER = 'X-Guzzle-Redirect-Status-History';
  23  
  24      public static $defaultSettings = [
  25          'max'             => 5,
  26          'protocols'       => ['http', 'https'],
  27          'strict'          => false,
  28          'referer'         => false,
  29          'track_redirects' => false,
  30      ];
  31  
  32      /** @var callable  */
  33      private $nextHandler;
  34  
  35      /**
  36       * @param callable $nextHandler Next handler to invoke.
  37       */
  38      public function __construct(callable $nextHandler)
  39      {
  40          $this->nextHandler = $nextHandler;
  41      }
  42  
  43      /**
  44       * @param RequestInterface $request
  45       * @param array            $options
  46       *
  47       * @return PromiseInterface
  48       */
  49      public function __invoke(RequestInterface $request, array $options)
  50      {
  51          $fn = $this->nextHandler;
  52  
  53          if (empty($options['allow_redirects'])) {
  54              return $fn($request, $options);
  55          }
  56  
  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');
  61          } else {
  62              // Merge the default settings with the provided settings
  63              $options['allow_redirects'] += self::$defaultSettings;
  64          }
  65  
  66          if (empty($options['allow_redirects']['max'])) {
  67              return $fn($request, $options);
  68          }
  69  
  70          return $fn($request, $options)
  71              ->then(function (ResponseInterface $response) use ($request, $options) {
  72                  return $this->checkRedirect($request, $options, $response);
  73              });
  74      }
  75  
  76      /**
  77       * @param RequestInterface  $request
  78       * @param array             $options
  79       * @param ResponseInterface $response
  80       *
  81       * @return ResponseInterface|PromiseInterface
  82       */
  83      public function checkRedirect(
  84          RequestInterface $request,
  85          array $options,
  86          ResponseInterface $response
  87      ) {
  88          if (substr($response->getStatusCode(), 0, 1) != '3'
  89              || !$response->hasHeader('Location')
  90          ) {
  91              return $response;
  92          }
  93  
  94          $this->guardMax($request, $options);
  95          $nextRequest = $this->modifyRequest($request, $options, $response);
  96  
  97          if (isset($options['allow_redirects']['on_redirect'])) {
  98              call_user_func(
  99                  $options['allow_redirects']['on_redirect'],
 100                  $request,
 101                  $response,
 102                  $nextRequest->getUri()
 103              );
 104          }
 105  
 106          /** @var PromiseInterface|ResponseInterface $promise */
 107          $promise = $this($nextRequest, $options);
 108  
 109          // Add headers to be able to track history of redirects.
 110          if (!empty($options['allow_redirects']['track_redirects'])) {
 111              return $this->withTracking(
 112                  $promise,
 113                  (string) $nextRequest->getUri(),
 114                  $response->getStatusCode()
 115              );
 116          }
 117  
 118          return $promise;
 119      }
 120  
 121      /**
 122       * Enable tracking on promise.
 123       *
 124       * @return PromiseInterface
 125       */
 126      private function withTracking(PromiseInterface $promise, $uri, $statusCode)
 127      {
 128          return $promise->then(
 129              function (ResponseInterface $response) use ($uri, $statusCode) {
 130                  // Note that we are pushing to the front of the list as this
 131                  // would be an earlier response than what is currently present
 132                  // in the history header.
 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);
 139              }
 140          );
 141      }
 142  
 143      /**
 144       * Check for too many redirects
 145       *
 146       * @return void
 147       *
 148       * @throws TooManyRedirectsException Too many redirects.
 149       */
 150      private function guardMax(RequestInterface $request, array &$options)
 151      {
 152          $current = isset($options['__redirect_count'])
 153              ? $options['__redirect_count']
 154              : 0;
 155          $options['__redirect_count'] = $current + 1;
 156          $max = $options['allow_redirects']['max'];
 157  
 158          if ($options['__redirect_count'] > $max) {
 159              throw new TooManyRedirectsException(
 160                  "Will not follow more than {$max} redirects",
 161                  $request
 162              );
 163          }
 164      }
 165  
 166      /**
 167       * @param RequestInterface  $request
 168       * @param array             $options
 169       * @param ResponseInterface $response
 170       *
 171       * @return RequestInterface
 172       */
 173      public function modifyRequest(
 174          RequestInterface $request,
 175          array $options,
 176          ResponseInterface $response
 177      ) {
 178          // Request modifications to apply.
 179          $modify = [];
 180          $protocols = $options['allow_redirects']['protocols'];
 181  
 182          // Use a GET request if this is an entity enclosing request and we are
 183          // not forcing RFC compliance, but rather emulating what all browsers
 184          // would do.
 185          $statusCode = $response->getStatusCode();
 186          if ($statusCode == 303 ||
 187              ($statusCode <= 302 && !$options['allow_redirects']['strict'])
 188          ) {
 189              $modify['method'] = 'GET';
 190              $modify['body'] = '';
 191          }
 192  
 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);
 197          }
 198  
 199          $modify['uri'] = $uri;
 200          Psr7\rewind_body($request);
 201  
 202          // Add the Referer header if it is told to do so and only
 203          // add the header if we are not redirecting from https to http.
 204          if ($options['allow_redirects']['referer']
 205              && $modify['uri']->getScheme() === $request->getUri()->getScheme()
 206          ) {
 207              $uri = $request->getUri()->withUserInfo('');
 208              $modify['set_headers']['Referer'] = (string) $uri;
 209          } else {
 210              $modify['remove_headers'][] = 'Referer';
 211          }
 212  
 213          // Remove Authorization header if host is different.
 214          if ($request->getUri()->getHost() !== $modify['uri']->getHost()) {
 215              $modify['remove_headers'][] = 'Authorization';
 216          }
 217  
 218          return Psr7\modify_request($request, $modify);
 219      }
 220  
 221      /**
 222       * Set the appropriate URL on the request based on the location header
 223       *
 224       * @param RequestInterface  $request
 225       * @param ResponseInterface $response
 226       * @param array             $protocols
 227       *
 228       * @return UriInterface
 229       */
 230      private function redirectUri(
 231          RequestInterface $request,
 232          ResponseInterface $response,
 233          array $protocols
 234      ) {
 235          $location = Psr7\UriResolver::resolve(
 236              $request->getUri(),
 237              new Psr7\Uri($response->getHeaderLine('Location'))
 238          );
 239  
 240          // Ensure that the redirect URI is allowed based on the protocols.
 241          if (!in_array($location->getScheme(), $protocols)) {
 242              throw new BadResponseException(
 243                  sprintf(
 244                      'Redirect URI, %s, does not use one of the allowed redirect protocols: %s',
 245                      $location,
 246                      implode(', ', $protocols)
 247                  ),
 248                  $request,
 249                  $response
 250              );
 251          }
 252  
 253          return $location;
 254      }
 255  }


Generated: Sun Feb 14 20:08:31 2021 Cross-referenced by PHPXref 0.7.1