Merge "maintenance: Script to rename titles for Unicode uppercasing changes"
[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 * @param string $caller The method making this request, for profiling
62 * @throws RuntimeException
63 * @return MWHttpRequest
64 * @see MWHttpRequest::__construct
65 */
66 public function create( $url, array $options = [], $caller = __METHOD__ ) {
67 if ( !Http::$httpEngine ) {
68 Http::$httpEngine = 'guzzle';
69 }
70
71 if ( !isset( $options['logger'] ) ) {
72 $options['logger'] = LoggerFactory::getInstance( 'http' );
73 }
74
75 switch ( Http::$httpEngine ) {
76 case 'guzzle':
77 return new GuzzleHttpRequest( $url, $options, $caller, Profiler::instance() );
78 case 'curl':
79 return new CurlHttpRequest( $url, $options, $caller, Profiler::instance() );
80 case 'php':
81 return new PhpHttpRequest( $url, $options, $caller, Profiler::instance() );
82 default:
83 throw new RuntimeException( __METHOD__ . ': The requested engine is not valid.' );
84 }
85 }
86
87 /**
88 * Simple function to test if we can make any sort of requests at all, using
89 * cURL or fopen()
90 * @return bool
91 */
92 public function canMakeRequests() {
93 return function_exists( 'curl_init' ) || wfIniGetBool( 'allow_url_fopen' );
94 }
95
96 /**
97 * Perform an HTTP request
98 *
99 * @since 1.34
100 * @param string $method HTTP method. Usually GET/POST
101 * @param string $url Full URL to act on. If protocol-relative, will be expanded to an http://
102 * URL
103 * @param array $options See HttpRequestFactory::create
104 * @param string $caller The method making this request, for profiling
105 * @return string|null null on failure or a string on success
106 */
107 public function request( $method, $url, array $options = [], $caller = __METHOD__ ) {
108 $logger = LoggerFactory::getInstance( 'http' );
109 $logger->debug( "$method: $url" );
110
111 $options['method'] = strtoupper( $method );
112
113 if ( !isset( $options['timeout'] ) ) {
114 $options['timeout'] = 'default';
115 }
116 if ( !isset( $options['connectTimeout'] ) ) {
117 $options['connectTimeout'] = 'default';
118 }
119
120 $req = $this->create( $url, $options, $caller );
121 $status = $req->execute();
122
123 if ( $status->isOK() ) {
124 return $req->getContent();
125 } else {
126 $errors = $status->getErrorsByType( 'error' );
127 $logger->warning( Status::wrap( $status )->getWikiText( false, false, 'en' ),
128 [ 'error' => $errors, 'caller' => $caller, 'content' => $req->getContent() ] );
129 return null;
130 }
131 }
132
133 /**
134 * Simple wrapper for request( 'GET' ), parameters have same meaning as for request()
135 *
136 * @since 1.34
137 * @param string $url
138 * @param array $options
139 * @param string $caller
140 * @return string|null
141 */
142 public function get( $url, array $options = [], $caller = __METHOD__ ) {
143 return $this->request( 'GET', $url, $options, $caller );
144 }
145
146 /**
147 * Simple wrapper for request( 'POST' ), parameters have same meaning as for request()
148 *
149 * @since 1.34
150 * @param string $url
151 * @param array $options
152 * @param string $caller
153 * @return string|null
154 */
155 public function post( $url, array $options = [], $caller = __METHOD__ ) {
156 return $this->request( 'POST', $url, $options, $caller );
157 }
158
159 /**
160 * @return string
161 */
162 public function getUserAgent() {
163 global $wgVersion;
164
165 return "MediaWiki/$wgVersion";
166 }
167 }