Merge "Make DBAccessBase use DBConnRef, rename $wiki, and hide getLoadBalancer()"
[lhc/web/wiklou.git] / includes / http / HttpRequestFactory.php
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
22 use CurlHttpRequest;
23 use GuzzleHttpRequest;
24 use Http;
25 use MediaWiki\Logger\LoggerFactory;
26 use MWHttpRequest;
27 use PhpHttpRequest;
28 use Profiler;
29 use RuntimeException;
30 use Status;
31
32 /**
33 * Factory creating MWHttpRequest objects.
34 */
35 class HttpRequestFactory {
36 /**
37 * Generate a new MWHttpRequest object
38 * @param string $url Url to use
39 * @param array $options Possible keys for the array:
40 * - timeout Timeout length in seconds
41 * - connectTimeout Timeout for connection, in seconds (curl only)
42 * - postData An array of key-value pairs or a url-encoded form data
43 * - proxy The proxy to use.
44 * Otherwise it will use $wgHTTPProxy (if set)
45 * Otherwise it will use the environment variable "http_proxy" (if set)
46 * - noProxy Don't use any proxy at all. Takes precedence over proxy value(s).
47 * - sslVerifyHost Verify hostname against certificate
48 * - sslVerifyCert Verify SSL certificate
49 * - caInfo Provide CA information
50 * - maxRedirects Maximum number of redirects to follow (defaults to 5)
51 * - followRedirects Whether to follow redirects (defaults to false).
52 * Note: this should only be used when the target URL is trusted,
53 * to avoid attacks on intranet services accessible by HTTP.
54 * - userAgent A user agent, if you want to override the default
55 * MediaWiki/$wgVersion
56 * - logger A \Psr\Logger\LoggerInterface instance for debug logging
57 * - username Username for HTTP Basic Authentication
58 * - password Password for HTTP Basic Authentication
59 * - originalRequest Information about the original request (as a WebRequest object or
60 * an associative array with 'ip' and 'userAgent').
61 * @codingStandardsIgnoreStart
62 * @phan-param array{timeout?:int,connectTimeout?:int,postData?:array,proxy?:string,noProxy?:bool,sslVerifyHost?:bool,sslVerifyCert?:bool,caInfo?:string,maxRedirects?:int,followRedirects?:bool,userAgent?:string,logger?:\Psr\Logger\LoggerInterface,username?:string,password?:string,originalRequest?:WebRequest|array{ip:string,userAgent:string}} $options
63 * @codingStandardsIgnoreEnd
64 * @param string $caller The method making this request, for profiling
65 * @throws RuntimeException
66 * @return MWHttpRequest
67 * @see MWHttpRequest::__construct
68 * @suppress PhanUndeclaredTypeParameter
69 */
70 public function create( $url, array $options = [], $caller = __METHOD__ ) {
71 if ( !Http::$httpEngine ) {
72 Http::$httpEngine = 'guzzle';
73 }
74
75 if ( !isset( $options['logger'] ) ) {
76 $options['logger'] = LoggerFactory::getInstance( 'http' );
77 }
78
79 switch ( Http::$httpEngine ) {
80 case 'guzzle':
81 return new GuzzleHttpRequest( $url, $options, $caller, Profiler::instance() );
82 case 'curl':
83 return new CurlHttpRequest( $url, $options, $caller, Profiler::instance() );
84 case 'php':
85 return new PhpHttpRequest( $url, $options, $caller, Profiler::instance() );
86 default:
87 throw new RuntimeException( __METHOD__ . ': The requested engine is not valid.' );
88 }
89 }
90
91 /**
92 * Simple function to test if we can make any sort of requests at all, using
93 * cURL or fopen()
94 * @return bool
95 */
96 public function canMakeRequests() {
97 return function_exists( 'curl_init' ) || wfIniGetBool( 'allow_url_fopen' );
98 }
99
100 /**
101 * Perform an HTTP request
102 *
103 * @since 1.34
104 * @param string $method HTTP method. Usually GET/POST
105 * @param string $url Full URL to act on. If protocol-relative, will be expanded to an http://
106 * URL
107 * @param array $options See HttpRequestFactory::create
108 * @param string $caller The method making this request, for profiling
109 * @return string|null null on failure or a string on success
110 */
111 public function request( $method, $url, array $options = [], $caller = __METHOD__ ) {
112 $logger = LoggerFactory::getInstance( 'http' );
113 $logger->debug( "$method: $url" );
114
115 $options['method'] = strtoupper( $method );
116
117 if ( !isset( $options['timeout'] ) ) {
118 $options['timeout'] = 'default';
119 }
120 if ( !isset( $options['connectTimeout'] ) ) {
121 $options['connectTimeout'] = 'default';
122 }
123
124 $req = $this->create( $url, $options, $caller );
125 $status = $req->execute();
126
127 if ( $status->isOK() ) {
128 return $req->getContent();
129 } else {
130 $errors = $status->getErrorsByType( 'error' );
131 $logger->warning( Status::wrap( $status )->getWikiText( false, false, 'en' ),
132 [ 'error' => $errors, 'caller' => $caller, 'content' => $req->getContent() ] );
133 return null;
134 }
135 }
136
137 /**
138 * Simple wrapper for request( 'GET' ), 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 get( $url, array $options = [], $caller = __METHOD__ ) {
147 return $this->request( 'GET', $url, $options, $caller );
148 }
149
150 /**
151 * Simple wrapper for request( 'POST' ), parameters have same meaning as for request()
152 *
153 * @since 1.34
154 * @param string $url
155 * @param array $options
156 * @param string $caller
157 * @return string|null
158 */
159 public function post( $url, array $options = [], $caller = __METHOD__ ) {
160 return $this->request( 'POST', $url, $options, $caller );
161 }
162
163 /**
164 * @return string
165 */
166 public function getUserAgent() {
167 global $wgVersion;
168
169 return "MediaWiki/$wgVersion";
170 }
171 }