From c07ec8fee64215e12d079d11c4416a79d3b432ea Mon Sep 17 00:00:00 2001 From: epriestley Date: Tue, 3 Jan 2017 09:50:16 -0800 Subject: [PATCH] Preserve nonstandard ports during 404 redirects which add "/" to the ends of URIs Summary: Fixes T12058. When the user visits `/maniphest`, for example, we redirect to `/maniphest/`. Since this redirect is very low-level (at the Aphront level, below the Site level) we need to preserve the request Host rather than correct it to `PhabricatorEnv::getURI()` or similar -- the request may be hiting a different Site like a blog domain. Currently, we do not preserve the port. Instead, preserve the port if it is not a standard port for the protocol (80 for http, 443 for https). Test Plan: - Made a request with a missing slash and a normal port in my browser, got redirected normally. - Made a request with a missing slash and a nonstandard port, got redirected on the same port. ``` $ curl -H 'Host: local.phacility.com:123' -v http://local.phacility.com/diffusion * Trying 127.0.0.1... * Connected to local.phacility.com (127.0.0.1) port 80 (#0) > GET /diffusion HTTP/1.1 ... > < HTTP/1.1 302 Found ... < Location: http://local.phacility.com:123/diffusion/ ... ``` Reviewers: chad Reviewed By: chad Maniphest Tasks: T12058 Differential Revision: https://secure.phabricator.com/D17134 --- src/aphront/AphrontRequest.php | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/aphront/AphrontRequest.php b/src/aphront/AphrontRequest.php index ea0313e2a3..9d806a851d 100644 --- a/src/aphront/AphrontRequest.php +++ b/src/aphront/AphrontRequest.php @@ -548,7 +548,31 @@ final class AphrontRequest extends Phobject { public function getAbsoluteRequestURI() { $uri = $this->getRequestURI(); $uri->setDomain($this->getHost()); - $uri->setProtocol($this->isHTTPS() ? 'https' : 'http'); + + if ($this->isHTTPS()) { + $protocol = 'https'; + } else { + $protocol = 'http'; + } + + $uri->setProtocol($protocol); + + // If the request used a nonstandard port, preserve it while building the + // absolute URI. + + // First, get the default port for the request protocol. + $default_port = id(new PhutilURI($protocol.'://example.com/')) + ->getPortWithProtocolDefault(); + + // NOTE: See note in getHost() about malicious "Host" headers. This + // construction defuses some obscure potential attacks. + $port = id(new PhutilURI($protocol.'://'.$this->host)) + ->getPort(); + + if (($port !== null) && ($port !== $default_port)) { + $uri->setPort($port); + } + return $uri; }