X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2Fhttp%2FMWHttpRequest.php;h=e04402fa815cbd45f47ec3bed489bf3b5a15c5f6;hb=74426f3cf796b149f1ae445e41815bbe148640b2;hp=08883ae44fe0ffd2db679644ef8315b2f316f901;hpb=52546163af81a588f3104d447657f24d071aa53f;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/http/MWHttpRequest.php b/includes/http/MWHttpRequest.php index 08883ae44f..ac16032ca3 100644 --- a/includes/http/MWHttpRequest.php +++ b/includes/http/MWHttpRequest.php @@ -18,7 +18,6 @@ * @file */ -use MediaWiki\Logger\LoggerFactory; use Psr\Log\LoggerInterface; use Psr\Log\LoggerAwareInterface; use Psr\Log\NullLogger; @@ -30,11 +29,15 @@ use Psr\Log\NullLogger; * Renamed from HttpRequest to MWHttpRequest to avoid conflict with * PHP's HTTP extension. */ -class MWHttpRequest implements LoggerAwareInterface { +abstract class MWHttpRequest implements LoggerAwareInterface { const SUPPORTS_FILE_POSTS = false; - protected $content; + /** + * @var int|string + */ protected $timeout = 'default'; + + protected $content; protected $headersOnly = null; protected $postData = null; protected $proxy = null; @@ -46,9 +49,11 @@ class MWHttpRequest implements LoggerAwareInterface { protected $reqHeaders = []; protected $url; protected $parsedUrl; + /** @var callable */ protected $callback; protected $maxRedirects = 5; protected $followRedirects = false; + protected $connectTimeout; /** * @var CookieJar @@ -60,7 +65,8 @@ class MWHttpRequest implements LoggerAwareInterface { protected $respStatus = "200 Ok"; protected $respHeaders = []; - public $status; + /** @var StatusValue */ + protected $status; /** * @var Profiler @@ -83,8 +89,8 @@ class MWHttpRequest implements LoggerAwareInterface { * @param string $caller The method making this request, for profiling * @param Profiler $profiler An instance of the profiler for profiling, or null */ - protected function __construct( - $url, $options = [], $caller = __METHOD__, $profiler = null + public function __construct( + $url, array $options = [], $caller = __METHOD__, $profiler = null ) { global $wgHTTPTimeout, $wgHTTPConnectTimeout; @@ -98,9 +104,9 @@ class MWHttpRequest implements LoggerAwareInterface { } if ( !$this->parsedUrl || !Http::isValidURI( $this->url ) ) { - $this->status = Status::newFatal( 'http-invalid-url', $url ); + $this->status = StatusValue::newFatal( 'http-invalid-url', $url ); } else { - $this->status = Status::newGood( 100 ); // continue + $this->status = StatusValue::newGood( 100 ); // continue } if ( isset( $options['timeout'] ) && $options['timeout'] != 'default' ) { @@ -116,6 +122,15 @@ class MWHttpRequest implements LoggerAwareInterface { if ( isset( $options['userAgent'] ) ) { $this->setUserAgent( $options['userAgent'] ); } + if ( isset( $options['username'] ) && isset( $options['password'] ) ) { + $this->setHeader( + 'Authorization', + 'Basic ' . base64_encode( $options['username'] . ':' . $options['password'] ) + ); + } + if ( isset( $options['originalRequest'] ) ) { + $this->setOriginalRequest( $options['originalRequest'] ); + } $members = [ "postData", "proxy", "noProxy", "sslVerifyHost", "caInfo", "method", "followRedirects", "maxRedirects", "sslVerifyCert", "callback" ]; @@ -123,7 +138,7 @@ class MWHttpRequest implements LoggerAwareInterface { foreach ( $members as $o ) { if ( isset( $options[$o] ) ) { // ensure that MWHttpRequest::method is always - // uppercased. Bug 36137 + // uppercased. T38137 if ( $o == 'method' ) { $options[$o] = strtoupper( $options[$o] ); } @@ -158,44 +173,18 @@ class MWHttpRequest implements LoggerAwareInterface { /** * Generate a new request object + * Deprecated: @see HttpRequestFactory::create * @param string $url Url to use * @param array $options (optional) extra params to pass (see Http::request()) * @param string $caller The method making this request, for profiling - * @throws MWException - * @return CurlHttpRequest|PhpHttpRequest + * @throws DomainException + * @return MWHttpRequest * @see MWHttpRequest::__construct */ - public static function factory( $url, $options = null, $caller = __METHOD__ ) { - if ( !Http::$httpEngine ) { - Http::$httpEngine = function_exists( 'curl_init' ) ? 'curl' : 'php'; - } elseif ( Http::$httpEngine == 'curl' && !function_exists( 'curl_init' ) ) { - throw new MWException( __METHOD__ . ': curl (http://php.net/curl) is not installed, but' . - ' Http::$httpEngine is set to "curl"' ); - } - - if ( !is_array( $options ) ) { - $options = []; - } - - if ( !isset( $options['logger'] ) ) { - $options['logger'] = LoggerFactory::getInstance( 'http' ); - } - - switch ( Http::$httpEngine ) { - case 'curl': - return new CurlHttpRequest( $url, $options, $caller, Profiler::instance() ); - case 'php': - if ( !wfIniGetBool( 'allow_url_fopen' ) ) { - throw new MWException( __METHOD__ . ': allow_url_fopen ' . - 'needs to be enabled for pure PHP http requests to ' . - 'work. If possible, curl should be used instead. See ' . - 'http://php.net/curl.' - ); - } - return new PhpHttpRequest( $url, $options, $caller, Profiler::instance() ); - default: - throw new MWException( __METHOD__ . ': The setting of Http::$httpEngine is not valid.' ); - } + public static function factory( $url, array $options = [], $caller = __METHOD__ ) { + return \MediaWiki\MediaWikiServices::getInstance() + ->getHttpRequestFactory() + ->create( $url, $options, $caller ); } /** @@ -222,7 +211,7 @@ class MWHttpRequest implements LoggerAwareInterface { * * @return void */ - public function proxySetup() { + protected function proxySetup() { // If there is an explicit proxy set and proxies are not disabled, then use it if ( $this->proxy && !$this->noProxy ) { return; @@ -300,7 +289,7 @@ class MWHttpRequest implements LoggerAwareInterface { * Get an array of the headers * @return array */ - public function getHeaderList() { + protected function getHeaderList() { $list = []; if ( $this->cookieJar ) { @@ -333,12 +322,14 @@ class MWHttpRequest implements LoggerAwareInterface { * bytes are reported handled than were passed to you, the HTTP fetch * will be aborted. * - * @param callable $callback - * @throws MWException + * @param callable|null $callback + * @throws InvalidArgumentException */ public function setCallback( $callback ) { - if ( !is_callable( $callback ) ) { - throw new MWException( 'Invalid MwHttpRequest callback' ); + if ( is_null( $callback ) ) { + $callback = [ $this, 'read' ]; + } elseif ( !is_callable( $callback ) ) { + throw new InvalidArgumentException( __METHOD__ . ': invalid callback' ); } $this->callback = $callback; } @@ -350,6 +341,7 @@ class MWHttpRequest implements LoggerAwareInterface { * @param resource $fh * @param string $content * @return int + * @internal */ public function read( $fh, $content ) { $this->content .= $content; @@ -359,9 +351,14 @@ class MWHttpRequest implements LoggerAwareInterface { /** * Take care of whatever is necessary to perform the URI request. * - * @return Status + * @return StatusValue + * @note currently returns Status for B/C */ public function execute() { + throw new LogicException( 'children must override this' ); + } + + protected function prepare() { $this->content = ""; if ( strtoupper( $this->method ) == "HEAD" ) { @@ -371,7 +368,7 @@ class MWHttpRequest implements LoggerAwareInterface { $this->proxySetup(); // set up any proxy as needed if ( !$this->callback ) { - $this->setCallback( [ $this, 'read' ] ); + $this->setCallback( null ); } if ( !isset( $this->reqHeaders['User-Agent'] ) ) { @@ -494,6 +491,8 @@ class MWHttpRequest implements LoggerAwareInterface { /** * Tells the MWHttpRequest object to use this pre-loaded CookieJar. * + * To read response cookies from the jar, getCookieJar must be called first. + * * @param CookieJar $jar */ public function setCookieJar( $jar ) { @@ -519,14 +518,18 @@ class MWHttpRequest implements LoggerAwareInterface { * Set-Cookie headers. * @see Cookie::set * @param string $name - * @param mixed $value + * @param string $value * @param array $attr */ - public function setCookie( $name, $value = null, $attr = null ) { + public function setCookie( $name, $value, $attr = [] ) { if ( !$this->cookieJar ) { $this->cookieJar = new CookieJar; } + if ( $this->parsedUrl && !isset( $attr['domain'] ) ) { + $attr['domain'] = $this->parsedUrl['host']; + } + $this->cookieJar->setCookie( $name, $value, $attr ); } @@ -557,7 +560,7 @@ class MWHttpRequest implements LoggerAwareInterface { * * Note that the multiple Location: headers are an artifact of * CURL -- they shouldn't actually get returned this way. Rewrite - * this when bug 29232 is taken care of (high-level redirect + * this when T31232 is taken care of (high-level redirect * handling rewrite). * * @return string @@ -583,19 +586,17 @@ class MWHttpRequest implements LoggerAwareInterface { } } - if ( $foundRelativeURI ) { - if ( $domain ) { - return $domain . $locations[$countLocations - 1]; - } else { - $url = parse_url( $this->url ); - if ( isset( $url['host'] ) ) { - return $url['scheme'] . '://' . $url['host'] . - $locations[$countLocations - 1]; - } - } - } else { + if ( !$foundRelativeURI ) { return $locations[$countLocations - 1]; } + if ( $domain ) { + return $domain . $locations[$countLocations - 1]; + } + $url = parse_url( $this->url ); + if ( isset( $url['host'] ) ) { + return $url['scheme'] . '://' . $url['host'] . + $locations[$countLocations - 1]; + } } return $this->url; @@ -609,4 +610,34 @@ class MWHttpRequest implements LoggerAwareInterface { public function canFollowRedirects() { return true; } + + /** + * Set information about the original request. This can be useful for + * endpoints/API modules which act as a proxy for some service, and + * throttling etc. needs to happen in that service. + * Calling this will result in the X-Forwarded-For and X-Original-User-Agent + * headers being set. + * @param WebRequest|array $originalRequest When in array form, it's + * expected to have the keys 'ip' and 'userAgent'. + * @note IP/user agent is personally identifiable information, and should + * only be set when the privacy policy of the request target is + * compatible with that of the MediaWiki installation. + */ + public function setOriginalRequest( $originalRequest ) { + if ( $originalRequest instanceof WebRequest ) { + $originalRequest = [ + 'ip' => $originalRequest->getIP(), + 'userAgent' => $originalRequest->getHeader( 'User-Agent' ), + ]; + } elseif ( + !is_array( $originalRequest ) + || array_diff( [ 'ip', 'userAgent' ], array_keys( $originalRequest ) ) + ) { + throw new InvalidArgumentException( __METHOD__ . ': $originalRequest must be a ' + . "WebRequest or an array with 'ip' and 'userAgent' keys" ); + } + + $this->reqHeaders['X-Forwarded-For'] = $originalRequest['ip']; + $this->reqHeaders['X-Original-User-Agent'] = $originalRequest['userAgent']; + } }