How to make an HTTP head request with headers in ruby? - ruby

I've been trying to use several libraries to make an HTTP HEAD request, but nothing seems to be working.
I've seen some examples, but nothing quite what I want.
Here's the Curl request, now I have to do it in ruby:
curl -XHEAD -H x-auth-user: myusername -H x-auth-key: mykey "url"
Also, this is an HTTPS url, if that makes a difference.

Try this:
require 'net/http'
url = 'http://...'
myusename = '...'
mykey = '...'
request = Net::HTTP.new(url, 80)
request.request_head('/', 'x-auth-user' => myusername, 'x-auth-key' => my_key)

Related

Healthcare API (Ruby client) returning null

I'm trying to fetch a Patient from the FHIR store via the Ruby client and it always returns null.
I am successful when querying via CURL. Here is the CURL command I'm running (full path redacted):
curl -X GET \
-H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
"https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Patient/PATIENT_ID"
This returns the proper FHIR Patient resource.
My Ruby code looks like:
require 'google/apis/healthcare_v1'
require 'googleauth'
service = Google::Apis::HealthcareV1::CloudHealthcareService.new
scope = 'https://www.googleapis.com/auth/cloud-platform'
service.authorization = Google::Auth::ServiceAccountCredentials.make_creds(
json_key_io: File.open('REDACTED'),
scope: scope
)
service.authorization.fetch_access_token!
project_id = REDACTED
location = REDACTED
dataset_id = REDACTED
fhir_store_id = REDACTED
resource_type = 'Patient'
patient_id = REDACTED
name = "projects/#{project_id}/locations/#{location}/datasets/#{dataset_id}/fhirStores/#{fhir_store_id}/fhir/Patient/#{patient_id}"
response = service.read_project_location_dataset_fhir_store_fhir(name)
puts response.to_json
I'm not getting any authentication errors. The CURL example returns the appropriate result, while the Ruby client example returns null.
Any ideas?
The Ruby library automatically tries to parse the response as JSON. Since the responses from the Healthcare API (or any FHIR server) is Content-Type: application/fhir+json, this isn't recognized by the Ruby library, and it just returns nil for the parsed response.
I got this to work by using the skip_deserialization option for the API call (docs), so instead you should try
require 'json'
name = "projects/#{project_id}/locations/#{location}/datasets/#{dataset_id}/fhirStores/#{fhir_store_id}/fhir/Patient/#{patient_id}"
response = service.read_project_location_dataset_fhir_store_fhir(name, options: {
skip_deserialization: true,
})
patient = JSON.parse(response)
You would actually have to parse the response yourself anyways, because the Ruby response type for these calls is Google::Apis::HealthcareV1::HttpBody, which is essentially just a wrapper around a raw JSON object.

Net::HTTP to Newrelic returns 404, but curl returns 200

I am currently using Ruby's Net::HTTP library to query a Newrelic endpoint. Recently, these queries have started returning 404. I tested my exact query through curl - in the hopes of perhaps getting a more detailed error message back - but the query through curl actually returns a 200 with the expected data. So the query does work, and I am sort of at a loss as to why Net::HTTP would be returning a 404 at this point.
Here are some code snippets of what I have so far, and if anyone can offer any suggestions of further things to try, that would be much appreciated!
Environment:
JRuby 1.7.26 (so Ruby 1.9.3p551)
Rails 3.2.21
Ruby code:
uri = URI('https://NEWRELIC_HOST/PATH/ACCOUNT_ID/query')
parameters = { :nrql => NRQL_QUERY_STRING }
uri.query = URI.encode_www_form(parameters)
request = Net::HTTP::Get.new(uri.to_s)
request['X-Query-Key'] = NEWRELIC_QUERY_KEY
Net::HTTP.start(uri.hostname, uri.port, {:use_ssl => true}) do |http|
response = http.request(request)
end
This returns me a 404 error code every time. I have tried it against a couple valid Newrelic endpoints/accounts and every time is a 404 error.
CURL code:
Now if I take that same request, and punt it to curl on the command line, there are no issues, I get a 200 with all data returned properly:
curl -H "X-Query-Key: NEWRELIC_QUERY_KEY" https://NEWRELIC_HOST/PATH/ACCOUNT_ID/query?NRQL_QUERY_STRING
Try changing
request = Net::HTTP::Get.new(uri.to_s)
to
request = Net::HTTP::Get.new(uri.request_uri)

Connect to Microsoft Push Notification Service for Windows Phone 8 from Ruby

We are developing a WP8 app that requires push notifications.
To test it we have run the push notification POST request with CURL command line, making sure that it actually connects, authenticates with the client SSL certificate and sends the correct data. We know for a fact that this work as we are receiving pushes to the devices.
This is the CURL command we have been using for testing purposes:
curl --cert client_cert.pem -v -H "Content-Type:text/xml" -H "X-WindowsPhone-Target:Toast" -H "X-NotificationClass:2" -X POST -d "<?xml version='1.0' encoding='utf-8'?><wp:Notification xmlns:wp='WPNotification'><wp:Toast><wp:Text1>My title</wp:Text1><wp:Text2>My subtitle</wp:Text2></wp:Toast></wp:Notification>" https://db3.notify.live.net/unthrottledthirdparty/01.00/AAF9MBULkDV0Tpyj24I3bzE3AgAAAAADCQAAAAQUZm52OkE1OUZCRDkzM0MyREY1RkE
Of course our SSL cert is needed to actually use the URL, but I was hoping someone else has done this and can see what we are doing wrong.
Now, our problem is that we need to make this work with Ruby instead, something we have been unable to get to work so far.
We have tried using HTTParty with no luck, and also net/http directly without any luck.
Here is a very simple HTTParty test script I have used to test with:
require "httparty"
payload = "<?xml version='1.0' encoding='utf-8'?><wp:Notification xmlns:wp='WPNotification'><wp:Toast><wp:Text1>My title</wp:Text1><wp:Text2>My subtitle</wp:Text2></wp:Toast></wp:Notification>"
uri = "https://db3.notify.live.net/unthrottledthirdparty/01.00/AAF9MBULkDV0Tpyj24I3bzE3AgAAAAADCQAAAAQUZm52OkE1OUZCRDkzM0MyREY1RkE"
opts = {
body: payload,
headers: {
"Content-Type" => "text/xml",
"X-WindowsPhone-Target" => "Toast",
"X-NotificationClass" => "2"
},
debug_output: $stderr,
pem: File.read("/Users/kenny/Desktop/client_cert.pem"),
ca_file: File.read('/usr/local/opt/curl-ca-bundle/share/ca-bundle.crt')
}
resp = HTTParty.post uri, opts
puts resp.code
This seems to connect with SSL properly, but then the MS IIS server returns 403 to us for some reason we don't get.
Here is essentially the same thing I've tried using net/http:
require "net/http"
url = URI.parse "https://db3.notify.live.net/unthrottledthirdparty/01.00/AAF9MBULkDV0Tpyj24I3bzE3AgAAAAADCQAAAAQUZm52OkE1OUZCRDkzM0MyREY1RkE"
payload = "<?xml version='1.0' encoding='utf-8'?><wp:Notification xmlns:wp='WPNotification'><wp:Toast><wp:Text1>My title</wp:Text1><wp:Text2>My subtitle</wp:Text2></wp:Toast></wp:Notification>"
pem_path = "./client_cert.pem"
cert = File.read pem_path
http = Net::HTTP.new url.host, url.port
http.use_ssl = true
http.cert = OpenSSL::X509::Certificate.new cert
http.key = OpenSSL::PKey::RSA.new cert
http.ca_path = '/etc/ssl/certs' if File.exists?('/etc/ssl/certs') # Ubuntu
http.ca_file = '/usr/local/opt/curl-ca-bundle/share/ca-bundle.crt' if File.exists?('/usr/local/opt/curl-ca-bundle/share/ca-bundle.crt') # Mac OS X
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
r = Net::HTTP::Post.new url.path
r.body = payload
r.content_type = "text/xml"
r["X-WindowsPhone-Target"] = "toast"
r["X-NotificationClass"] = "2"
http.start do
resp = http.request r
puts resp.code, resp.body
end
Like the HTTParty version, this also returns 403..
I'm starting to get the feeling that this won't actually work with net/http, but I've also seen a few examples of code claiming to work, but I can't see any difference compared to what we have tested with here.
Does anyone know how to fix this? Is it possible? Should I use libcurl instead perhaps? Or even do a system call to curl? (I may have to do the last one as an interim solution if we can't get this to work soon).
Any input is greatly appreciated!
Thanks,
Kenny
Try using some tool like http://mitmproxy.org to compare requests from your code and curl.
For example curl in addition to specified headers does send User-Agent and Accept-headers, microsoft servers may be checking for these for some reason.
If this does not help - then it's ssl-related

How do I form a Github API POST request to add a new comment to a gist?

I'm doing a Post request to github at this url:
https://api.github.com/gists/2710948/comments
Theoretically, this should create a comment with the text being formed from what's in the request body. However, when I try to make that post, I get a 404 error. That leads me to believe that the gist is not being found, however, if you do a Get request at the same address it comes up just fine.
Is there an authentication thing I need to be doing? I've tried adding a username and password to my headers collection but I've got no idea if I'm using the right format. I've tried making this work via Ruby, HTTP Client, and curl, and I get the same error either way.
The curl command I'm using is this:
curl -X POST -d "This is my sample comment" https://api.github.com/gists/2710948/comments
I think that if I can get the curl command working, I'll be able to figure out the HTTP Client and then the Ruby. This will be my first attempt at consuming an API, so there's nothing too basic for me to double-check; all suggestions will be helpful.
curl -d '{ "body": "Test comment" }' -u "Username:Pass" -X POST https://api.github.com/gists/2710948/comments
Ruby code:
require 'net/http'
uri = URI("https://api.github.com/gists/2710948/comments")
req = Net::HTTP::Post.new(uri.to_s)
req.basic_auth("Username", "Pass")
req.body = '{"body": "Test message"}' # `to_json` can be used
req["content-type"] = "application/json"
Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |http|
p response = http.request(req)
end
See also http://developer.github.com/v3/gists/comments/

Is there a way to attach Ruby Net::HTTP request to a specific IP address / network interface?

Im looking a way to use different IP addresses for each GET request with standard Net::HTTP library. Server has 5 ip addresses and assuming that some API`s are blocking access when request limit per IP is reached. So, only way to do it - use another server. I cant find anything about it in ruby docs.
For example, curl allows you to attach it to specific ip address (in PHP):
$req = curl_init($url)
curl_setopt($req, CURLOPT_INTERFACE, 'ip.address.goes.here';
$result = curl_exec($req);
Is there any way to do it with Net::HTTP library? As alternative - CURB (ruby curl binding). But it will be the last thing i`ll try.
Suggestions / Ideas?
P.S. The solution with CURB (with dirty tests, ip`s being replaced):
require 'rubygems'
require 'curb'
ip_addresses = [
'1.1.1.1',
'2.2.2.2',
'3.3.3.3',
'4.4.4.4',
'5.5.5.5'
]
ip_addresses.each do |address|
url = 'http://www.ip-adress.com/'
c = Curl::Easy.new(url)
c.interface = address
c.perform
ip = c.body_str.scan(/<h2>My IP address is: ([\d\.]{1,})<\/h2>/).first
puts "for #{address} got response: #{ip}"
end
I know this is old, but hopefully someone else finds this useful, as I needed this today. You can do the following:
http = Net::HTTP.new(uri.host, uri.port)
http.local_host = ip
response = http.request(request)
Note that you I don't believe you can use Net::HTTP.start, as it doesn't accept local_host as an option.
There is in fact a way to do this if you monkey patch TCPSocket:
https://gist.github.com/800214
Curb is awesome but won't work with Jruby so I've been looking into alternatives...
Doesn't look like you can do it with Net:HTTP. Here's the source
http://github.com/ruby/ruby/blob/trunk/lib/net/http.rb
Line 644 is where the connection is opened
s = timeout(#open_timeout) { TCPSocket.open(conn_address(), conn_port()) }
The third and fourth arguments to TCPSocket.open are local_address and local_port, and since they're not specified, it's not possible. Looks like you'll have to go with curb.
Of course you can. I did as below:
# remote_host can be IP or hostname
uri = URI.parse( "http://" + remote_host )
http = Net::HTTP.new( uri.host, uri.port )
request = Net::HTTP::Get.new(uri.request_uri)
request.initialize_http_header( { "Host" => domain })
response = http.request( request )

Resources