Skip to content

Change: Use IClientService instead of straight Guzzle Client#3672

Merged
Grotax merged 2 commits into
masterfrom
fix/feedio/use_iclientservice
Apr 25, 2026
Merged

Change: Use IClientService instead of straight Guzzle Client#3672
Grotax merged 2 commits into
masterfrom
fix/feedio/use_iclientservice

Conversation

@SMillerDev
Copy link
Copy Markdown
Contributor

Summary

This puts news more in line with the other nextcloud apps

Checklist

@SMillerDev
Copy link
Copy Markdown
Contributor Author

This isn't actually possible because the two aren't compatible.

@Grotax
Copy link
Copy Markdown
Member

Grotax commented Apr 12, 2026

nextcloud/server#59530

@kesselb
Copy link
Copy Markdown
Contributor

kesselb commented Apr 24, 2026

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
Copy link
Copy Markdown

codecov Bot commented Apr 25, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@Grotax Grotax force-pushed the fix/feedio/use_iclientservice branch 3 times, most recently from 2b3462c to 484a0d8 Compare April 25, 2026 08:20
Sign-off-by: Sean Molenaar <SMillerDev@users.noreply.github.com>
Signed-off-by: Benjamin Brahmer <info@b-brahmer.de>
@Grotax Grotax force-pushed the fix/feedio/use_iclientservice branch from 484a0d8 to 034e097 Compare April 25, 2026 08:24
@Grotax
Copy link
Copy Markdown
Member

Grotax commented Apr 25, 2026

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?

Comment thread lib/Fetcher/FaviconDataAccess.php
Comment thread lib/Fetcher/FeedFetcher.php Outdated
Comment thread lib/Http/Client.php
Comment thread lib/Http/Client.php
Comment thread lib/Http/Client.php Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 bridge IClient into 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.).

Comment thread lib/Config/FetcherConfig.php
Comment thread lib/Config/FetcherConfig.php
Comment thread lib/Config/FetcherConfig.php
Comment thread lib/Fetcher/FaviconDataAccess.php
Comment thread tests/Unit/Scraper/ScraperTest.php Outdated
Comment thread lib/Scraper/Scraper.php Outdated
Comment thread lib/Scraper/Scraper.php
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 15 changed files in this pull request and generated 4 comments.

Comment thread lib/Config/FetcherConfig.php
Comment thread lib/Scraper/Scraper.php
Comment thread tests/Unit/Scraper/ScraperTest.php
Comment thread lib/Fetcher/FeedFetcher.php Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 15 changed files in this pull request and generated 4 comments.

Comment thread lib/Http/Client.php
Comment thread lib/Fetcher/Client/FeedIoClient.php
Comment thread lib/Scraper/Scraper.php Outdated
Comment thread lib/Http/Client.php
Comment thread lib/Fetcher/FaviconDataAccess.php Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 15 changed files in this pull request and generated 1 comment.

Comment thread lib/Fetcher/FeedFetcher.php Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 uses IClient->get(), but the try only catches RequestException|ConnectException|LocalServerException. With IClient it’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 / the OCP\Http\Client exception 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,

Comment thread lib/Config/FetcherConfig.php Outdated
Comment thread tests/Unit/Scraper/ScraperTest.php
Comment thread tests/Unit/Fetcher/FaviconDataAccessTest.php Outdated
Comment thread lib/Fetcher/Client/FeedIoClient.php
@Grotax Grotax changed the title fix: use IClientService instead of straight Guzzle Client Change: Use IClientService instead of straight Guzzle Client Apr 25, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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's IClient ($client->get(...)), but the catch block still only handles Guzzle RequestException|ConnectException plus LocalServerException. If IClient throws 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 relevant OCP\Http\Client\* exception types) and keep the existing log+null behavior.
        } 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_AGENT is now unused (the getUserAgent() 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';

Comment thread lib/Fetcher/FeedFetcher.php
Comment thread lib/Fetcher/Client/FeedIoClient.php
…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>
@Grotax Grotax force-pushed the fix/feedio/use_iclientservice branch from d24b72d to 5010e9e Compare April 25, 2026 14:44
@Grotax Grotax merged commit a1b545b into master Apr 25, 2026
28 checks passed
@Grotax Grotax deleted the fix/feedio/use_iclientservice branch April 25, 2026 14:47
@Grotax Grotax mentioned this pull request Apr 25, 2026
Grotax added a commit that referenced this pull request Apr 25, 2026
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>
@nextcloud nextcloud deleted a comment from BaniMontoya May 1, 2026
@nextcloud nextcloud locked and limited conversation to collaborators May 1, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants