From 98e9a03d1a1c2bdf7e8f79d4de62bebdc5efbf0b Mon Sep 17 00:00:00 2001 From: "J. King" Date: Thu, 7 May 2020 19:30:14 -0400 Subject: [PATCH] Fix null-authority URLs --- lib/Url.php | 63 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/lib/Url.php b/lib/Url.php index d7d92d0..feb78a8 100644 --- a/lib/Url.php +++ b/lib/Url.php @@ -94,33 +94,45 @@ PCRE; public function __construct(string $url, string $baseUrl = null) { $url = str_replace(["\t", "\n", "\r"], "", trim($url, self::WHITESPACE_CHARS)); + reprocess: if (preg_match(self::URI_PATTERN, $url, $match)) { [$url, $scheme, $authority, $path, $query, $fragment] = array_pad($match, 6, ""); - if (!$scheme && $baseUrl) { - $base = new static($baseUrl); - $this->setScheme($base->scheme); - } elseif ($scheme) { - $this->setScheme($scheme); - if ($authority && !in_array($authority[1] ?? "", ["/", "\\"])) { - // the URI is something like x:/example.com/ - if ($baseUrl && ($base = new static($baseUrl)) && $this->scheme === $base->scheme) { - // URI is a relative URL; add authority to path instead - $path = $authority.$path; - $authority = ""; - } elseif ($this->scheme === "file") { - $path = $authority.$path; - $authority = "//"; - } elseif ($this->specialScheme) { - // URI is an absolute URL with a typo; add a slash to the authority - $authority = "/$authority"; - } else { - // URI is a URN; add authority to path instead - $path = $authority.$path; - $authority = ""; - } + $this->setScheme($scheme); + if ($authority && !in_array($authority[1] ?? "", ["/", "\\"])) { + // the URI is something like x:/example.com/ + if ($baseUrl && ($base = new static($baseUrl)) && $this->scheme === $base->scheme && !$base->isUrn()) { + // URI is a relative URL; add authority to path instead + $path = $authority.$path; + $authority = ""; + } elseif ($this->scheme === "file") { + // URI is an absolute file: URL; add authority to path and set the authority to the default authority + $path = $authority.$path; + $authority = "//"; + } elseif ($this->specialScheme) { + // URI is an absolute URL with a typo; add a slash to the authority + $authority = "/$authority"; + } else { + // URI is a URN; add authority to path instead + $path = $authority.$path; + $authority = ""; + } + } elseif ($scheme && !$authority) { + // the URI is something like x:example.com/ + if ($baseUrl && ($base = new static($baseUrl)) && $this->scheme === $base->scheme && !$base->isUrn()) { + // URI is a relative URL; continue processing + } elseif ($this->scheme === "file") { + // URI is an absolute file: URL; add the authority delimiter and default authority to the URL and reprocess + $url = preg_replace("/:/", ":///", $url, 1); + goto reprocess; + } elseif ($this->specialScheme) { + // URI is an absolute URL; add the authority delimiter to the URL and reprocess + $url = preg_replace("/:/", "://", $url, 1); + goto reprocess; + } else { + // URI is a URN; continue processing } } - if (strlen($authority)) { + if ($authority) { $authority = substr($authority, 2); if (($cleft = strrpos($authority, "@")) !== false) { if (preg_match(self::USER_PATTERN, substr($authority, 0, $cleft), $match)) { @@ -136,6 +148,11 @@ PCRE; $this->setPort($match[2] ?? ""); } } + if (!$scheme && $baseUrl) { + // the effective URL scheme must be known to correctly process the path + $base = $base ?? new static($baseUrl); + $this->setScheme($base->scheme); + } $this->setPath($path); if ($query) { $this->setQuery(substr($query, 1));