X-Git-Url: https://git.heureux-cyclage.org/?p=lhc%2Fweb%2Fwiklou.git;a=blobdiff_plain;f=includes%2Flibs%2Fhttp%2FMultiHttpClient.php;h=b195a085ef4ffab5074b99864ed9efc2f4e9bb5e;hp=5e233aeb12bb33e2f3d5bd58bfb48b62f693a5c6;hb=134e933e610b712089feab62736ddb2f88ea4f86;hpb=52a21ace03540c85c293e09898a90e048e2234bd diff --git a/includes/libs/http/MultiHttpClient.php b/includes/libs/http/MultiHttpClient.php index 5e233aeb12..b195a085ef 100644 --- a/includes/libs/http/MultiHttpClient.php +++ b/includes/libs/http/MultiHttpClient.php @@ -161,6 +161,8 @@ class MultiHttpClient implements LoggerAwareInterface { */ public function runMulti( array $reqs, array $opts = [] ) { $this->normalizeRequests( $reqs ); + $opts += [ 'connTimeout' => $this->connTimeout, 'reqTimeout' => $this->reqTimeout ]; + if ( $this->isCurlEnabled() ) { return $this->runMultiCurl( $reqs, $opts ); } else { @@ -188,10 +190,14 @@ class MultiHttpClient implements LoggerAwareInterface { * - reqTimeout : post-connection timeout per request (seconds) * - usePipelining : whether to use HTTP pipelining if possible * - maxConnsPerHost : maximum number of concurrent connections (per host) + * @codingStandardsIgnoreStart + * @phan-param array{connTimeout?:int,reqTimeout?:int,usePipelining?:bool,maxConnsPerHost?:int} $opts + * @codingStandardsIgnoreEnd * @return array $reqs With response array populated for each * @throws Exception + * @suppress PhanTypeInvalidDimOffset */ - private function runMultiCurl( array $reqs, array $opts = [] ) { + private function runMultiCurl( array $reqs, array $opts ) { $chm = $this->getCurlMulti(); $selectTimeout = $this->getSelectTimeout( $opts ); @@ -288,21 +294,21 @@ class MultiHttpClient implements LoggerAwareInterface { /** * @param array &$req HTTP request map + * @codingStandardsIgnoreStart + * @phan-param array{url:string,proxy?:?string,query:mixed,method:string,body:string|resource,headers:string[],stream?:resource,flags:array} $req + * @codingStandardsIgnoreEnd * @param array $opts - * - connTimeout : default connection timeout - * - reqTimeout : default request timeout + * - connTimeout : default connection timeout + * - reqTimeout : default request timeout * @return resource * @throws Exception - * @suppress PhanTypeMismatchArgumentInternal */ - protected function getCurlHandle( array &$req, array $opts = [] ) { + protected function getCurlHandle( array &$req, array $opts ) { $ch = curl_init(); - curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT_MS, - ( $opts['connTimeout'] ?? $this->connTimeout ) * 1000 ); curl_setopt( $ch, CURLOPT_PROXY, $req['proxy'] ?? $this->proxy ); - curl_setopt( $ch, CURLOPT_TIMEOUT_MS, - ( $opts['reqTimeout'] ?? $this->reqTimeout ) * 1000 ); + curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT_MS, intval( $opts['connTimeout'] * 1e3 ) ); + curl_setopt( $ch, CURLOPT_TIMEOUT_MS, intval( $opts['reqTimeout'] * 1e3 ) ); curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 1 ); curl_setopt( $ch, CURLOPT_MAXREDIRS, 4 ); curl_setopt( $ch, CURLOPT_HEADER, 0 ); @@ -318,11 +324,8 @@ class MultiHttpClient implements LoggerAwareInterface { $url .= strpos( $req['url'], '?' ) === false ? "?$query" : "&$query"; } curl_setopt( $ch, CURLOPT_URL, $url ); - curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, $req['method'] ); - if ( $req['method'] === 'HEAD' ) { - curl_setopt( $ch, CURLOPT_NOBODY, 1 ); - } + curl_setopt( $ch, CURLOPT_NOBODY, ( $req['method'] === 'HEAD' ) ); if ( $req['method'] === 'PUT' ) { curl_setopt( $ch, CURLOPT_PUT, 1 ); @@ -349,17 +352,11 @@ class MultiHttpClient implements LoggerAwareInterface { } curl_setopt( $ch, CURLOPT_READFUNCTION, function ( $ch, $fd, $length ) { - $data = fread( $fd, $length ); - $len = strlen( $data ); - return $data; + return (string)fread( $fd, $length ); } ); } elseif ( $req['method'] === 'POST' ) { curl_setopt( $ch, CURLOPT_POST, 1 ); - // Don't interpret POST parameters starting with '@' as file uploads, because this - // makes it impossible to POST plain values starting with '@' (and causes security - // issues potentially exposing the contents of local files). - curl_setopt( $ch, CURLOPT_SAFE_UPLOAD, true ); curl_setopt( $ch, CURLOPT_POSTFIELDS, $req['body'] ); } else { if ( is_resource( $req['body'] ) || $req['body'] !== '' ) { @@ -408,23 +405,20 @@ class MultiHttpClient implements LoggerAwareInterface { } ); - if ( isset( $req['stream'] ) ) { - // Don't just use CURLOPT_FILE as that might give: - // curl_setopt(): cannot represent a stream of type Output as a STDIO FILE* - // The callback here handles both normal files and php://temp handles. - curl_setopt( $ch, CURLOPT_WRITEFUNCTION, - function ( $ch, $data ) use ( &$req ) { + // This works with both file and php://temp handles (unlike CURLOPT_FILE) + $hasOutputStream = isset( $req['stream'] ); + curl_setopt( $ch, CURLOPT_WRITEFUNCTION, + function ( $ch, $data ) use ( &$req, $hasOutputStream ) { + if ( $hasOutputStream ) { return fwrite( $req['stream'], $data ); - } - ); - } else { - curl_setopt( $ch, CURLOPT_WRITEFUNCTION, - function ( $ch, $data ) use ( &$req ) { + } else { + // @phan-suppress-next-line PhanTypeArraySuspiciousNullable $req['response']['body'] .= $data; + return strlen( $data ); } - ); - } + } + ); return $ch; } @@ -508,6 +502,7 @@ class MultiHttpClient implements LoggerAwareInterface { if ( isset( $svErrors[0]['params'][0] ) ) { if ( is_numeric( $svErrors[0]['params'][0] ) ) { if ( isset( $svErrors[0]['params'][1] ) ) { + // @phan-suppress-next-line PhanTypeInvalidDimOffset $req['response']['reason'] = $svErrors[0]['params'][1]; } } else {