From 9018579681d345a0e63854e12ddc87a47bf171f3 Mon Sep 17 00:00:00 2001 From: Aryeh Gregor Date: Mon, 15 Apr 2019 16:23:02 +0300 Subject: [PATCH] Deprecate the Http class All methods got moved to HttpRequestFactory or MWHttpRequest or dropped. I made the return value of the new HttpRequestFactory::request/get/post methods null on error instead of false, so that when we drop PHP 7 support, we can use a "?string" return value. This could theoretically change behavior of code that was switched from the old Http methods, but probably won't. I kept the old behavior for the deprecated methods. I changed the default value of $wgHTTPProxy from false to ''. This way it should be usable directly without a trivial wrapper method. For the benefit of anyone who might have set it to false in LocalSettings.php, I also recommend casting to string just in case. Http::$httpEngine is deprecated. Eventually it will be removed along with the curl and PHP engines, leaving only the Guzlle engine. I also added deprecation of MWHttpRequest::factory, which occurred in 1.31, to the release notes for 1.34. Now hopefully we can hard-deprecate it in another couple of versions. Bug: T214390 Change-Id: I2a316a758d793857f248bd251b90f5e9a6440e3a --- RELEASE-NOTES-1.34 | 9 +- includes/DefaultSettings.php | 2 +- includes/Pingback.php | 3 +- includes/externalstore/ExternalStoreHttp.php | 5 +- includes/filerepo/ForeignAPIRepo.php | 5 +- includes/filerepo/file/File.php | 3 +- includes/filerepo/file/ForeignDBFile.php | 3 +- includes/http/CurlHttpRequest.php | 12 ++ includes/http/GuzzleHttpRequest.php | 2 +- includes/http/Http.php | 92 +++++--------- includes/http/HttpRequestFactory.php | 114 +++++++++++++++--- includes/http/MWHttpRequest.php | 32 ++++- includes/http/PhpHttpRequest.php | 11 ++ includes/import/ImportStreamSource.php | 2 +- .../ImportableUploadRevisionImporter.php | 4 +- includes/installer/Installer.php | 6 +- maintenance/benchmarks/bench_HTTP_HTTPS.php | 5 +- maintenance/findHooks.php | 4 +- maintenance/importSiteScripts.php | 8 +- maintenance/populateInterwiki.php | 2 +- .../includes/http/MWHttpRequestTestCase.php | 48 ++++---- .../includes/filebackend/FileBackendTest.php | 4 +- tests/phpunit/includes/http/HttpTest.php | 2 + 23 files changed, 256 insertions(+), 122 deletions(-) diff --git a/RELEASE-NOTES-1.34 b/RELEASE-NOTES-1.34 index 1050c4d582..76ee2efff1 100644 --- a/RELEASE-NOTES-1.34 +++ b/RELEASE-NOTES-1.34 @@ -116,7 +116,7 @@ because of Phabricator reports. * … === Deprecations in 1.34 === -* The MWNamespace class is deprecated. Use MediaWikiServices::getNamespaceInfo. +* The MWNamespace class is deprecated. Use NamespaceInfo. * ExtensionRegistry->load() is deprecated, as it breaks dependency checking. Instead, use ->queue(). * User::isBlocked() is deprecated since it does not tell you if the user is @@ -135,6 +135,13 @@ because of Phabricator reports. RevisionLookup::getPreviousRevision and RevisionLookup::getNextRevision. * The Title parameter to RevisionLookup::getPreviousRevision and RevisionLookup::getNextRevision is deprecated and should be omitted. +* MWHttpRequest::factory is deprecated. Use HttpRequestFactory. +* The Http class is deprecated. For the request, get, and post methods, use + HttpRequestFactory. For isValidURI, use MWHttpRequest::isValidURI. For + getProxy, use (string)$wgHTTPProxy. For createMultiClient, construct a + MultiHttpClient directly. +* Http::$httpEngine is deprecated and has no replacement. The default 'guzzle' + engine will eventually be made the only engine for HTTP requests. === Other changes in 1.34 === * … diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index 8a2828f9a4..4cafc8f23e 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -8399,7 +8399,7 @@ $wgAsyncHTTPTimeout = 25; /** * Proxy to use for CURL requests. */ -$wgHTTPProxy = false; +$wgHTTPProxy = ''; /** * Local virtual hosts. diff --git a/includes/Pingback.php b/includes/Pingback.php index 8d7c3b6e4d..f4e85adfdb 100644 --- a/includes/Pingback.php +++ b/includes/Pingback.php @@ -22,6 +22,7 @@ use Psr\Log\LoggerInterface; use MediaWiki\Logger\LoggerFactory; +use MediaWiki\MediaWikiServices; /** * Send information about this MediaWiki instance to MediaWiki.org. @@ -229,7 +230,7 @@ class Pingback { $json = FormatJson::encode( $data ); $queryString = rawurlencode( str_replace( ' ', '\u0020', $json ) ) . ';'; $url = 'https://www.mediawiki.org/beacon/event?' . $queryString; - return Http::post( $url ) !== false; + return MediaWikiServices::getInstance()->getHttpRequestFactory()->post( $url ) !== null; } /** diff --git a/includes/externalstore/ExternalStoreHttp.php b/includes/externalstore/ExternalStoreHttp.php index 879686f724..a723557786 100644 --- a/includes/externalstore/ExternalStoreHttp.php +++ b/includes/externalstore/ExternalStoreHttp.php @@ -20,6 +20,8 @@ * @file */ +use MediaWiki\MediaWikiServices; + /** * Example class for HTTP accessible external objects. * Only supports reading, not storing. @@ -28,7 +30,8 @@ */ class ExternalStoreHttp extends ExternalStoreMedium { public function fetchFromURL( $url ) { - return Http::get( $url, [], __METHOD__ ); + return MediaWikiServices::getInstance()->getHttpRequestFactory()-> + get( $url, [], __METHOD__ ); } public function store( $location, $data ) { diff --git a/includes/filerepo/ForeignAPIRepo.php b/includes/filerepo/ForeignAPIRepo.php index 346ec8ec15..2c6f29632f 100644 --- a/includes/filerepo/ForeignAPIRepo.php +++ b/includes/filerepo/ForeignAPIRepo.php @@ -502,8 +502,9 @@ class ForeignAPIRepo extends FileRepo { } /** - * Like a Http:get request, but with custom User-Agent. - * @see Http::get + * Like a HttpRequestFactory::get request, but with custom User-Agent. + * @see HttpRequestFactory::get + * @todo Can this use HttpRequestFactory::get() but just pass the 'userAgent' option? * @param string $url * @param string $timeout * @param array $options diff --git a/includes/filerepo/file/File.php b/includes/filerepo/file/File.php index 7d4f4dfe85..92be7d4ec9 100644 --- a/includes/filerepo/file/File.php +++ b/includes/filerepo/file/File.php @@ -2070,7 +2070,8 @@ abstract class File implements IDBAccessObject { $this->repo->descriptionCacheExpiry ?: $cache::TTL_UNCACHEABLE, function ( $oldValue, &$ttl, array &$setOpts ) use ( $renderUrl, $fname ) { wfDebug( "Fetching shared description from $renderUrl\n" ); - $res = Http::get( $renderUrl, [], $fname ); + $res = MediaWikiServices::getInstance()->getHttpRequestFactory()-> + get( $renderUrl, [], $fname ); if ( !$res ) { $ttl = WANObjectCache::TTL_UNCACHEABLE; } diff --git a/includes/filerepo/file/ForeignDBFile.php b/includes/filerepo/file/ForeignDBFile.php index 3438a6388b..e083a4e4e0 100644 --- a/includes/filerepo/file/ForeignDBFile.php +++ b/includes/filerepo/file/ForeignDBFile.php @@ -165,7 +165,8 @@ class ForeignDBFile extends LocalFile { $this->repo->descriptionCacheExpiry ?: $cache::TTL_UNCACHEABLE, function ( $oldValue, &$ttl, array &$setOpts ) use ( $renderUrl, $fname ) { wfDebug( "Fetching shared description from $renderUrl\n" ); - $res = Http::get( $renderUrl, [], $fname ); + $res = MediaWikiServices::getInstance()->getHttpRequestFactory()-> + get( $renderUrl, [], $fname ); if ( !$res ) { $ttl = WANObjectCache::TTL_UNCACHEABLE; } diff --git a/includes/http/CurlHttpRequest.php b/includes/http/CurlHttpRequest.php index 8ef9cc226b..5130e36fb5 100644 --- a/includes/http/CurlHttpRequest.php +++ b/includes/http/CurlHttpRequest.php @@ -27,6 +27,18 @@ class CurlHttpRequest extends MWHttpRequest { protected $curlOptions = []; protected $headerText = ""; + /** + * @throws RuntimeException + */ + public function __construct() { + if ( !function_exists( 'curl_init' ) ) { + throw new RuntimeException( + __METHOD__ . ': curl (https://www.php.net/curl) is not installed' ); + } + + parent::__construct( ...func_get_args() ); + } + /** * @param resource $fh * @param string $content diff --git a/includes/http/GuzzleHttpRequest.php b/includes/http/GuzzleHttpRequest.php index e6b289206a..3af7f56a5d 100644 --- a/includes/http/GuzzleHttpRequest.php +++ b/includes/http/GuzzleHttpRequest.php @@ -45,7 +45,7 @@ class GuzzleHttpRequest extends MWHttpRequest { /** * @param string $url Url to use. If protocol-relative, will be expanded to an http:// URL - * @param array $options (optional) extra params to pass (see Http::request()) + * @param array $options (optional) extra params to pass (see HttpRequestFactory::create()) * @param string $caller The method making this request, for profiling * @param Profiler|null $profiler An instance of the profiler for profiling, or null * @throws Exception diff --git a/includes/http/Http.php b/includes/http/Http.php index f0972dcf24..9596169b45 100644 --- a/includes/http/Http.php +++ b/includes/http/Http.php @@ -19,74 +19,40 @@ */ use MediaWiki\Logger\LoggerFactory; +use MediaWiki\MediaWikiServices; /** * Various HTTP related functions + * @deprecated since 1.34 * @ingroup HTTP */ class Http { - public static $httpEngine = false; + /** @deprecated since 1.34, just use the default engine */ + public static $httpEngine = null; /** * Perform an HTTP request * + * @deprecated since 1.34, use HttpRequestFactory::request() + * * @param string $method HTTP method. Usually GET/POST * @param string $url Full URL to act on. If protocol-relative, will be expanded to an http:// URL - * @param array $options Options to pass to MWHttpRequest object. - * Possible keys for the array: - * - timeout Timeout length in seconds - * - connectTimeout Timeout for connection, in seconds (curl only) - * - postData An array of key-value pairs or a url-encoded form data - * - proxy The proxy to use. - * Otherwise it will use $wgHTTPProxy (if set) - * Otherwise it will use the environment variable "http_proxy" (if set) - * - noProxy Don't use any proxy at all. Takes precedence over proxy value(s). - * - sslVerifyHost Verify hostname against certificate - * - sslVerifyCert Verify SSL certificate - * - caInfo Provide CA information - * - maxRedirects Maximum number of redirects to follow (defaults to 5) - * - followRedirects Whether to follow redirects (defaults to false). - * Note: this should only be used when the target URL is trusted, - * to avoid attacks on intranet services accessible by HTTP. - * - userAgent A user agent, if you want to override the default - * MediaWiki/$wgVersion - * - logger A \Psr\Logger\LoggerInterface instance for debug logging - * - username Username for HTTP Basic Authentication - * - password Password for HTTP Basic Authentication - * - originalRequest Information about the original request (as a WebRequest object or - * an associative array with 'ip' and 'userAgent'). + * @param array $options Options to pass to MWHttpRequest object. See HttpRequestFactory::create + * docs * @param string $caller The method making this request, for profiling * @return string|bool (bool)false on failure or a string on success */ public static function request( $method, $url, array $options = [], $caller = __METHOD__ ) { - $logger = LoggerFactory::getInstance( 'http' ); - $logger->debug( "$method: $url" ); - - $options['method'] = strtoupper( $method ); - - if ( !isset( $options['timeout'] ) ) { - $options['timeout'] = 'default'; - } - if ( !isset( $options['connectTimeout'] ) ) { - $options['connectTimeout'] = 'default'; - } - - $req = MWHttpRequest::factory( $url, $options, $caller ); - $status = $req->execute(); - - if ( $status->isOK() ) { - return $req->getContent(); - } else { - $errors = $status->getErrorsByType( 'error' ); - $logger->warning( Status::wrap( $status )->getWikiText( false, false, 'en' ), - [ 'error' => $errors, 'caller' => $caller, 'content' => $req->getContent() ] ); - return false; - } + $ret = MediaWikiServices::getInstance()->getHttpRequestFactory()->request( + $method, $url, $options, $caller ); + return is_string( $ret ) ? $ret : false; } /** * Simple wrapper for Http::request( 'GET' ) - * @see Http::request() + * + * @deprecated since 1.34, use HttpRequestFactory::get() + * * @since 1.25 Second parameter $timeout removed. Second parameter * is now $options which can be given a 'timeout' * @@ -111,7 +77,8 @@ class Http { /** * Simple wrapper for Http::request( 'POST' ) - * @see Http::request() + * + * @deprecated since 1.34, use HttpRequestFactory::post() * * @param string $url * @param array $options @@ -124,11 +91,12 @@ class Http { /** * A standard user-agent we can use for external requests. + * + * @deprecated since 1.34, use HttpRequestFactory::getUserAgent() * @return string */ public static function userAgent() { - global $wgVersion; - return "MediaWiki/$wgVersion"; + return MediaWikiServices::getInstance()->getHttpRequestFactory()->getUserAgent(); } /** @@ -143,37 +111,37 @@ class Http { * * @todo FIXME this is wildly inaccurate and fails to actually check most stuff * + * @deprecated since 1.34, use MWHttpRequest::isValidURI * @param string $uri URI to check for validity * @return bool */ public static function isValidURI( $uri ) { - return (bool)preg_match( - '/^https?:\/\/[^\/\s]\S*$/D', - $uri - ); + return MWHttpRequest::isValidURI( $uri ); } /** * Gets the relevant proxy from $wgHTTPProxy * - * @return mixed The proxy address or an empty string if not set. + * @deprecated since 1.34, use $wgHTTPProxy directly + * @return string The proxy address or an empty string if not set. */ public static function getProxy() { - global $wgHTTPProxy; + wfDeprecated( __METHOD__, '1.34' ); - if ( $wgHTTPProxy ) { - return $wgHTTPProxy; - } - - return ""; + global $wgHTTPProxy; + return (string)$wgHTTPProxy; } /** * Get a configured MultiHttpClient + * + * @deprecated since 1.34, construct it directly * @param array $options * @return MultiHttpClient */ public static function createMultiClient( array $options = [] ) { + wfDeprecated( __METHOD__, '1.34' ); + global $wgHTTPConnectTimeout, $wgHTTPTimeout, $wgHTTPProxy; return new MultiHttpClient( $options + [ diff --git a/includes/http/HttpRequestFactory.php b/includes/http/HttpRequestFactory.php index f15534816b..08520b765a 100644 --- a/includes/http/HttpRequestFactory.php +++ b/includes/http/HttpRequestFactory.php @@ -20,34 +20,52 @@ namespace MediaWiki\Http; use CurlHttpRequest; -use DomainException; +use GuzzleHttpRequest; use Http; use MediaWiki\Logger\LoggerFactory; use MWHttpRequest; use PhpHttpRequest; use Profiler; -use GuzzleHttpRequest; +use RuntimeException; +use Status; /** * Factory creating MWHttpRequest objects. */ class HttpRequestFactory { - /** * Generate a new MWHttpRequest object * @param string $url Url to use - * @param array $options (optional) extra params to pass (see Http::request()) + * @param array $options Possible keys for the array: + * - timeout Timeout length in seconds + * - connectTimeout Timeout for connection, in seconds (curl only) + * - postData An array of key-value pairs or a url-encoded form data + * - proxy The proxy to use. + * Otherwise it will use $wgHTTPProxy (if set) + * Otherwise it will use the environment variable "http_proxy" (if set) + * - noProxy Don't use any proxy at all. Takes precedence over proxy value(s). + * - sslVerifyHost Verify hostname against certificate + * - sslVerifyCert Verify SSL certificate + * - caInfo Provide CA information + * - maxRedirects Maximum number of redirects to follow (defaults to 5) + * - followRedirects Whether to follow redirects (defaults to false). + * Note: this should only be used when the target URL is trusted, + * to avoid attacks on intranet services accessible by HTTP. + * - userAgent A user agent, if you want to override the default + * MediaWiki/$wgVersion + * - logger A \Psr\Logger\LoggerInterface instance for debug logging + * - username Username for HTTP Basic Authentication + * - password Password for HTTP Basic Authentication + * - originalRequest Information about the original request (as a WebRequest object or + * an associative array with 'ip' and 'userAgent'). * @param string $caller The method making this request, for profiling - * @throws DomainException + * @throws RuntimeException * @return MWHttpRequest * @see MWHttpRequest::__construct */ public function create( $url, array $options = [], $caller = __METHOD__ ) { if ( !Http::$httpEngine ) { Http::$httpEngine = 'guzzle'; - } elseif ( Http::$httpEngine == 'curl' && !function_exists( 'curl_init' ) ) { - throw new DomainException( __METHOD__ . ': curl (https://www.php.net/curl) is not ' . - 'installed, but Http::$httpEngine is set to "curl"' ); } if ( !isset( $options['logger'] ) ) { @@ -60,16 +78,9 @@ class HttpRequestFactory { case 'curl': return new CurlHttpRequest( $url, $options, $caller, Profiler::instance() ); case 'php': - if ( !wfIniGetBool( 'allow_url_fopen' ) ) { - throw new DomainException( __METHOD__ . ': allow_url_fopen ' . - 'needs to be enabled for pure PHP http requests to ' . - 'work. If possible, curl should be used instead. See ' . - 'https://www.php.net/curl.' - ); - } return new PhpHttpRequest( $url, $options, $caller, Profiler::instance() ); default: - throw new DomainException( __METHOD__ . ': The setting of Http::$httpEngine is not valid.' ); + throw new RuntimeException( __METHOD__ . ': The requested engine is not valid.' ); } } @@ -82,4 +93,75 @@ class HttpRequestFactory { return function_exists( 'curl_init' ) || wfIniGetBool( 'allow_url_fopen' ); } + /** + * Perform an HTTP request + * + * @since 1.34 + * @param string $method HTTP method. Usually GET/POST + * @param string $url Full URL to act on. If protocol-relative, will be expanded to an http:// + * URL + * @param array $options See HttpRequestFactory::create + * @param string $caller The method making this request, for profiling + * @return string|null null on failure or a string on success + */ + public function request( $method, $url, array $options = [], $caller = __METHOD__ ) { + $logger = LoggerFactory::getInstance( 'http' ); + $logger->debug( "$method: $url" ); + + $options['method'] = strtoupper( $method ); + + if ( !isset( $options['timeout'] ) ) { + $options['timeout'] = 'default'; + } + if ( !isset( $options['connectTimeout'] ) ) { + $options['connectTimeout'] = 'default'; + } + + $req = $this->create( $url, $options, $caller ); + $status = $req->execute(); + + if ( $status->isOK() ) { + return $req->getContent(); + } else { + $errors = $status->getErrorsByType( 'error' ); + $logger->warning( Status::wrap( $status )->getWikiText( false, false, 'en' ), + [ 'error' => $errors, 'caller' => $caller, 'content' => $req->getContent() ] ); + return null; + } + } + + /** + * Simple wrapper for request( 'GET' ), parameters have same meaning as for request() + * + * @since 1.34 + * @param string $url + * @param array $options + * @param string $caller + * @return string|null + */ + public function get( $url, array $options = [], $caller = __METHOD__ ) { + $this->request( 'GET', $url, $options, $caller ); + } + + /** + * Simple wrapper for request( 'POST' ), parameters have same meaning as for request() + * + * @since 1.34 + * @param string $url + * @param array $options + * @param string $caller + * @return string|null + */ + public function post( $url, array $options = [], $caller = __METHOD__ ) { + $this->request( 'POST', $url, $options, $caller ); + } + + /** + * @return string + */ + public function getUserAgent() { + global $wgVersion; + + return "MediaWiki/$wgVersion"; + } } diff --git a/includes/http/MWHttpRequest.php b/includes/http/MWHttpRequest.php index b4ac9a750e..41ea1dce35 100644 --- a/includes/http/MWHttpRequest.php +++ b/includes/http/MWHttpRequest.php @@ -85,7 +85,7 @@ abstract class MWHttpRequest implements LoggerAwareInterface { /** * @param string $url Url to use. If protocol-relative, will be expanded to an http:// URL - * @param array $options (optional) extra params to pass (see Http::request()) + * @param array $options (optional) extra params to pass (see HttpRequestFactory::create()) * @param string $caller The method making this request, for profiling * @param Profiler|null $profiler An instance of the profiler for profiling, or null * @throws Exception @@ -172,9 +172,9 @@ abstract class MWHttpRequest implements LoggerAwareInterface { /** * Generate a new request object - * Deprecated: @see HttpRequestFactory::create + * @deprecated since 1.34, use HttpRequestFactory instead * @param string $url Url to use - * @param array|null $options (optional) extra params to pass (see Http::request()) + * @param array|null $options (optional) extra params to pass (see HttpRequestFactory::create()) * @param string $caller The method making this request, for profiling * @throws DomainException * @return MWHttpRequest @@ -224,7 +224,8 @@ abstract class MWHttpRequest implements LoggerAwareInterface { if ( self::isLocalURL( $this->url ) || $this->noProxy ) { $this->proxy = ''; } else { - $this->proxy = Http::getProxy(); + global $wgHTTPProxy; + $this->proxy = (string)$wgHTTPProxy; } } @@ -662,4 +663,27 @@ abstract class MWHttpRequest implements LoggerAwareInterface { $this->reqHeaders['X-Forwarded-For'] = $originalRequest['ip']; $this->reqHeaders['X-Original-User-Agent'] = $originalRequest['userAgent']; } + + /** + * Check that the given URI is a valid one. + * + * This hardcodes a small set of protocols only, because we want to + * deterministically reject protocols not supported by all HTTP-transport + * methods. + * + * "file://" specifically must not be allowed, for security reasons + * (see ). + * + * @todo FIXME this is wildly inaccurate and fails to actually check most stuff + * + * @since 1.34 + * @param string $uri URI to check for validity + * @return bool + */ + public static function isValidURI( $uri ) { + return (bool)preg_match( + '/^https?:\/\/[^\/\s]\S*$/D', + $uri + ); + } } diff --git a/includes/http/PhpHttpRequest.php b/includes/http/PhpHttpRequest.php index d2af8c8568..c987c62b1c 100644 --- a/includes/http/PhpHttpRequest.php +++ b/includes/http/PhpHttpRequest.php @@ -22,6 +22,17 @@ class PhpHttpRequest extends MWHttpRequest { private $fopenErrors = []; + public function __construct() { + if ( !wfIniGetBool( 'allow_url_fopen' ) ) { + throw new RuntimeException( __METHOD__ . ': allow_url_fopen needs to be enabled for ' . + 'pure PHP http requests to work. If possible, curl should be used instead. See ' . + 'https://www.php.net/curl.' + ); + } + + parent::__construct( ...func_get_args() ); + } + /** * @param string $url * @return string diff --git a/includes/import/ImportStreamSource.php b/includes/import/ImportStreamSource.php index ebac200a4a..e6936cb2e3 100644 --- a/includes/import/ImportStreamSource.php +++ b/includes/import/ImportStreamSource.php @@ -112,7 +112,7 @@ class ImportStreamSource implements ImportSource { # quicker and sorts out user-agent problems which might # otherwise prevent importing from large sites, such # as the Wikimedia cluster, etc. - $data = Http::request( + $data = MediaWikiServices::getInstance()->getHttpRequestFactory()->request( $method, $url, [ diff --git a/includes/import/ImportableUploadRevisionImporter.php b/includes/import/ImportableUploadRevisionImporter.php index 4b378c1ec4..f1ac42c013 100644 --- a/includes/import/ImportableUploadRevisionImporter.php +++ b/includes/import/ImportableUploadRevisionImporter.php @@ -1,5 +1,6 @@ getSrc(); - $data = Http::get( $src, [], __METHOD__ ); + $data = MediaWikiServices::getInstance()->getHttpRequestFactory()-> + get( $src, [], __METHOD__ ); if ( !$data ) { $this->logger->debug( "IMPORT: couldn't fetch source $src\n" ); fclose( $f ); diff --git a/includes/installer/Installer.php b/includes/installer/Installer.php index 9053f8d195..c2312883c5 100644 --- a/includes/installer/Installer.php +++ b/includes/installer/Installer.php @@ -1203,9 +1203,11 @@ abstract class Installer { } try { - $text = Http::get( $url . $file, [ 'timeout' => 3 ], __METHOD__ ); + $text = MediaWikiServices::getInstance()->getHttpRequestFactory()-> + get( $url . $file, [ 'timeout' => 3 ], __METHOD__ ); } catch ( Exception $e ) { - // Http::get throws with allow_url_fopen = false and no curl extension. + // HttpRequestFactory::get can throw with allow_url_fopen = false and no curl + // extension. $text = null; } unlink( $dir . $file ); diff --git a/maintenance/benchmarks/bench_HTTP_HTTPS.php b/maintenance/benchmarks/bench_HTTP_HTTPS.php index 5e1feb739b..b7d584ad2d 100644 --- a/maintenance/benchmarks/bench_HTTP_HTTPS.php +++ b/maintenance/benchmarks/bench_HTTP_HTTPS.php @@ -24,6 +24,8 @@ * @author Platonides */ +use MediaWiki\MediaWikiServices; + require_once __DIR__ . '/Benchmarker.php'; /** @@ -45,7 +47,8 @@ class BenchHttpHttps extends Benchmarker { } private function doRequest( $proto ) { - Http::get( "$proto://localhost/", [], __METHOD__ ); + MediaWikiServices::getInstance()->getHttpRequestFactory()-> + get( "$proto://localhost/", [], __METHOD__ ); } // bench function 1 diff --git a/maintenance/findHooks.php b/maintenance/findHooks.php index 900752fe4f..b57db8f18c 100644 --- a/maintenance/findHooks.php +++ b/maintenance/findHooks.php @@ -34,6 +34,8 @@ * @author Antoine Musso */ +use MediaWiki\MediaWikiServices; + require_once __DIR__ . '/Maintenance.php'; /** @@ -216,7 +218,7 @@ class FindHooks extends Maintenance { $retval = []; while ( true ) { - $json = Http::get( + $json = MediaWikiServices::getInstance()->getHttpRequestFactory()->get( wfAppendQuery( 'https://www.mediawiki.org/w/api.php', $params ), [], __METHOD__ diff --git a/maintenance/importSiteScripts.php b/maintenance/importSiteScripts.php index e60e776328..1d4b496e4c 100644 --- a/maintenance/importSiteScripts.php +++ b/maintenance/importSiteScripts.php @@ -21,6 +21,8 @@ * @ingroup Maintenance */ +use MediaWiki\MediaWikiServices; + require_once __DIR__ . '/Maintenance.php'; /** @@ -64,7 +66,8 @@ class ImportSiteScripts extends Maintenance { $url = wfAppendQuery( $baseUrl, [ 'action' => 'raw', 'title' => "MediaWiki:{$page}" ] ); - $text = Http::get( $url, [], __METHOD__ ); + $text = MediaWikiServices::getInstance()->getHttpRequestFactory()-> + get( $url, [], __METHOD__ ); $wikiPage = WikiPage::factory( $title ); $content = ContentHandler::makeContent( $text, $wikiPage->getTitle() ); @@ -86,7 +89,8 @@ class ImportSiteScripts extends Maintenance { while ( true ) { $url = wfAppendQuery( $baseUrl, $data ); - $strResult = Http::get( $url, [], __METHOD__ ); + $strResult = MediaWikiServices::getInstance()->getHttpRequestFactory()-> + get( $url, [], __METHOD__ ); $result = FormatJson::decode( $strResult, true ); $page = null; diff --git a/maintenance/populateInterwiki.php b/maintenance/populateInterwiki.php index acc66c5199..a654a1fc95 100644 --- a/maintenance/populateInterwiki.php +++ b/maintenance/populateInterwiki.php @@ -86,7 +86,7 @@ TEXT $url = rtrim( $this->source, '?' ) . '?' . $url; } - $json = Http::get( $url ); + $json = MediaWikiServices::getInstance()->getHttpRequestFactory()->get( $url ); $data = json_decode( $json, true ); if ( is_array( $data ) ) { diff --git a/tests/integration/includes/http/MWHttpRequestTestCase.php b/tests/integration/includes/http/MWHttpRequestTestCase.php index 603f4c26f2..f7a4cc479c 100644 --- a/tests/integration/includes/http/MWHttpRequestTestCase.php +++ b/tests/integration/includes/http/MWHttpRequestTestCase.php @@ -1,19 +1,25 @@ oldHttpEngine = Http::$httpEngine; Http::$httpEngine = static::$httpEngine; + $this->factory = MediaWikiServices::getInstance()->getHttpRequestFactory(); + try { - $request = MWHttpRequest::factory( 'null:' ); - } catch ( DomainException $e ) { + $request = $factory->create( 'null:' ); + } catch ( RuntimeException $e ) { $this->markTestSkipped( static::$httpEngine . ' engine not supported' ); } @@ -32,19 +38,19 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase { // -------------------- public function testIsRedirect() { - $request = MWHttpRequest::factory( 'http://httpbin.org/get' ); + $request = $this->factory->create( 'http://httpbin.org/get' ); $status = $request->execute(); $this->assertTrue( $status->isGood() ); $this->assertFalse( $request->isRedirect() ); - $request = MWHttpRequest::factory( 'http://httpbin.org/redirect/1' ); + $request = $this->factory->create( 'http://httpbin.org/redirect/1' ); $status = $request->execute(); $this->assertTrue( $status->isGood() ); $this->assertTrue( $request->isRedirect() ); } public function testgetFinalUrl() { - $request = MWHttpRequest::factory( 'http://httpbin.org/redirect/3' ); + $request = $this->factory->create( 'http://httpbin.org/redirect/3' ); if ( !$request->canFollowRedirects() ) { $this->markTestSkipped( 'cannot follow redirects' ); } @@ -52,14 +58,14 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase { $this->assertTrue( $status->isGood() ); $this->assertNotSame( 'http://httpbin.org/get', $request->getFinalUrl() ); - $request = MWHttpRequest::factory( 'http://httpbin.org/redirect/3', [ 'followRedirects' + $request = $this->factory->create( 'http://httpbin.org/redirect/3', [ 'followRedirects' => true ] ); $status = $request->execute(); $this->assertTrue( $status->isGood() ); $this->assertSame( 'http://httpbin.org/get', $request->getFinalUrl() ); $this->assertResponseFieldValue( 'url', 'http://httpbin.org/get', $request ); - $request = MWHttpRequest::factory( 'http://httpbin.org/redirect/3', [ 'followRedirects' + $request = $this->factory->create( 'http://httpbin.org/redirect/3', [ 'followRedirects' => true ] ); $status = $request->execute(); $this->assertTrue( $status->isGood() ); @@ -71,7 +77,7 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase { return; } - $request = MWHttpRequest::factory( 'http://httpbin.org/redirect/3', [ 'followRedirects' + $request = $this->factory->create( 'http://httpbin.org/redirect/3', [ 'followRedirects' => true, 'maxRedirects' => 1 ] ); $status = $request->execute(); $this->assertTrue( $status->isGood() ); @@ -79,7 +85,7 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase { } public function testSetCookie() { - $request = MWHttpRequest::factory( 'http://httpbin.org/cookies' ); + $request = $this->factory->create( 'http://httpbin.org/cookies' ); $request->setCookie( 'foo', 'bar' ); $request->setCookie( 'foo2', 'bar2', [ 'domain' => 'example.com' ] ); $status = $request->execute(); @@ -88,7 +94,7 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase { } public function testSetCookieJar() { - $request = MWHttpRequest::factory( 'http://httpbin.org/cookies' ); + $request = $this->factory->create( 'http://httpbin.org/cookies' ); $cookieJar = new CookieJar(); $cookieJar->setCookie( 'foo', 'bar', [ 'domain' => 'httpbin.org' ] ); $cookieJar->setCookie( 'foo2', 'bar2', [ 'domain' => 'example.com' ] ); @@ -97,7 +103,7 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase { $this->assertTrue( $status->isGood() ); $this->assertResponseFieldValue( 'cookies', [ 'foo' => 'bar' ], $request ); - $request = MWHttpRequest::factory( 'http://httpbin.org/cookies/set?foo=bar' ); + $request = $this->factory->create( 'http://httpbin.org/cookies/set?foo=bar' ); $cookieJar = new CookieJar(); $request->setCookieJar( $cookieJar ); $status = $request->execute(); @@ -106,7 +112,7 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase { $this->markTestIncomplete( 'CookieJar does not handle deletion' ); - // $request = MWHttpRequest::factory( 'http://httpbin.org/cookies/delete?foo' ); + // $request = $this->factory->create( 'http://httpbin.org/cookies/delete?foo' ); // $cookieJar = new CookieJar(); // $cookieJar->setCookie( 'foo', 'bar', [ 'domain' => 'httpbin.org' ] ); // $cookieJar->setCookie( 'foo2', 'bar2', [ 'domain' => 'httpbin.org' ] ); @@ -118,7 +124,7 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase { } public function testGetResponseHeaders() { - $request = MWHttpRequest::factory( 'http://httpbin.org/response-headers?Foo=bar' ); + $request = $this->factory->create( 'http://httpbin.org/response-headers?Foo=bar' ); $status = $request->execute(); $this->assertTrue( $status->isGood() ); $headers = array_change_key_case( $request->getResponseHeaders(), CASE_LOWER ); @@ -127,7 +133,7 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase { } public function testSetHeader() { - $request = MWHttpRequest::factory( 'http://httpbin.org/headers' ); + $request = $this->factory->create( 'http://httpbin.org/headers' ); $request->setHeader( 'Foo', 'bar' ); $status = $request->execute(); $this->assertTrue( $status->isGood() ); @@ -135,14 +141,14 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase { } public function testGetStatus() { - $request = MWHttpRequest::factory( 'http://httpbin.org/status/418' ); + $request = $this->factory->create( 'http://httpbin.org/status/418' ); $status = $request->execute(); $this->assertFalse( $status->isOK() ); $this->assertSame( $request->getStatus(), 418 ); } public function testSetUserAgent() { - $request = MWHttpRequest::factory( 'http://httpbin.org/user-agent' ); + $request = $this->factory->create( 'http://httpbin.org/user-agent' ); $request->setUserAgent( 'foo' ); $status = $request->execute(); $this->assertTrue( $status->isGood() ); @@ -150,7 +156,7 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase { } public function testSetData() { - $request = MWHttpRequest::factory( 'http://httpbin.org/post', [ 'method' => 'POST' ] ); + $request = $this->factory->create( 'http://httpbin.org/post', [ 'method' => 'POST' ] ); $request->setData( [ 'foo' => 'bar', 'foo2' => 'bar2' ] ); $status = $request->execute(); $this->assertTrue( $status->isGood() ); @@ -163,7 +169,7 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase { return; } - $request = MWHttpRequest::factory( 'http://httpbin.org/ip' ); + $request = $this->factory->create( 'http://httpbin.org/ip' ); $data = ''; $request->setCallback( function ( $fh, $content ) use ( &$data ) { $data .= $content; @@ -177,7 +183,7 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase { } public function testBasicAuthentication() { - $request = MWHttpRequest::factory( 'http://httpbin.org/basic-auth/user/pass', [ + $request = $this->factory->create( 'http://httpbin.org/basic-auth/user/pass', [ 'username' => 'user', 'password' => 'pass', ] ); @@ -185,7 +191,7 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase { $this->assertTrue( $status->isGood() ); $this->assertResponseFieldValue( 'authenticated', true, $request ); - $request = MWHttpRequest::factory( 'http://httpbin.org/basic-auth/user/pass', [ + $request = $this->factory->create( 'http://httpbin.org/basic-auth/user/pass', [ 'username' => 'user', 'password' => 'wrongpass', ] ); @@ -195,7 +201,7 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase { } public function testFactoryDefaults() { - $request = MWHttpRequest::factory( 'http://acme.test' ); + $request = $this->factory->create( 'http://acme.test' ); $this->assertInstanceOf( MWHttpRequest::class, $request ); } diff --git a/tests/phpunit/includes/filebackend/FileBackendTest.php b/tests/phpunit/includes/filebackend/FileBackendTest.php index 4dc2f9e0ca..50696af8e9 100644 --- a/tests/phpunit/includes/filebackend/FileBackendTest.php +++ b/tests/phpunit/includes/filebackend/FileBackendTest.php @@ -1,5 +1,6 @@ backend->getFileHttpUrl( [ 'src' => $source ] ); if ( $url !== null ) { // supported - $data = Http::request( "GET", $url, [], __METHOD__ ); + $data = MediaWikiServices::getInstance()->getHttpRequestFactory()-> + get( $url, [], __METHOD__ ); $this->assertEquals( $content, $data, "HTTP GET of URL has right contents ($backendName)." ); } diff --git a/tests/phpunit/includes/http/HttpTest.php b/tests/phpunit/includes/http/HttpTest.php index eee4296281..a8c53d9112 100644 --- a/tests/phpunit/includes/http/HttpTest.php +++ b/tests/phpunit/includes/http/HttpTest.php @@ -67,6 +67,8 @@ class HttpTest extends MediaWikiTestCase { * @covers Http::getProxy */ public function testGetProxy() { + $this->hideDeprecated( 'Http::getProxy' ); + $this->setMwGlobals( 'wgHTTPProxy', false ); $this->assertEquals( '', -- 2.20.1