Requests_Transport_cURL::setup_handle()

最后更新于:2021-11-26 04:06:54

Requests_Transport_cURL::setup_handle( string$url, array$headers, string|array$data, array$options)

Setup the cURL handle for the given data

参数

$url

(string) (Required) URL to request

$headers

(array) (Required) Associative array of request headers

$data

(string|array) (Required) Data to send either as the POST body, or as parameters in the URL for a GET/HEAD

$options

(array) (Required) Request options, see Requests::response() for documentation

源文件

文件: gc-includes/Requests/Transport/cURL.php

	protected function setup_handle($url, $headers, $data, $options) {
		$options['hooks']->dispatch('curl.before_request', array(&$this->handle));

		// Force closing the connection for old versions of cURL (<7.22).
		if (!isset($headers['Connection'])) {
			$headers['Connection'] = 'close';
		}

		/**
		 * Add "Expect" header.
		 *
		 * By default, cURL adds a "Expect: 100-Continue" to most requests. This header can
		 * add as much as a second to the time it takes for cURL to perform a request. To
		 * prevent this, we need to set an empty "Expect" header. To match the behaviour of
		 * Guzzle, we'll add the empty header to requests that are smaller than 1 MB and use
		 * HTTP/1.1.
		 *
		 * https://curl.se/mail/lib-2017-07/0013.html
		 */
		if (!isset($headers['Expect']) && $options['protocol_version'] === 1.1) {
			$headers['Expect'] = $this->get_expect_header($data);
		}

		$headers = Requests::flatten($headers);

		if (!empty($data)) {
			$data_format = $options['data_format'];

			if ($data_format === 'query') {
				$url  = self::format_get($url, $data);
				$data = '';
			}
			elseif (!is_string($data)) {
				$data = http_build_query($data, null, '&');
			}
		}

		switch ($options['type']) {
			case Requests::POST:
				curl_setopt($this->handle, CURLOPT_POST, true);
				curl_setopt($this->handle, CURLOPT_POSTFIELDS, $data);
				break;
			case Requests::HEAD:
				curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']);
				curl_setopt($this->handle, CURLOPT_NOBODY, true);
				break;
			case Requests::TRACE:
				curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']);
				break;
			case Requests::PATCH:
			case Requests::PUT:
			case Requests::DELETE:
			case Requests::OPTIONS:
			default:
				curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']);
				if (!empty($data)) {
					curl_setopt($this->handle, CURLOPT_POSTFIELDS, $data);
				}
		}

		// cURL requires a minimum timeout of 1 second when using the system
		// DNS resolver, as it uses `alarm()`, which is second resolution only.
		// There's no way to detect which DNS resolver is being used from our
		// end, so we need to round up regardless of the supplied timeout.
		//
		// https://github.com/curl/curl/blob/4f45240bc84a9aa648c8f7243be7b79e9f9323a5/lib/hostip.c#L606-L609
		$timeout = max($options['timeout'], 1);

		if (is_int($timeout) || $this->version < self::CURL_7_16_2) {
			curl_setopt($this->handle, CURLOPT_TIMEOUT, ceil($timeout));
		}
		else {
			// phpcs:ignore PHPCompatibility.Constants.NewConstants.curlopt_timeout_msFound
			curl_setopt($this->handle, CURLOPT_TIMEOUT_MS, round($timeout * 1000));
		}

		if (is_int($options['connect_timeout']) || $this->version < self::CURL_7_16_2) {
			curl_setopt($this->handle, CURLOPT_CONNECTTIMEOUT, ceil($options['connect_timeout']));
		}
		else {
			// phpcs:ignore PHPCompatibility.Constants.NewConstants.curlopt_connecttimeout_msFound
			curl_setopt($this->handle, CURLOPT_CONNECTTIMEOUT_MS, round($options['connect_timeout'] * 1000));
		}
		curl_setopt($this->handle, CURLOPT_URL, $url);
		curl_setopt($this->handle, CURLOPT_REFERER, $url);
		curl_setopt($this->handle, CURLOPT_USERAGENT, $options['useragent']);
		if (!empty($headers)) {
			curl_setopt($this->handle, CURLOPT_HTTPHEADER, $headers);
		}
		if ($options['protocol_version'] === 1.1) {
			curl_setopt($this->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
		}
		else {
			curl_setopt($this->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
		}

		if ($options['blocking'] === true) {
			curl_setopt($this->handle, CURLOPT_HEADERFUNCTION, array($this, 'stream_headers'));
			curl_setopt($this->handle, CURLOPT_WRITEFUNCTION, array($this, 'stream_body'));
			curl_setopt($this->handle, CURLOPT_BUFFERSIZE, Requests::BUFFER_SIZE);
		}
	}