GuzzleHttpRedirectMiddleware

Request redirect middleware.

Defined (1)

The class is defined in the following location(s).

/lib/Azure/GuzzleHttp/RedirectMiddleware.php  
  1. class RedirectMiddleware 
  2. const HISTORY_HEADER = 'X-Guzzle-Redirect-History'; 
  3.  
  4. public static $defaultSettings = [ 
  5. 'max' => 5,  
  6. 'protocols' => ['http', 'https'],  
  7. 'strict' => false,  
  8. 'referer' => false,  
  9. 'track_redirects' => false,  
  10. ]; 
  11.  
  12. /** @var callable */ 
  13. private $nextHandler; 
  14.  
  15. /** 
  16. * @param callable $nextHandler Next handler to invoke. 
  17. */ 
  18. public function __construct(callable $nextHandler) 
  19. $this->nextHandler = $nextHandler; 
  20.  
  21. /** 
  22. * @param RequestInterface $request 
  23. * @param array $options 
  24. * @return PromiseInterface 
  25. */ 
  26. public function __invoke(RequestInterface $request, array $options) 
  27. $fn = $this->nextHandler; 
  28.  
  29. if (empty($options['allow_redirects'])) { 
  30. return $fn($request, $options); 
  31.  
  32. if ($options['allow_redirects'] === true) { 
  33. $options['allow_redirects'] = self::$defaultSettings; 
  34. } elseif (!is_array($options['allow_redirects'])) { 
  35. throw new \InvalidArgumentException('allow_redirects must be true, false, or array'); 
  36. } else { 
  37. // Merge the default settings with the provided settings 
  38. $options['allow_redirects'] += self::$defaultSettings; 
  39.  
  40. if (empty($options['allow_redirects']['max'])) { 
  41. return $fn($request, $options); 
  42.  
  43. return $fn($request, $options) 
  44. ->then(function (ResponseInterface $response) use ($request, $options) { 
  45. return $this->checkRedirect($request, $options, $response); 
  46. }); 
  47.  
  48. /** 
  49. * @param RequestInterface $request 
  50. * @param array $options 
  51. * @param ResponseInterface|PromiseInterface $response 
  52. * @return ResponseInterface|PromiseInterface 
  53. */ 
  54. public function checkRedirect( 
  55. RequestInterface $request,  
  56. array $options,  
  57. ResponseInterface $response 
  58. ) { 
  59. if (substr($response->getStatusCode(), 0, 1) != '3' 
  60. || !$response->hasHeader('Location') 
  61. ) { 
  62. return $response; 
  63.  
  64. $this->guardMax($request, $options); 
  65. $nextRequest = $this->modifyRequest($request, $options, $response); 
  66.  
  67. if (isset($options['allow_redirects']['on_redirect'])) { 
  68. call_user_func( 
  69. $options['allow_redirects']['on_redirect'],  
  70. $request,  
  71. $response,  
  72. $nextRequest->getUri() 
  73. ); 
  74.  
  75. /** @var PromiseInterface|ResponseInterface $promise */ 
  76. $promise = $this($nextRequest, $options); 
  77.  
  78. // Add headers to be able to track history of redirects. 
  79. if (!empty($options['allow_redirects']['track_redirects'])) { 
  80. return $this->withTracking( 
  81. $promise,  
  82. (string) $nextRequest->getUri() 
  83. ); 
  84.  
  85. return $promise; 
  86.  
  87. private function withTracking(PromiseInterface $promise, $uri) 
  88. return $promise->then( 
  89. function (ResponseInterface $response) use ($uri) { 
  90. // Note that we are pushing to the front of the list as this 
  91. // would be an earlier response than what is currently present 
  92. // in the history header. 
  93. $header = $response->getHeader(self::HISTORY_HEADER); 
  94. array_unshift($header, $uri); 
  95. return $response->withHeader(self::HISTORY_HEADER, $header); 
  96. ); 
  97.  
  98. private function guardMax(RequestInterface $request, array &$options) 
  99. $current = isset($options['__redirect_count']) 
  100. ? $options['__redirect_count'] 
  101. : 0; 
  102. $options['__redirect_count'] = $current + 1; 
  103. $max = $options['allow_redirects']['max']; 
  104.  
  105. if ($options['__redirect_count'] > $max) { 
  106. throw new TooManyRedirectsException( 
  107. "Will not follow more than {$max} redirects",  
  108. $request 
  109. ); 
  110.  
  111. /** 
  112. * @param RequestInterface $request 
  113. * @param array $options 
  114. * @param ResponseInterface $response 
  115. * @return RequestInterface 
  116. */ 
  117. public function modifyRequest( 
  118. RequestInterface $request,  
  119. array $options,  
  120. ResponseInterface $response 
  121. ) { 
  122. // Request modifications to apply. 
  123. $modify = []; 
  124. $protocols = $options['allow_redirects']['protocols']; 
  125.  
  126. // Use a GET request if this is an entity enclosing request and we are 
  127. // not forcing RFC compliance, but rather emulating what all browsers 
  128. // would do. 
  129. $statusCode = $response->getStatusCode(); 
  130. if ($statusCode == 303 || 
  131. ($statusCode <= 302 && $request->getBody() && !$options['allow_redirects']['strict']) 
  132. ) { 
  133. $modify['method'] = 'GET'; 
  134. $modify['body'] = ''; 
  135.  
  136. $modify['uri'] = $this->redirectUri($request, $response, $protocols); 
  137. Psr7\rewind_body($request); 
  138.  
  139. // Add the Referer header if it is told to do so and only 
  140. // add the header if we are not redirecting from https to http. 
  141. if ($options['allow_redirects']['referer'] 
  142. && $modify['uri']->getScheme() === $request->getUri()->getScheme() 
  143. ) { 
  144. $uri = $request->getUri()->withUserInfo('', ''); 
  145. $modify['set_headers']['Referer'] = (string) $uri; 
  146. } else { 
  147. $modify['remove_headers'][] = 'Referer'; 
  148.  
  149. // Remove Authorization header if host is different. 
  150. if ($request->getUri()->getHost() !== $modify['uri']->getHost()) { 
  151. $modify['remove_headers'][] = 'Authorization'; 
  152.  
  153. return Psr7\modify_request($request, $modify); 
  154.  
  155. /** 
  156. * Set the appropriate URL on the request based on the location header 
  157. * @param RequestInterface $request 
  158. * @param ResponseInterface $response 
  159. * @param array $protocols 
  160. * @return UriInterface 
  161. */ 
  162. private function redirectUri( 
  163. RequestInterface $request,  
  164. ResponseInterface $response,  
  165. array $protocols 
  166. ) { 
  167. $location = Psr7\Uri::resolve( 
  168. $request->getUri(),  
  169. $response->getHeaderLine('Location') 
  170. ); 
  171.  
  172. // Ensure that the redirect URI is allowed based on the protocols. 
  173. if (!in_array($location->getScheme(), $protocols)) { 
  174. throw new BadResponseException( 
  175. sprintf( 
  176. 'Redirect URI, %s, does not use one of the allowed redirect protocols: %s',  
  177. $location,  
  178. implode(', ', $protocols) 
  179. ),  
  180. $request,  
  181. $response 
  182. ); 
  183.  
  184. return $location;