Merge "Allow using a reverse proxy for local HTTP requests"

This commit is contained in:
jenkins-bot 2021-10-16 04:41:08 +00:00 committed by Gerrit Code Review
commit 93821348aa
3 changed files with 57 additions and 4 deletions

View file

@ -9675,6 +9675,8 @@ $wgHTTPProxy = '';
* Local virtual hosts.
*
* This lists domains that are configured as virtual hosts on the same machine.
* It is expected that each domain can be identified by its hostname alone,
* without any ports.
*
* This affects the following:
* - MWHttpRequest: If a request is to be made to a domain listed here, or any
@ -9687,12 +9689,16 @@ $wgHTTPProxy = '';
$wgLocalVirtualHosts = [];
/**
* Proxy to use to requests to domains in $wgLocalVirtualHosts
* Reverse proxy to use for requests to domains in $wgLocalVirtualHosts
*
* If set to false, no proxy will be used for local requests
* When used, any port in the request URL will be dropped. The behavior of
* redirects and cookies is dependent upon the reverse proxy actually in use,
* as MediaWiki doesn't implement any special handling for them.
*
* If set to false, no reverse proxy will be used for local requests.
*
* @var string|bool
* @since 1.37
* @since 1.38
*/
$wgLocalHTTPProxy = false;

View file

@ -239,12 +239,47 @@ abstract class MWHttpRequest implements LoggerAwareInterface {
// Otherwise, fallback to $wgLocalHTTPProxy for local URLs
// or $wgHTTPProxy for everything else
if ( self::isLocalURL( $this->url ) ) {
$this->proxy = (string)$wgLocalHTTPProxy;
if ( $wgLocalHTTPProxy !== false ) {
$this->setReverseProxy( $wgLocalHTTPProxy );
}
} else {
$this->proxy = (string)$wgHTTPProxy;
}
}
/**
* Enable use of a reverse proxy in which the hostname is
* passed as a "Host" header, and the request is sent to the
* proxy's host:port instead.
*
* Note that any custom port in the request URL will be lost
* and cookies and redirects may not work properly.
*
* @param string $proxy URL of proxy
*/
protected function setReverseProxy( string $proxy ) {
$parsedProxy = wfParseUrl( $proxy );
if ( $parsedProxy === false ) {
throw new Exception( "Invalid reverseProxy configured: $proxy" );
}
// Set the current host in the Host header
$this->setHeader( 'Host', $this->parsedUrl['host'] );
// Set current protocol in X-Forwarded-Proto
// TODO: consider supporting the standardized "Forwarded" header too
$this->setHeader( 'X-Forwarded-Proto', $this->parsedUrl['scheme'] );
// Replace scheme, host and port in the request
$this->parsedUrl['scheme'] = $parsedProxy['scheme'];
$this->parsedUrl['host'] = $parsedProxy['host'];
if ( isset( $parsedProxy['port'] ) ) {
$this->parsedUrl['port'] = $parsedProxy['port'];
} else {
unset( $this->parsedUrl['port'] );
}
$this->url = wfAssembleUrl( $this->parsedUrl );
// Mark that we're already using a proxy
$this->noProxy = true;
}
/**
* Check if the URL can be served by localhost
*

View file

@ -1,5 +1,7 @@
<?php
use Wikimedia\TestingAccessWrapper;
/**
* @covers MWHttpRequest
*/
@ -85,4 +87,14 @@ class MWHttpRequestTest extends PHPUnit\Framework\TestCase {
$this->assertSame( $expect, MWHttpRequest::isValidURI( $uri ), $message );
}
public function testSetReverseProxy() {
$req = TestingAccessWrapper::newFromObject(
MWHttpRequest::factory( 'https://example.org/path?query=string' )
);
$req->setReverseProxy( 'http://localhost:1234' );
$this->assertSame( $req->url, 'http://localhost:1234/path?query=string' );
$this->assertSame( $req->reqHeaders['Host'], 'example.org' );
$this->assertSame( $req->reqHeaders['X-Forwarded-Proto'], 'https' );
}
}