X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FNetwork%2FHTTPRequest.php;h=74cf9cd0554d01a62beb0a1486b391bb734f4f69;hb=befc2af5043a3afde251721c0d27df695db1bb7e;hp=c37db4c9a06a7aa5abe6a14e98076853c63f4001;hpb=b526e6b4159c64dd463b27626fa0b520ed20c309;p=friendica.git diff --git a/src/Network/HTTPRequest.php b/src/Network/HTTPRequest.php index c37db4c9a0..74cf9cd055 100644 --- a/src/Network/HTTPRequest.php +++ b/src/Network/HTTPRequest.php @@ -1,6 +1,6 @@ baseUrl = $baseUrl->get(); } + /** {@inheritDoc} + * + * @throws HTTPException\InternalServerErrorException + */ + public function head(string $url, array $opts = []) + { + $opts['nobody'] = true; + + return $this->get($url, $opts); + } + /** * {@inheritDoc} + * + * @param int $redirects The recursion counter for internal use - default 0 + * + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public function get(string $url, bool $binary = false, array $opts = []) + public function get(string $url, array $opts = [], int &$redirects = 0) { $stamp1 = microtime(true); if (strlen($url) > 1000) { $this->logger->debug('URL is longer than 1000 characters.', ['url' => $url, 'callstack' => System::callstack(20)]); + $this->profiler->saveTimestamp($stamp1, 'network'); return CurlResult::createErrorCurl(substr($url, 0, 200)); } @@ -85,143 +95,124 @@ class HTTPRequest implements IHTTPRequest if (Network::isUrlBlocked($url)) { $this->logger->info('Domain is blocked.', ['url' => $url]); + $this->profiler->saveTimestamp($stamp1, 'network'); return CurlResult::createErrorCurl($url); } - $curlOptions = []; + $ch = @curl_init($url); + + if (($redirects > 8) || (!$ch)) { + $this->profiler->saveTimestamp($stamp1, 'network'); + return CurlResult::createErrorCurl($url); + } - $curlOptions[CURLOPT_HEADER] = true; + @curl_setopt($ch, CURLOPT_HEADER, true); if (!empty($opts['cookiejar'])) { - $curlOptions[CURLOPT_COOKIEJAR] = $opts["cookiejar"]; - $curlOptions[CURLOPT_COOKIEFILE] = $opts["cookiejar"]; + curl_setopt($ch, CURLOPT_COOKIEJAR, $opts["cookiejar"]); + curl_setopt($ch, CURLOPT_COOKIEFILE, $opts["cookiejar"]); } // These settings aren't needed. We're following the location already. - // $curlOptions[CURLOPT_FOLLOWLOCATION] =true; - // $curlOptions[CURLOPT_MAXREDIRS] = 5; + // @curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + // @curl_setopt($ch, CURLOPT_MAXREDIRS, 5); if (!empty($opts['accept_content'])) { - if (empty($curlOptions[CURLOPT_HTTPHEADER])) { - $curlOptions[CURLOPT_HTTPHEADER] = []; - } - array_push($curlOptions[CURLOPT_HTTPHEADER], 'Accept: ' . $opts['accept_content']); + curl_setopt( + $ch, + CURLOPT_HTTPHEADER, + ['Accept: ' . $opts['accept_content']] + ); } if (!empty($opts['header'])) { - if (empty($curlOptions[CURLOPT_HTTPHEADER])) { - $curlOptions[CURLOPT_HTTPHEADER] = []; - } - $curlOptions[CURLOPT_HTTPHEADER] = array_merge($opts['header'], $curlOptions[CURLOPT_HTTPHEADER]); + curl_setopt($ch, CURLOPT_HTTPHEADER, $opts['header']); } - $curlOptions[CURLOPT_RETURNTRANSFER] = true; - $curlOptions[CURLOPT_USERAGENT] = $this->getUserAgent(); + @curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + @curl_setopt($ch, CURLOPT_USERAGENT, $this->getUserAgent()); $range = intval($this->config->get('system', 'curl_range_bytes', 0)); if ($range > 0) { - $curlOptions[CURLOPT_RANGE] = '0-' . $range; + @curl_setopt($ch, CURLOPT_RANGE, '0-' . $range); } // Without this setting it seems as if some webservers send compressed content // This seems to confuse curl so that it shows this uncompressed. /// @todo We could possibly set this value to "gzip" or something similar - $curlOptions[CURLOPT_ENCODING] = ''; + curl_setopt($ch, CURLOPT_ENCODING, ''); if (!empty($opts['headers'])) { - if (empty($curlOptions[CURLOPT_HTTPHEADER])) { - $curlOptions[CURLOPT_HTTPHEADER] = []; - } - $curlOptions[CURLOPT_HTTPHEADER] = array_merge($opts['headers'], $curlOptions[CURLOPT_HTTPHEADER]); + $this->logger->notice('Wrong option \'headers\' used.'); + @curl_setopt($ch, CURLOPT_HTTPHEADER, $opts['headers']); } if (!empty($opts['nobody'])) { - $curlOptions[CURLOPT_NOBODY] = $opts['nobody']; + @curl_setopt($ch, CURLOPT_NOBODY, $opts['nobody']); } - $curlOptions[CURLOPT_CONNECTTIMEOUT] = 10; + @curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); if (!empty($opts['timeout'])) { - $curlOptions[CURLOPT_TIMEOUT] = $opts['timeout']; + @curl_setopt($ch, CURLOPT_TIMEOUT, $opts['timeout']); } else { $curl_time = $this->config->get('system', 'curl_timeout', 60); - $curlOptions[CURLOPT_TIMEOUT] = intval($curl_time); + @curl_setopt($ch, CURLOPT_TIMEOUT, intval($curl_time)); } // by default we will allow self-signed certs // but you can override this $check_cert = $this->config->get('system', 'verifyssl'); - $curlOptions[CURLOPT_SSL_VERIFYPEER] = ($check_cert) ? true : false; + @curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, (($check_cert) ? true : false)); if ($check_cert) { - $curlOptions[CURLOPT_SSL_VERIFYHOST] = 2; + @curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); } $proxy = $this->config->get('system', 'proxy'); if (!empty($proxy)) { - $curlOptions[CURLOPT_HTTPPROXYTUNNEL] = 1; - $curlOptions[CURLOPT_PROXY] = $proxy; + @curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1); + @curl_setopt($ch, CURLOPT_PROXY, $proxy); $proxyuser = $this->config->get('system', 'proxyuser'); if (!empty($proxyuser)) { - $curlOptions[CURLOPT_PROXYUSERPWD] = $proxyuser; + @curl_setopt($ch, CURLOPT_PROXYUSERPWD, $proxyuser); } } if ($this->config->get('system', 'ipv4_resolve', false)) { - $curlOptions[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V4; + curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); } - if ($binary) { - $curlOptions[CURLOPT_BINARYTRANSFER] = 1; - } + $s = @curl_exec($ch); + $curl_info = @curl_getinfo($ch); - $logger = $this->logger; + // Special treatment for HTTP Code 416 + // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/416 + if (($curl_info['http_code'] == 416) && ($range > 0)) { + @curl_setopt($ch, CURLOPT_RANGE, ''); + $s = @curl_exec($ch); + $curl_info = @curl_getinfo($ch); + } - $onRedirect = function( - RequestInterface $request, - ResponseInterface $response, - UriInterface $uri - ) use ($logger) { - $logger->notice('Curl redirect.', ['url' => $request->getUri(), 'to' => $uri]); - }; + $curlResponse = new CurlResult($url, $s, $curl_info, curl_errno($ch), curl_error($ch)); - $onHeaders = function (ResponseInterface $response) use ($opts) { - if (!empty($opts['content_length']) && - $response->getHeaderLine('Content-Length') > $opts['content_length']) { - throw new TransferException('The file is too big!'); - } - }; - - $client = new Client([ - 'allow_redirect' => [ - 'max' => 8, - 'on_redirect' => $onRedirect, - 'track_redirect' => true, - 'strict' => true, - 'referer' => true, - ], - 'on_headers' => $onHeaders, - 'sink' => tempnam(get_temppath(), 'guzzle'), - 'curl' => $curlOptions - ]); - - try { - $response = $client->get($url); - return new GuzzleResponse($response, $url); - } catch (TransferException $exception) { - if ($exception instanceof RequestException && - $exception->hasResponse()) { - return new GuzzleResponse($exception->getResponse(), $url, $exception->getCode(), ''); - } else { - return new CurlResult($url, '', ['http_code' => $exception->getCode()], $exception->getCode(), ''); - } - } finally { + if (!Network::isRedirectBlocked($url) && $curlResponse->isRedirectUrl()) { + $redirects++; + $this->logger->notice('Curl redirect.', ['url' => $url, 'to' => $curlResponse->getRedirectUrl()]); + @curl_close($ch); $this->profiler->saveTimestamp($stamp1, 'network'); + return $this->get($curlResponse->getRedirectUrl(), $opts, $redirects); } + + @curl_close($ch); + + $this->profiler->saveTimestamp($stamp1, 'network'); + + return $curlResponse; } /** @@ -237,12 +228,14 @@ class HTTPRequest implements IHTTPRequest if (Network::isUrlBlocked($url)) { $this->logger->info('Domain is blocked.' . ['url' => $url]); + $this->profiler->saveTimestamp($stamp1, 'network'); return CurlResult::createErrorCurl($url); } $ch = curl_init($url); if (($redirects > 8) || (!$ch)) { + $this->profiler->saveTimestamp($stamp1, 'network'); return CurlResult::createErrorCurl($url); } @@ -302,6 +295,7 @@ class HTTPRequest implements IHTTPRequest $redirects++; $this->logger->info('Post redirect.', ['url' => $url, 'to' => $curlResponse->getRedirectUrl()]); curl_close($ch); + $this->profiler->saveTimestamp($stamp1, 'network'); return $this->post($curlResponse->getRedirectUrl(), $params, $headers, $redirects, $timeout); } @@ -453,9 +447,9 @@ class HTTPRequest implements IHTTPRequest * * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public function fetch(string $url, bool $binary = false, int $timeout = 0, string $accept_content = '', string $cookiejar = '', int &$redirects = 0) + public function fetch(string $url, int $timeout = 0, string $accept_content = '', string $cookiejar = '', int &$redirects = 0) { - $ret = $this->fetchFull($url, $binary, $timeout, $accept_content, $cookiejar, $redirects); + $ret = $this->fetchFull($url, $timeout, $accept_content, $cookiejar, $redirects); return $ret->getBody(); } @@ -467,16 +461,16 @@ class HTTPRequest implements IHTTPRequest * * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public function fetchFull(string $url, bool $binary = false, int $timeout = 0, string $accept_content = '', string $cookiejar = '', int &$redirects = 0) + public function fetchFull(string $url, int $timeout = 0, string $accept_content = '', string $cookiejar = '', int &$redirects = 0) { return $this->get( $url, - $binary, [ 'timeout' => $timeout, 'accept_content' => $accept_content, 'cookiejar' => $cookiejar - ] + ], + $redirects ); }