It should have something like
    
    RequestError = Class.new(StandardError)
    BadUrl = Class.new(RequestError)  
    def url_to_uri(url)
      begin
        uri = URI.parse(url)
      rescue URI::InvalidURIError, SocketError => e
        raise BadUrl.new(e)
      end
    end
    uri = url_to_uri(response['location'])
    path = uri.path # or uri.request_uri to include the query
    host = uri.host

though this won't handle meta content refresh

I would separate out the actual connection.request code to avoid too much recursion

As an aside, I see you're not handling all the Net:HTTP errors

    HTTP_ERRORS = [Timeout::Error, Errno::EINVAL, Errno::ECONNRESET,
       Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError]

I have elsewhere done something like

    BadResponse = Class.new(RequestError)
    BasicResponse = Struct.new('BasicResponse', :url, :code)
    def get_response(url)
      uri = url_to_uri(url)
      Net::HTTP.get_response(uri)
    rescue EOFError => e
      BasicResponse.new(url, '200')
    rescue *HTTP_ERRORS => e
      log url.inspect + e.inspect
      raise BadResponse.new(e)
    end

Also, why VERIFY_NONE ?