I am trying to use net/http to get a response for API call based on an old library I dug up https://github.com/jurisgalang/facebook/blob/master/lib/facebook/graph-object.rb#L22
require 'net/http'
API_HOST = "graph.facebook.com"
API_BASE_URL = "https://#{API_HOST}"
path = "/boo"
uri = URI.parse "#{API_BASE_URL}#{path}"
http = Net::HTTP.new(uri.host, uri.port)
res = http.get(uri.request_uri, nil)
The uri ends up as <URI::HTTPS:0x0000010091fc48 URL:https://graph.facebook.com/boo>
This results in
NoMethodError: undefined method `keys' for nil:NilClass
I assumed it is because dest argument is obsolete: http://ruby-doc.org/stdlib-1.9.3/libdoc/net/http/rdoc/Net/HTTP.html#method-i-get
So I did it without
res = http.get(uri.request_uri)
Which results in
NoMethodError: undefined method `empty?' for
#<URI::HTTPS:0x0000010091fc48 URL:https://graph.facebook.com/boo>
How can one request a response using net/http and http.get?
Just at a very quick glance of the documentation, the second argument to get is a hash, and you're passing nil, see:
http.get(uri.request_uri, nil)
Your second attempt should be OK, though I did find that with my setup (ruby 1.9.3 and MacPorts' openssl library) that Net::HTTP was rejecting Facebook's ssl certificate (I was getting "Connection reset by peer". The following code snippet worked for me:
require 'net/http'
API_HOST = "graph.facebook.com"
API_BASE_URL = "https://#{API_HOST}"
path = "/boo"
uri = URI.parse "#{API_BASE_URL}#{path}"
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
res = http.get(uri.request_uri)
puts res.body
Note that I'm not verifying the SSL certificate, which is a potential security problem. As a proof of concept, however, this snippet worked for me - so hopefully this will give you a good data point in your debugging effort.
Related
I am using net-http-persistent gem to fetch pages. It works perfectly fine for most of the cases. But, recently I noted that it returns 401 for urls prefixed with username:password# e.g. https://username:password#somesite.com. If i try other options like excon/curl they fetch such pages without problem. I saw the logs of the requests made by Net::HTTP::Persistent and found out net::http totally discards the username:password part while connecting to the server.
Can anybody help me how to make Net::HTTP::Persistent make use of username:password# part.
----------------------EDITED--------------------
Sample code:
url = "https://user:pass#example.com/feed"
uri = URI(url)
http = Net::HTTP::Persistent.new
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
response = http.request uri
http.shutdown
response.code # yields 401 which it should not as url has username and password.
#Incase of excon, if you do
response = Excon.get(url)
response.status # yields 200 as it is making use of username:password prefix
Based on this issue, try code like:
uri = URI("https://example.com/feed")
req = Net::HTTP::Get.new(uri.request_uri)
req.basic_auth 'user', 'pass'
http = Net::HTTP::Persistent.new
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
response = http.request uri, req
http.shutdown
puts response.code
I'm trying to set up a web hook, following this GitHub tutorial
require 'sinatra'
require 'json'
require 'net/http'
require 'pp'
set :port, 31415
# Descarga las diferencias hechas para un push
post '/' do
push = JSON.parse(request.body.read)
piezas = push["compare"].split("/")
api_url = "/repos/#{piezas[3]}/#{piezas[4]}/compare/#{piezas[6]}"
diff = Net::HTTP.get(URI("https://api.github.com#{api_url}"))
puts diff.class
pp(JSON.parse(diff))
end
diff.class prints:
String
And, as a matter of fact, the last sentence works correctly, printing via pp the structure. However, after printing, it yields the error
[2018-10-25 20:00:23] ERROR TypeError: no implicit conversion of Array into String
It's not referencing any line in the script, but would it be possible that the error would be in the first JSON.parse? Could it be that request.body.read would be an array?
Update I couldn't golf it down to any of the JSON.parse separately. Downloading the hook payload works OK, downloading the JSON from the GitHub API works without a glithc. Somehow it's using them together what does not work.
It's possible the library is treating the response like text. Try adding an Accept header. This worked for me:
request["Accept"] = "application/json"
example:
uri = URI.parse("https://api.github.com")
req = Net::HTTP::Get.new(URI("https://api.github.com/repos/JJ/microservices-broker/compare/d5d39c5db99d...bbbf695d1bf2"))
req["Accept"] = 'application/json'
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
response = http.request(req)
json = JSON.parse(response.body)
json['url']
# or
json = JSON.parse(response.body, symbolize_names: true)
json[:url]
(EDIT:) Also, Using Net::HTTP is really painful. Please checkout these libraries:
https://github.com/lostisland/faraday
https://github.com/octokit/octokit.rb
I have the following method in our Ruby 1.8.7 project:
def self.ping_server
request_data = get_request_data
uri = 'another_server.our_company.com'
https = Net::HTTP.new(uri)
https.use_ssl = true
path = "/our_service"
data = request_data.to_json
response = https.post(path, data, {'Content-Type' => 'application/json'})
return response
end
Whenever I run this method, I get the following time out error:
Completed 500 Internal Server Error in 128936ms
Errno::ETIMEDOUT (Connection timed out - connect(2)):
lib/my_class.rb:51:in `ping_our_server'
I checked with a coworker who has access to the logs for another_server.our_company.com. My request isn't arriving at the other server.
What should I do to get my request to work?
EDIT: On further inspection, this is what I think is happening (but I'm not completely sure): Our other server will only accept HTTPS requests, but it looks like my request is being sent over HTTP for some reason. Is there something I need to add to make sure my request is sent over HTTPS?
According to this website, this is how you send an HTTPS request:
require "net/https"
require "uri"
uri = URI.parse("https://secure.com/")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new(uri.request_uri)
response = http.request(request)
response.body
response.status
response["header-here"] # All headers are lowercase
According to this website (which is linked from my first link), you should also do this to close up a vulnerability in the net/https library:
To get going, you need a local CA certificates bundle, the official
curl site maintains an up to date cacert.pem / ca-bundle.crt file
containing all of the major certificates if you need one.
Next, after a gem install always_verify_ssl_certificates, you can be
up and running with a test as simply as:
require 'always_verify_ssl_certificates'
AlwaysVerifySSLCertificates.ca_file = "/path/path/path/cacert.pem"
http= Net::HTTP.new('https://some.ssl.site', 443)
http.use_ssl = true
req = Net::HTTP::Get.new('/')
response = http.request(req)
If the site
has a bad certificate an error will be raised at this point. If not, a
legitimate HTTP response object will be returned.
I'm trying to use Net::HTTP.get() for an https URL:
#data = Net::HTTP.get(uri, Net::HTTP.https_default_port())
However, I get the following result when I try to print the results:
can't convert URI::HTTPS into String
What's the deal? I'm using Ruby 1.8.7 (OS X)
Original answer:
uri = URI.parse("https://example.com/some/path")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
#data = http.get(uri.request_uri)
As pointed out in the comments, this is more elegant:
require "open-uri"
#data = URI.parse("https://example.com/some/path").read
EDIT: My approach works, but #jason-yeo's approach is far easier.
It appears as of 2.1.2 the preferred a documented method is as follows (directly quoting the documentation):
HTTPS is enabled for an HTTP connection by #use_ssl=.
uri = URI('https://secure.example.com/some_path?query=string')
Net::HTTP.start(uri.host, uri.port,
:use_ssl => uri.scheme == 'https') do |http|
request = Net::HTTP::Get.new uri
response = http.request request # Net::HTTPResponse object
end
In previous versions of Ruby you would need to require ‘net/https’ to use
HTTPS. This is no longer true.
In Ruby 2.0.0 and above, simply passing in an uri object with a https url is sufficient to do a HTTPS get request.
uri = URI('https://encrypted.google.com')
Net::HTTP.get(uri)
You may verify this by performing a get request on a domain with an expired certificate.
uri = URI('https://expired.badssl.com/')
Net::HTTP.get(uri)
# OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=error: certificate verify failed
It was introduced by this commit in Ruby 2.0.0.
The get_response method, which is called by the Net::HTTP.get method, sets :use_ssl to true when the uri.scheme is "https".
Disclaimer: I understand that the question is for Ruby 1.8.7, but since this is one of the top few search results when one searches for "https ruby", I've decided to answer anyway.
this should look as:
uri.port = Net::HTTP.https_default_port()
#data = Net::HTTP.get(uri)
I've tried this on a few machines on different networks, all running ruby 1.8.7 and I get the same result after a long wait.
Net::HTTP.get(URI.parse('https://encrypted.google.com/'))
Timeout::Error: execution expired
but HTTP works fine
Net::HTTP.get(URI.parse('http://www.google.com/'))
After the inital timeout I get an EOFError instead
EOFError: end of file reached
It's really got me stumped. If you have any ideas or you can let me know if you get the same results I'd really appreciate it.
I think you need to set use_ssl to true...
example:
uri = URI.parse("https://www.google.com/")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri.request_uri)
response = http.request(request)
puts response.body
This is cannibalized from the following Ruby Inside post.