summaryrefslogtreecommitdiff
path: root/www/wiki/includes/http/Http.php
blob: 6eff6c9cbd12a33e5c065574ec6bd51f9ac13bca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
<?php
/**
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 * http://www.gnu.org/copyleft/gpl.html
 *
 * @file
 */

use MediaWiki\Logger\LoggerFactory;

/**
 * Various HTTP related functions
 * @ingroup HTTP
 */
class Http {
	static public $httpEngine = false;

	/**
	 * Perform an HTTP 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 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, $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;
		}
	}

	/**
	 * Simple wrapper for Http::request( 'GET' )
	 * @see Http::request()
	 * @since 1.25 Second parameter $timeout removed. Second parameter
	 * is now $options which can be given a 'timeout'
	 *
	 * @param string $url
	 * @param array $options
	 * @param string $caller The method making this request, for profiling
	 * @return string|bool false on error
	 */
	public static function get( $url, $options = [], $caller = __METHOD__ ) {
		$args = func_get_args();
		if ( isset( $args[1] ) && ( is_string( $args[1] ) || is_numeric( $args[1] ) ) ) {
			// Second was used to be the timeout
			// And third parameter used to be $options
			wfWarn( "Second parameter should not be a timeout.", 2 );
			$options = isset( $args[2] ) && is_array( $args[2] ) ?
				$args[2] : [];
			$options['timeout'] = $args[1];
			$caller = __METHOD__;
		}
		return self::request( 'GET', $url, $options, $caller );
	}

	/**
	 * Simple wrapper for Http::request( 'POST' )
	 * @see Http::request()
	 *
	 * @param string $url
	 * @param array $options
	 * @param string $caller The method making this request, for profiling
	 * @return string|bool false on error
	 */
	public static function post( $url, $options = [], $caller = __METHOD__ ) {
		return self::request( 'POST', $url, $options, $caller );
	}

	/**
	 * A standard user-agent we can use for external requests.
	 * @return string
	 */
	public static function userAgent() {
		global $wgVersion;
		return "MediaWiki/$wgVersion";
	}

	/**
	 * Checks that the given URI is a valid one. Hardcoding the
	 * protocols, because we only want protocols that both cURL
	 * and php support.
	 *
	 * file:// should not be allowed here for security purpose (r67684)
	 *
	 * @todo FIXME this is wildly inaccurate and fails to actually check most stuff
	 *
	 * @param string $uri URI to check for validity
	 * @return bool
	 */
	public static function isValidURI( $uri ) {
		return (bool)preg_match(
			'/^https?:\/\/[^\/\s]\S*$/D',
			$uri
		);
	}

	/**
	 * Gets the relevant proxy from $wgHTTPProxy
	 *
	 * @return mixed The proxy address or an empty string if not set.
	 */
	public static function getProxy() {
		global $wgHTTPProxy;

		if ( $wgHTTPProxy ) {
			return $wgHTTPProxy;
		}

		return "";
	}

	/**
	 * Get a configured MultiHttpClient
	 * @param array $options
	 * @return MultiHttpClient
	 */
	public static function createMultiClient( $options = [] ) {
		global $wgHTTPConnectTimeout, $wgHTTPTimeout, $wgHTTPProxy;

		return new MultiHttpClient( $options + [
			'connTimeout' => $wgHTTPConnectTimeout,
			'reqTimeout' => $wgHTTPTimeout,
			'userAgent' => self::userAgent(),
			'proxy' => $wgHTTPProxy,
			'logger' => LoggerFactory::getInstance( 'http' )
		] );
	}
}