[ Index ]

PHP Cross Reference of phpBB-3.3.14-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 authorization is handled by curl, unset it if URI is cross-origin.
  98          if (Psr7\UriComparator::isCrossOrigin($request->getUri(), $nextRequest->getUri()) && defined('\CURLOPT_HTTPAUTH')) {
  99              unset(
 100                  $options['curl'][\CURLOPT_HTTPAUTH],
 101                  $options['curl'][\CURLOPT_USERPWD]
 102              );
 103          }
 104  
 105          if (isset($options['allow_redirects']['on_redirect'])) {
 106              call_user_func(
 107                  $options['allow_redirects']['on_redirect'],
 108                  $request,
 109                  $response,
 110                  $nextRequest->getUri()
 111              );
 112          }
 113  
 114          /** @var PromiseInterface|ResponseInterface $promise */
 115          $promise = $this($nextRequest, $options);
 116  
 117          // Add headers to be able to track history of redirects.
 118          if (!empty($options['allow_redirects']['track_redirects'])) {
 119              return $this->withTracking(
 120                  $promise,
 121                  (string) $nextRequest->getUri(),
 122                  $response->getStatusCode()
 123              );
 124          }
 125  
 126          return $promise;
 127      }
 128  
 129      /**
 130       * Enable tracking on promise.
 131       *
 132       * @return PromiseInterface
 133       */
 134      private function withTracking(PromiseInterface $promise, $uri, $statusCode)
 135      {
 136          return $promise->then(
 137              function (ResponseInterface $response) use ($uri, $statusCode) {
 138                  // Note that we are pushing to the front of the list as this
 139                  // would be an earlier response than what is currently present
 140                  // in the history header.
 141                  $historyHeader = $response->getHeader(self::HISTORY_HEADER);
 142                  $statusHeader = $response->getHeader(self::STATUS_HISTORY_HEADER);
 143                  array_unshift($historyHeader, $uri);
 144                  array_unshift($statusHeader, $statusCode);
 145                  return $response->withHeader(self::HISTORY_HEADER, $historyHeader)
 146                                  ->withHeader(self::STATUS_HISTORY_HEADER, $statusHeader);
 147              }
 148          );
 149      }
 150  
 151      /**
 152       * Check for too many redirects.
 153       *
 154       * @return void
 155       *
 156       * @throws TooManyRedirectsException Too many redirects.
 157       */
 158      private function guardMax(RequestInterface $request, array &$options)
 159      {
 160          $current = isset($options['__redirect_count'])
 161              ? $options['__redirect_count']
 162              : 0;
 163          $options['__redirect_count'] = $current + 1;
 164          $max = $options['allow_redirects']['max'];
 165  
 166          if ($options['__redirect_count'] > $max) {
 167              throw new TooManyRedirectsException(
 168                  "Will not follow more than {$max} redirects",
 169                  $request
 170              );
 171          }
 172      }
 173  
 174      /**
 175       * @param RequestInterface  $request
 176       * @param array             $options
 177       * @param ResponseInterface $response
 178       *
 179       * @return RequestInterface
 180       */
 181      public function modifyRequest(
 182          RequestInterface $request,
 183          array $options,
 184          ResponseInterface $response
 185      ) {
 186          // Request modifications to apply.
 187          $modify = [];
 188          $protocols = $options['allow_redirects']['protocols'];
 189  
 190          // Use a GET request if this is an entity enclosing request and we are
 191          // not forcing RFC compliance, but rather emulating what all browsers
 192          // would do.
 193          $statusCode = $response->getStatusCode();
 194          if ($statusCode == 303 ||
 195              ($statusCode <= 302 && !$options['allow_redirects']['strict'])
 196          ) {
 197              $modify['method'] = 'GET';
 198              $modify['body'] = '';
 199          }
 200  
 201          $uri = self::redirectUri($request, $response, $protocols);
 202          if (isset($options['idn_conversion']) && ($options['idn_conversion'] !== false)) {
 203              $idnOptions = ($options['idn_conversion'] === true) ? IDNA_DEFAULT : $options['idn_conversion'];
 204              $uri = Utils::idnUriConvert($uri, $idnOptions);
 205          }
 206  
 207          $modify['uri'] = $uri;
 208          Psr7\rewind_body($request);
 209  
 210          // Add the Referer header if it is told to do so and only
 211          // add the header if we are not redirecting from https to http.
 212          if ($options['allow_redirects']['referer']
 213              && $modify['uri']->getScheme() === $request->getUri()->getScheme()
 214          ) {
 215              $uri = $request->getUri()->withUserInfo('');
 216              $modify['set_headers']['Referer'] = (string) $uri;
 217          } else {
 218              $modify['remove_headers'][] = 'Referer';
 219          }
 220  
 221          // Remove Authorization and Cookie headers if URI is cross-origin.
 222          if (Psr7\UriComparator::isCrossOrigin($request->getUri(), $modify['uri'])) {
 223              $modify['remove_headers'][] = 'Authorization';
 224              $modify['remove_headers'][] = 'Cookie';
 225          }
 226  
 227          return Psr7\modify_request($request, $modify);
 228      }
 229  
 230      /**
 231       * Set the appropriate URL on the request based on the location header.
 232       *
 233       * @param RequestInterface  $request
 234       * @param ResponseInterface $response
 235       * @param array             $protocols
 236       *
 237       * @return UriInterface
 238       */
 239      private static function redirectUri(
 240          RequestInterface $request,
 241          ResponseInterface $response,
 242          array $protocols
 243      ) {
 244          $location = Psr7\UriResolver::resolve(
 245              $request->getUri(),
 246              new Psr7\Uri($response->getHeaderLine('Location'))
 247          );
 248  
 249          // Ensure that the redirect URI is allowed based on the protocols.
 250          if (!in_array($location->getScheme(), $protocols)) {
 251              throw new BadResponseException(
 252                  sprintf(
 253                      'Redirect URI, %s, does not use one of the allowed redirect protocols: %s',
 254                      $location,
 255                      implode(', ', $protocols)
 256                  ),
 257                  $request,
 258                  $response
 259              );
 260          }
 261  
 262          return $location;
 263      }
 264  }


Generated: Mon Nov 25 19:05:08 2024 Cross-referenced by PHPXref 0.7.1