@@ -73,74 +73,75 @@ public function it_redirects_on_302(
73
73
$ finalPromise ->wait ()->shouldReturn ($ finalResponse );
74
74
}
75
75
76
- public function it_use_storage_on_301 (UriInterface $ uri , UriInterface $ uriRedirect , RequestInterface $ request , RequestInterface $ modifiedRequest )
77
- {
78
- $ this ->beAnInstanceOf (RedirectPluginStub::class);
79
- $ this ->beConstructedWith ($ uriRedirect , '/original ' , '301 ' );
80
-
81
- $ next = function () {
82
- throw new \Exception ('Must not be called ' );
83
- };
84
-
85
- $ request ->getUri ()->willReturn ($ uri );
86
- $ uri ->__toString ()->willReturn ('/original ' );
87
- $ request ->withUri ($ uriRedirect )->willReturn ($ modifiedRequest );
88
-
89
- $ modifiedRequest ->getUri ()->willReturn ($ uriRedirect );
90
- $ modifiedRequest ->getMethod ()->willReturn ('GET ' );
91
-
92
- $ uriRedirect ->__toString ()->willReturn ('/redirect ' );
93
-
94
- $ this ->handleRequest ($ request , $ next , PluginStub::first ());
95
- }
96
-
97
- public function it_stores_a_301 (
76
+ public function it_use_storage_on_301 (
98
77
UriInterface $ uri ,
99
78
UriInterface $ uriRedirect ,
100
79
RequestInterface $ request ,
101
- ResponseInterface $ responseRedirect ,
102
80
RequestInterface $ modifiedRequest ,
103
81
ResponseInterface $ finalResponse ,
104
- Promise $ promise
82
+ ResponseInterface $ redirectResponse
105
83
) {
106
- $ this ->beAnInstanceOf (RedirectPluginStub::class);
107
- $ this ->beConstructedWith ($ uriRedirect , '' , '301 ' );
108
-
109
84
$ request ->getUri ()->willReturn ($ uri );
110
- $ uri ->__toString ()->willReturn ('/301-url ' );
111
-
112
- $ responseRedirect ->getStatusCode ()->willReturn ('301 ' );
113
- $ responseRedirect ->hasHeader ('Location ' )->willReturn (true );
114
- $ responseRedirect ->getHeaderLine ('Location ' )->willReturn ('/redirect ' );
115
-
85
+ $ uri ->__toString ()->willReturn ('/original ' );
116
86
$ uri ->withPath ('/redirect ' )->willReturn ($ uriRedirect );
117
- $ uriRedirect ->withFragment ('' )->willReturn ($ uriRedirect );
118
87
$ uriRedirect ->withQuery ('' )->willReturn ($ uriRedirect );
119
-
88
+ $ uriRedirect -> withFragment ( '' )-> willReturn ( $ uriRedirect );
120
89
$ request ->withUri ($ uriRedirect )->willReturn ($ modifiedRequest );
121
90
122
91
$ modifiedRequest ->getUri ()->willReturn ($ uriRedirect );
123
92
$ modifiedRequest ->getMethod ()->willReturn ('GET ' );
124
93
125
94
$ uriRedirect ->__toString ()->willReturn ('/redirect ' );
126
95
127
- $ next = function (RequestInterface $ receivedRequest ) use ($ request , $ responseRedirect ) {
128
- if (Argument::is ($ request ->getWrappedObject ())->scoreArgument ($ receivedRequest )) {
129
- return new HttpFulfilledPromise ($ responseRedirect ->getWrappedObject ());
130
- }
131
- };
96
+ $ finalResponse ->getStatusCode ()->willReturn (200 );
132
97
133
- $ first = function (RequestInterface $ receivedRequest ) use ($ modifiedRequest , $ promise ) {
134
- if (Argument::is ($ modifiedRequest ->getWrappedObject ())->scoreArgument ($ receivedRequest )) {
135
- return $ promise ->getWrappedObject ();
98
+ $ redirectResponse ->getStatusCode ()->willReturn (301 );
99
+ $ redirectResponse ->hasHeader ('Location ' )->willReturn (true );
100
+ $ redirectResponse ->getHeaderLine ('Location ' )->willReturn ('/redirect ' );
101
+
102
+ $ nextCalled = false ;
103
+ $ next = function (RequestInterface $ request ) use (&$ nextCalled , $ finalResponse , $ redirectResponse ): Promise {
104
+ switch ($ request ->getUri ()) {
105
+ case '/original ' :
106
+ if ($ nextCalled ) {
107
+ throw new \Exception ('Must only be called once ' );
108
+ }
109
+ $ nextCalled = true ;
110
+
111
+ return new HttpFulfilledPromise ($ redirectResponse ->getWrappedObject ());
112
+ case '/redirect ' :
113
+
114
+ return new HttpFulfilledPromise ($ finalResponse ->getWrappedObject ());
115
+ default :
116
+ throw new \Exception ('Test setup error with request uri ' .$ request ->getUri ());
136
117
}
137
118
};
119
+ $ first = $ this ->buildFirst ($ modifiedRequest , $ next );
138
120
139
- $ promise ->getState ()->willReturn (Promise::FULFILLED );
140
- $ promise ->wait ()->shouldBeCalled ()->willReturn ($ finalResponse );
121
+ $ this ->handleRequest ($ request , $ next , $ first );
141
122
123
+ // rebuild first as this is expected to be called again
124
+ $ first = $ this ->buildFirst ($ modifiedRequest , $ next );
125
+ // next should not be called again
142
126
$ this ->handleRequest ($ request , $ next , $ first );
143
- $ this ->hasStorage ('/301-url ' )->shouldReturn (true );
127
+ }
128
+
129
+ private function buildFirst (RequestInterface $ modifiedRequest , callable $ next ): callable
130
+ {
131
+ $ redirectPlugin = $ this ;
132
+ $ firstCalled = false ;
133
+
134
+ return function (RequestInterface $ request ) use (&$ modifiedRequest , $ redirectPlugin , $ next , &$ firstCalled ) {
135
+ if ($ firstCalled ) {
136
+ throw new \Exception ('Only one restart expected ' );
137
+ }
138
+ $ firstCalled = true ;
139
+ if ($ modifiedRequest ->getWrappedObject () !== $ request ) {
140
+ //throw new \Exception('Redirection failed');
141
+ }
142
+
143
+ return $ redirectPlugin ->getWrappedObject ()->handleRequest ($ request , $ next , $ this );
144
+ };
144
145
}
145
146
146
147
public function it_replace_full_url (
@@ -359,35 +360,100 @@ public function it_clears_headers(
359
360
$ this ->handleRequest ($ request , $ next , $ first );
360
361
}
361
362
362
- public function it_throws_circular_redirection_exception (UriInterface $ uri , UriInterface $ uriRedirect , RequestInterface $ request , ResponseInterface $ responseRedirect , RequestInterface $ modifiedRequest )
363
- {
364
- $ first = function () {};
363
+ /**
364
+ * This is the "redirection does not redirect case.
365
+ */
366
+ public function it_throws_circular_redirection_exception_on_redirect_that_does_not_change_url (
367
+ UriInterface $ redirectUri ,
368
+ RequestInterface $ request ,
369
+ ResponseInterface $ redirectResponse
370
+ ) {
371
+ $ redirectResponse ->getStatusCode ()->willReturn (302 );
372
+ $ redirectResponse ->hasHeader ('Location ' )->willReturn (true );
373
+ $ redirectResponse ->getHeaderLine ('Location ' )->willReturn ('/redirect ' );
365
374
366
- $ this ->beAnInstanceOf (RedirectPluginStubCircular::class);
367
- $ this ->beConstructedWith (spl_object_hash ((object ) $ first ));
375
+ $ next = function () use ($ redirectResponse ): Promise {
376
+ return new HttpFulfilledPromise ($ redirectResponse ->getWrappedObject ());
377
+ };
368
378
369
- $ request ->getUri ()->willReturn ($ uri );
370
- $ uri ->__toString ()->willReturn ('/original ' );
379
+ $ first = function () {
380
+ throw new \Exception ('First should never be called ' );
381
+ };
371
382
372
- $ responseRedirect ->getStatusCode ()->willReturn ('302 ' );
373
- $ responseRedirect ->hasHeader ('Location ' )->willReturn (true );
374
- $ responseRedirect ->getHeaderLine ('Location ' )->willReturn ('/redirect ' );
383
+ $ request ->getUri ()->willReturn ($ redirectUri );
384
+ $ redirectUri ->__toString ()->willReturn ('/redirect ' );
375
385
376
- $ uri ->withPath ('/redirect ' )->willReturn ($ uriRedirect );
377
- $ uriRedirect ->withFragment ('' )->willReturn ($ uriRedirect );
378
- $ uriRedirect ->withQuery ('' )->willReturn ($ uriRedirect );
386
+ $ redirectUri ->withPath ('/redirect ' )->willReturn ($ redirectUri );
387
+ $ redirectUri ->withFragment ('' )->willReturn ($ redirectUri );
388
+ $ redirectUri ->withQuery ('' )->willReturn ($ redirectUri );
379
389
380
- $ request ->withUri ($ uriRedirect )->willReturn ($ modifiedRequest );
381
- $ modifiedRequest ->getUri ()->willReturn ($ uriRedirect );
382
- $ uriRedirect ->__toString ()->willReturn ('/redirect ' );
383
- $ modifiedRequest ->getMethod ()->willReturn ('GET ' );
390
+ $ request ->withUri ($ redirectUri )->willReturn ($ request );
391
+ $ redirectUri ->__toString ()->willReturn ('/redirect ' );
392
+ $ request ->getMethod ()->willReturn ('GET ' );
384
393
385
- $ next = function (RequestInterface $ receivedRequest ) use ($ request , $ responseRedirect ) {
386
- if (Argument::is ($ request ->getWrappedObject ())->scoreArgument ($ receivedRequest )) {
387
- return new HttpFulfilledPromise ($ responseRedirect ->getWrappedObject ());
394
+ $ promise = $ this ->handleRequest ($ request , $ next , $ first );
395
+ $ promise ->shouldReturnAnInstanceOf (HttpRejectedPromise::class);
396
+ $ promise ->shouldThrow (CircularRedirectionException::class)->duringWait ();
397
+ }
398
+
399
+ /**
400
+ * This is a redirection flipping back and forth between two paths.
401
+ *
402
+ * There could be a larger loop but the logic in the plugin stays the same with as many redirects as needed.
403
+ */
404
+ public function it_throws_circular_redirection_exception_on_alternating_redirect (
405
+ UriInterface $ uri ,
406
+ UriInterface $ redirectUri ,
407
+ RequestInterface $ request ,
408
+ ResponseInterface $ redirectResponse1 ,
409
+ ResponseInterface $ redirectResponse2 ,
410
+ RequestInterface $ modifiedRequest
411
+ ) {
412
+ $ redirectResponse1 ->getStatusCode ()->willReturn (302 );
413
+ $ redirectResponse1 ->hasHeader ('Location ' )->willReturn (true );
414
+ $ redirectResponse1 ->getHeaderLine ('Location ' )->willReturn ('/redirect ' );
415
+
416
+ $ redirectResponse2 ->getStatusCode ()->willReturn (302 );
417
+ $ redirectResponse2 ->hasHeader ('Location ' )->willReturn (true );
418
+ $ redirectResponse2 ->getHeaderLine ('Location ' )->willReturn ('/original ' );
419
+
420
+ $ next = function (RequestInterface $ currentRequest ) use ($ request , $ redirectResponse1 , $ redirectResponse2 ): Promise {
421
+ return ($ currentRequest === $ request ->getWrappedObject ())
422
+ ? new HttpFulfilledPromise ($ redirectResponse1 ->getWrappedObject ())
423
+ : new HttpFulfilledPromise ($ redirectResponse2 ->getWrappedObject ())
424
+ ;
425
+ };
426
+
427
+ $ redirectPlugin = $ this ;
428
+ $ firstCalled = false ;
429
+ $ first = function (RequestInterface $ request ) use (&$ firstCalled , $ redirectPlugin , $ next , &$ first ) {
430
+ if ($ firstCalled ) {
431
+ throw new \Exception ('only one redirect expected ' );
388
432
}
433
+ $ firstCalled = true ;
434
+
435
+ return $ redirectPlugin ->getWrappedObject ()->handleRequest ($ request , $ next , $ first );
389
436
};
390
437
438
+ $ request ->getUri ()->willReturn ($ uri );
439
+ $ uri ->__toString ()->willReturn ('/original ' );
440
+
441
+ $ modifiedRequest ->getUri ()->willReturn ($ redirectUri );
442
+ $ redirectUri ->__toString ()->willReturn ('/redirect ' );
443
+
444
+ $ uri ->withPath ('/redirect ' )->willReturn ($ redirectUri );
445
+ $ redirectUri ->withFragment ('' )->willReturn ($ redirectUri );
446
+ $ redirectUri ->withQuery ('' )->willReturn ($ redirectUri );
447
+
448
+ $ redirectUri ->withPath ('/original ' )->willReturn ($ uri );
449
+ $ uri ->withFragment ('' )->willReturn ($ uri );
450
+ $ uri ->withQuery ('' )->willReturn ($ uri );
451
+
452
+ $ request ->withUri ($ redirectUri )->willReturn ($ modifiedRequest );
453
+ $ request ->getMethod ()->willReturn ('GET ' );
454
+ $ modifiedRequest ->withUri ($ uri )->willReturn ($ request );
455
+ $ modifiedRequest ->getMethod ()->willReturn ('GET ' );
456
+
391
457
$ promise = $ this ->handleRequest ($ request , $ next , $ first );
392
458
$ promise ->shouldReturnAnInstanceOf (HttpRejectedPromise::class);
393
459
$ promise ->shouldThrow (CircularRedirectionException::class)->duringWait ();
@@ -440,33 +506,3 @@ public function it_redirects_http_to_https(
440
506
$ finalPromise ->wait ()->shouldReturn ($ finalResponse );
441
507
}
442
508
}
443
-
444
- class RedirectPluginStub extends RedirectPlugin
445
- {
446
- public function __construct (UriInterface $ uri , $ storedUrl , $ status , array $ config = [])
447
- {
448
- parent ::__construct ($ config );
449
-
450
- $ this ->redirectStorage [$ storedUrl ] = [
451
- 'uri ' => $ uri ,
452
- 'status ' => $ status ,
453
- ];
454
- }
455
-
456
- public function hasStorage ($ url )
457
- {
458
- return isset ($ this ->redirectStorage [$ url ]);
459
- }
460
- }
461
-
462
- class RedirectPluginStubCircular extends RedirectPlugin
463
- {
464
- public function __construct ($ chainHash )
465
- {
466
- $ this ->circularDetection = [
467
- $ chainHash => [
468
- '/redirect ' ,
469
- ],
470
- ];
471
- }
472
- }
0 commit comments