HttpRequestFactory.php 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. <?php
  2. /**
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation; either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License along
  14. * with this program; if not, write to the Free Software Foundation, Inc.,
  15. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  16. * http://www.gnu.org/copyleft/gpl.html
  17. *
  18. * @file
  19. */
  20. namespace MediaWiki\Http;
  21. use CurlHttpRequest;
  22. use GuzzleHttpRequest;
  23. use Http;
  24. use MediaWiki\Logger\LoggerFactory;
  25. use MWHttpRequest;
  26. use PhpHttpRequest;
  27. use Profiler;
  28. use RuntimeException;
  29. use Status;
  30. /**
  31. * Factory creating MWHttpRequest objects.
  32. */
  33. class HttpRequestFactory {
  34. /**
  35. * Generate a new MWHttpRequest object
  36. * @param string $url Url to use
  37. * @param array $options Possible keys for the array:
  38. * - timeout Timeout length in seconds or 'default'
  39. * - connectTimeout Timeout for connection, in seconds (curl only) or 'default'
  40. * - postData An array of key-value pairs or a url-encoded form data
  41. * - proxy The proxy to use.
  42. * Otherwise it will use $wgHTTPProxy (if set)
  43. * Otherwise it will use the environment variable "http_proxy" (if set)
  44. * - noProxy Don't use any proxy at all. Takes precedence over proxy value(s).
  45. * - sslVerifyHost Verify hostname against certificate
  46. * - sslVerifyCert Verify SSL certificate
  47. * - caInfo Provide CA information
  48. * - maxRedirects Maximum number of redirects to follow (defaults to 5)
  49. * - followRedirects Whether to follow redirects (defaults to false).
  50. * Note: this should only be used when the target URL is trusted,
  51. * to avoid attacks on intranet services accessible by HTTP.
  52. * - userAgent A user agent, if you want to override the default
  53. * MediaWiki/$wgVersion
  54. * - logger A \Psr\Logger\LoggerInterface instance for debug logging
  55. * - username Username for HTTP Basic Authentication
  56. * - password Password for HTTP Basic Authentication
  57. * - originalRequest Information about the original request (as a WebRequest object or
  58. * an associative array with 'ip' and 'userAgent').
  59. * @codingStandardsIgnoreStart
  60. * @phan-param array{timeout?:int|string,connectTimeout?:int|string,postData?:array,proxy?:string,noProxy?:bool,sslVerifyHost?:bool,sslVerifyCert?:bool,caInfo?:string,maxRedirects?:int,followRedirects?:bool,userAgent?:string,method?:string,logger?:\Psr\Log\LoggerInterface,username?:string,password?:string,originalRequest?:\WebRequest|array{ip:string,userAgent:string}} $options
  61. * @codingStandardsIgnoreEnd
  62. * @param string $caller The method making this request, for profiling
  63. * @throws RuntimeException
  64. * @return MWHttpRequest
  65. * @see MWHttpRequest::__construct
  66. */
  67. public function create( $url, array $options = [], $caller = __METHOD__ ) {
  68. if ( !Http::$httpEngine ) {
  69. Http::$httpEngine = 'guzzle';
  70. }
  71. if ( !isset( $options['logger'] ) ) {
  72. $options['logger'] = LoggerFactory::getInstance( 'http' );
  73. }
  74. switch ( Http::$httpEngine ) {
  75. case 'guzzle':
  76. return new GuzzleHttpRequest( $url, $options, $caller, Profiler::instance() );
  77. case 'curl':
  78. return new CurlHttpRequest( $url, $options, $caller, Profiler::instance() );
  79. case 'php':
  80. return new PhpHttpRequest( $url, $options, $caller, Profiler::instance() );
  81. default:
  82. throw new RuntimeException( __METHOD__ . ': The requested engine is not valid.' );
  83. }
  84. }
  85. /**
  86. * Simple function to test if we can make any sort of requests at all, using
  87. * cURL or fopen()
  88. * @return bool
  89. */
  90. public function canMakeRequests() {
  91. return function_exists( 'curl_init' ) || wfIniGetBool( 'allow_url_fopen' );
  92. }
  93. /**
  94. * Perform an HTTP request
  95. *
  96. * @since 1.34
  97. * @param string $method HTTP method. Usually GET/POST
  98. * @param string $url Full URL to act on. If protocol-relative, will be expanded to an http://
  99. * URL
  100. * @param array $options See HttpRequestFactory::create
  101. * @param string $caller The method making this request, for profiling
  102. * @return string|null null on failure or a string on success
  103. */
  104. public function request( $method, $url, array $options = [], $caller = __METHOD__ ) {
  105. $logger = LoggerFactory::getInstance( 'http' );
  106. $logger->debug( "$method: $url" );
  107. $options['method'] = strtoupper( $method );
  108. if ( !isset( $options['timeout'] ) ) {
  109. $options['timeout'] = 'default';
  110. }
  111. if ( !isset( $options['connectTimeout'] ) ) {
  112. $options['connectTimeout'] = 'default';
  113. }
  114. $req = $this->create( $url, $options, $caller );
  115. $status = $req->execute();
  116. if ( $status->isOK() ) {
  117. return $req->getContent();
  118. } else {
  119. $errors = $status->getErrorsByType( 'error' );
  120. $logger->warning( Status::wrap( $status )->getWikiText( false, false, 'en' ),
  121. [ 'error' => $errors, 'caller' => $caller, 'content' => $req->getContent() ] );
  122. return null;
  123. }
  124. }
  125. /**
  126. * Simple wrapper for request( 'GET' ), parameters have same meaning as for request()
  127. *
  128. * @since 1.34
  129. * @param string $url
  130. * @param array $options
  131. * @param string $caller
  132. * @return string|null
  133. */
  134. public function get( $url, array $options = [], $caller = __METHOD__ ) {
  135. return $this->request( 'GET', $url, $options, $caller );
  136. }
  137. /**
  138. * Simple wrapper for request( 'POST' ), parameters have same meaning as for request()
  139. *
  140. * @since 1.34
  141. * @param string $url
  142. * @param array $options
  143. * @param string $caller
  144. * @return string|null
  145. */
  146. public function post( $url, array $options = [], $caller = __METHOD__ ) {
  147. return $this->request( 'POST', $url, $options, $caller );
  148. }
  149. /**
  150. * @return string
  151. */
  152. public function getUserAgent() {
  153. global $wgVersion;
  154. return "MediaWiki/$wgVersion";
  155. }
  156. }