From 9973f731dfb0b34ae4c1d3d86143eee346ff5641 Mon Sep 17 00:00:00 2001 From: Dag <me@dvikan.no> Date: Thu, 8 Aug 2024 02:13:04 +0200 Subject: [PATCH] feat: introduce RateLimitException (#4199) --- actions/DisplayAction.php | 8 ++++++-- bridges/RedditBridge.php | 6 ++++-- bridges/Vk2Bridge.php | 2 +- bridges/VkBridge.php | 2 +- bridges/YoutubeBridge.php | 3 ++- lib/http.php | 10 ++++++++++ 6 files changed, 24 insertions(+), 7 deletions(-) diff --git a/actions/DisplayAction.php b/actions/DisplayAction.php index c51bb7cd..55f0d2fd 100644 --- a/actions/DisplayAction.php +++ b/actions/DisplayAction.php @@ -121,8 +121,12 @@ class DisplayAction implements ActionInterface $items = $feedItems; } $feed = $bridge->getFeed(); - } catch (\Exception $e) { - // Probably an exception inside a bridge + } catch (\Throwable $e) { + if ($e instanceof RateLimitException) { + // These are internally generated by bridges + $this->logger->info(sprintf('RateLimitException in DisplayAction(%s): %s', $bridge->getShortName(), create_sane_exception_message($e))); + return new Response(render(__DIR__ . '/../templates/exception.html.php', ['e' => $e]), 429); + } if ($e instanceof HttpException) { // Reproduce (and log) these responses regardless of error output and report limit if ($e->getCode() === 429) { diff --git a/bridges/RedditBridge.php b/bridges/RedditBridge.php index ef74fdcd..03f279d8 100644 --- a/bridges/RedditBridge.php +++ b/bridges/RedditBridge.php @@ -93,12 +93,12 @@ class RedditBridge extends BridgeAbstract { $forbiddenKey = 'reddit_forbidden'; if ($this->cache->get($forbiddenKey)) { - throw new HttpException('403 Forbidden', 403); + throw new RateLimitException(); } $rateLimitKey = 'reddit_rate_limit'; if ($this->cache->get($rateLimitKey)) { - throw new HttpException('429 Too Many Requests', 429); + throw new RateLimitException(); } try { @@ -108,8 +108,10 @@ class RedditBridge extends BridgeAbstract // 403 Forbidden // This can possibly mean that reddit has permanently blocked this server's ip address $this->cache->set($forbiddenKey, true, 60 * 61); + throw new RateLimitException(); } elseif ($e->getCode() === 429) { $this->cache->set($rateLimitKey, true, 60 * 61); + throw new RateLimitException(); } throw $e; } diff --git a/bridges/Vk2Bridge.php b/bridges/Vk2Bridge.php index 6fecba84..62ba8e05 100644 --- a/bridges/Vk2Bridge.php +++ b/bridges/Vk2Bridge.php @@ -194,7 +194,7 @@ class Vk2Bridge extends BridgeAbstract public function collectData() { if ($this->cache->get($this->rateLimitCacheKey)) { - throw new HttpException('429 Too Many Requests', 429); + throw new RateLimitException(); } $u = $this->getInput('u'); diff --git a/bridges/VkBridge.php b/bridges/VkBridge.php index 22957f26..0d62305b 100644 --- a/bridges/VkBridge.php +++ b/bridges/VkBridge.php @@ -519,7 +519,7 @@ class VkBridge extends BridgeAbstract $uri = urljoin(self::URI, $headers['location'][0]); if (str_contains($uri, '/429.html')) { - returnServerError('VK responded "Too many requests"'); + throw new RateLimitException(); } if (!preg_match('#^https?://vk.com/#', $uri)) { diff --git a/bridges/YoutubeBridge.php b/bridges/YoutubeBridge.php index af14c856..647b1c42 100644 --- a/bridges/YoutubeBridge.php +++ b/bridges/YoutubeBridge.php @@ -82,13 +82,14 @@ class YoutubeBridge extends BridgeAbstract { $cacheKey = 'youtube_rate_limit'; if ($this->cache->get($cacheKey)) { - throw new HttpException('429 Too Many Requests', 429); + throw new RateLimitException(); } try { $this->collectDataInternal(); } catch (HttpException $e) { if ($e->getCode() === 429) { $this->cache->set($cacheKey, true, 60 * 16); + throw new RateLimitException(); } throw $e; } diff --git a/lib/http.php b/lib/http.php index 39f0c727..0d21b958 100644 --- a/lib/http.php +++ b/lib/http.php @@ -1,5 +1,15 @@ <?php +/** + * Thrown by bridges + */ +final class RateLimitException extends \Exception +{ +} + +/** + * @internal Do not use this class in bridges + */ class HttpException extends \Exception { public ?Response $response;