Skip to content

Commit

Permalink
Merge pull request #10363 from nextcloud/fix/avatar/favicon-http-client
Browse files Browse the repository at this point in the history
fix(avatar): Use Nextcloud HTTP client for favicons
  • Loading branch information
ChristophWurst authored Nov 18, 2024
2 parents cb06c58 + eee2d6a commit d20c87e
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 0 deletions.
9 changes: 9 additions & 0 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
use OCA\Mail\Provider\MailProvider;
use OCA\Mail\Search\FilteringProvider;
use OCA\Mail\Service\Attachment\AttachmentService;
use OCA\Mail\Service\Avatar\FaviconDataAccess;
use OCA\Mail\Service\AvatarService;
use OCA\Mail\Service\DkimService;
use OCA\Mail\Service\DkimValidator;
Expand All @@ -64,6 +65,7 @@
use OCA\Mail\Service\Search\MailSearch;
use OCA\Mail\Service\TrustedSenderService;
use OCA\Mail\Service\UserPreferenceService;
use OCA\Mail\Vendor\Favicon\Favicon;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
Expand Down Expand Up @@ -97,6 +99,13 @@ public function register(IRegistrationContext $context): void {

return $userContainer->getUserFolder($uid);
});
$context->registerService(Favicon::class, function (ContainerInterface $c) {
$favicon = new Favicon();
$favicon->setDataAccess(
$c->get(FaviconDataAccess::class),
);
return $favicon;
});

$context->registerServiceAlias(IAvatarService::class, AvatarService::class);
$context->registerServiceAlias(IAttachmentService::class, AttachmentService::class);
Expand Down
54 changes: 54 additions & 0 deletions lib/Service/Avatar/FaviconDataAccess.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

declare(strict_types=1);
/*
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/

namespace OCA\Mail\Service\Avatar;

use Exception;
use OCA\Mail\Vendor\Favicon\DataAccess;
use OCP\Http\Client\IClientService;

class FaviconDataAccess extends DataAccess {

public function __construct(
private IClientService $clientService,
) {
}

public function retrieveUrl($url) {
$client = $this->clientService->newClient();
try {
$response = $client->get($url);
} catch (Exception $e) {
// Ignore any error, like the parent method
return false;
}
return $response->getBody();
}

public function retrieveHeader($url) {
$client = $this->clientService->newClient();
try {
$response = $client->get($url, [
'allow_redirects' => [
'max' => 1,
],
]);
} catch (Exception $e) {
// Ignore any error, like the parent method
return false;
}
// Build the data structure get_headers returns. The status reason
// and protocol are inaccurate, but the favicon lib will only extract
// the status code.
return [
0 => 'HTTP/1.1 ' . $response->getStatusCode() . ' FOO',
...array_change_key_case($response->getHeaders()),
];
}

}
80 changes: 80 additions & 0 deletions tests/Unit/Service/Avatar/FaviconDataAccessTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php

declare(strict_types=1);

/*
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/

namespace OCA\Mail\Service\Avatar;

use ChristophWurst\Nextcloud\Testing\TestCase;
use OCP\Http\Client\IClient;
use OCP\Http\Client\IClientService;
use OCP\Http\Client\IResponse;
use PHPUnit\Framework\MockObject\MockObject;

class FaviconDataAccessTest extends TestCase {

private IClientService|MockObject $clientService;
private FaviconDataAccess $dataAccess;

protected function setUp(): void {
parent::setUp();

$this->clientService = $this->createMock(IClientService::class);

$this->dataAccess = new FaviconDataAccess(
$this->clientService,
);
}

public function testRetrieveUrl() {
$client = $this->createMock(IClient::class);
$this->clientService->expects(self::once())
->method('newClient')
->willReturn($client);
$response = $this->createMock(IResponse::class);
$client->expects(self::once())
->method('get')
->with('https://localhost/favicon.ico', self::anything())
->willReturn($response);
$response->method('getBody')
->willReturn('html');

$body = $this->dataAccess->retrieveUrl('https://localhost/favicon.ico');

self::assertNotNull($body);
self::assertSame('html', $body);
}

public function testRetrieveHeader() {
$client = $this->createMock(IClient::class);
$this->clientService->expects(self::once())
->method('newClient')
->willReturn($client);
$response = $this->createMock(IResponse::class);
$client->expects(self::once())
->method('get')
->with('https://localhost/favicon.ico', self::anything())
->willReturn($response);
$response->method('getStatusCode')
->willReturn(200);
$response->method('getHeaders')
->willReturn([
'Content-Type' => 'image/png',
]);

$headers = $this->dataAccess->retrieveHeader('https://localhost/favicon.ico');

self::assertIsArray($headers);
self::assertSame(
[
0 => 'HTTP/1.1 200 FOO',
'content-type' => 'image/png',
],
$headers,
);
}
}

0 comments on commit d20c87e

Please sign in to comment.