Change: Use IClientService instead of straight Guzzle Client#3672
Conversation
|
This isn't actually possible because the two aren't compatible. |
|
Here's an example how the bookmarks app solved it https://github.com/nextcloud/bookmarks/blob/master/lib/Http/Client.php. That could be a workaround until you drop support for versions older then 34. |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
2b3462c to
484a0d8
Compare
Sign-off-by: Sean Molenaar <SMillerDev@users.noreply.github.com> Signed-off-by: Benjamin Brahmer <info@b-brahmer.de>
484a0d8 to
034e097
Compare
|
Looks good to me, I included the changes from the other related PRs was easier to test, what do you think @SMillerDev fine like this? |
There was a problem hiding this comment.
Pull request overview
This PR migrates News’ outbound HTTP usage away from directly constructed Guzzle clients to Nextcloud’s IClientService, aligning with other Nextcloud apps and leveraging built-in SSRF protection and proxy handling.
Changes:
- Refactor scraping, feed fetching, and favicon fetching to use
IClientService/IClient. - Add a PSR-18 adapter (
OCA\News\Http\Client) to bridgeIClientinto feed-io’s HTTP expectations. - Update unit/integration tests and CI workflows to accommodate SSRF/local-network restrictions.
Reviewed changes
Copilot reviewed 14 out of 15 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
lib/Scraper/Scraper.php |
Switch scraper HTTP requests to IClientService and add redirect SSRF handling. |
lib/Config/FetcherConfig.php |
Replace Guzzle client construction with IClientService-backed clients; adjust API. |
lib/Fetcher/Client/FeedIoClient.php |
Feed-io HTTP adapter now uses a PSR-18 wrapper over IClientService. |
lib/Http/Client.php |
New PSR-18 adapter wrapping Nextcloud IClient. |
lib/Fetcher/FaviconDataAccess.php |
Replace file_get_contents()/get_headers() with IClientService. |
lib/Fetcher/FeedFetcher.php |
Update favicon download + Last-Modified probe to use IClient; resolve relative favicon URLs. |
lib/AppInfo/Application.php |
Wire updated FaviconDataAccess dependencies via DI. |
tests/Unit/Scraper/ScraperTest.php |
Update scraper tests to mock IClientService and IResponse; add redirect-history test. |
tests/Unit/Fetcher/FeedIoClientTest.php |
Update FeedIoClient tests to use IClientService/IClient mocks. |
tests/Unit/Fetcher/FaviconDataAccessTest.php |
New unit tests for the new FaviconDataAccess behavior. |
tests/Unit/Config/FetcherConfigTest.php |
Update tests for new FetcherConfig constructor and getHttpClient() return type. |
.github/workflows/api-integration-tests.yml |
Enable allow_local_remote_servers so CI can reach local feed server under SSRF rules. |
.github/workflows/updater-test.yml |
Same as above for updater test workflow. |
CHANGELOG.md |
Add changelog entry for the HTTP client migration. |
composer.lock |
Dependency lockfile updates (league/uri, symfony/html-sanitizer, etc.). |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 16 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (1)
lib/Fetcher/FeedFetcher.php:651
downloadFavicon()now usesIClient->get(), but thetryonly catchesRequestException|ConnectException|LocalServerException. WithIClientit’s common to see other exception types (e.g. timeouts / generic\Exception) which would currently bubble up and can abort feed updates. Consider broadening this catch to\Throwable(or at least\Exception/ theOCP\Http\Clientexception types) and handling it the same way (log + return null).
try {
$client = $this->fetcherConfig->getHttpClient();
$response = $client->get(
$absoluteFaviconUrl,
[
'timeout' => 10,
'headers' => [
'Accept' => 'image/*',
'If-Modified-Since' => date(DateTime::RFC7231, $last_modified),
'Accept-Encoding' => $this->fetcherConfig->checkEncoding(),
'User-Agent' => $this->fetcherConfig->getUserAgent(),
]
]
);
$this->logger->debug(
"Feed:{feed} Logo:{logo} Status:{status}",
[
'status' => $response->getStatusCode(),
'feed' => $feed_url,
'logo' => $favicon_url
]
);
// Logo not modified, keep old url
if ($response->getStatusCode() === 304) {
return $favicon_url;
}
$body = $response->getBody();
if ($body === null || $body === '') {
return null;
}
file_put_contents($favicon_cache, $body);
if (!file_exists($favicon_cache) || filesize($favicon_cache) === 0) {
return null;
}
} catch (RequestException | ConnectException | LocalServerException $e) {
$this->logger->info(
'An error occurred while trying to download the feed logo of {url}: {error}',
[
'url' => $feed_url,
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 16 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (2)
lib/Fetcher/FeedFetcher.php:655
downloadFavicon()now uses Nextcloud'sIClient($client->get(...)), but the catch block still only handles GuzzleRequestException|ConnectExceptionplusLocalServerException. IfIClientthrows other Nextcloud client exceptions (or any non-Guzzle\Throwable), this method will now bubble the error up and potentially break feed fetching. Consider broadening this to catch\Throwable(or the relevantOCP\Http\Client\*exception types) and keep the existing log+nullbehavior.
} catch (RequestException | ConnectException | LocalServerException $e) {
$this->logger->info(
'An error occurred while trying to download the feed logo of {url}: {error}',
[
'url' => $feed_url,
'error' => $e->getMessage() ?? 'Unknown'
]
);
return null;
lib/Config/FetcherConfig.php:54
FetcherConfig::DEFAULT_USER_AGENTis now unused (thegetUserAgent()implementation always builds'NextCloud-News/' . $this->version). If no longer needed, consider removing the constant (or using it as a fallback if an empty/unknown version is possible) to avoid dead code.
/**
* User agent for the client.
* @var string
*/
const DEFAULT_USER_AGENT = 'NextCloud-News/1.0';
…aper classes - Updated FaviconDataAccess to use OCP\Http\Client\IClientService for fetching URLs and headers, improving error handling with logging. - Refactored FeedFetcher to utilize IClient for HEAD and GET requests, resolving favicon URLs correctly and enhancing error handling. - Modified Scraper to leverage IClientService for HTTP requests, implementing SSRF protection and handling redirects effectively. - Introduced a new PSR-18 adapter for Nextcloud's IClient, allowing compatibility with PSR-18 libraries. - Added unit tests for FaviconDataAccess to ensure correct behavior for URL retrieval and header fetching. - Updated existing tests in FeedIoClientTest and ScraperTest to accommodate changes in HTTP client implementation. Signed-off-by: Benjamin Brahmer <info@b-brahmer.de>
d24b72d to
5010e9e
Compare
Changed - Replace direct Guzzle HTTP client usage with Nextcloud's `IClientService` for SSRF protection and automatic system proxy support (#3672, #3671, #3679) Fixed - Starred view fired an endless stream of requests due to a `fetchKey` mismatch between the component and the store (#3682) Signed-off-by: Benjamin Brahmer <info@b-brahmer.de>
Summary
This puts news more in line with the other nextcloud apps
Checklist