discourse/lib/final_destination/http.rb
Ted Johansson f1a43f2319
DEV: Handle SSL errors in push notification pusher (#22771)
We're seeing unhandled errors in production when web push notifications are failing with an SSL error. This is happening for a few users, but generating a large amount of log noise due to the sheer number of notifications.

This adds handling of SSL errors in two places:

1. In FinalDestination::HTTP, this is handled the same as a timeout error, and gives a chance to recover.
2. In PushNotificationPusher. This will cause the notification to retry a number of times, and if it keeps failing, disable push notifications for the user. (Existing behaviour.)

I wanted to wrap the SSL error in e.g. WebPush::RequestError, but the gem doesn't have request error handling, so didn't want to have the freedom patch diverge from the gem as well. Instead just propagating the raw SSL error.
2023-07-25 15:01:02 +08:00

41 lines
1.2 KiB
Ruby

# frozen_string_literal: true
class FinalDestination::HTTP < Net::HTTP
def connect
original_open_timeout = @open_timeout
return super if @ipaddr
timeout_at = current_time + @open_timeout
# This iteration through addresses would normally happen in Socket#tcp
# We do it here because we're tightly controlling addresses rather than
# handing Socket#tcp a hostname
ips = FinalDestination::SSRFDetector.lookup_and_filter_ips(@address, timeout: @connect_timeout)
ips.each_with_index do |ip, index|
debug "[FinalDestination] Attempting connection to #{ip}..."
self.ipaddr = ip
remaining_time = timeout_at - current_time
if remaining_time <= 0
raise Net::OpenTimeout.new("Operation timed out - FinalDestination::HTTP")
end
@open_timeout = remaining_time
return super
rescue OpenSSL::SSL::SSLError, SystemCallError, Net::OpenTimeout => e
debug "[FinalDestination] Error connecting to #{ip}... #{e.message}"
was_last_attempt = index == ips.length - 1
raise if was_last_attempt
end
ensure
@open_timeout = original_open_timeout
end
private
def current_time
Process.clock_gettime(Process::CLOCK_MONOTONIC)
end
end