diff --git a/core/lib/Drupal/Core/Utility/UnroutedUrlAssembler.php b/core/lib/Drupal/Core/Utility/UnroutedUrlAssembler.php index dc1c237..5ff7c7a 100644 --- a/core/lib/Drupal/Core/Utility/UnroutedUrlAssembler.php +++ b/core/lib/Drupal/Core/Utility/UnroutedUrlAssembler.php @@ -130,6 +130,18 @@ protected function buildLocalUrl($uri, array $options = [], $collect_bubbleable_ // Add any subdirectory where Drupal is installed. $current_base_path = $request->getBasePath() . '/'; + // We cannot rely on Symfony's $request->getBasePath() method here, + // as it assumes that the SCRIPT_NAME points to a file at the project + // root. This fails for us if the SCRIPT_NAME is core/authorize.php + // or similar, as we end up with an extraneous '/core/'. + // DrupalKernel.initializeRequestGlobals() does the right thing + // when it initializes $base_path. We can re-use $base_path, or + // duplicate the operations that it does. Can we extend / modify + // the $request object so that getBasePath() works correctly, + // or maybe provide another version of this routine we can use + // where needed? + $current_base_path = preg_replace('#/core/$#', '/', $current_base_path); + if ($options['absolute']) { $current_base_url = $request->getSchemeAndHttpHost() . $current_base_path; if (isset($options['https'])) { @@ -156,8 +168,15 @@ protected function buildLocalUrl($uri, array $options = [], $collect_bubbleable_ $prefix = empty($uri) ? rtrim($options['prefix'], '/') : $options['prefix']; $uri = str_replace('%2F', '/', rawurlencode($prefix . $uri)); + + // We only want to include 'script' if it is index.php. + $script = $options['script']; + if ($script != 'index.php') { + $script = ""; + } + $query = $options['query'] ? ('?' . UrlHelper::buildQuery($options['query'])) : ''; - $url = $base . $options['script'] . $uri . $query . $options['fragment']; + $url = $base . $script . $uri . $query . $options['fragment']; return $collect_bubbleable_metadata ? $generated_url->setGeneratedUrl($url) : $url; } diff --git a/core/tests/Drupal/Tests/Core/Utility/UnroutedUrlAssemblerTest.php b/core/tests/Drupal/Tests/Core/Utility/UnroutedUrlAssemblerTest.php index e13b85b..792d095 100644 --- a/core/tests/Drupal/Tests/Core/Utility/UnroutedUrlAssemblerTest.php +++ b/core/tests/Drupal/Tests/Core/Utility/UnroutedUrlAssemblerTest.php @@ -111,8 +111,8 @@ public function providerTestAssembleWithExternalUrl() { * * @dataProvider providerTestAssembleWithLocalUri */ - public function testAssembleWithLocalUri($uri, array $options, $subdir, $expected) { - $this->setupRequestStack($subdir); + public function testAssembleWithLocalUri($uri, array $options, $subdir, $script_path, $expected) { + $this->setupRequestStack($subdir, $script_path); $this->assertEquals($expected, $this->unroutedUrlAssembler->assemble($uri, $options)); } @@ -122,18 +122,23 @@ public function testAssembleWithLocalUri($uri, array $options, $subdir, $expecte */ public function providerTestAssembleWithLocalUri() { return [ - ['base:example', [], FALSE, '/example'], - ['base:example', ['query' => ['foo' => 'bar']], FALSE, '/example?foo=bar'], - ['base:example', ['query' => ['foo' => '"bar"']], FALSE, '/example?foo=%22bar%22'], - ['base:example', ['query' => ['foo' => '"bar"', 'zoo' => 'baz']], FALSE, '/example?foo=%22bar%22&zoo=baz'], - ['base:example', ['fragment' => 'example', ], FALSE, '/example#example'], - ['base:example', [], TRUE, '/subdir/example'], - ['base:example', ['query' => ['foo' => 'bar']], TRUE, '/subdir/example?foo=bar'], - ['base:example', ['fragment' => 'example', ], TRUE, '/subdir/example#example'], - ['base:/drupal.org', [], FALSE, '/drupal.org'], + ['base:example', [], FALSE, '', '/example'], + ['base:example', ['query' => ['foo' => 'bar']], FALSE, '', '/example?foo=bar'], + ['base:example', ['query' => ['foo' => '"bar"']], FALSE, '', '/example?foo=%22bar%22'], + ['base:example', ['query' => ['foo' => '"bar"', 'zoo' => 'baz']], FALSE, '', '/example?foo=%22bar%22&zoo=baz'], + ['base:example', ['fragment' => 'example', ], FALSE, '', '/example#example'], + ['base:example', [], TRUE, '', '/subdir/example'], + ['base:example', ['query' => ['foo' => 'bar']], TRUE, '', '/subdir/example?foo=bar'], + ['base:example', ['fragment' => 'example', ], TRUE, '', '/subdir/example#example'], + ['base:/drupal.org', [], FALSE, '', '/drupal.org'], + ['base:', [], FALSE, 'core/authorize.php', '/'], + ['base:', [], TRUE, 'core/authorize.php', '/subdir/'], + ['base:core/authorize.php', [], FALSE, 'core/authorize.php', '/core/authorize.php'], + ['base:core/authorize.php', [], TRUE, 'core/authorize.php', '/subdir/core/authorize.php'], ]; } + /** * @covers ::assemble */ @@ -174,25 +179,67 @@ public function testAssembleWithEnabledProcessing() { * * @param string $subdir * The wanted subdir. + * @param string $script_path + * Path to the script, e.g. 'index.php' or 'core/authorize.php'. */ - protected function setupRequestStack($subdir) { - $server = []; - if ($subdir) { - // Setup a fake request which looks like a Drupal installed under the - // subdir "subdir" on the domain www.example.com. - // To reproduce the values install Drupal like that and use a debugger. - $server = [ - 'SCRIPT_NAME' => '/subdir/index.php', - 'SCRIPT_FILENAME' => $this->root . '/index.php', - 'SERVER_NAME' => 'http://www.example.com', - ]; - $request = Request::create('/subdir/'); - } - else { - $request = Request::create('/'); + protected function setupRequestStack($subdir, $script_path = "") { + $base_dir = $subdir ? '/subdir/' : '/'; + $request_uri = $script_path; + $default_script_path = $script_path; + if (empty($default_script_path)) { + $default_script_path = "index.php"; } + // Setup a fake request which looks like a Drupal installed under the + // subdir "subdir" on the domain www.example.com. + // To reproduce the values install Drupal like that and use a debugger. + // + // Common values, for any kind of request: + // + // DOCUMENT_ROOT = __ROOT__ + // SERVER_NAME = www.example.com + // SERVER_ADDR = 127.0.0.1 + // SERVER_PORT = 7777 + // HTTP_HOST = www.example.com:7777 + // HTTP_ORIGIN = www.example.com:7777 + // + // For a __ROOT__/index.php request: + // + // REQUEST_URI = / + // SCRIPT_NAME = /index.php + // PHP_SELF = /index.php + // SCRIPT_FILENAME = __ROOT__/index.php + // + // For a __ROOT__/subdir/index.php request: + // + // REQUEST_URI = /subdir/ + // SCRIPT_NAME = /subdir/index.php + // PHP_SELF = /subdir/index.php + // SCRIPT_FILENAME = __ROOT__/subdir/index.php + // + // For a __ROOT__/core/authorize.php request, the differences are: + // + // REQUEST_URI = /core/authorize.php + // SCRIPT_NAME = /core/authorize.php + // PHP_SELF = /core/authorize.php + // SCRIPT_FILENAME = __ROOT__/core/authorize.php + // + // For a __ROOT__/subdir/core/authorize.php request, the differences are: + // + // REQUEST_URI = /subdir/core/authorize.php + // SCRIPT_NAME = /subdir/core/authorize.php + // PHP_SELF = /subdir/core/authorize.php + // SCRIPT_FILENAME = __ROOT__/subdir/core/authorize.php + // + $server = [ + 'REQUEST_URI' => $base_dir . $script_path, + 'SCRIPT_NAME' => $base_dir . $default_script_path, + 'SCRIPT_FILENAME' => $this->root . $base_dir . $default_script_path, + 'SERVER_NAME' => 'www.example.com', + ]; + $request = Request::create($base_dir); // do we need to put script_path here sometimes? $request->server->add($server); $this->requestStack->push($request); } } +