From 765e39d6228b18e6244efe26cdd9b0d1db860aa9 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 21 May 2024 11:12:18 -0400 Subject: [PATCH 1/2] Wrap common http-level errors into constant --- app/controllers/application_controller.rb | 2 +- app/controllers/concerns/api/error_handling.rb | 8 ++++---- app/controllers/concerns/signature_verification.rb | 4 ++-- app/controllers/media_proxy_controller.rb | 2 +- app/lib/activitypub/activity/create.rb | 2 +- app/models/account_alias.rb | 2 +- app/models/account_migration.rb | 2 +- app/models/concerns/remotable.rb | 2 +- app/models/form/redirect.rb | 2 +- app/models/remote_follow.rb | 2 +- app/services/activitypub/process_account_service.rb | 6 +++--- .../activitypub/process_status_update_service.rb | 2 +- app/services/fetch_link_card_service.rb | 2 +- app/services/fetch_resource_service.rb | 2 +- app/services/import_service.rb | 2 +- app/services/keys/claim_service.rb | 2 +- app/services/keys/query_service.rb | 2 +- app/services/process_mentions_service.rb | 2 +- app/services/software_update_check_service.rb | 2 +- app/services/verify_link_service.rb | 2 +- app/workers/refollow_worker.rb | 2 +- lib/exceptions.rb | 13 +++++++++++++ lib/mastodon/cli/accounts.rb | 2 +- 23 files changed, 41 insertions(+), 28 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 66e0f7e3051..adb3e450b64 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -33,7 +33,7 @@ class ApplicationController < ActionController::Base rescue_from ActionController::InvalidAuthenticityToken, with: :unprocessable_entity rescue_from Mastodon::RateLimitExceededError, with: :too_many_requests - rescue_from HTTP::Error, OpenSSL::SSL::SSLError, with: :internal_server_error + rescue_from(*Mastodon::HTTP_CONNECTION_ERRORS, with: :internal_server_error) rescue_from Mastodon::RaceConditionError, Stoplight::Error::RedLight, ActiveRecord::SerializationFailure, with: :service_unavailable rescue_from Seahorse::Client::NetworkingError do |e| diff --git a/app/controllers/concerns/api/error_handling.rb b/app/controllers/concerns/api/error_handling.rb index ad559fe2d71..8d9e6ce60f1 100644 --- a/app/controllers/concerns/api/error_handling.rb +++ b/app/controllers/concerns/api/error_handling.rb @@ -20,14 +20,14 @@ module Api::ErrorHandling render json: { error: 'Record not found' }, status: 404 end - rescue_from HTTP::Error, Mastodon::UnexpectedResponseError do - render json: { error: 'Remote data could not be fetched' }, status: 503 - end - rescue_from OpenSSL::SSL::SSLError do render json: { error: 'Remote SSL certificate could not be verified' }, status: 503 end + rescue_from(*Mastodon::HTTP_CONNECTION_ERRORS) do + render json: { error: 'Remote data could not be fetched' }, status: 503 + end + rescue_from Mastodon::NotPermittedError do render json: { error: 'This action is not allowed' }, status: 403 end diff --git a/app/controllers/concerns/signature_verification.rb b/app/controllers/concerns/signature_verification.rb index 68f09ee0238..b053e772acf 100644 --- a/app/controllers/concerns/signature_verification.rb +++ b/app/controllers/concerns/signature_verification.rb @@ -80,12 +80,12 @@ module SignatureVerification fail_with! "Verification failed for #{actor.to_log_human_identifier} #{actor.uri} using rsa-sha256 (RSASSA-PKCS1-v1_5 with SHA-256)", signed_string: compare_signed_string, signature: signature_params['signature'] rescue SignatureVerificationError => e fail_with! e.message - rescue HTTP::Error, OpenSSL::SSL::SSLError => e - fail_with! "Failed to fetch remote data: #{e.message}" rescue Mastodon::UnexpectedResponseError fail_with! 'Failed to fetch remote data (got unexpected reply from server)' rescue Stoplight::Error::RedLight fail_with! 'Fetching attempt skipped because of recent connection failure' + rescue *Mastodon::HTTP_CONNECTION_ERRORS => e + fail_with! "Failed to fetch remote data: #{e.message}" end def request_body diff --git a/app/controllers/media_proxy_controller.rb b/app/controllers/media_proxy_controller.rb index c4230d62c38..f68d85e44e2 100644 --- a/app/controllers/media_proxy_controller.rb +++ b/app/controllers/media_proxy_controller.rb @@ -13,7 +13,7 @@ class MediaProxyController < ApplicationController rescue_from ActiveRecord::RecordInvalid, with: :not_found rescue_from Mastodon::UnexpectedResponseError, with: :not_found rescue_from Mastodon::NotPermittedError, with: :not_found - rescue_from HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError, with: :internal_server_error + rescue_from(*Mastodon::HTTP_CONNECTION_ERRORS, with: :internal_server_error) def show with_redis_lock("media_download:#{params[:id]}") do diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb index 5d700b49613..4e56a684dc2 100644 --- a/app/lib/activitypub/activity/create.rb +++ b/app/lib/activitypub/activity/create.rb @@ -279,7 +279,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity media_attachment.download_file! media_attachment.download_thumbnail! media_attachment.save - rescue Mastodon::UnexpectedResponseError, HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError + rescue *Mastodon::HTTP_CONNECTION_ERRORS RedownloadMediaWorker.perform_in(rand(30..600).seconds, media_attachment.id) rescue Seahorse::Client::NetworkingError => e Rails.logger.warn "Error storing media attachment: #{e}" diff --git a/app/models/account_alias.rb b/app/models/account_alias.rb index 3b75919afe2..09001351698 100644 --- a/app/models/account_alias.rb +++ b/app/models/account_alias.rb @@ -35,7 +35,7 @@ class AccountAlias < ApplicationRecord def set_uri target_account = ResolveAccountService.new.call(acct) self.uri = ActivityPub::TagManager.instance.uri_for(target_account) unless target_account.nil? - rescue Webfinger::Error, HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::Error + rescue Webfinger::Error, *Mastodon::HTTP_CONNECTION_ERRORS # Validation will take care of it end diff --git a/app/models/account_migration.rb b/app/models/account_migration.rb index dc22e329421..cf611e8c550 100644 --- a/app/models/account_migration.rb +++ b/app/models/account_migration.rb @@ -57,7 +57,7 @@ class AccountMigration < ApplicationRecord def set_target_account self.target_account = ResolveAccountService.new.call(acct, skip_cache: true) - rescue Webfinger::Error, HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::Error, Addressable::URI::InvalidURIError + rescue Webfinger::Error, Mastodon::Error, *Mastodon::HTTP_CONNECTION_ERRORS # Validation will take care of it end diff --git a/app/models/concerns/remotable.rb b/app/models/concerns/remotable.rb index 8382c915996..4e986640a63 100644 --- a/app/models/concerns/remotable.rb +++ b/app/models/concerns/remotable.rb @@ -26,7 +26,7 @@ module Remotable public_send(:"#{attachment_name}=", ResponseWithLimit.new(response, limit)) end - rescue Mastodon::UnexpectedResponseError, HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError => e + rescue *Mastodon::HTTP_CONNECTION_ERRORS => e Rails.logger.debug { "Error fetching remote #{attachment_name}: #{e}" } public_send(:"#{attachment_name}=", nil) if public_send(:"#{attachment_name}_file_name").present? raise e unless suppress_errors diff --git a/app/models/form/redirect.rb b/app/models/form/redirect.rb index 3cd5731e6d6..e37d6b809a0 100644 --- a/app/models/form/redirect.rb +++ b/app/models/form/redirect.rb @@ -32,7 +32,7 @@ class Form::Redirect def set_target_account @target_account = ResolveAccountService.new.call(acct, skip_cache: true) - rescue Webfinger::Error, HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::Error, Addressable::URI::InvalidURIError + rescue Webfinger::Error, Mastodon::Error, *Mastodon::HTTP_CONNECTION_ERRORS # Validation will take care of it end diff --git a/app/models/remote_follow.rb b/app/models/remote_follow.rb index 10715ac97da..dbafe46e900 100644 --- a/app/models/remote_follow.rb +++ b/app/models/remote_follow.rb @@ -67,7 +67,7 @@ class RemoteFollow def acct_resource @acct_resource ||= webfinger!("acct:#{acct}") - rescue Webfinger::Error, HTTP::ConnectionError + rescue Webfinger::Error, *Mastodon::HTTP_CONNECTION_ERRORS nil end diff --git a/app/services/activitypub/process_account_service.rb b/app/services/activitypub/process_account_service.rb index b667e97f4d8..7c1e9621bdf 100644 --- a/app/services/activitypub/process_account_service.rb +++ b/app/services/activitypub/process_account_service.rb @@ -127,13 +127,13 @@ class ActivityPub::ProcessAccountService < BaseService begin @account.avatar_remote_url = image_url('icon') || '' unless skip_download? @account.avatar = nil if @account.avatar_remote_url.blank? - rescue Mastodon::UnexpectedResponseError, HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError + rescue *Mastodon::HTTP_CONNECTION_ERRORS RedownloadAvatarWorker.perform_in(rand(30..600).seconds, @account.id) end begin @account.header_remote_url = image_url('image') || '' unless skip_download? @account.header = nil if @account.header_remote_url.blank? - rescue Mastodon::UnexpectedResponseError, HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError + rescue *Mastodon::HTTP_CONNECTION_ERRORS RedownloadHeaderWorker.perform_in(rand(30..600).seconds, @account.id) end @account.statuses_count = outbox_total_items if outbox_total_items.present? @@ -276,7 +276,7 @@ class ActivityPub::ProcessAccountService < BaseService total_items = collection.is_a?(Hash) && collection['totalItems'].present? && collection['totalItems'].is_a?(Numeric) ? collection['totalItems'] : nil has_first_page = collection.is_a?(Hash) && collection['first'].present? @collections[type] = [total_items, has_first_page] - rescue HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::LengthValidationError + rescue *Mastodon::HTTP_CONNECTION_ERRORS @collections[type] = [nil, nil] end diff --git a/app/services/activitypub/process_status_update_service.rb b/app/services/activitypub/process_status_update_service.rb index 1dbed27f28d..29c243e4c9d 100644 --- a/app/services/activitypub/process_status_update_service.rb +++ b/app/services/activitypub/process_status_update_service.rb @@ -109,7 +109,7 @@ class ActivityPub::ProcessStatusUpdateService < BaseService media_attachment.download_file! if media_attachment.remote_url_previously_changed? media_attachment.download_thumbnail! if media_attachment.thumbnail_remote_url_previously_changed? media_attachment.save - rescue Mastodon::UnexpectedResponseError, HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError + rescue *Mastodon::HTTP_CONNECTION_ERRORS RedownloadMediaWorker.perform_in(rand(30..600).seconds, media_attachment.id) rescue Seahorse::Client::NetworkingError => e Rails.logger.warn "Error storing media attachment: #{e}" diff --git a/app/services/fetch_link_card_service.rb b/app/services/fetch_link_card_service.rb index adabb1096e8..5a42c6c8f77 100644 --- a/app/services/fetch_link_card_service.rb +++ b/app/services/fetch_link_card_service.rb @@ -29,7 +29,7 @@ class FetchLinkCardService < BaseService end attach_card if @card&.persisted? - rescue HTTP::Error, OpenSSL::SSL::SSLError, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError, EncodingError, ActiveRecord::RecordInvalid => e + rescue *Mastodon::HTTP_CONNECTION_ERRORS, EncodingError, ActiveRecord::RecordInvalid => e Rails.logger.debug { "Error fetching link #{@original_url}: #{e}" } nil end diff --git a/app/services/fetch_resource_service.rb b/app/services/fetch_resource_service.rb index 84c36f6a101..5f812c9060f 100644 --- a/app/services/fetch_resource_service.rb +++ b/app/services/fetch_resource_service.rb @@ -12,7 +12,7 @@ class FetchResourceService < BaseService return if url.blank? process(url) - rescue HTTP::Error, OpenSSL::SSL::SSLError, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError => e + rescue *Mastodon::HTTP_CONNECTION_ERRORS => e Rails.logger.debug { "Error fetching resource #{@url}: #{e}" } nil end diff --git a/app/services/import_service.rb b/app/services/import_service.rb index 6dafb5a0bb1..365c5f6ab31 100644 --- a/app/services/import_service.rb +++ b/app/services/import_service.rb @@ -115,7 +115,7 @@ class ImportService < BaseService next if status.nil? && ActivityPub::TagManager.instance.local_uri?(uri) status || ActivityPub::FetchRemoteStatusService.new.call(uri) - rescue HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::UnexpectedResponseError + rescue *Mastodon::HTTP_CONNECTION_ERRORS nil rescue => e Rails.logger.warn "Unexpected error when importing bookmark: #{e}" diff --git a/app/services/keys/claim_service.rb b/app/services/keys/claim_service.rb index ebce9cce7d8..bd6d6917722 100644 --- a/app/services/keys/claim_service.rb +++ b/app/services/keys/claim_service.rb @@ -57,7 +57,7 @@ class Keys::ClaimService < BaseService return unless json.present? && json['publicKeyBase64'].present? @result = Result.new(@target_account, @device_id, key_id: json['id'], key: json['publicKeyBase64'], signature: json.dig('signature', 'signatureValue')) - rescue HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::Error => e + rescue *Mastodon::HTTP_CONNECTION_ERRORS, Mastodon::Error => e Rails.logger.debug { "Claiming one-time key for #{@target_account.acct}:#{@device_id} failed: #{e}" } nil end diff --git a/app/services/keys/query_service.rb b/app/services/keys/query_service.rb index 33e13293f31..fc57dcee892 100644 --- a/app/services/keys/query_service.rb +++ b/app/services/keys/query_service.rb @@ -72,7 +72,7 @@ class Keys::QueryService < BaseService @devices = as_array(json['items']).map do |device| Device.new(device_id: device['id'], name: device['name'], identity_key: device.dig('identityKey', 'publicKeyBase64'), fingerprint_key: device.dig('fingerprintKey', 'publicKeyBase64'), claim_url: device['claim']) end - rescue HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::Error => e + rescue *Mastodon::HTTP_CONNECTION_ERRORS, Mastodon::Error => e Rails.logger.debug { "Querying devices for #{@account.acct} failed: #{e}" } nil end diff --git a/app/services/process_mentions_service.rb b/app/services/process_mentions_service.rb index 1c4c7805f14..b73c462f2b9 100644 --- a/app/services/process_mentions_service.rb +++ b/app/services/process_mentions_service.rb @@ -44,7 +44,7 @@ class ProcessMentionsService < BaseService if mention_undeliverable?(mentioned_account) begin mentioned_account = ResolveAccountService.new.call(Regexp.last_match(1)) - rescue Webfinger::Error, HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::UnexpectedResponseError + rescue Webfinger::Error, *Mastodon::HTTP_CONNECTION_ERRORS mentioned_account = nil end end diff --git a/app/services/software_update_check_service.rb b/app/services/software_update_check_service.rb index c8ce1753f5f..24a6955b885 100644 --- a/app/services/software_update_check_service.rb +++ b/app/services/software_update_check_service.rb @@ -22,7 +22,7 @@ class SoftwareUpdateCheckService < BaseService Request.new(:get, "#{api_url}?version=#{version}").add_headers('Accept' => 'application/json', 'User-Agent' => 'Mastodon update checker').perform do |res| return Oj.load(res.body_with_limit, mode: :strict) if res.code == 200 end - rescue HTTP::Error, OpenSSL::SSL::SSLError, Oj::ParseError + rescue *Mastodon::HTTP_CONNECTION_ERRORS, Oj::ParseError nil end diff --git a/app/services/verify_link_service.rb b/app/services/verify_link_service.rb index b317fc31a85..562a0c4d0ee 100644 --- a/app/services/verify_link_service.rb +++ b/app/services/verify_link_service.rb @@ -10,7 +10,7 @@ class VerifyLinkService < BaseService return unless link_back_present? field.mark_verified! - rescue OpenSSL::SSL::SSLError, HTTP::Error, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError, IPAddr::AddressFamilyError => e + rescue *Mastodon::HTTP_CONNECTION_ERRORS => e Rails.logger.debug { "Error fetching link #{@url}: #{e}" } nil end diff --git a/app/workers/refollow_worker.rb b/app/workers/refollow_worker.rb index 4b712d3aaeb..863be955707 100644 --- a/app/workers/refollow_worker.rb +++ b/app/workers/refollow_worker.rb @@ -21,7 +21,7 @@ class RefollowWorker # Schedule re-follow begin FollowService.new.call(follower, target_account, reblogs: reblogs, notify: notify, languages: languages, bypass_limit: true) - rescue Mastodon::NotPermittedError, ActiveRecord::RecordNotFound, Mastodon::UnexpectedResponseError, HTTP::Error, OpenSSL::SSL::SSLError + rescue Mastodon::NotPermittedError, ActiveRecord::RecordNotFound, *Mastodon::HTTP_CONNECTION_ERRORS next end end diff --git a/lib/exceptions.rb b/lib/exceptions.rb index d3b92f4a093..7cbcdbc35b1 100644 --- a/lib/exceptions.rb +++ b/lib/exceptions.rb @@ -35,4 +35,17 @@ module Mastodon super() end end + + HTTP_CONNECTION_ERRORS = [ + Addressable::URI::InvalidURIError, + HTTP::ConnectionError, + HTTP::Error, + HTTP::TimeoutError, + IPAddr::AddressFamilyError, + Mastodon::HostValidationError, + Mastodon::LengthValidationError, + Mastodon::PrivateNetworkAddressError, + Mastodon::UnexpectedResponseError, + OpenSSL::SSL::SSLError, + ].freeze end diff --git a/lib/mastodon/cli/accounts.rb b/lib/mastodon/cli/accounts.rb index d3b7ebe5805..fa1236e961b 100644 --- a/lib/mastodon/cli/accounts.rb +++ b/lib/mastodon/cli/accounts.rb @@ -305,7 +305,7 @@ module Mastodon::CLI begin code = Request.new(:head, account.uri).perform(&:code) - rescue HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError, Mastodon::PrivateNetworkAddressError + rescue *Mastodon::HTTP_CONNECTION_ERRORS skip_domains << account.domain end From ba4c8a5f33d52f5a9c1045eb879a65e73cb54458 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 21 May 2024 11:19:15 -0400 Subject: [PATCH 2/2] Dont need module namespace --- lib/exceptions.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/exceptions.rb b/lib/exceptions.rb index 7cbcdbc35b1..1709157f0d1 100644 --- a/lib/exceptions.rb +++ b/lib/exceptions.rb @@ -38,14 +38,14 @@ module Mastodon HTTP_CONNECTION_ERRORS = [ Addressable::URI::InvalidURIError, + HostValidationError, HTTP::ConnectionError, HTTP::Error, HTTP::TimeoutError, IPAddr::AddressFamilyError, - Mastodon::HostValidationError, - Mastodon::LengthValidationError, - Mastodon::PrivateNetworkAddressError, - Mastodon::UnexpectedResponseError, + LengthValidationError, OpenSSL::SSL::SSLError, + PrivateNetworkAddressError, + UnexpectedResponseError, ].freeze end