Skip to content

Commit c754501

Browse files
authored
Added strict option for RedirectPlugin not to modify request method on statuses 300, 301, 302 (#208)
1 parent e37e46c commit c754501

File tree

3 files changed

+68
-8
lines changed

3 files changed

+68
-8
lines changed

CHANGELOG.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Change Log
22

3+
## 2.4.0 (unreleased)
4+
5+
### Added
6+
7+
- `strict` option to `RedirectPlugin` to allow preserving the request method on redirections with status 300, 301 and 302.
8+
39
## 2.3.0 - 2020-07-21
410

511
### Fixed
@@ -112,7 +118,7 @@
112118

113119
## 1.7.0 - 2017-11-30
114120

115-
### Added
121+
### Added
116122

117123
- Symfony 4 support
118124

@@ -132,12 +138,12 @@
132138

133139
### Changed
134140

135-
- The `RetryPlugin` does now wait between retries. To disable/change this feature you must write something like:
136-
141+
- The `RetryPlugin` does now wait between retries. To disable/change this feature you must write something like:
142+
137143
```php
138-
$plugin = new RetryPlugin(['delay' => function(RequestInterface $request, Exception $e, $retries) {
139-
return 0;
140-
});
144+
$plugin = new RetryPlugin(['delay' => function(RequestInterface $request, Exception $e, $retries) {
145+
return 0;
146+
});
141147
```
142148

143149
### Deprecated

spec/Plugin/RedirectPluginSpec.php

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,11 +286,56 @@ public function it_switch_method_for_302(
286286

287287
$request->withUri($uriRedirect)->willReturn($modifiedRequest);
288288
$modifiedRequest->getUri()->willReturn($uriRedirect);
289+
$uriRedirect->__toString()->willReturn('/redirect');
290+
$modifiedRequest->getMethod()->willReturn('POST');
291+
$modifiedRequest->withMethod('GET')->shouldBeCalled()->willReturn($modifiedRequest);
292+
293+
$next = function (RequestInterface $receivedRequest) use ($request, $responseRedirect) {
294+
if (Argument::is($request->getWrappedObject())->scoreArgument($receivedRequest)) {
295+
return new HttpFulfilledPromise($responseRedirect->getWrappedObject());
296+
}
297+
};
298+
299+
$first = function (RequestInterface $receivedRequest) use ($modifiedRequest, $promise) {
300+
if (Argument::is($modifiedRequest->getWrappedObject())->scoreArgument($receivedRequest)) {
301+
return $promise->getWrappedObject();
302+
}
303+
};
304+
305+
$promise->getState()->willReturn(Promise::FULFILLED);
306+
$promise->wait()->shouldBeCalled()->willReturn($finalResponse);
307+
308+
$this->handleRequest($request, $next, $first);
309+
}
310+
311+
public function it_does_not_switch_method_for_302_with_strict_option(
312+
UriInterface $uri,
313+
UriInterface $uriRedirect,
314+
RequestInterface $request,
315+
ResponseInterface $responseRedirect,
316+
RequestInterface $modifiedRequest,
317+
ResponseInterface $finalResponse,
318+
Promise $promise
319+
) {
320+
$this->beConstructedWith(['strict' => true]);
321+
322+
$request->getUri()->willReturn($uri);
323+
$uri->__toString()->willReturn('/original');
289324

325+
$responseRedirect->getStatusCode()->willReturn(302);
326+
$responseRedirect->hasHeader('Location')->willReturn(true);
327+
$responseRedirect->getHeaderLine('Location')->willReturn('/redirect');
328+
329+
$request->getUri()->willReturn($uri);
330+
$uri->withPath('/redirect')->willReturn($uriRedirect);
331+
$uriRedirect->withFragment('')->willReturn($uriRedirect);
332+
$uriRedirect->withQuery('')->willReturn($uriRedirect);
333+
334+
$request->withUri($uriRedirect)->willReturn($modifiedRequest);
290335
$modifiedRequest->getUri()->willReturn($uriRedirect);
291336
$uriRedirect->__toString()->willReturn('/redirect');
292337
$modifiedRequest->getMethod()->willReturn('POST');
293-
$modifiedRequest->withMethod('GET')->willReturn($modifiedRequest);
338+
$modifiedRequest->withMethod('GET')->shouldNotBeCalled();
294339

295340
$next = function (RequestInterface $receivedRequest) use ($request, $responseRedirect) {
296341
if (Argument::is($request->getWrappedObject())->scoreArgument($receivedRequest)) {

src/Plugin/RedirectPlugin.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ final class RedirectPlugin implements Plugin
105105
* @param array $config {
106106
*
107107
* @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
108-
* @var bool $use_default_for_multiple Whether the location header must be directly used for a multiple redirection status code (300).
108+
* @var bool $use_default_for_multiple Whether the location header must be directly used for a multiple redirection status code (300)
109+
* @var bool $strict When true, redirect codes 300, 301, 302 will not modify request method and body.
109110
* }
110111
*/
111112
public function __construct(array $config = [])
@@ -114,9 +115,11 @@ public function __construct(array $config = [])
114115
$resolver->setDefaults([
115116
'preserve_header' => true,
116117
'use_default_for_multiple' => true,
118+
'strict' => false,
117119
]);
118120
$resolver->setAllowedTypes('preserve_header', ['bool', 'array']);
119121
$resolver->setAllowedTypes('use_default_for_multiple', 'bool');
122+
$resolver->setAllowedTypes('strict', 'bool');
120123
$resolver->setNormalizer('preserve_header', function (OptionsResolver $resolver, $value) {
121124
if (is_bool($value) && false === $value) {
122125
return [];
@@ -128,6 +131,12 @@ public function __construct(array $config = [])
128131

129132
$this->preserveHeader = $options['preserve_header'];
130133
$this->useDefaultForMultiple = $options['use_default_for_multiple'];
134+
135+
if ($options['strict']) {
136+
$this->redirectCodes[300]['switch'] = false;
137+
$this->redirectCodes[301]['switch'] = false;
138+
$this->redirectCodes[302]['switch'] = false;
139+
}
131140
}
132141

133142
/**

0 commit comments

Comments
 (0)