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