49 lines
1.6 KiB
PHP
49 lines
1.6 KiB
PHP
|
|
<?php
|
||
|
|
namespace AfFulltext;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* The `direct` backend inside tt-rss.
|
||
|
|
*
|
||
|
|
* Deliberately goes through UrlHelper rather than cURL directly, so article
|
||
|
|
* fetches keep tt-rss's own SSRF protection (UrlHelper::validate refuses private
|
||
|
|
* and link-local addresses). Feeds are attacker-influenced input; a plugin that
|
||
|
|
* fetches whatever a feed points at must not be the hole in that.
|
||
|
|
*
|
||
|
|
* FirecrawlFetcher is the deliberate exception -- it talks to one operator-configured
|
||
|
|
* in-cluster endpoint, which UrlHelper would refuse precisely because it is private.
|
||
|
|
*/
|
||
|
|
final class TtrssFetcher implements Fetcher {
|
||
|
|
public function __construct(private readonly int $timeout = 20) {}
|
||
|
|
|
||
|
|
public function name(): string { return 'direct'; }
|
||
|
|
|
||
|
|
public function fetch(string $url, array $headers = []): FetchResult {
|
||
|
|
if (!class_exists('\UrlHelper'))
|
||
|
|
return new FetchResult(error: 'UrlHelper unavailable (not running inside tt-rss)');
|
||
|
|
|
||
|
|
$options = [
|
||
|
|
'url' => $url,
|
||
|
|
'http_accept' => 'text/*',
|
||
|
|
'type' => 'text/html',
|
||
|
|
'timeout' => $this->timeout,
|
||
|
|
];
|
||
|
|
|
||
|
|
// Site configs routinely set a user-agent to get the article rather than a
|
||
|
|
// consent wall; UrlHelper takes it as a first-class option.
|
||
|
|
if (isset($headers['user-agent'])) $options['useragent'] = $headers['user-agent'];
|
||
|
|
|
||
|
|
$body = \UrlHelper::fetch($options);
|
||
|
|
|
||
|
|
if (!is_string($body) || $body === '') {
|
||
|
|
$error = \UrlHelper::$fetch_last_error ?: 'fetch returned nothing';
|
||
|
|
return new FetchResult(error: $error, status: (int) \UrlHelper::$fetch_last_error_code);
|
||
|
|
}
|
||
|
|
|
||
|
|
return new FetchResult(
|
||
|
|
html: $body,
|
||
|
|
effective_url: \UrlHelper::$fetch_effective_url ?: $url,
|
||
|
|
status: 200,
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|