[ Index ]

PHP Cross Reference of phpBB-3.2.11-deutsch

title

Body

[close]

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

   1  <?php
   2  namespace GuzzleHttp\Subscriber;
   3  
   4  use GuzzleHttp\Event\CompleteEvent;
   5  use GuzzleHttp\Event\RequestEvents;
   6  use GuzzleHttp\Event\SubscriberInterface;
   7  use GuzzleHttp\Exception\BadResponseException;
   8  use GuzzleHttp\Exception\CouldNotRewindStreamException;
   9  use GuzzleHttp\Exception\TooManyRedirectsException;
  10  use GuzzleHttp\Message\RequestInterface;
  11  use GuzzleHttp\Message\ResponseInterface;
  12  use GuzzleHttp\Url;
  13  
  14  /**
  15   * Subscriber used to implement HTTP redirects.
  16   *
  17   * **Request options**
  18   *
  19   * - redirect: Associative array containing the 'max', 'strict', and 'referer'
  20   *   keys.
  21   *
  22   *   - max: Maximum number of redirects allowed per-request
  23   *   - strict: You can use strict redirects by setting this value to ``true``.
  24   *     Strict redirects adhere to strict RFC compliant redirection (e.g.,
  25   *     redirect POST with POST) vs doing what most clients do (e.g., redirect
  26   *     POST request with a GET request).
  27   *   - referer: Set to true to automatically add the "Referer" header when a
  28   *     redirect request is sent.
  29   *   - protocols: Array of allowed protocols. Defaults to 'http' and 'https'.
  30   *     When a redirect attempts to utilize a protocol that is not white listed,
  31   *     an exception is thrown.
  32   */
  33  class Redirect implements SubscriberInterface
  34  {
  35      public function getEvents()
  36      {
  37          return ['complete' => ['onComplete', RequestEvents::REDIRECT_RESPONSE]];
  38      }
  39  
  40      /**
  41       * Rewind the entity body of the request if needed
  42       *
  43       * @param RequestInterface $redirectRequest
  44       * @throws CouldNotRewindStreamException
  45       */
  46      public static function rewindEntityBody(RequestInterface $redirectRequest)
  47      {
  48          // Rewind the entity body of the request if needed
  49          if ($body = $redirectRequest->getBody()) {
  50              // Only rewind the body if some of it has been read already, and
  51              // throw an exception if the rewind fails
  52              if ($body->tell() && !$body->seek(0)) {
  53                  throw new CouldNotRewindStreamException(
  54                      'Unable to rewind the non-seekable request body after redirecting',
  55                      $redirectRequest
  56                  );
  57              }
  58          }
  59      }
  60  
  61      /**
  62       * Called when a request receives a redirect response
  63       *
  64       * @param CompleteEvent $event Event emitted
  65       * @throws TooManyRedirectsException
  66       */
  67      public function onComplete(CompleteEvent $event)
  68      {
  69          $response = $event->getResponse();
  70  
  71          if (substr($response->getStatusCode(), 0, 1) != '3'
  72              || !$response->hasHeader('Location')
  73          ) {
  74              return;
  75          }
  76  
  77          $request = $event->getRequest();
  78          $config = $request->getConfig();
  79  
  80          // Increment the redirect and initialize the redirect state.
  81          if ($redirectCount = $config['redirect_count']) {
  82              $config['redirect_count'] = ++$redirectCount;
  83          } else {
  84              $config['redirect_scheme'] = $request->getScheme();
  85              $config['redirect_count'] = $redirectCount = 1;
  86          }
  87  
  88          $max = $config->getPath('redirect/max') ?: 5;
  89  
  90          if ($redirectCount > $max) {
  91              throw new TooManyRedirectsException(
  92                  "Will not follow more than {$redirectCount} redirects",
  93                  $request
  94              );
  95          }
  96  
  97          $this->modifyRedirectRequest($request, $response);
  98          $event->retry();
  99      }
 100  
 101      private function modifyRedirectRequest(
 102          RequestInterface $request,
 103          ResponseInterface $response
 104      ) {
 105          $config = $request->getConfig();
 106          $protocols = $config->getPath('redirect/protocols') ?: ['http', 'https'];
 107  
 108          // Use a GET request if this is an entity enclosing request and we are
 109          // not forcing RFC compliance, but rather emulating what all browsers
 110          // would do.
 111          $statusCode = $response->getStatusCode();
 112          if ($statusCode == 303 ||
 113              ($statusCode <= 302 && $request->getBody() && !$config->getPath('redirect/strict'))
 114          ) {
 115              $request->setMethod('GET');
 116              $request->setBody(null);
 117          }
 118  
 119          $previousUrl = $request->getUrl();
 120          $this->setRedirectUrl($request, $response, $protocols);
 121          $this->rewindEntityBody($request);
 122  
 123          // Add the Referer header if it is told to do so and only
 124          // add the header if we are not redirecting from https to http.
 125          if ($config->getPath('redirect/referer')
 126              && ($request->getScheme() == 'https' || $request->getScheme() == $config['redirect_scheme'])
 127          ) {
 128              $url = Url::fromString($previousUrl);
 129              $url->setUsername(null);
 130              $url->setPassword(null);
 131              $request->setHeader('Referer', (string) $url);
 132          } else {
 133              $request->removeHeader('Referer');
 134          }
 135      }
 136  
 137      /**
 138       * Set the appropriate URL on the request based on the location header
 139       *
 140       * @param RequestInterface  $request
 141       * @param ResponseInterface $response
 142       * @param array             $protocols
 143       */
 144      private function setRedirectUrl(
 145          RequestInterface $request,
 146          ResponseInterface $response,
 147          array $protocols
 148      ) {
 149          $location = $response->getHeader('Location');
 150          $location = Url::fromString($location);
 151  
 152          // Combine location with the original URL if it is not absolute.
 153          if (!$location->isAbsolute()) {
 154              $originalUrl = Url::fromString($request->getUrl());
 155              // Remove query string parameters and just take what is present on
 156              // the redirect Location header
 157              $originalUrl->getQuery()->clear();
 158              $location = $originalUrl->combine($location);
 159          }
 160  
 161          // Ensure that the redirect URL is allowed based on the protocols.
 162          if (!in_array($location->getScheme(), $protocols)) {
 163              throw new BadResponseException(
 164                  sprintf(
 165                      'Redirect URL, %s, does not use one of the allowed redirect protocols: %s',
 166                      $location,
 167                      implode(', ', $protocols)
 168                  ),
 169                  $request,
 170                  $response
 171              );
 172          }
 173  
 174          $request->setUrl($location);
 175      }
 176  }


Generated: Wed Nov 11 20:33:01 2020 Cross-referenced by PHPXref 0.7.1