22use Psr\Log\LoggerAwareInterface;
23use Psr\Log\LoggerInterface;
24use Psr\Log\NullLogger;
99 $url, array $options = [], $caller = __METHOD__,
Profiler $profiler =
null
104 $this->logger = $options[
'logger'] ??
new NullLogger();
106 if ( !$this->parsedUrl || !self::isValidURI( $this->url ) ) {
107 $this->status = StatusValue::newFatal(
'http-invalid-url',
$url );
109 $this->status = StatusValue::newGood( 100 );
112 if ( isset( $options[
'timeout'] ) && $options[
'timeout'] !=
'default' ) {
113 $this->timeout = $options[
'timeout'];
117 wfDeprecated( __METHOD__ .
' without the timeout option',
'1.35' );
121 if ( isset( $options[
'connectTimeout'] ) && $options[
'connectTimeout'] !=
'default' ) {
122 $this->connectTimeout = $options[
'connectTimeout'];
126 wfDeprecated( __METHOD__ .
' without the connectTimeout option',
'1.35' );
130 if ( isset( $options[
'userAgent'] ) ) {
133 if ( isset( $options[
'username'] ) && isset( $options[
'password'] ) ) {
136 'Basic ' . base64_encode( $options[
'username'] .
':' . $options[
'password'] )
139 if ( isset( $options[
'originalRequest'] ) ) {
143 $this->
setHeader(
'X-Request-Id', WebRequest::getRequestId() );
145 $members = [
"postData",
"proxy",
"noProxy",
"sslVerifyHost",
"caInfo",
146 "method",
"followRedirects",
"maxRedirects",
"sslVerifyCert",
"callback" ];
148 foreach ( $members as $o ) {
149 if ( isset( $options[$o] ) ) {
152 if ( $o ==
'method' ) {
153 $options[$o] = strtoupper( $options[$o] );
155 $this->$o = $options[$o];
159 if ( $this->noProxy ) {
165 $this->profileName = $caller;
172 $this->logger = $logger;
181 return function_exists(
'curl_init' ) ||
wfIniGetBool(
'allow_url_fopen' );
194 public static function factory( $url, array $options =
null, $caller = __METHOD__ ) {
195 if ( $options ===
null ) {
198 return MediaWikiServices::getInstance()->getHttpRequestFactory()
199 ->create(
$url, $options, $caller );
218 $this->postData =
$args;
228 if ( $this->proxy && !$this->noProxy ) {
234 if ( self::isLocalURL( $this->url ) || $this->noProxy ) {
257 if ( preg_match(
'!^https?://([\w.-]+)[/:].*$!',
$url,
$matches ) ) {
260 $domainParts = explode(
'.', $host );
262 $domainParts = array_reverse( $domainParts );
265 $countParts = count( $domainParts );
266 for ( $i = 0; $i < $countParts; $i++ ) {
267 $domainPart = $domainParts[$i];
269 $domain = $domainPart;
271 $domain = $domainPart .
'.' . $domain;
297 $this->reqHeaders[$name] = $value;
307 if ( $this->cookieJar ) {
308 $this->reqHeaders[
'Cookie'] =
309 $this->cookieJar->serializeToHttpRequest(
310 $this->parsedUrl[
'path'],
311 $this->parsedUrl[
'host']
315 foreach ( $this->reqHeaders as $name => $value ) {
316 $list[] =
"$name: $value";
355 $this->status->fatal(
'http-internal-error' );
356 throw new InvalidArgumentException( __METHOD__ .
': invalid callback' );
382 throw new LogicException(
'children must override this' );
388 if ( strtoupper( $this->method ) ==
"HEAD" ) {
389 $this->headersOnly =
true;
394 if ( !$this->callback ) {
398 if ( !isset( $this->reqHeaders[
'User-Agent'] ) ) {
399 $http = MediaWikiServices::getInstance()->getHttpRequestFactory();
413 if ( !$this->status->isOK() ) {
414 $this->respStatus =
'0 Error';
417 foreach ( $this->headerList as
$header ) {
418 if ( preg_match(
"#^HTTP/([0-9.]+) (.*)#",
$header, $match ) ) {
419 $this->respVersion = $match[1];
420 $this->respStatus = $match[2];
421 } elseif ( preg_match(
"#^[ \t]#",
$header ) ) {
422 $last = count( $this->respHeaders[$lastname] ) - 1;
423 $this->respHeaders[$lastname][$last] .=
"\r\n$header";
424 } elseif ( preg_match(
"#^([^:]*):[\t ]*(.*)#",
$header, $match ) ) {
425 $this->respHeaders[strtolower( $match[1] )][] = $match[2];
426 $lastname = strtolower( $match[1] );
441 if ( !$this->respHeaders ) {
445 if ( (
int)$this->respStatus > 0 && (
int)$this->respStatus < 400 ) {
446 $this->status->setResult(
true, (
int)$this->respStatus );
448 list( $code, $message ) = explode(
" ", $this->respStatus, 2 );
449 $this->status->setResult(
false, (
int)$this->respStatus );
450 $this->status->fatal(
"http-bad-status", $code, $message );
462 if ( !$this->respHeaders ) {
466 return (
int)$this->respStatus;
475 if ( !$this->respHeaders ) {
479 $status = (int)$this->respStatus;
498 if ( !$this->respHeaders ) {
502 return $this->respHeaders;
512 if ( !$this->respHeaders ) {
516 if ( isset( $this->respHeaders[strtolower(
$header )] ) ) {
517 $v = $this->respHeaders[strtolower(
$header )];
518 return $v[count( $v ) - 1];
532 $this->cookieJar = $jar;
541 if ( !$this->respHeaders ) {
545 return $this->cookieJar;
557 public function setCookie( $name, $value, array $attr = [] ) {
558 if ( !$this->cookieJar ) {
562 if ( $this->parsedUrl && !isset( $attr[
'domain'] ) ) {
563 $attr[
'domain'] = $this->parsedUrl[
'host'];
566 $this->cookieJar->
setCookie( $name, $value, $attr );
573 if ( !$this->cookieJar ) {
577 if ( isset( $this->respHeaders[
'set-cookie'] ) ) {
579 foreach ( $this->respHeaders[
'set-cookie'] as $cookie ) {
580 $this->cookieJar->parseCookieResponseHeader( $cookie,
$url[
'host'] );
605 if ( isset( $headers[
'location'] ) ) {
606 $locations = $headers[
'location'];
608 $foundRelativeURI =
false;
609 $countLocations = count( $locations );
611 for ( $i = $countLocations - 1; $i >= 0; $i-- ) {
612 $url = parse_url( $locations[$i] );
614 if ( isset(
$url[
'host'] ) ) {
615 $domain =
$url[
'scheme'] .
'://' .
$url[
'host'];
618 $foundRelativeURI =
true;
622 if ( !$foundRelativeURI ) {
623 return $locations[$countLocations - 1];
626 return $domain . $locations[$countLocations - 1];
628 $url = parse_url( $this->url );
629 if ( isset(
$url[
'host'] ) ) {
630 return $url[
'scheme'] .
'://' .
$url[
'host'] .
631 $locations[$countLocations - 1];
660 if ( $originalRequest instanceof
WebRequest ) {
662 'ip' => $originalRequest->getIP(),
663 'userAgent' => $originalRequest->getHeader(
'User-Agent' ),
666 !is_array( $originalRequest )
667 || array_diff( [
'ip',
'userAgent' ], array_keys( $originalRequest ) )
669 throw new InvalidArgumentException( __METHOD__ .
': $originalRequest must be a '
670 .
"WebRequest or an array with 'ip' and 'userAgent' keys" );
673 $this->reqHeaders[
'X-Forwarded-For'] = $originalRequest[
'ip'];
674 $this->reqHeaders[
'X-Original-User-Agent'] = $originalRequest[
'userAgent'];
694 return (
bool)preg_match(
695 '/^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 a deprecated feature was used.
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 ...
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...