Collect the headers as they are received

@param resource $handle cURL resource
@param string $headers Header string
@return integer Length of provided header
334160
protected function stream_headers($handle, $headers) {
		// Why do we do this? cURL will send both the final response and any
		// interim responses, such as a 100 Continue. We don't need that.
		// (We may want to keep this somewhere just in case)
		if ($this->done_headers) {
			$this->headers = '';
			$this->done_headers = false;
		}
		$this->headers .= $headers;

		if ($headers === "\r\n") {
			$this->done_headers = true;
		}
		return strlen($headers);
	}
861652
public function sendRequest(NetDriverHandleInterface $handle, HttpRequest $request)
    {
        $url = $request->getUrl();

        try{
            $ch = $handle->reset();

            // set default options
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_HEADER, true);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

            $this->debug('Set URL: ' . $url);

            // follow redirection URL
            curl_setopt($ch,CURLOPT_FOLLOWLOCATION,true);

            // set max redirection
            curl_setopt($ch,CURLOPT_MAXREDIRS, self::DEFAULT_MAX_REDIRECTION);

            // add referer in redirection
            curl_setopt($ch,CURLOPT_AUTOREFERER,true);

            // set total timeout
            curl_setopt($ch, CURLOPT_TIMEOUT_MS, $request->getTotalTimeoutMs());

            // set connect timeout
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, $request->getConnectTimeoutMs());

            // fire event after received HTTP response
            $request = $this->fireOnSendingRequest($request);

            // set request header
            $headers = $request->getHttpHeaders();
            $headers_curl = array();
            foreach($headers as $key => $value){
                $headers_curl[] = "$key: $value";
            }
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers_curl);
            $this->debug('HTTP request headers: ' . print_r($headers_curl, true));

            // set extra options
            $extra_options = $request->getExtraOptions();
            foreach($extra_options as $opt => $value){
                curl_setopt($ch, $opt, $value);
            }

            // set proxy options
            if ($request instanceof HttpProxyRequestInterface){
                curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, TRUE);
                curl_setopt($ch, CURLOPT_PROXYPORT, $request->getProxyPort());
                $proxy_type = $request->getProxyType();
                switch($proxy_type){
                    case 'http':
                        curl_setopt($ch, CURLOPT_PROXY, 'http://' . $request->getProxyServer());
                        break;
                    case 'https':
                        curl_setopt($ch, CURLOPT_PROXY, 'https://' . $request->getProxyServer());
                        break;
                }
                $proxy_auth = $request->getProxyAuth();
                if (!empty($proxy_auth)){
                    curl_setopt($ch, CURLOPT_PROXYAUTH, $proxy_auth);
                    curl_setopt($ch, CURLOPT_PROXYUSERPWD, $request->getProxyUserPassword());
                }
                else{
                    curl_setopt($ch, CURLOPT_PROXYUSERPWD, "anonymous:");
                }
            }

            // set custome request
            if ($request instanceof HttpPostRequest){
                //curl_setopt($ch, CURLOPT_CUSTOMREQUEST, EnumHttpMethod::POST);
                $this->debug('Method: POST');
                curl_setopt($ch, CURLOPT_POST, 1);
                curl_setopt($ch, CURLOPT_POSTFIELDS, $request->getPostFields());
                $this->debug('POST fields: ' . print_r($request->getPostFields(), true));
            }
            else if ($request instanceof HttpPutRequest){
                $this->debug('Method: PUT');
                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $request->getMethod());
                curl_setopt($ch, CURLOPT_POSTFIELDS, $request->getPutFields());
            }
            else{
                $method = $request->getMethod();
                $this->debug('Method: ' . $method);
                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
            }

            // verbose
            $verbose = $this->getVerbose() | $request->getVerbose();
            curl_setopt($ch, CURLOPT_VERBOSE, $verbose ? 1 : 0);

            // verbose output
            $strerr_file = new CurlOutputFile();
            curl_setopt($ch, CURLOPT_STDERR, $strerr_file->handle());

            $header_file = new CurlOutputFile();
            curl_setopt($ch, CURLOPT_WRITEHEADER, $header_file->handle());

            $output_file = new CurlOutputFile();
            curl_setopt($ch, CURLOPT_FILE, $output_file->handle());

            // send request
            $result = curl_exec($ch);

            $this->debug('curl_exec result: ' . $result);

            // get verbose output
            $strerr = $strerr_file->readAll();
            $header = $header_file->readAll();
            $output = $output_file->readAll();

            $this->debug('strerr: ' . $strerr);
            $this->debug('header: ' . $header);
            $this->debug('output: ' . $output);

            // fire event after received verbose
            $this->fireOnReceivedVerbose($strerr, $header, $output);

            if ($result === false)
            {
                switch(curl_errno($ch))
                {
                    case CURLE_OPERATION_TIMEDOUT:
                        throw new TimeoutException($request);
                        break;
                }
                throw new CurlException('curl_exec', $ch);
            }

            // get response
            $info = curl_getinfo ($ch);

            $response = new CurlResponse($info, $output);

            $this->debug('status code: ' . $response->getStatusCode());
            $this->debug('response headers: ' . $response->getHeaders());

            // fire event after received HTTP response
            $this->fireOnReceivedResponse($response);

            return $response;
        }
        catch (CurlException $e){
            throw new NetDriverException($url, $e);
        }
    }
1250184
protected function _do_request($method, $path, $headers = NULL, $body= NULL, $file_handle= NULL) {/*{{{*/
        $uri = "/{$this->_bucketname}{$path}";
        $ch = curl_init("http://{$this->endpoint}{$uri}");

        $_headers = array('Expect:');
        if (!is_null($headers) && is_array($headers)){
            foreach($headers as $k => $v) {
                array_push($_headers, "{$k}: {$v}");
            }
        }

        $length = 0;
		$date = gmdate('D, d M Y H:i:s \G\M\T');

        if (!is_null($body)) {
            if(is_resource($body)){
                fseek($body, 0, SEEK_END);
                $length = ftell($body);
                fseek($body, 0);

                array_push($_headers, "Content-Length: {$length}");
                curl_setopt($ch, CURLOPT_INFILE, $body);
                curl_setopt($ch, CURLOPT_INFILESIZE, $length);
            } else {
                $length = @strlen($body);
                array_push($_headers, "Content-Length: {$length}");
                curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
            }
        } else {
            array_push($_headers, "Content-Length: {$length}");
        }

        array_push($_headers, "Authorization: {$this->sign($method, $uri, $date, $length)}");
        array_push($_headers, "Date: {$date}");

        curl_setopt($ch, CURLOPT_HTTPHEADER, $_headers);
        curl_setopt($ch, CURLOPT_TIMEOUT, $this->_timeout);
        curl_setopt($ch, CURLOPT_HEADER, 1);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        //curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
		curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);

        if ($method == 'PUT' || $method == 'POST') {
			curl_setopt($ch, CURLOPT_POST, 1);
        } else {
			curl_setopt($ch, CURLOPT_POST, 0);
        }

        if ($method == 'GET' && is_resource($file_handle)) {
            curl_setopt($ch, CURLOPT_HEADER, 0);
			curl_setopt($ch, CURLOPT_FILE, $file_handle);
        }

        if ($method == 'HEAD') {
            curl_setopt($ch, CURLOPT_NOBODY, true);
        }

        $response = curl_exec($ch);
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);


        if ($http_code == 0) throw new UpYunException('Connection Failed', $http_code);

        curl_close($ch);

        $header_string = '';
        $body = '';

        if ($method == 'GET' && is_resource($file_handle)) {
            $header_string = '';
            $body = $response;
        } else {
            list($header_string, $body) = explode("\r\n\r\n", $response, 2);
        }
        $this->setXRequestId($header_string);
        if ($http_code == 200) {
            if ($method == 'GET' && is_null($file_handle)) {
                return $body;
            } else {
                $data = $this->_getHeadersData($header_string);
                return count($data) > 0 ? $data : true;
            }
        } else {
            $message = $this->_getErrorMessage($header_string);
            if (is_null($message) && $method == 'GET' && is_resource($file_handle)) {
                $message = 'File Not Found';
            }
            switch($http_code) {
                case 401:
                    throw new UpYunAuthorizationException($message);
                    break;
                case 403:
                    throw new UpYunForbiddenException($message);
                    break;
                case 404:
                    throw new UpYunNotFoundException($message);
                    break;
                case 406:
                    throw new UpYunNotAcceptableException($message);
                    break;
                case 503:
                    throw new UpYunServiceUnavailable($message);
                    break;
                default:
                    throw new UpYunException($message, $http_code);
            }
        }
    }
290236
public function get(string $url, array $headers = [])
    {
        $ctx = $this->getContext('GET', null, $headers);
        $response = file_get_contents($url, false, $ctx);
        $this->saveCookies($http_response_header);

        return $response;
    }
300177
public function receiveResponseHeader($curl, $header)
    {
        static $normalize = array("\r", "\n");
        $length = strlen($header);
        $header = str_replace($normalize, '', $header);

        if (strpos($header, 'HTTP/') === 0) {

            $startLine = explode(' ', $header, 3);
            $code = $startLine[1];
            $status = isset($startLine[2]) ? $startLine[2] : '';

            // Only download the body of the response to the specified response
            // body when a successful response is received.
            if ($code >= 200 && $code < 300) {
                $body = $this->request->getResponseBody();
            } else {
                $body = EntityBody::factory();
            }

            $response = new Response($code, null, $body);
            $response->setStatus($code, $status);
            $this->request->startResponse($response);

            $this->request->dispatch('request.receive.status_line', array(
                'request'       => $this,
                'line'          => $header,
                'status_code'   => $code,
                'reason_phrase' => $status
            ));

        } elseif ($pos = strpos($header, ':')) {
            $this->request->getResponse()->addHeader(
                trim(substr($header, 0, $pos)),
                trim(substr($header, $pos + 1))
            );
        }

        return $length;
    }
502965
protected function request($url, $data, array $headers = array())
    {
        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));

        curl_exec($ch);
        $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        return floor($statusCode / 100) == 2;
    }
198517
private function request($path, $method, $headers = null, $body = null){
	        $ch  = curl_init($path);

	        $_headers = array('Expect:');
	        if (!is_null($headers) && is_array($headers)){
	            foreach($headers as $k => $v) {
	                array_push($_headers, "{$k}: {$v}");
	            }
	        }

	        $length = 0;
			$date   = gmdate('D, d M Y H:i:s \G\M\T');

	        if (!is_null($body)) {
	            if(is_resource($body)){
	                fseek($body, 0, SEEK_END);
	                $length = ftell($body);
	                fseek($body, 0);

	                array_push($_headers, "Content-Length: {$length}");
	                curl_setopt($ch, CURLOPT_INFILE, $body);
	                curl_setopt($ch, CURLOPT_INFILESIZE, $length);
	            } else {
	                $length = @strlen($body);
	                array_push($_headers, "Content-Length: {$length}");
	                curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
	            }
	        } else {
	            array_push($_headers, "Content-Length: {$length}");
	        }

	        // array_push($_headers, 'Authorization: ' . $this->sign($method, $uri, $date, $length));
	        array_push($_headers, "Date: {$date}");

	        curl_setopt($ch, CURLOPT_HTTPHEADER, $_headers);
	        curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
	        curl_setopt($ch, CURLOPT_HEADER, 1);
	        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
	        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
			curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);

	        if ($method == 'PUT' || $method == 'POST') {
				curl_setopt($ch, CURLOPT_POST, 1);
	        } else {
				curl_setopt($ch, CURLOPT_POST, 0);
	        }

	        if ($method == 'HEAD') {
	            curl_setopt($ch, CURLOPT_NOBODY, true);
	        }

	        $response = curl_exec($ch);
	        $status   = curl_getinfo($ch, CURLINFO_HTTP_CODE);
	        curl_close($ch);
	        list($header, $body) = explode("\r\n\r\n", $response, 2);
	        if ($status == 200) {
	            if ($method == 'GET') {
	                return $body;
	            } else {
	                return $this->response($response);
	            }
	        } else {
	            $this->error($header , $body);
	            return false;
	        }
	    }
253214
private function readLine($handle)
    {
        $size = 4096;
        $ret = $line = fgets($handle, $size);
        while (strlen($line) === $size - 1 && substr($line, -1) !== "\n") {
            $line = fgets($handle, $size);
        }
        return $ret;
    }
931466
public static function getCurl($url, $header=false) {
      if ( ! function_exists('curl_init') ) return false;
      global $last_http_response;
      global $LastHeadersSent;
      global $LastHeadersReceived;

      $ch = curl_init();
      curl_setopt($ch, CURLOPT_URL, $url);

      // Make sure that the header is an array and pitch white space
      $LastHeadersSent = trim($header);
      $header = explode("\n", trim($header));
      $htrim = Array();
      foreach ( $header as $h ) {
        $htrim[] = trim($h);
      }
      curl_setopt ($ch, CURLOPT_HTTPHEADER, $htrim);

      curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // ask for results to be returned
      curl_setopt($ch, CURLOPT_HEADER, 1);

      // Thanks to more and more PHP's not shipping with CA's installed
      // This becomes necessary
      if ( self::$VERIFY_PEER ) {
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
      } else {
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
      }

      // Send to remote and return data to caller.
      $result = curl_exec($ch);
      $info = curl_getinfo($ch);
      $last_http_response = $info['http_code'];
      $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
      $LastHeadersReceived = substr($result, 0, $header_size);
      $body = substr($result, $header_size);
      if ( $body === false ) $body = "";
      curl_close($ch);
      return $body;
    }
588090
protected function handleDoRequest($uri, $method, $headers, $in = NULL) {

    // XXX: I don't like this, but I'm getting bug reports that mistakenly
    // assume this library is broken, when in fact CURL is not installed.
    if (!function_exists('curl_init')) {
      throw new \HPCloud\Exception('The CURL library is not available.');
    }

    // A majority of curl users suggest allowing curl to automatically calculate
    // the content-length header. Ensure that the header is not set in code.
    // http://stackoverflow.com/questions/9152165/php-curl-content-length-und-content-type-wrong
    if (!empty($headers['Content-Length'])) {
      unset($headers['Content-Length']);
    }

    //syslog(LOG_WARNING, "Real Operation: $method $uri");

    //$urlParts = parse_url($uri);
    $opts = array(
      CURLOPT_USERAGENT => self::HTTP_USER_AGENT . self::HTTP_USER_AGENT_SUFFIX,
      // CURLOPT_RETURNTRANSFER => TRUE, // Make curl_exec return the results.
      // CURLOPT_BINARYTRANSFER => TRUE, // Raw output if RETURNTRANSFER is TRUE.

      // Timeout if the remote has not connected in 30 sec.
      //CURLOPT_CONNECTTIMEOUT => 30,

      // If this is set, CURL will auto-deflate any encoding it can.
      // CURLOPT_ENCODING => '',

      // Later, we may want to do this to support range-based
      // fetching of large objects.
      // CURLOPT_RANGE => 'X-Y',

      // Limit curl to only these protos.
      // CURLOPT_PROTOCOLS => CURLPROTO_HTTP | CURLPROTO_HTTPS,

      // (Re-)set defaults.
      //CURLOPT_POSTFIELDS => NULL,
      //CURLOPT_INFILE => NULL,
      //CURLOPT_INFILESIZE => NULL,
    );

    // Write to in-mem handle backed by a temp file.
    $out = fopen('php://temp', 'wb+');
    $headerFile = fopen('php://temp', 'w+');

    $curl = curl_init($uri);

    // Set method
    $this->determineMethod($curl, $method);

    // Set the upload
    $copy = NULL;

    // If we get a string, we send the string data.
    if (is_string($in)) {
      $opts[CURLOPT_POSTFIELDS] = $in;
    }
    // If we get a resource, we treat it like a stream
    // and pass it into CURL as a file.
    elseif (is_resource($in)) {
      $opts[CURLOPT_INFILE] = $in;
    }

    // Set headers.
    $this->setHeaders($curl, $headers);

    // Get the output.
    $opts[CURLOPT_FILE] = $out;

    // We need to capture the headers, too.
    $opts[CURLOPT_WRITEHEADER] = $headerFile;


    if (Bootstrap::hasConfig('transport.debug')) {
      $debug = Bootstrap::config('transport.debug', NULL);
      $opts[CURLOPT_VERBOSE] = (int) $debug;
    }

    if (Bootstrap::hasConfig('transport.timeout')) {
      $opts[CURLOPT_TIMEOUT] = (int) Bootstrap::config('transport.timeout');
    }

    if (Bootstrap::hasConfig('transport.ssl.verify')) {
      $validate = (boolean) Bootstrap::config('transport.ssl.verify', TRUE);
      $opts[CURLOPT_SSL_VERIFYPEER] = $validate;
    }

    // PROXY settings
    $proxyMap = array(
      'proxy' => CURLOPT_PROXY,
      'proxy.tunnel' => CURLOPT_HTTPPROXYTUNNEL,
      'proxy.auth' => CURLOPT_PROXYAUTH,
      'proxy.port' => CURLOPT_PROXYPORT,
      'proxy.type' => CURLOPT_PROXYTYPE,
      'proxy.userpwd' => CURLOPT_PROXYUSERPWD,
    );

    foreach ($proxyMap as $conf => $opt) {
      if (Bootstrap::hasConfig($conf)) {
        $val = Bootstrap::config($conf);
        $opts[$opt] = $val;
      }
    }

    // Set all of the curl opts and then execute.
    curl_setopt_array($curl, $opts);
    $ret = $this->execCurl($curl);
    $info = curl_getinfo($curl);
    $status = $info['http_code'];

    rewind($headerFile);
    $responseHeaders = $this->fetchHeaders($headerFile);
    fclose($headerFile);

    if (!$ret || $status < 200 || $status > 299) {
      if (empty($responseHeaders)) {
        $err = 'Unknown (non-HTTP) error: ' . $status;
      }
      else {
        $err = $responseHeaders[0];
      }
      //rewind($out);
      //fwrite(STDERR, stream_get_contents($out));
      Response::failure($status, $err, $info['url'], $method, $info);
    }


    rewind($out);
    // Now we need to build a response.
    $resp = new Response($out, $info, $responseHeaders);

    //curl_close($curl);
    if (is_resource($copy)) {
      fclose($copy);
    }

    return $resp;
  }
706146
private function releaseMultiHandle($handle, $maxHandles)
    {
        $id = (int) $handle;

        if (count($this->multiHandles) <= $maxHandles) {
            $this->multiOwned[$id] = false;
        } elseif (isset($this->multiHandles[$id], $this->multiOwned[$id])) {
            // Prune excessive handles
            curl_multi_close($this->multiHandles[$id]);
            unset($this->multiHandles[$id], $this->multiOwned[$id]);
        }
    }
64190
protected function __curl($path, $method = 'GET', array $params = array(), array $headers = array()) {
        $this->ret = [];
        
        // only JSON for now
        $headers[] = 'Content-Type: application/json';
        $headers[] = 'Accept: application/json';

        $options = array();
        $options[CURLOPT_RETURNTRANSFER] = true;
        $options[CURLOPT_HEADER] = true;
        $options[CURLOPT_TIMEOUT] = $this->timeout;
        $options[CURLOPT_CUSTOMREQUEST] = $method;
        $options[CURLOPT_HTTPHEADER] = $headers;

        if ($method == 'POST') {
            // not doing this, since we are json-only for now
            //$options[CURLOPT_POST] = 1;

            $options[CURLOPT_POSTFIELDS] = json_encode($params);            

        } elseif ($method == 'GET') {
            $par = http_build_query($params);

            if (strlen($par)) {
                if (preg_match('/\?/', $path)) {
                    $path .= '&' . $par;
                } else {
                    $path .= '?' . $par;
                }
            }

        }

        $options[CURLOPT_URL] = $path;

        $this->req = [
            'path' => $path, 
            'method' => $method, 
            'headers' => $headers, 
            'options' => $options,
        ];
        
        $curl = curl_init();
        curl_setopt_array($curl, $options); 
        
        $resp = curl_exec($curl);
        $header_size = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
        $this->ret['header'] = substr($resp, 0, $header_size);
        $this->ret['body'] = substr($resp, $header_size);        
        $this->ret['error'] = curl_error($curl);
        $this->ret['code'] = curl_getinfo($curl, CURLINFO_HTTP_CODE);
        curl_close($curl);
        
        return $this->ret;        
        
    }
991446
private function executeCurl($parameters, $url, array $headers, $method)
    {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);

        if ($method == 'POST') {
            curl_setopt($curl, CURLOPT_POST, true);
        } elseif ($method == 'PUT') {
            curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT');
        }

        if ($parameters !== null) {
            curl_setopt($curl, CURLOPT_POSTFIELDS, $parameters);
        }

        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, !$this->sandbox);

        $result = curl_exec($curl);

        $getInfo = curl_getinfo($curl);
        if (isset($getInfo['http_code']) && $getInfo['http_code'] == '503') {
            $this->log->error('Serviço em manutenção.', ['Retorno:' => $result]);

            throw new PagSeguroException('Serviço em manutenção.', 1000);
        }
        if ($result === false) {
            $this->log->error('Erro ao enviar a transação', ['Retorno:' => $result]);

            throw new PagSeguroException(curl_error($curl), curl_errno($curl));
        }

        curl_close($curl);

        return $result;
    }
1143632
public function curl_before_send(&$handle) {
		curl_setopt($handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
		curl_setopt($handle, CURLOPT_USERPWD, $this->getAuthString());
	}
347753
private static function parseHeaderLine($ch, string $data, array &$info, array &$headers, ?array $options, CurlClientState $multi, int $id, ?string &$location, ?callable $resolveRedirect, ?LoggerInterface $logger): int
    {
        if (!\in_array($waitFor = @curl_getinfo($ch, CURLINFO_PRIVATE), ['headers', 'destruct'], true)) {
            return \strlen($data); // Ignore HTTP trailers
        }

        if ("\r\n" !== $data) {
            // Regular header line: add it to the list
            self::addResponseHeaders([substr($data, 0, -2)], $info, $headers);

            if (0 === strpos($data, 'HTTP') && 300 <= $info['http_code'] && $info['http_code'] < 400) {
                if (curl_getinfo($ch, CURLINFO_REDIRECT_COUNT) === $options['max_redirects']) {
                    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
                } elseif (303 === $info['http_code'] || ('POST' === $info['http_method'] && \in_array($info['http_code'], [301, 302], true))) {
                    $info['http_method'] = 'HEAD' === $info['http_method'] ? 'HEAD' : 'GET';
                    curl_setopt($ch, CURLOPT_POSTFIELDS, '');
                }
            }

            if (0 === stripos($data, 'Location:')) {
                $location = trim(substr($data, 9, -2));
            }

            return \strlen($data);
        }

        // End of headers: handle redirects and add to the activity list
        $statusCode = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
        $info['redirect_url'] = null;

        if (300 <= $statusCode && $statusCode < 400 && null !== $location) {
            $info['redirect_url'] = $resolveRedirect($ch, $location);
            $url = parse_url($location ?? ':');

            if (isset($url['host']) && null !== $ip = $multi->dnsCache->hostnames[$url['host'] = strtolower($url['host'])] ?? null) {
                // Populate DNS cache for redirects if needed
                $port = $url['port'] ?? ('http' === ($url['scheme'] ?? parse_url(curl_getinfo($ch, CURLINFO_EFFECTIVE_URL), PHP_URL_SCHEME)) ? 80 : 443);
                curl_setopt($ch, CURLOPT_RESOLVE, ["{$url['host']}:$port:$ip"]);
                $multi->dnsCache->removals["-{$url['host']}:$port"] = "-{$url['host']}:$port";
            }
        }

        $location = null;

        if ($statusCode < 300 || 400 <= $statusCode || curl_getinfo($ch, CURLINFO_REDIRECT_COUNT) === $options['max_redirects']) {
            // Headers and redirects completed, time to get the response's body
            $multi->handlesActivity[$id] = [new FirstChunk()];

            if ('destruct' === $waitFor) {
                return 0;
            }

            if ($certinfo = curl_getinfo($ch, CURLINFO_CERTINFO)) {
                $info['peer_certificate_chain'] = array_map('openssl_x509_read', array_column($certinfo, 'Cert'));
            }

            curl_setopt($ch, CURLOPT_PRIVATE, 'content');
        } elseif (null !== $info['redirect_url'] && $logger) {
            $logger->info(sprintf('Redirecting: "%s %s"', $info['http_code'], $info['redirect_url']));
        }

        return \strlen($data);
    }
1169362
public function read($handle, $fd, $length)
    {
      if(!is_resource($handle))
        throw new Exception(__METHOD__ . '; cURL handle is not valid');

      $data = fread($fd, $length);
      $len = strlen($data);

      return $data;
    }
974366
public static function getFieldByHandleContext($handle, $context)
    {
        $fields = Craft::$app->fields->getAllFields(null, $context);
        foreach ($fields as $field) {
            if ($field->handle == $handle) {
                return $field;
            }
        }

        return false;
    }