function CurlDownloader::initDownload
Parameters
mixed[] $options:
array{retryAuthFailure?: bool, redirects?: int<0, max>, retries?: int<0, max>, storeAuth?: 'prompt'|bool, ipResolve?: 4|6|null} $attributes:
non-empty-string $url:
Return value
int internal job id
2 calls to CurlDownloader::initDownload()
- CurlDownloader::download in vendor/
composer/ composer/ src/ Composer/ Util/ Http/ CurlDownloader.php - CurlDownloader::restartJob in vendor/
composer/ composer/ src/ Composer/ Util/ Http/ CurlDownloader.php
File
-
vendor/
composer/ composer/ src/ Composer/ Util/ Http/ CurlDownloader.php, line 143
Class
- CurlDownloader
- @internal @author Jordi Boggiano <j.boggiano@seld.be> @author Nicolas Grekas <p@tchwork.com> @phpstan-type Attributes array{retryAuthFailure: bool, redirects: int<0, max>, retries: int<0, max>, storeAuth:…
Namespace
Composer\Util\HttpCode
private function initDownload(callable $resolve, callable $reject, string $origin, string $url, array $options, ?string $copyTo = null, array $attributes = []) : int {
$attributes = array_merge([
'retryAuthFailure' => true,
'redirects' => 0,
'retries' => 0,
'storeAuth' => false,
'ipResolve' => null,
], $attributes);
if ($attributes['ipResolve'] === null && Platform::getEnv('COMPOSER_IPRESOLVE') === '4') {
$attributes['ipResolve'] = 4;
}
elseif ($attributes['ipResolve'] === null && Platform::getEnv('COMPOSER_IPRESOLVE') === '6') {
$attributes['ipResolve'] = 6;
}
$originalOptions = $options;
// check URL can be accessed (i.e. is not insecure), but allow insecure Packagist calls to $hashed providers as file integrity is verified with sha256
if (!Preg::isMatch('{^http://(repo\\.)?packagist\\.org/p/}', $url) || false === strpos($url, '$') && false === strpos($url, '%24')) {
$this->config
->prohibitUrlByConfig($url, $this->io, $options);
}
$curlHandle = curl_init();
$headerHandle = fopen('php://temp/maxmemory:32768', 'w+b');
if (false === $headerHandle) {
throw new \RuntimeException('Failed to open a temp stream to store curl headers');
}
if ($copyTo !== null) {
$bodyTarget = $copyTo . '~';
}
else {
$bodyTarget = 'php://temp/maxmemory:524288';
}
$errorMessage = '';
set_error_handler(static function (int $code, string $msg) use (&$errorMessage) : bool {
if ($errorMessage) {
$errorMessage .= "\n";
}
$errorMessage .= Preg::replace('{^fopen\\(.*?\\): }', '', $msg);
return true;
});
$bodyHandle = fopen($bodyTarget, 'w+b');
restore_error_handler();
if (false === $bodyHandle) {
throw new TransportException('The "' . $url . '" file could not be written to ' . ($copyTo ?? 'a temporary file') . ': ' . $errorMessage);
}
curl_setopt($curlHandle, CURLOPT_URL, $url);
curl_setopt($curlHandle, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($curlHandle, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($curlHandle, CURLOPT_TIMEOUT, max((int) ini_get("default_socket_timeout"), 300));
curl_setopt($curlHandle, CURLOPT_WRITEHEADER, $headerHandle);
curl_setopt($curlHandle, CURLOPT_FILE, $bodyHandle);
curl_setopt($curlHandle, CURLOPT_ENCODING, "");
// let cURL set the Accept-Encoding header to what it supports
curl_setopt($curlHandle, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
if ($attributes['ipResolve'] === 4) {
curl_setopt($curlHandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
}
elseif ($attributes['ipResolve'] === 6) {
curl_setopt($curlHandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
}
if (function_exists('curl_share_init')) {
curl_setopt($curlHandle, CURLOPT_SHARE, $this->shareHandle);
}
if (!isset($options['http']['header'])) {
$options['http']['header'] = [];
}
$options['http']['header'] = array_diff($options['http']['header'], [
'Connection: close',
]);
$options['http']['header'][] = 'Connection: keep-alive';
$version = curl_version();
$features = $version['features'];
if (0 === strpos($url, 'https://') && \defined('CURL_VERSION_HTTP2') && \defined('CURL_HTTP_VERSION_2_0') && (CURL_VERSION_HTTP2 & $features) !== 0) {
curl_setopt($curlHandle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
}
// curl 8.7.0 - 8.7.1 has a bug whereas automatic accept-encoding header results in an error when reading the response
// https://github.com/composer/composer/issues/11913
if (isset($version['version']) && in_array($version['version'], [
'8.7.0',
'8.7.1',
], true) && \defined('CURL_VERSION_LIBZ') && (CURL_VERSION_LIBZ & $features) !== 0) {
curl_setopt($curlHandle, CURLOPT_ENCODING, "gzip");
}
$options['http']['header'] = $this->authHelper
->addAuthenticationHeader($options['http']['header'], $origin, $url);
$options = StreamContextFactory::initOptions($url, $options, true);
foreach (self::$options as $type => $curlOptions) {
foreach ($curlOptions as $name => $curlOption) {
if (isset($options[$type][$name])) {
if ($type === 'ssl' && $name === 'verify_peer_name') {
curl_setopt($curlHandle, $curlOption, $options[$type][$name] === true ? 2 : $options[$type][$name]);
}
else {
curl_setopt($curlHandle, $curlOption, $options[$type][$name]);
}
}
}
}
$proxy = ProxyManager::getInstance()->getProxyForRequest($url);
curl_setopt_array($curlHandle, $proxy->getCurlOptions($options['ssl'] ?? []));
$progress = array_diff_key(curl_getinfo($curlHandle), self::$timeInfo);
$this->jobs[(int) $curlHandle] = [
'url' => $url,
'origin' => $origin,
'attributes' => $attributes,
'options' => $originalOptions,
'progress' => $progress,
'curlHandle' => $curlHandle,
'filename' => $copyTo,
'headerHandle' => $headerHandle,
'bodyHandle' => $bodyHandle,
'resolve' => $resolve,
'reject' => $reject,
'primaryIp' => '',
];
$usingProxy = $proxy->getStatus(' using proxy (%s)');
$ifModified = false !== stripos(implode(',', $options['http']['header']), 'if-modified-since:') ? ' if modified' : '';
if ($attributes['redirects'] === 0 && $attributes['retries'] === 0) {
$this->io
->writeError('Downloading ' . Url::sanitize($url) . $usingProxy . $ifModified, true, IOInterface::DEBUG);
}
$this->checkCurlResult(curl_multi_add_handle($this->multiHandle, $curlHandle));
// TODO progress
return (int) $curlHandle;
}