[ Index ] |
PHP Cross Reference of phpBB-3.3.14-deutsch |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Mon Nov 25 19:05:08 2024 | Cross-referenced by PHPXref 0.7.1 |