php-http /
plugins
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | namespace Http\Client\Plugin; |
||
| 4 | |||
| 5 | @trigger_error('The '.__NAMESPACE__.'\RedirectPlugin class is deprecated since version 1.1 and will be removed in 2.0. Use Http\Client\Common\Plugin\RedirectPlugin instead.', E_USER_DEPRECATED); |
||
|
0 ignored issues
–
show
|
|||
| 6 | |||
| 7 | use Http\Client\Exception\HttpException; |
||
| 8 | use Http\Client\Plugin\Exception\CircularRedirectionException; |
||
| 9 | use Http\Client\Plugin\Exception\MultipleRedirectionException; |
||
| 10 | use Psr\Http\Message\MessageInterface; |
||
| 11 | use Psr\Http\Message\RequestInterface; |
||
| 12 | use Psr\Http\Message\ResponseInterface; |
||
| 13 | use Psr\Http\Message\UriInterface; |
||
| 14 | use Symfony\Component\OptionsResolver\OptionsResolver; |
||
| 15 | |||
| 16 | /** |
||
| 17 | * Follow redirect responses from the server. |
||
| 18 | * |
||
| 19 | * @author Joel Wurtz <[email protected]> |
||
| 20 | * |
||
| 21 | * @deprecated since since version 1.1, and will be removed in 2.0. Use {@link \Http\Client\Common\Plugin\RedirectPlugin} instead. |
||
| 22 | */ |
||
| 23 | class RedirectPlugin implements Plugin |
||
|
0 ignored issues
–
show
The interface
Http\Client\Plugin\Plugin has been deprecated with message: since since version 1.1, and will be removed in 2.0. Use {@link \Http\Client\Common\Plugin} instead.
This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead. Loading history...
|
|||
| 24 | { |
||
| 25 | /** |
||
| 26 | * Rule on how to redirect, change method for the new request. |
||
| 27 | * |
||
| 28 | * @var array |
||
| 29 | */ |
||
| 30 | protected $redirectCodes = [ |
||
| 31 | 300 => [ |
||
| 32 | 'switch' => [ |
||
| 33 | 'unless' => ['GET', 'HEAD'], |
||
| 34 | 'to' => 'GET', |
||
| 35 | ], |
||
| 36 | 'multiple' => true, |
||
| 37 | 'permanent' => false, |
||
| 38 | ], |
||
| 39 | 301 => [ |
||
| 40 | 'switch' => [ |
||
| 41 | 'unless' => ['GET', 'HEAD'], |
||
| 42 | 'to' => 'GET', |
||
| 43 | ], |
||
| 44 | 'multiple' => false, |
||
| 45 | 'permanent' => true, |
||
| 46 | ], |
||
| 47 | 302 => [ |
||
| 48 | 'switch' => [ |
||
| 49 | 'unless' => ['GET', 'HEAD'], |
||
| 50 | 'to' => 'GET', |
||
| 51 | ], |
||
| 52 | 'multiple' => false, |
||
| 53 | 'permanent' => false, |
||
| 54 | ], |
||
| 55 | 303 => [ |
||
| 56 | 'switch' => [ |
||
| 57 | 'unless' => ['GET', 'HEAD'], |
||
| 58 | 'to' => 'GET', |
||
| 59 | ], |
||
| 60 | 'multiple' => false, |
||
| 61 | 'permanent' => false, |
||
| 62 | ], |
||
| 63 | 307 => [ |
||
| 64 | 'switch' => false, |
||
| 65 | 'multiple' => false, |
||
| 66 | 'permanent' => false, |
||
| 67 | ], |
||
| 68 | 308 => [ |
||
| 69 | 'switch' => false, |
||
| 70 | 'multiple' => false, |
||
| 71 | 'permanent' => true, |
||
| 72 | ], |
||
| 73 | ]; |
||
| 74 | |||
| 75 | /** |
||
| 76 | * Determine how header should be preserved from old request. |
||
| 77 | * |
||
| 78 | * @var bool|array |
||
| 79 | * |
||
| 80 | * true will keep all previous headers (default value) |
||
| 81 | * false will ditch all previous headers |
||
| 82 | * string[] will keep only headers with the specified names |
||
| 83 | */ |
||
| 84 | protected $preserveHeader; |
||
| 85 | |||
| 86 | /** |
||
| 87 | * Store all previous redirect from 301 / 308 status code. |
||
| 88 | * |
||
| 89 | * @var array |
||
| 90 | */ |
||
| 91 | protected $redirectStorage = []; |
||
| 92 | |||
| 93 | /** |
||
| 94 | * Whether the location header must be directly used for a multiple redirection status code (300). |
||
| 95 | * |
||
| 96 | * @var bool |
||
| 97 | */ |
||
| 98 | protected $useDefaultForMultiple; |
||
| 99 | |||
| 100 | /** |
||
| 101 | * @var array |
||
| 102 | */ |
||
| 103 | protected $circularDetection = []; |
||
| 104 | |||
| 105 | /** |
||
| 106 | * @param array $config { |
||
| 107 | * |
||
| 108 | * @var bool|string[] $preserve_header true keeps all headers, false remove all of them, an array is interpreted as a list of header names to keep |
||
| 109 | * @var bool $use_default_for_multiple Whether the location header must be directly used for a multiple redirection status code (300). |
||
| 110 | * } |
||
| 111 | */ |
||
| 112 | 12 | public function __construct(array $config = []) |
|
| 113 | { |
||
| 114 | 12 | $resolver = new OptionsResolver(); |
|
| 115 | 12 | $resolver->setDefaults([ |
|
| 116 | 12 | 'preserve_header' => true, |
|
| 117 | 12 | 'use_default_for_multiple' => true, |
|
| 118 | 12 | ]); |
|
| 119 | 12 | $resolver->setAllowedTypes('preserve_header', ['bool', 'array']); |
|
| 120 | 12 | $resolver->setAllowedTypes('use_default_for_multiple', 'bool'); |
|
| 121 | $resolver->setNormalizer('preserve_header', function (OptionsResolver $resolver, $value) { |
||
| 122 | 12 | if (is_bool($value) && false === $value) { |
|
| 123 | return []; |
||
| 124 | } |
||
| 125 | |||
| 126 | 12 | return $value; |
|
| 127 | 12 | }); |
|
| 128 | 12 | $options = $resolver->resolve($config); |
|
| 129 | |||
| 130 | 12 | $this->preserveHeader = $options['preserve_header']; |
|
| 131 | 12 | $this->useDefaultForMultiple = $options['use_default_for_multiple']; |
|
| 132 | 12 | } |
|
| 133 | |||
| 134 | /** |
||
| 135 | * {@inheritdoc} |
||
| 136 | */ |
||
| 137 | 11 | public function handleRequest(RequestInterface $request, callable $next, callable $first) |
|
| 138 | { |
||
| 139 | // Check in storage |
||
| 140 | 11 | if (array_key_exists($request->getRequestTarget(), $this->redirectStorage)) { |
|
| 141 | 1 | $uri = $this->redirectStorage[$request->getRequestTarget()]['uri']; |
|
| 142 | 1 | $statusCode = $this->redirectStorage[$request->getRequestTarget()]['status']; |
|
| 143 | 1 | $redirectRequest = $this->buildRedirectRequest($request, $uri, $statusCode); |
|
| 144 | |||
| 145 | 1 | return $first($redirectRequest); |
|
| 146 | } |
||
| 147 | |||
| 148 | 10 | return $next($request)->then(function (ResponseInterface $response) use ($request, $first) { |
|
| 149 | 10 | $statusCode = $response->getStatusCode(); |
|
| 150 | |||
| 151 | 10 | if (!array_key_exists($statusCode, $this->redirectCodes)) { |
|
| 152 | return $response; |
||
| 153 | } |
||
| 154 | |||
| 155 | 10 | $uri = $this->createUri($response, $request); |
|
| 156 | 6 | $redirectRequest = $this->buildRedirectRequest($request, $uri, $statusCode); |
|
| 157 | 6 | $chainIdentifier = spl_object_hash((object) $first); |
|
| 158 | |||
| 159 | 6 | if (!array_key_exists($chainIdentifier, $this->circularDetection)) { |
|
| 160 | 5 | $this->circularDetection[$chainIdentifier] = []; |
|
| 161 | 5 | } |
|
| 162 | |||
| 163 | 6 | $this->circularDetection[$chainIdentifier][] = $request->getRequestTarget(); |
|
| 164 | |||
| 165 | 6 | if (in_array($redirectRequest->getRequestTarget(), $this->circularDetection[$chainIdentifier])) { |
|
|
0 ignored issues
–
show
The method
getRequestTarget() does not seem to exist on object<Psr\Http\Message\MessageInterface>.
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. Loading history...
|
|||
| 166 | 1 | throw new CircularRedirectionException('Circular redirection detected', $request, $response); |
|
|
0 ignored issues
–
show
The class
Http\Client\Plugin\Excep...larRedirectionException has been deprecated with message: since since version 1.1, and will be removed in 2.0. Use {@link \Http\Client\Common\Exception\CircularRedirectionException} instead.
This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead. Loading history...
|
|||
| 167 | } |
||
| 168 | |||
| 169 | 5 | if ($this->redirectCodes[$statusCode]['permanent']) { |
|
| 170 | 1 | $this->redirectStorage[$request->getRequestTarget()] = [ |
|
| 171 | 1 | 'uri' => $uri, |
|
| 172 | 1 | 'status' => $statusCode, |
|
| 173 | ]; |
||
| 174 | 1 | } |
|
| 175 | |||
| 176 | // Call redirect request in synchrone |
||
| 177 | 5 | $redirectPromise = $first($redirectRequest); |
|
| 178 | |||
| 179 | 5 | return $redirectPromise->wait(); |
|
| 180 | 10 | }); |
|
| 181 | } |
||
| 182 | |||
| 183 | /** |
||
| 184 | * Builds the redirect request. |
||
| 185 | * |
||
| 186 | * @param RequestInterface $request Original request |
||
| 187 | * @param UriInterface $uri New uri |
||
| 188 | * @param int $statusCode Status code from the redirect response |
||
| 189 | * |
||
| 190 | * @return MessageInterface|RequestInterface |
||
| 191 | */ |
||
| 192 | 7 | protected function buildRedirectRequest(RequestInterface $request, UriInterface $uri, $statusCode) |
|
| 193 | { |
||
| 194 | 7 | $request = $request->withUri($uri); |
|
| 195 | |||
| 196 | 7 | if (false !== $this->redirectCodes[$statusCode]['switch'] && !in_array($request->getMethod(), $this->redirectCodes[$statusCode]['switch']['unless'])) { |
|
| 197 | 1 | $request = $request->withMethod($this->redirectCodes[$statusCode]['switch']['to']); |
|
| 198 | 1 | } |
|
| 199 | |||
| 200 | 7 | if (is_array($this->preserveHeader)) { |
|
| 201 | 1 | $headers = array_keys($request->getHeaders()); |
|
| 202 | |||
| 203 | 1 | foreach ($headers as $name) { |
|
| 204 | 1 | if (!in_array($name, $this->preserveHeader)) { |
|
| 205 | 1 | $request = $request->withoutHeader($name); |
|
| 206 | 1 | } |
|
| 207 | 1 | } |
|
| 208 | 1 | } |
|
| 209 | |||
| 210 | 7 | return $request; |
|
| 211 | } |
||
| 212 | |||
| 213 | /** |
||
| 214 | * Creates a new Uri from the old request and the location header. |
||
| 215 | * |
||
| 216 | * @param ResponseInterface $response The redirect response |
||
| 217 | * @param RequestInterface $request The original request |
||
| 218 | * |
||
| 219 | * @throws HttpException If location header is not usable (missing or incorrect) |
||
| 220 | * @throws MultipleRedirectionException If a 300 status code is received and default location cannot be resolved (doesn't use the location header or not present) |
||
| 221 | * |
||
| 222 | * @return UriInterface |
||
| 223 | */ |
||
| 224 | 10 | private function createUri(ResponseInterface $response, RequestInterface $request) |
|
| 225 | { |
||
| 226 | 10 | if ($this->redirectCodes[$response->getStatusCode()]['multiple'] && (!$this->useDefaultForMultiple || !$response->hasHeader('Location'))) { |
|
| 227 | 2 | throw new MultipleRedirectionException('Cannot choose a redirection', $request, $response); |
|
|
0 ignored issues
–
show
The class
Http\Client\Plugin\Excep...pleRedirectionException has been deprecated with message: since since version 1.1, and will be removed in 2.0. Use {@link \Http\Client\Common\Exception\MultipleRedirectionException} instead.
This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead. Loading history...
|
|||
| 228 | } |
||
| 229 | |||
| 230 | 8 | if (!$response->hasHeader('Location')) { |
|
| 231 | 1 | throw new HttpException('Redirect status code, but no location header present in the response', $request, $response); |
|
| 232 | } |
||
| 233 | |||
| 234 | 7 | $location = $response->getHeaderLine('Location'); |
|
| 235 | 7 | $parsedLocation = parse_url($location); |
|
| 236 | |||
| 237 | 7 | if (false === $parsedLocation) { |
|
| 238 | 1 | throw new HttpException(sprintf('Location %s could not be parsed', $location), $request, $response); |
|
| 239 | } |
||
| 240 | |||
| 241 | 6 | $uri = $request->getUri(); |
|
| 242 | |||
| 243 | 6 | if (array_key_exists('scheme', $parsedLocation)) { |
|
| 244 | 1 | $uri = $uri->withScheme($parsedLocation['scheme']); |
|
| 245 | 1 | } |
|
| 246 | |||
| 247 | 6 | if (array_key_exists('host', $parsedLocation)) { |
|
| 248 | 1 | $uri = $uri->withHost($parsedLocation['host']); |
|
| 249 | 1 | } |
|
| 250 | |||
| 251 | 6 | if (array_key_exists('port', $parsedLocation)) { |
|
| 252 | 1 | $uri = $uri->withPort($parsedLocation['port']); |
|
| 253 | 1 | } |
|
| 254 | |||
| 255 | 6 | if (array_key_exists('path', $parsedLocation)) { |
|
| 256 | 6 | $uri = $uri->withPath($parsedLocation['path']); |
|
| 257 | 6 | } |
|
| 258 | |||
| 259 | 6 | if (array_key_exists('query', $parsedLocation)) { |
|
| 260 | 1 | $uri = $uri->withQuery($parsedLocation['query']); |
|
| 261 | 1 | } else { |
|
| 262 | 5 | $uri = $uri->withQuery(''); |
|
| 263 | } |
||
| 264 | |||
| 265 | 6 | if (array_key_exists('fragment', $parsedLocation)) { |
|
| 266 | 1 | $uri = $uri->withFragment($parsedLocation['fragment']); |
|
| 267 | 1 | } else { |
|
| 268 | 5 | $uri = $uri->withFragment(''); |
|
| 269 | } |
||
| 270 | |||
| 271 | 6 | return $uri; |
|
| 272 | } |
||
| 273 | } |
||
| 274 |
If you suppress an error, we recommend checking for the error condition explicitly: