I have partial solution for this issue:
Check the external file headers. The app is sending a header request to the external server.
1.1 If the status is 200 (success), then the app starts the retrieve process as before.
1.2 If the status is any other value, then an error page is displayed with the appropriate error message.
And the code looks like this:
uri = URI.parse(link)
net_http = Net::HTTP.new(uri.host, uri.port)
net_http.open_timeout = options[:timeout]
net_http.read_timeout = options[:timeout]
net_http.use_ssl = (uri.scheme == 'https')
if net_http.use_ssl?
net_http.cert = OpenSSL::X509::Certificate.new(File.read(options[:cert]))
net_http.key = OpenSSL::PKey::RSA.new(File.read(options[:cert]))
net_http.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
begin
request = Net::HTTP::Get.new(uri.request_uri)
res = net_http.request(request)
if res.code.to_i == 200
self.response.headers['Pragma'] = 'no-cache'
self.response.headers['Cache-Control'] = 'private,max-age=0,must-revalidate,no-store'
self.response.headers['Last-Modified'] = Time.now.ctime.to_s
self.response.headers['Accept-Ranges'] = 'bytes'
self.response.headers['Content-Type'] = type
self.response.headers['Content-Disposition'] = "attachment; filename=\"#{save_as}\""
self.response.headers['Content-Transfer-Encoding'] = 'binary'
self.response.headers['Content-Description'] = 'File Transfer'
self.response.headers['Content-Length'] = "#{filesize}"
self.response_body = FileStreamer.new(link, options)
else
raise "The requested file is not available at the moment"
end
rescue SocketError => se
raise 'It seems the URL is not correct'
rescue Errno::ECONNREFUSED => cr
raise 'It seems the server refused the connection request'
rescue Errno::EHOSTUNREACH => hu
raise 'It seems the server cannot be reached'
rescue Errno::ENETUNREACH => nu
raise 'It seems the network cannot be reached'
rescue Timeout::Error => te
raise 'Request timed out while connecting to the server'
rescue StandardError => e
raise e.message
end
The FileStreamer is a rack middleware which response to each method.
def each
begin
@net_http.start do |http|
http.request_get(@uri.request_uri(),
{'User-Agent' => 'FileStreamer'}) do |response|
case response
when Net::HTTPSuccess then
response.read_body do |segment|
yield segment
end
when Net::HTTPRedirection then
raise 'Redirection not allowed'
else
raise "Error trying to retrieve a file:\n" \
" URL: #{@uri.to_s}\n" \
" Error: #{response.message.to_s}"
end
end
end
rescue SocketError => se
raise 'It seems the URL is not correct'
rescue Errno::ECONNREFUSED => cr
raise 'It seems the server refused the connection request'
rescue Errno::EHOSTUNREACH => hu
raise 'It seems the server cannot be reached'
rescue Errno::ENETUNREACH => nu
raise 'It seems the network cannot be reached'
rescue Timeout::Error => te
raise 'Request timed out while connecting to the server'
rescue StandardError => e
raise e.message
end
end
Keep in mind this solution is not including errors happening in the middle of the process, I guess if an error happens in the middle, then the app will display the ugly error page.