diff --git a/core/lib/Drupal/Core/Routing/UrlGenerator.php b/core/lib/Drupal/Core/Routing/UrlGenerator.php index 518c02d..d68f7c5 100644 --- a/core/lib/Drupal/Core/Routing/UrlGenerator.php +++ b/core/lib/Drupal/Core/Routing/UrlGenerator.php @@ -43,6 +43,48 @@ class UrlGenerator extends ProviderBasedGenerator implements PathBasedGeneratorI protected $config; /** + * The base path to use for urls. + * + * @var string + */ + protected $basePath; + + /** + * The base url to use for urls. + * + * @var string + */ + protected $baseUrl; + + /** + * The base url to use for urls, using 'http' as the scheme. + * + * @var string + */ + protected $baseSecureUrl; + + /** + * The base url to use for urls, using 'https' as the scheme. + * + * @var string + */ + protected $baseInsecureUrl; + + /** + * The script path to use for urls. + * + * @var string + */ + protected $scriptPath; + + /** + * Whether or not the server properties needed for url generation have been set. + * + * @var bool + */ + protected $serverPropertiesInitialized = FALSE; + + /** * Constructs a new generator object. * * @param \Symfony\Cmf\Component\Routing\RouteProviderInterface $provider @@ -74,19 +116,34 @@ public function generate($name, $parameters = array(), $absolute = FALSE) { */ public function setRequest(Request $request) { $this->request = $request; + $this->basePath = $request->getBasePath() . '/'; + $base_path_with_script = $request->getBaseUrl(); + $this->baseUrl = $request->getSchemeAndHttpHost() . $base_path_with_script; + $this->baseSecureUrl = str_replace('http://', 'https://', $this->baseUrl); + $this->baseInsecureUrl = str_replace('https://', 'http://', $this->baseUrl); + $this->scriptPath = ''; + $script_name = $this->request->getScriptName(); + if (!empty($base_path_with_script) && strpos($base_path_with_script, $script_name) !== FALSE) { + $this->scriptPath = ltrim($script_name, '/') . '/'; + } + $this->serverPropertiesInitialized = TRUE; } /** * Implements \Drupal\Core\Routing\PathBasedGeneratorInterface::generateFromPath(). */ public function generateFromPath($path = NULL, $options = array()) { + + if (!$this->serverPropertiesInitialized) { + $this->setServerPropertiesWithoutRequest(); + } + // Merge in defaults. $options += array( 'fragment' => '', 'query' => array(), 'absolute' => FALSE, 'prefix' => '', - 'script' => $GLOBALS['script_path'], ); if (!isset($options['external'])) { @@ -131,32 +188,26 @@ public function generateFromPath($path = NULL, $options = array()) { $path = ltrim($this->processPath($path, $options), '/'); } - if (isset($this->request)) { - $base_url = $this->request->getSchemeAndHttpHost() . $this->request->getBaseUrl(); - $base_secure_url = str_replace('http://', 'https://', $base_url); - $base_insecure_url = str_replace('https://', 'http://', $base_url); - } - else { - // @todo Figure out how to deal with url() calls when there is no request. - global $base_url, $base_secure_url, $base_insecure_url; + if (!isset($options['script'])) { + $options['script'] = $this->scriptPath; } // The base_url might be rewritten from the language rewrite in domain mode. if (!isset($options['base_url'])) { if (isset($options['https']) && variable_get('https', FALSE)) { if ($options['https'] === TRUE) { - $options['base_url'] = $base_secure_url; + $options['base_url'] = $this->baseSecureUrl; $options['absolute'] = TRUE; } elseif ($options['https'] === FALSE) { - $options['base_url'] = $base_insecure_url; + $options['base_url'] = $this->baseInsecureUrl; $options['absolute'] = TRUE; } } else { - $options['base_url'] = $base_url; + $options['base_url'] = $this->baseUrl; } } - $base = $options['absolute'] ? $options['base_url'] . '/' : base_path(); + $base = $options['absolute'] ? $options['base_url'] . '/' : $this->basePath; $prefix = empty($path) ? rtrim($options['prefix'], '/') : $options['prefix']; $path = str_replace('%2F', '/', rawurlencode($prefix . $path)); @@ -237,4 +288,21 @@ protected function processPath($path, &$options = array()) { return $path; } + /** + * Sets various server-related properties using globals. + * + * @todo Remove this once we've eliminated all calls to the generateFromPath() + * method that happen without a request object having been set. + * + */ + protected function setServerPropertiesWithoutRequest() { + global $base_url, $base_path, $script_path; + $this->basePath = $base_path; + $this->baseUrl = $base_url; + $this->baseSecureUrl = str_replace('http://', 'https://', $base_url); + $this->baseInsecureUrl = str_replace('https://', 'http://', $base_url); + $this->scriptPath = $script_path; + $this->serverPropertiesInitialized = TRUE; + } + } diff --git a/core/modules/language/lib/Drupal/language/HttpKernel/PathProcessorLanguage.php b/core/modules/language/lib/Drupal/language/HttpKernel/PathProcessorLanguage.php index 0081856..32a2385 100644 --- a/core/modules/language/lib/Drupal/language/HttpKernel/PathProcessorLanguage.php +++ b/core/modules/language/lib/Drupal/language/HttpKernel/PathProcessorLanguage.php @@ -33,6 +33,35 @@ class PathProcessorLanguage implements InboundPathProcessorInterface, OutboundPa */ protected $languageManager; + + /** + * A request object. + * + * @var \Symfony\Component\HttpFoundation\Request + */ + protected $request; + + /** + * The url scheme to use for urls. + * + * @var string + */ + protected $urlScheme = 'http'; + + /** + * The host to use for urls. + * + * @var string + */ + protected $httpHost; + + /** + * The port to use for urls. + * + * @var string + */ + protected $port = 80; + public function __construct(ConfigFactory $config, LanguageManager $language_manager) { $this->config = $config; $this->languageManager = $language_manager; @@ -40,9 +69,22 @@ public function __construct(ConfigFactory $config, LanguageManager $language_man } /** + * Sets the request and request-related properties. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * The HttpRequest object representing the current request. + */ + public function setRequest(Request $request) { + $this->request = $request; + $this->urlScheme = $request->getScheme(); + $this->port = $request->getPort(); + } + + /** * Implements Drupal\Core\PathProcessor\InboundPathProcessorInterface::processInbound(). */ public function processInbound($path, Request $request) { + $this->setRequest($request); if (!empty($path)) { $args = explode('/', $path); $prefix = array_shift($args); @@ -66,6 +108,9 @@ public function processOutbound($path, &$options = array(), Request $request = N if (!$this->languageManager->isMultilingual()) { return $path; } + if ($request && $request !== $this->request) { + $this->setRequest($request); + } $languages = array_flip(array_keys($this->languages)); // Language can be passed as an option, or we go for current URL language. if (!isset($options['language'])) { @@ -88,13 +133,6 @@ public function processOutbound($path, &$options = array(), Request $request = N elseif ($url_source == 'domain') { $domains = $this->config->get('language.negotiation')->get('url.domains'); if (is_object($options['language']) && !empty($domains[$options['language']->langcode])) { - $is_https = FALSE; - $http_host = NULL; - if ($request !== NULL) { - $https = $request->server->get('HTTPS'); - $is_https = $https && strtolower($https) == 'on'; - $http_host = $request->server->get('HTTP_HOST'); - } // Save the original base URL. If it contains a port, we need to // retain it below. @@ -104,9 +142,8 @@ public function processOutbound($path, &$options = array(), Request $request = N } // Ask for an absolute URL with our modified base URL. - $url_scheme = ($is_https) ? 'https://' : 'http://'; $options['absolute'] = TRUE; - $options['base_url'] = $url_scheme . $domains[$options['language']->langcode]; + $options['base_url'] = $this->urlScheme . '://' . $domains[$options['language']->langcode]; // In case either the original base URL or the HTTP host contains a // port, retain it. @@ -114,9 +151,8 @@ public function processOutbound($path, &$options = array(), Request $request = N list($host, $port) = explode(':', $normalized_base_url); $options['base_url'] .= ':' . $port; } - elseif (strpos($http_host, ':') !== FALSE) { - list($host, $port) = explode(':', $http_host); - $options['base_url'] .= ':' . $port; + elseif ($this->port != 80) { + $options['base_url'] .= ':' . $this->port; } if (isset($options['https']) && variable_get('https', FALSE)) { diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageUrlRewritingTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageUrlRewritingTest.php index 7b3fa09..4eccd52 100644 --- a/core/modules/language/lib/Drupal/language/Tests/LanguageUrlRewritingTest.php +++ b/core/modules/language/lib/Drupal/language/Tests/LanguageUrlRewritingTest.php @@ -125,9 +125,9 @@ function testDomainNameNegotiationPort() { // URLs as well. $index_php = strpos(url('', array('absolute' => TRUE)), 'index.php') !== FALSE; - $http_host = $this->container->get('request')->server->get('HTTP_HOST'); + $http_host = $this->container->get('request')->getHost(); $generator = $this->container->get('router.generator'); - $request = Request::create('', 'GET', array(), array(), array(), array('HTTP_HOST' => $http_host . ':88')); + $request = Request::create('', 'GET', array(), array(), array(), array('SERVER_PORT' => '88')); $generator->setRequest($request); // Create an absolute French link. @@ -144,11 +144,10 @@ function testDomainNameNegotiationPort() { $url = url('', array( 'absolute' => TRUE, 'language' => $language, - 'base_url' => $GLOBALS['base_url'] . ':90', + 'base_url' => $request->getBaseUrl() . ':90', )); $expected = $index_php ? 'http://example.fr:90/index.php/' : 'http://example.fr:90/'; - $this->assertEqual($url, $expected, 'A given port is not overriden.'); }