diff --git a/core/lib/Drupal/Core/EventSubscriber/RedirectResponseSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/RedirectResponseSubscriber.php index a92a5a8..4b802d2 100644 --- a/core/lib/Drupal/Core/EventSubscriber/RedirectResponseSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/RedirectResponseSubscriber.php @@ -68,7 +68,7 @@ public function checkRedirectUrl(FilterResponseEvent $event) { // be absolute (start with a '/'). For such a case, prepend the // scheme and host, because the 'Location' header must be absolute. if (strpos($destination, '/') === 0) { - $destination = $this->requestContext->getCompleteBaseUrl() . $destination; + $destination = $request->getSchemeAndHttpHost() . $destination; } else { // Legacy destination query parameters can be relative paths that diff --git a/core/tests/Drupal/Tests/Core/EventSubscriber/RedirectResponseSubscriberTest.php b/core/tests/Drupal/Tests/Core/EventSubscriber/RedirectResponseSubscriberTest.php index 3d5baf1..bbb78ad 100644 --- a/core/tests/Drupal/Tests/Core/EventSubscriber/RedirectResponseSubscriberTest.php +++ b/core/tests/Drupal/Tests/Core/EventSubscriber/RedirectResponseSubscriberTest.php @@ -53,7 +53,7 @@ public function testDestinationRedirect(Request $request, $expected) { ['example.com', ['query' => [], 'fragment' => '', 'absolute' => TRUE], 'http://example.com/drupal/example.com'], ['example:com', ['query' => [], 'fragment' => '', 'absolute' => TRUE], 'http://example.com/drupal/example:com'], ['javascript:alert(0)', ['query' => [], 'fragment' => '', 'absolute' => TRUE], 'http://example.com/drupal/javascript:alert(0)'], - ['/test', ['query' => [], 'fragment' => '', 'absolute' => TRUE], 'http://example.com/drupal/test'], + ['/test', ['query' => [], 'fragment' => '', 'absolute' => TRUE], 'http://example.com/test'], ]); } @@ -63,6 +63,7 @@ public function testDestinationRedirect(Request $request, $expected) { $request_context->expects($this->any()) ->method('getCompleteBaseUrl') ->willReturn('http://example.com/drupal'); + $request->headers->set('HOST', 'example.com'); $listener = new RedirectResponseSubscriber($url_generator, $request_context); $dispatcher->addListener(KernelEvents::RESPONSE, array($listener, 'checkRedirectUrl')); @@ -86,22 +87,49 @@ public function testDestinationRedirect(Request $request, $expected) { public static function providerTestDestinationRedirect() { return array( array(new Request(), FALSE), -// array(new Request(array('destination' => 'http://example.com')), FALSE), -// array(new Request(array('destination' => 'http://example.com/foobar')), FALSE), -// array(new Request(array('destination' => 'http://example.ca/drupal')), FALSE), -// array(new Request(array('destination' => 'test')), 'http://example.com/drupal/test'), -// array(new Request(array('destination' => '/test')), 'http://example.com/drupal/test'), - array(new Request(array('destination' => '/example.com')), 'http://example.com/drupal/example.com'), -// array(new Request(array('destination' => 'example:com')), 'http://example.com/drupal/example:com'), -// array(new Request(array('destination' => '//example:com')), FALSE), -// array(new Request(array('destination' => '//example:com/test')), FALSE), -// array(new Request(array('destination' => 'javascript:alert(0)')), 'http://example.com/drupal/javascript:alert(0)'), -// array(new Request(array('destination' => 'http://example.com/drupal/')), 'http://example.com/drupal/'), -// array(new Request(array('destination' => 'http://example.com/drupal/test')), 'http://example.com/drupal/test'), + array(new Request(array('destination' => 'http://example.com')), FALSE), + array(new Request(array('destination' => 'http://example.com/foobar')), FALSE), + array(new Request(array('destination' => 'http://example.ca/drupal')), FALSE), + array(new Request(array('destination' => 'test')), 'http://example.com/drupal/test'), + array(new Request(array('destination' => '/test')), 'http://example.com/test'), + array(new Request(array('destination' => '/example.com')), 'http://example.com/example.com'), + array(new Request(array('destination' => 'example:com')), 'http://example.com/drupal/example:com'), + array(new Request(array('destination' => 'javascript:alert(0)')), 'http://example.com/drupal/javascript:alert(0)'), + array(new Request(array('destination' => 'http://example.com/drupal/')), 'http://example.com/drupal/'), + array(new Request(array('destination' => 'http://example.com/drupal/test')), 'http://example.com/drupal/test'), ); } /** + * @expectedException \InvalidArgumentException + * + * @dataProvider providerTestDestinationRedirectWithInvalidUrl + */ + public function testDestinationRedirectWithInvalidUrl($request) { + $dispatcher = new EventDispatcher(); + $kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface'); + $response = new RedirectResponse('http://example.com/drupal'); + $url_generator = $this->getMock('Drupal\Core\Routing\UrlGeneratorInterface'); + + $request_context = $this->getMockBuilder('Drupal\Core\Routing\RequestContext') + ->disableOriginalConstructor() + ->getMock(); + + $listener = new RedirectResponseSubscriber($url_generator, $request_context); + $dispatcher->addListener(KernelEvents::RESPONSE, array($listener, 'checkRedirectUrl')); + $event = new FilterResponseEvent($kernel, $request, HttpKernelInterface::SUB_REQUEST, $response); + $dispatcher->dispatch(KernelEvents::RESPONSE, $event); + } + + public function providerTestDestinationRedirectWithInvalidUrl() { + $data = []; + $data[] = [new Request(array('destination' => '//example:com'))]; + $data[] = [new Request(array('destination' => '//example:com/test'))]; + + return $data; + } + + /** * Tests that $_GET only contain internal URLs. * * @covers ::sanitizeDestination