Search code examples
ruby-on-railsrubynet-http

Ruby 2.3/Rails - net uri not working anymore after update to Ubuntu 16.04


I used to have a working code in my Admin Panel , checking if a url inputed existed and giving a friendly message to the Administrator in case it did not..

def get_url_response(url)
    uri = URI(url)
    request = Net::HTTP.get_response(uri)
    return request
end

url_response = get_url_response("http://www.example.com").code
    if  url_response === "200" || url_response === "304"
       link_to http://www.example.com, http://www.example.com, target: :blank
    else                                                          
        status_tag("We have a problem ! Response code: "+url_response, :class => 'red')  
    end

It works great when the address ("http://www.example.com" in the example above) exists, that it to say sends back a 200 code, but as soon as I have a non existing address such as http://www.examplenotexistingotallyfake.com, it should send a 404 code and display ""We have a problem ! Response code:" but it fails with the error message:

SocketError: Failed to open TCP connection to examplenotexistingotallyfake.com:443 (getaddrinfo: Name or service not known)
from /home/mreisner/.rvm/rubies/ruby-2.3.1/lib/ruby/2.3.0/net/http.rb:882:in `rescue in block in connect'

I verified this by opening my Rails console (Rails c) and if I type:

 Net::HTTP.get(URI('https://www.examplenotexistingotallyfake.com')).code

I get the same error message:

 SocketError: Failed to open TCP connection to examplenotexistingotallyfake.com:443 (getaddrinfo: Name or service not known)
from /home/mreisner/.rvm/rubies/ruby-2.3.1/lib/ruby/2.3.0/net/http.rb:882:in `rescue in block in connect'

How can it work for correct urls and not for non-existing addreses? it should just work but send me back a 404 code, shouldn't it?

I can only see the upgrade to Ubutun 16.04 i made a few days ago, that might have tampered with some critical dns/localhost settings as the source of this issue but not 100% totally sure.

EDIT

After some suggestions, I now try to avoid the app crashing by rescuing this

def get_url_response(url)       
    begin
        uri = URI(url)
          request = Net::HTTP.get_response(uri)
          return request

        rescue SocketError => e
        puts "Got socket error: #{e}"
        end

  end

but the app still crashes with a socket Error message


Solution

  • That's the correct behaviour.

    The problem there is that examplenotexistingotallyfake.com doesn't exists in the DNSs entries.

    If you look at the description of what the 404: https://en.wikipedia.org/wiki/HTTP_404

    to indicate that the client was able to communicate with a given server, but the server could not find what was requested.

    So, in order to get the 404 code you'll need first to be able to communicate with the server in question.

    You can double check this behaviour using chrome or even curl, visiting the following urls: examplenotexistingotallyfake.com or google.com/missing

    Each will give a different result.

    in curl:

    $ curl -I examplenotexistingotallyfake.com
    curl: (6) Could not resolve host: examplenotexistingotallyfake.com
    
    # google
    curl -I google.com/missing
    HTTP/1.1 404 Not Found
    Content-Type: text/html; charset=UTF-8
    Referrer-Policy: no-referrer
    Content-Length: 1568
    Date: Fri, 12 Jan 2018 09:25:27 GMT
    

    If you want your code to behave in the same way (even though I'd suggest that give the user a different message, you can do the following):

    require 'uri'
    require 'net/http'
    require 'ostruct'
    
    def get_url_response(url)
      uri = URI(url)
      request = Net::HTTP.get_response(uri)
      return request
    rescue Errno::ECONNREFUSED => e
      OpenStruct.new(code: 404)
    end