22use Psr\Log\LoggerAwareInterface;
23use Psr\Log\LoggerInterface;
24use Psr\Log\NullLogger;
100 $url, array $options = [], $caller = __METHOD__,
Profiler $profiler =
null
105 $this->logger = $options[
'logger'] ??
new NullLogger();
107 if ( !$this->parsedUrl || !self::isValidURI( $this->url ) ) {
108 $this->status = StatusValue::newFatal(
'http-invalid-url',
$url );
110 $this->status = StatusValue::newGood( 100 );
113 if ( isset( $options[
'timeout'] ) && $options[
'timeout'] !=
'default' ) {
114 $this->timeout = $options[
'timeout'];
118 wfDeprecated( __METHOD__ .
' without the timeout option',
'1.35' );
122 if ( isset( $options[
'connectTimeout'] ) && $options[
'connectTimeout'] !=
'default' ) {
123 $this->connectTimeout = $options[
'connectTimeout'];
127 wfDeprecated( __METHOD__ .
' without the connectTimeout option',
'1.35' );
131 if ( isset( $options[
'userAgent'] ) ) {
134 if ( isset( $options[
'username'] ) && isset( $options[
'password'] ) ) {
137 'Basic ' . base64_encode( $options[
'username'] .
':' . $options[
'password'] )
140 if ( isset( $options[
'originalRequest'] ) ) {
144 $this->
setHeader(
'X-Request-Id', WebRequest::getRequestId() );
146 $members = [
"postData",
"proxy",
"noProxy",
"sslVerifyHost",
"caInfo",
147 "method",
"followRedirects",
"maxRedirects",
"sslVerifyCert",
"callback" ];
149 foreach ( $members as $o ) {
150 if ( isset( $options[$o] ) ) {
153 if ( $o ==
'method' ) {
154 $options[$o] = strtoupper( $options[$o] );
156 $this->$o = $options[$o];
160 if ( $this->noProxy ) {
166 $this->profileName = $caller;
173 $this->logger = $logger;
182 return function_exists(
'curl_init' ) ||
wfIniGetBool(
'allow_url_fopen' );
195 public static function factory( $url, array $options =
null, $caller = __METHOD__ ) {
196 if ( $options ===
null ) {
199 return MediaWikiServices::getInstance()->getHttpRequestFactory()
200 ->create(
$url, $options, $caller );
219 $this->postData =
$args;
229 if ( $this->proxy && !$this->noProxy ) {
235 if ( self::isLocalURL( $this->url ) || $this->noProxy ) {
258 if ( preg_match(
'!^https?://([\w.-]+)[/:].*$!',
$url,
$matches ) ) {
261 $domainParts = explode(
'.', $host );
263 $domainParts = array_reverse( $domainParts );
266 $countParts = count( $domainParts );
267 for ( $i = 0; $i < $countParts; $i++ ) {
268 $domainPart = $domainParts[$i];
270 $domain = $domainPart;
272 $domain = $domainPart .
'.' . $domain;
299 $this->reqHeaders[$name] = $value;
309 if ( $this->cookieJar ) {
310 $this->reqHeaders[
'Cookie'] =
311 $this->cookieJar->serializeToHttpRequest(
312 $this->parsedUrl[
'path'],
313 $this->parsedUrl[
'host']
317 foreach ( $this->reqHeaders as $name => $value ) {
318 $list[] =
"$name: $value";
357 $this->status->fatal(
'http-internal-error' );
358 throw new InvalidArgumentException( __METHOD__ .
': invalid callback' );
384 throw new LogicException(
'children must override this' );
390 if ( strtoupper( $this->method ) ==
"HEAD" ) {
391 $this->headersOnly =
true;
396 if ( !$this->callback ) {
400 if ( !isset( $this->reqHeaders[
'User-Agent'] ) ) {
401 $http = MediaWikiServices::getInstance()->getHttpRequestFactory();
415 if ( !$this->status->isOK() ) {
416 $this->respStatus =
'0 Error';
419 foreach ( $this->headerList as
$header ) {
420 if ( preg_match(
"#^HTTP/([0-9.]+) (.*)#",
$header, $match ) ) {
421 $this->respVersion = $match[1];
422 $this->respStatus = $match[2];
423 } elseif ( preg_match(
"#^[ \t]#",
$header ) ) {
424 $last = count( $this->respHeaders[$lastname] ) - 1;
425 $this->respHeaders[$lastname][$last] .=
"\r\n$header";
426 } elseif ( preg_match(
"#^([^:]*):[\t ]*(.*)#",
$header, $match ) ) {
427 $this->respHeaders[strtolower( $match[1] )][] = $match[2];
428 $lastname = strtolower( $match[1] );
443 if ( !$this->respHeaders ) {
447 if ( ( (
int)$this->respStatus > 0 && (
int)$this->respStatus < 400 ) ) {
448 $this->status->setResult(
true, (
int)$this->respStatus );
450 list( $code, $message ) = explode(
" ", $this->respStatus, 2 );
451 $this->status->setResult(
false, (
int)$this->respStatus );
452 $this->status->fatal(
"http-bad-status", $code, $message );
464 if ( !$this->respHeaders ) {
468 return (
int)$this->respStatus;
477 if ( !$this->respHeaders ) {
481 $status = (int)$this->respStatus;
500 if ( !$this->respHeaders ) {
504 return $this->respHeaders;
514 if ( !$this->respHeaders ) {
518 if ( isset( $this->respHeaders[strtolower(
$header )] ) ) {
519 $v = $this->respHeaders[strtolower(
$header )];
520 return $v[count( $v ) - 1];
534 $this->cookieJar = $jar;
543 if ( !$this->respHeaders ) {
547 return $this->cookieJar;
559 public function setCookie( $name, $value, array $attr = [] ) {
560 if ( !$this->cookieJar ) {
564 if ( $this->parsedUrl && !isset( $attr[
'domain'] ) ) {
565 $attr[
'domain'] = $this->parsedUrl[
'host'];
568 $this->cookieJar->
setCookie( $name, $value, $attr );
575 if ( !$this->cookieJar ) {
579 if ( isset( $this->respHeaders[
'set-cookie'] ) ) {
581 foreach ( $this->respHeaders[
'set-cookie'] as $cookie ) {
582 $this->cookieJar->parseCookieResponseHeader( $cookie,
$url[
'host'] );
607 if ( isset( $headers[
'location'] ) ) {
608 $locations = $headers[
'location'];
610 $foundRelativeURI =
false;
611 $countLocations = count( $locations );
613 for ( $i = $countLocations - 1; $i >= 0; $i-- ) {
614 $url = parse_url( $locations[$i] );
616 if ( isset(
$url[
'host'] ) ) {
617 $domain =
$url[
'scheme'] .
'://' .
$url[
'host'];
620 $foundRelativeURI =
true;
624 if ( !$foundRelativeURI ) {
625 return $locations[$countLocations - 1];
628 return $domain . $locations[$countLocations - 1];
630 $url = parse_url( $this->url );
631 if ( isset(
$url[
'host'] ) ) {
632 return $url[
'scheme'] .
'://' .
$url[
'host'] .
633 $locations[$countLocations - 1];
662 if ( $originalRequest instanceof
WebRequest ) {
664 'ip' => $originalRequest->getIP(),
665 'userAgent' => $originalRequest->getHeader(
'User-Agent' ),
668 !is_array( $originalRequest )
669 || array_diff( [
'ip',
'userAgent' ], array_keys( $originalRequest ) )
671 throw new InvalidArgumentException( __METHOD__ .
': $originalRequest must be a '
672 .
"WebRequest or an array with 'ip' and 'userAgent' keys" );
675 $this->reqHeaders[
'X-Forwarded-For'] = $originalRequest[
'ip'];
676 $this->reqHeaders[
'X-Original-User-Agent'] = $originalRequest[
'userAgent'];
696 return (
bool)preg_match(
697 '/^https?:\/\/[^\/\s]\S*$/D',
$wgHTTPProxy
Proxy to use for CURL requests.
float int $wgHTTPTimeout
Timeout for HTTP requests done internally, in seconds.
$wgLocalVirtualHosts
Local virtual hosts.
float int $wgHTTPConnectTimeout
Timeout for connections done internally (in seconds).
global $wgCommandLineMode
wfParseUrl( $url)
parse_url() work-alike, but non-broken.
wfIniGetBool( $setting)
Safety wrapper around ini_get() for boolean settings.
wfExpandUrl( $url, $defaultProto=PROTO_CURRENT)
Expand a potentially local URL to a fully-qualified URL.
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that $function is deprecated.
Cookie jar to use with MWHttpRequest.
setCookie( $name, $value, $attr)
Set a cookie in the cookie jar.
This wrapper class will call out to curl (if available) or fallback to regular PHP if necessary for h...
getContent()
Get the body, or content, of the response to the request.
setLogger(LoggerInterface $logger)
setCookie( $name, $value, array $attr=[])
Sets a cookie.
getResponseHeaders()
Returns an associative array of response headers after the request has been executed.
static isLocalURL( $url)
Check if the URL can be served by localhost.
doSetCallback( $callback)
Worker function for setting callbacks.
setHeader( $name, $value)
Set an arbitrary header.
getCookieJar()
Returns the cookie jar in use.
setOriginalRequest( $originalRequest)
Set information about the original request.
isRedirect()
Returns true if the last status code was a redirect.
read( $fh, $content)
A generic callback to read the body of the response from a remote server.
getFinalUrl()
Returns the final URL after all redirections.
setStatus()
Sets HTTPRequest status member to a fatal value with the error message if the returned integer value ...
setUserAgent( $UA)
Set the user agent.
parseHeader()
Parses the headers, including the HTTP status code and any Set-Cookie headers.
canFollowRedirects()
Returns true if the backend can follow redirects.
__construct( $url, array $options=[], $caller=__METHOD__, Profiler $profiler=null)
setCallback( $callback)
Set a read callback to accept data read from the HTTP request.
static canMakeRequests()
Simple function to test if we can make any sort of requests at all, using cURL or fopen()
static factory( $url, array $options=null, $caller=__METHOD__)
Generate a new request object.
static isValidURI( $uri)
Check that the given URI is a valid one.
getStatus()
Get the integer value of the HTTP status code (e.g.
const SUPPORTS_FILE_POSTS
execute()
Take care of whatever is necessary to perform the URI request.
getResponseHeader( $header)
Returns the value of the given response header.
proxySetup()
Take care of setting up the proxy (do nothing if "noProxy" is set)
setData(array $args)
Set the parameters of the request.
parseCookies()
Parse the cookies in the response headers and store them in the cookie jar.
getHeaderList()
Get an array of the headers.
setCookieJar(CookieJar $jar)
Tells the MWHttpRequest object to use this pre-loaded CookieJar.
Profiler base class that defines the interface and some shared functionality.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form stripping il...