unsupported proxy in HTTPClient - ruby

I want to use Ruby httpclient to make requests. I tried to implement this code:
def submit!
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = HTTPClient.new(url)
request.basic_auth('username', 'pass')
request['content-type'] = 'application/xml'
request['cache-control'] = 'no-cache'
request.body = request_body
response = http.request(request).body
response = Response.new(response)
check_for_approved_response(response)
response
end
But I get error:
unsupported proxy https://staging.gate.some_address.net/process/3ab20f2ddbe78ab8be9f5a9645c1010330dc868f
Can you recommend some solution how to fix it?

make sure ruby can see and read /etc/resolv.conf and that you don't have HTTP_PROXY env variable set. Also check that your ssl isn't using a non-standard ssl port.

Run echo $HTTP_PROXY on your terminal. If you see any value, its not good. You'll have to unset that variable.
See - https://github.com/savonrb/savon/issues/123#issuecomment-620825

https://www.rubydoc.info/gems/httpclient/2.1.5.2/HTTPClient
Accessing resources through HTTP proxy. You can use environment variable 'http_proxy' or 'HTTP_PROXY' instead.
clnt = HTTPClient.new('http://myproxy:8080')
So in your code request = HTTPClient.new(url) is putting target url as proxy of HTTPClient. (It is indeed a little confusing when you come from net/http)

Related

Fetch urls prefixed with username:password#

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

Net::HTTP not sending request

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.

Executing requests in ruby using net/http

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.

HTTPS request using Net::HTTP's block form -- is it possible?

To do a Net::HTTP https request without the block form you can do this:
...
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
...
But is there a way to tell Net::HTTP to use https when doing the block form?
u = URI.parse(url)
Net::HTTP.start(u.host, u.port) do |http|
# if I put http.use_ssl = true here, ruby complains that this can't
# be done becuase the sesion has already started
resp = http.get(u.request_uri)
end
I'm on ruby 1.8.7
See the documentation for Net::HTTP.start which takes an optional hash. From the documentation:
opt sets following values by its accessor. The keys are ca_file, ca_path, cert, cert_store, ciphers, close_on_empty_response, key, open_timeout, read_timeout, ssl_timeout, ssl_version, use_ssl, verify_callback, verify_depth and verify_mode. If you set :use_ssl as true, you can use https and default value of verify_mode is set as OpenSSL::SSL::VERIFY_PEER.
Net::HTTP.start(url.host, url.port, :use_ssl => true)

Using Net::HTTP.get for an https url

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)

Resources