Rails HTTP Ping to unreliable Target - ruby-on-rails

I would like to send an HTTP GET request to an ip address and port to determine if there is a device online that can respond at that address.
I want to have a relatively reasonable timeout so that my application does not hang while connecting, if there's no. I have been using Net::HTTP, but there does not seem to be a way to set a timeout when using an ip address.
res = Net::HTTP.get_response(ip_address, '/index.html', port)
Is there a best practice or better method to perform this request or a way to set a timeout in Net::HTTP when using an ip address rather than domain name?
I'm using Ruby 2.1.5 and Rails 4.1.0 with hosting on Heroku.

You can see about HTTParty gem. This gem provide many options and easy to use.
You set timeout for the request to return the response
response = HTTParty.get('https://www.google.co.in/', timeout: 60)
timeout is in seconds.
or in Net http you can set as,
uri = URI.parse(ip_address + '/index.html')
request = Net::HTTP::Get.new(uri.path)
begin
response = Net::HTTP.start(uri.host, uri.port) {|http|
http.read_timeout = 100 #Default is 60 seconds
http.request(request)
}
rescue Net::ReadTimeout => e
puts e.message
end

There's no major difference between requesting via an ip address or by dns name, in the latter case DNS query is made and usually a Host-header is set, after that request is done via the ip.
In Net::HTTP there's open_timeout setting that raises Net::OpenTimeout when set if connection cannot be established during that period. By default it's nil which means 'forever'

Not sure what you are looking for. In the Net::HTTP-class there is read_timeout-setter. See here: http://docs.ruby-lang.org/en/2.1.0/Net/HTTP.html#method-i-read_timeout-3D

Related

In ruby/rails, can you differentiate between no network response vs long-running response?

We have a Rails app with an integration with box.com. It happens fairly frequently that a request for a box action to our app results in a Passenger process being tied up for right around 15 minutes, and then we get the following exception:
Errno::ETIMEDOUT: Connection timed out - SSL_connect
Often it's on something that should be fairly quick, such as listing the contents of a small folder, or deleting a single document.
I'm under the impression that these requests never actually got to an open channel, that either at the tcp or ssl levels we got no initial response, or the full handshake/session-setup never completed.
I'd like to get either such condition to timeout quickly, say 15 seconds, but allow for a large file that is successfully transferring to continue.
Is there any way to get TCP or SSL to raise a timeout much sooner when the connection at either of those levels fails to complete setup, but not raise an exception if the session is successfully established and it's just taking a long time to actually transfer the data?
Here is what our current code looks like - we are not tied to doing it this way (and I didn't write this code):
def box_delete(uri)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Delete.new(uri.request_uri)
http.request(request)
end

Advice on how to set up a connection between nancy service and server

I am working on a project whereby we have sites (developed with ruby on rails) hosted on an Ubuntu server using tomcat. We want these sites to make HTTP calls to a service developed using Nancy. We have this working locally whereby the service is hosted on a machine that we can call within our network. We cannot however get it working when live. Here is an example call:
def get_call(routePath)
started_at = Time.now
enc_url = URI.encode("#{settings.service_endpoint}#{routePath}")
uri = URI.parse(enc_url)
http = Net::HTTP.new(uri.host, uri.port)
req = Net::HTTP::Get.new(uri.request_uri)
resp = http.request(req)
logger.bench 'SERVICE - GET', started_at, routePath
return resp if response_ok?(resp)
end
When working locally the settings are as follows:
settings.service_endpoint = http://10.10.10.27:7820
routePath = /Customers
When we upload it to the server we use the following:
settings.service_endpoint = http://127.0.0.1:24099
routePath = /Customers
We currently get the following error:
SocketError at /register
initialize: name or service not know
with the following line being highlighted:
resp = http.request(req)
Are we completely wrong with the IP being called. Should it be 127.0.0.1, localhost. 10.10.10.27 or something entirely different? The strange thing is we can do a GET call via telnet in our Ubuntu server (telnet 127.0.0.1 24099) so that must mean the server can make the calls but the site hosted on the server cannot. Do we need to include a HTTP proxy (have read some reference to that but dont really know if its needed).
Apologies if its obvious but we have never tried anything like this before so its all very perplexing. Any further information required just let me know.
We changed the service_endpoint to localhost and it worked. Not sure if this is because it didnt like "http://" or some other reason. Any explanation as to why this is the case would be much appreciated, just so we know. Thanks!

How to use $remote_addr with rails and nginx secure_link

I have a rails application that makes calls to another server via net::http to retrieve documents.
I have set up Nginx with secure_link.
The nginx config has
secure_link $arg_md5,$arg_expires;
secure_link_md5 "$secure_link_expires$uri$remote_addr mySecretCode";
On the client side (which is in fact my rails server) I have to create the secure url something like:
time = (Time.now + 5.minute).to_i
hmac = Digest::MD5.base64digest("#{time}/#{file_path}#{IP_ADDRESS} mySecretCode").tr("+/","-_").gsub("==",'')
return "#{DOCUMENT_BASE_URL}/#{file_path}?md5=#{hmac}&expires=#{time}"
What I want to know is the best way to get the value above for IP_ADDRESS
There are multiple answers in SO on how to get the ip address but alot of them do not seem as reliable as actually making a request to a web service that returns the ip address of the request as this is what the nginx secure link will see (we don't want some sort of localhost address).
I put the following method on my staging server:
def get_client_ip
data=Hash.new
begin
data[:ip_address]=request.ip
data[:error]=nil
rescue Exception =>ex
data[:error]=ex.message
end
render :json=>data
end
I then called the method from the requesting server:
response = Net::HTTP.get_response(URI("myserver.com/web_service/get_client_ip"))
if response.class==Net::HTTPOK
response_hash=JSON.parse response.body
ip=response_hash["ip_address"] unless response_hash[:error]
else
#deal with error
end
After getting the ip address successfully I just cached it and did not keep on calling the web service method.

How to set the timeout for a proxy connection in Ruby

I know how to set the open/read timeout for the request going through the proxy. My problem, however, is that occasionally my proxy goes down, and therefore I am unable to ever connect to the proxy. So I want to be able to set the timeout to connect to the proxy to some value, and then handle the timeout by trying something else. Any idea how I can set the timeout value for connecting to an http proxy? Thanks!
First the code, then a bit of explaination below:
# get an instance of Net::HTTP that has proxy settings embedded
# see the source: http://ruby-doc.org/stdlib-1.9.3/libdoc/net/http/rdoc/Net/HTTP.html#method-c-Proxy
proxyclass = Net::HTTP::Proxy("proxy_host");
# Create a new instance of the URL you want to connect to
# NOTE: no connection is attempted yet
proxyinstance = proxyclass.new("google.com");
# Make your setting changes, specifically the timeouts
proxyinstance.open_timeout = 5;
proxyinstance.read_timeout = 5;
# now, attempt connecting through the proxy with the desired
# timeout settings.
proxyinstance.start do |http|
# do something with the http instance
end
The key is realizing open_timeout and read_timeout are instance variables and that Net::HTTP::Proxy actually returns a decorated Net::HTTP class.
You would run into this same problem with similar Net::HTTP usage. You must construct it the "long" way, not using the Net::HTTP.start() class method shortcut.

Setting outgoing IP address in open-uri with RoR

I'm new to open-uri and trying to set an outgoing IP address using open-uri in ruby on rails. I used this post as a reference to get started. I'm porting an app from PHP where I could use CURLOPT_INTERFACE in curl_setopt. What's the best way to do this using open-uri in rails? (Doing this from the controller - not command line.)
If there's not a way to do this - any suggestions on an alternative to open-uri? My goal is to take in and parse JSON data.
What I understand from your questions is you want to hit another server from a specific IP which suggests you have a server with couple of addresses.
What I can suggest you is try to execute curl directly and do what you want to do or use a wrapper for it.
Doesn't look like open-uri can do this. But with net/https it's fairly easy.
require 'net/https'
require 'json'
uri = URI('https://jsonvat.com/')
http = Net::HTTP.new(uri.host, uri.port)
http.local_host = '1.2.3.4'
http.use_ssl = true
request = Net::HTTP::Get.new('/')
request.content_type = 'application/json'
request.initialize_http_header('Content-Type' => 'application/json')
response = http.request(request)
json = JSON.parse(response.body)
Probably you don't need the "require" lines inside Rails Controllers.
You can specify the outgoing IP address with the http.local_host line.
https://stackoverflow.com/a/24896074/1371731
https://yukimotopress.github.io/http

Resources