Checking URL availability Ruby on Rails - ruby

Suppose that after primitive validation of user submitted URL I have the string that looks like URL:
url = 'http://www.thisdomaindoesntexist.com/dont_even_ask_about/this/uri'
How can I check if its available or not?
I tried this in my is_valid_link function:
require "net/http"
url = URI.parse(url)
req = Net::HTTP.new(url.host, url.port)
res = req.request_head(url.path)
It works if the server exists giving me back the HTTP response, but the problem is that in case of bad url I get an error like this:
SocketError in PostsController#create
getaddrinfo: nodename nor servname provided, or not known
How should I do this kind of validation properly?
Thanks in advance.

You can use rescue to catch errors and do some error handling
begin
require "net/http"
url = URI.parse(url)
req = Net::HTTP.new(url.host, url.port)
res = req.request_head(url.path)
rescue
# error occured, return false
false
else
# valid site
true
end
Use rescue inline:
require "net/http"
url = URI.parse(url)
req = Net::HTTP.new(url.host, url.port)
res = req.request_head(url.path) rescue false

I've looked for a way to check if URL existed for 5 hours and this thread actually helped me.
I'm a newbie in rails and wanted to find something easy.
Here how I integrated the code into controller:
require "net/http"
def url
url = URI.parse('http://www.url that you want to check.com/' + "/")
end
def req
#req = Net::HTTP.new(url.host, url.port)
end
def res #res
#res = req.request_head(url.path)
rescue
false
end
def test
if res == false
"something"
else
"another thing"
end
you have to make sure that URL ends with "/", else the code won't work.

Related

How To change a URI object's path attribute?

I want to call an API using only slightly different URIs. This code snippet does what I want, but I want to know if there is a more efficient way to do it.
require 'net/http'
require 'json'
# These URIs differ only in the path
orders = URI('https://hft-api.lykke.com/api/Orders?orderType=Unknown')
asset_pairs = URI('https://hft-api.lykke.com/api/AssetPairs')
lykke_req = Net::HTTP::Get.new(orders)
lykke_req['User-Agent'] = 'curl/7.67.0'
lykke_req['api-key'] = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
lykke_req['Accept'] = 'application/json'
response = Net::HTTP.start(orders.hostname,
orders.port,
:use_ssl => true) {|http| http.request(lykke_req)}
puts JSON.parse(response.body)
lykke_req = Net::HTTP::Get.new(asset_pairs)
lykke_req['User-Agent'] = 'curl/7.67.0'
lykke_req['Accept'] = 'application/json'
response = Net::HTTP.start(asset_pairs.hostname,
asset_pairs.port,
:use_ssl => true) {|http| http.request(lykke_req)}
puts JSON.parse(response.body)
All I do is to reuse the same code but with a slightly different URI.
For my lykke_req objects, I can write
puts lykke_req
puts lykke_req.path
which gives me
#<Net::HTTP::Get:0x00007f947f1fdce8>
/api/Orders?orderType=Unknown
So it seems to me all i have to do is change the value of lykke_req.path. But I can't work out how to do it. I am looking for something like this
lykke_req.path = "/api/AssetPairs"
which fails with
undefined method `path=' for #<Net::HTTP::Get GET> (NoMethodError)
I found this on the official documentation page, but I can't find out what [R] means. Does it mean read only? Do I really have to go through the hassle of creating a new URI object, then creating a new Net::HTTP::Get object each time?
path [R]
The problem here is that you're trying to alter the net request object instead of the uri object:
irb(main):001:0> uri = URI('https://hft-api.lykke.com/api/Orders?orderType=Unknown')
=> #<URI::HTTPS https://hft-api.lykke.com/api/Orders?orderType=Unknown>
irb(main):002:0> uri.path = '/foo'
=> "/foo"
irb(main):003:0> uri.to_s
=> "https://hft-api.lykke.com/foo?orderType=Unknown"
But I would really just wrap this in a class so that you can encapsulate and structure your code and avoid duplication:
class LykkeAPIClient
BASE_URI = URI('https://hft-api.lykke.com/api')
def initalize(api_key:)
#api_key = api_key
end
def get_orders
get '/Orders?orderType=Unknown'
end
def get_asset_pairs
get '/AssetPairs'
end
def get(path)
req = Net::HTTP::Get.new(BASE_URI.join(path))
req['User-Agent'] = 'curl/7.67.0'
req['Accept'] = 'application/json'
req['api-key'] = #api_key
response = Net::HTTP.start(req.hostname, req.port, use_ssl: true) do |http|
http.request(uri)
end
# #todo check response status!
JSON.parse(response.body)
end
end
#client = LykkeAPIClient.new(api_key: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')
#orders = #client.get_orders
Insstead of lykke_req.path= do lykke_req.uri.path=
https://ruby-doc.org/stdlib-2.6.5/libdoc/net/http/rdoc/Net/HTTPGenericRequest.html

Ruby SocketError Handing

In Ruby none of the error handling that I do seems to take any effect. For example in this function.
def http (uri)
url = URI.parse(uri)
if Addressable::url.host
if url.scheme=='https'
response = Net::HTTP.start(url.host, use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_NONE) do |http|
http.get url.request_uri, 'User-Agent' => 'MyLib v1.2'
end
elsif url.scheme=='http'
begin
http = Net::HTTP.new(url.host, url.port)
response = http.request(Net::HTTP::Get.new(url.request_uri))
rescue
response.body = "lol"
end
end
else
response.body = "lol"
end
return response.body
end
Regardless of the error handling, the code would still crash and give me error on the line right after begin.
I know that the url host is not valid, but is the error handling not supposed to fix it?
`initialize': getaddrinfo: nodename nor servname provided, or not known (SocketError)

Net::HTTP follow maximum of three redirects?

I have this method in my class:
def self.get(url)
#TODO We could test with https too
if url.match(/^http/)
correct_url = url
else
correct_url = "http://#{url}"
end
uri = URI.parse(correct_url)
if uri.respond_to? 'request_uri'
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Get.new(uri.request_uri)
http.request(request)
else
puts "Incorrect URI"
end
end
Unfortunately it's not following the redirects.
Can someone tell me how to make this method allow a maximum of three redirects?
Try this:
def self.get(url)
# TODO: test with https too
url = "http://#{url}" unless url.match(/^http/)
3.times do
uri = URI.parse(url)
if uri.respond_to?(:request_uri)
response = Net::HTTP.get_response(uri)
case response.code
when '301', '302'
url = response.header['location']
else
return response
end
end
end
end

Ruby making a web request

Hi this is my very first Ruby program.
I'm trying to write a simple ruby app to make a request to a URL and see if it's available. If it is, it'll print OK and else it'll print false.
This is what I've got so far, can you please assist, do I need to import any libs?
class WebRequest
def initialize(name)
#name = name.capitalize
end
def makeRequest
puts "Hello #{#name}!"
#uri = URI.parse("https://example.com/some/path")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE # read into this
#data = http.get(uri.request_uri)
end
end
req = WebRequest.new("Archie")
req.makeRequest
Here is sample code to do any request:
require 'net/http'
require 'uri'
url = URI.parse('http://www.example.com/index.html')
req = Net::HTTP::Get.new(url.path)
res = Net::HTTP.start(url.host, url.port) do |http|
http.request(req)
end
puts res.body
gem install httparty
then
require 'httparty'
response = HTTParty.get('https://example.com/some/pathm')
puts response.body
Something simpler:
[1] pry(main)> require 'open-uri'
=> true
[2] pry(main)> payload = open('http://www.google.com')
=> #<File:/var/folders/2p/24pztc5s63d69hhx81002bq80000gn/T/open-uri20131217-84948-ttwnho>
[3] pry(main)> payload.inspect
=> "#<Tempfile:/var/folders/2p/24pztc5s63d69hhx81002bq80000gn/T/open-uri20131217-84948-ttwnho>"
[4] pry(main)> payload.read
payload.read would return the response body and you can easy use payload as File object since it is an instance of Tempfile
This is what I've ended up with
require 'net/http'
class WebRequest
def initialize()
#url_addr = 'http://www.google.com/'
end
def makeRequest
puts ""
begin
url = URI.parse(#url_addr)
req = Net::HTTP::Get.new(url.path)
res = Net::HTTP.start(url.host, url.port) {|http|
http.request(req)
}
puts "OK Connected to #{#url_addr} with status code #{res.code}"
rescue
puts "Failed to connect to #{#url_addr}"
end
end
end
req = WebRequest.new()
req.makeRequest

Unable to make HTTP Delete request in my ruby code using Net::HTTP

Im using Net::HTTP in my ruby code to make http requests. For example to make a post request i do
require 'net/http'
Net::HTTP.post_form(url,{'email' => email,'password' => password})
This works. But im unable to make a delete request, i.e.
require 'net/http'
Net::HTTP::Delete(url)
gives the following error
NoMethodError: undefined method `Delete' for Net::HTTP:Class
The documentation at http://ruby-doc.org/stdlib-1.9.3/libdoc/net/http/rdoc/Net/HTTP.html shows Delete is available. So why is it not working in my case ?
Thank You
The documentation tells you that Net::HTTP::Delete is a class, not a method.
Try Net::HTTP.new('www.server.com').delete('/path') instead.
uri = URI('http://localhost:8080/customer/johndoe')
http = Net::HTTP.new(uri.host, uri.port)
req = Net::HTTP::Delete.new(uri.path)
res = http.request(req)
puts "deleted #{res}"
Simple post and delete requests, see docs for more:
puts Net::HTTP.new("httpbin.org").post("/post", "a=1").body
puts Net::HTTP.new("httpbin.org").delete("/delete").body
This works for me:
uri = URI(YOUR_URL)
req = Net::HTTP::Delete.new(uri, {}) # params on second place
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
http.request req
end

Resources