Ruby sending xml to server - ruby

Im new to network programming and now have a problem with sending some xml data to a server.
I have the following code:
require "net/http"
require "net/https"
require "uri"
xml = <<XML
<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?><data appname="dhl_entwicklerportal" language-code="de" password="Dhl_123!" request="get-status- for-public-user"><data piece-code="034234"></data></data>
XML
uri = URI('https://cig.dhl.de/services/sandbox/rest/sendungsverfolgung')
nhttp = Net::HTTP.new(uri.host, uri.port)
nhttp.use_ssl=true
nhttp.verify_mode=OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new(uri)
request.basic_auth 'hidden', 'hidden'
response = nhttp.start {|http|
http.request(request, xml: xml)
}
puts response.body
Although i get some response, it is not the right one. For some reason it isn`t sending the body(my xml) properly. If i type the URL manually:
https://cig.dhl.de/services/sandbox/rest/sendungsverfolgung?xml=<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?><data appname="dhl_entwicklerportal" language-code="de" password="Dhl_123!" request="get-status- for-public-user"><data piece-code="034234"></data></data>
it works.
---------------------------EDIT-------------------------------
I edited my code above following the solution from Alex Wayne. Now I get this error:
d:/Ruby200/lib/ruby/2.0.0/net/http/generic_request.rb:179:in `send_request_with_body': undefined method `bytesize' for #<Hash:0x29bcff8> (NoMethodError)

HTTP GET requests cannot have a body, so it the second argument is for data that gets appended to the url as the query string. You probably want to use POST which supports a real request body.
http.request_post(request, xml)
UPDATE: I think I misunderstood...
According to the query string that works, it's working with GET. But it's expecting the XML to be after ?xml=. So you need to encode you request body/query string as a hash with xml as the key and the xml string as the value.
So not this:
http.request(request, xml)
# GET http://domain.com/path?<myxml></myxml>
But this:
http.request(request, xml: xml)
# GET http://domain.com/path?xml=<myxml></myxml>

Related

How to send XML file using Post request in Ruby

I am writing a code that send http post request. Now I write xml body in my code, and its working correctly.
But if I want to send request using xml file I get
undefined method `bytesize' for #
Did you mean? bytes
My code below
require 'net/http'
request_body = <<EOF
<xml_expamle>
EOF
uri = URI.parse('http://example')
post = Net::HTTP::Post.new(uri.path, 'content-type' => 'text/xml; charset=UTF-8')
post.basic_auth 'user','passcode'
Net::HTTP.new(uri.host, uri.port).start {|http|
http.request(post, request_body) {|response|
puts response.body
}
}
**But if I want to make send file**
require 'net/http'
request_body = File.open('example/file.xml')
uri = URI.parse('http://example')
post = Net::HTTP::Post.new(uri.path, 'content-type' => 'application/xml; charset=UTF-8')
post.basic_auth 'user','passcode'
Net::HTTP.new(uri.host, uri.port).start {|http|
http.request(post, request_body) {|response|
puts response.body
}
}
I get
undefined method `bytesize' for #
Did you mean? bytes
You need to load the file content to memory if you want to use it as a request body, use #read method:
request_body = File.open('example/file.xml').read
and it'll work.

Ruby putting token key in requests

I dont know how to put my key into my requests so they are sent back as
{"status"=>"400", "message"=>"Token parameter is required."}
This is the code I have been using
require 'net/http'
require 'json'
token = 'YiwwVvywLngtPT***************'
url = 'https://www.ncdc.noaa.gov/cdo-web/api/v2/stations?locationid=FIPS:23&limit=5&sortfield=mindate'
uri = URI(url)
response = Net::HTTP.get(uri)
response.authorization = token
puts JSON.parse(response)
I have tried a couple different things I've found on the internet but all of them just give errors for
undefined method `methodname' for #<String:0x00007fd97519abd0>
According to the API documentation (based on the URL you referenced), you need to provide the token in a header named token.
So, you should probably try some variation of the below (code untested):
token = 'YiwwVvywLngtPT***************'
url = 'https://www.ncdc.noaa.gov/cdo-web/api/v2/stations?locationid=FIPS:23&limit=5&sortfield=mindate'
uri = URI(url)
request = Net::HTTP::Get.new(uri)
request['token'] = token
response = Net::HTTP.start(uri.hostname, uri.port) do |http|
http.request(request)
end
More information about Net:HTTP headers can be found in this StackOverflow answer.
As a side note, if you are not locked on using Net::HTTP, consider switching to a friendlier HTTP client, perhaps HTTParty. Then, the complete code looks like this:
require 'httparty'
token = 'YiwwVvywLngtPT***************'
url = 'https://www.ncdc.noaa.gov/cdo-web/api/v2/stations?locationid=FIPS:23&limit=5&sortfield=mindate'
response = HTTParty.get url, headers: { token: token }
puts response.body

How to URL encode http post xml data with Ruby

Looking to properly url encode xml_data via http post with Ruby? I tried different variations of URI::encode(xml), and xml.URI.encode_www_form with no luck on the below ('Content-Length') code. However puts URI::encode(xml) works fine after the fact but I need to send the urlencoded xml data within the http post body for it to work properly.
# Server connection
uri = URI.parse(url)
req = Net::HTTP.new(uri.hostname, uri.port)
# Start test:
puts "\n\nStarting test on: #{url}\n"
# URL encoded SAML POST
SAMLResponse = %{
<samlp:Response
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
ID="identifier_2"
Version="2.0"
IssueInstant="instant"
Destination="http://localhost:80">
<saml:Issuer>http://localhost:80:Issuer>
<samlp:Status>
<samlp:StatusCode
Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<saml:Assertion
ID="ee4432"
Version="6.0"
IssueInstant="instant">
<saml:Issuer>http://localhost:80:Issuer>
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid- vformat:unspecified">test_user</saml:NameID>
<saml:SubjectConfirmation
</saml:AttributeStatement>
</saml:Assertion>
</samlp:Response>
}
# HTTP POST | URL Encoded
res = req.post(
uri.path,
SAMLResponse,
{
'Content-Type' => 'text/xml',
'Content-Length' => SAMLResponse.length.to_s,
#'Content-Length' => URI::encode(SAMLResponse), // not working
#'Content-Length' => SAMLResponse.URI.encode_www_form, // not working
"Connection" => "keep-alive"
}
)
#puts res.body # uncomment once url encoding works
puts SAMLResponse

Ruby httpclient url

I am making a call to a webservice via HTTPClient ruby gem. The location doesn't matter, but let's say it is at: https://mywebservice.com/api/v1/accounts/login/
When I send a post request:
url = "https://mywebservice.com/api/v1/accounts/login/"
client = HTTPClient.new
client.post url
I get a 404 response, that the page was not found. I setup a proxy and checked out exactly what was being sent it seems like the gem is messing up the url, it actually sends the request to:
https://mywebservice.comhttps://mywebservice.com:443/api/v1/accounts/login/
I am completely lost, I have no why it is doing that. Does it have anything to do with the fact that it's https and I should handle https differently?
Thanks
Yes, if you are requesting a https url do this:
require 'net/http'
require 'net/https'
require 'uri'
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri)
#you need to set this field to true
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
response = http.request(request)
Here is a link that should help:
http://bibwild.wordpress.com/2012/04/30/httpclient-is-a-nice-http-client-forin-ruby/
You should post to an uri with a body of params. Something like
client.post "http://mysite.com:8080", data
where data is a hash with the required parameters for the page.
For instance:
data = {"var" => "var"}

Ruby Mechanize, Nokogiri and Net::HTTP

I am using Net::HTTP for HTTP requests and getting a response back:
uri = URI("http://www.example.com")
http = Net::HTTP.start(uri.host, uri.port, proxy_host, proxy_port)
request = Net::HTTP::Get.new uri.request_uri
response = http.request request # Net::HTTPResponse object
body = response.body
If I have to use the Nokogiri gem in order to parse this HTML response I will do:
nokogiri_obj = Nokogiri::HTML(body)
But if I want to use Mechanize gem I need to do this:
agent = Mechanize.new
mechanize_obj = agent.get("http://www.example.com")
Is it possible for me to use Net::Http for getting the HTML response and then use the Mechanize gem to convert it into a Mechanize object instead of using agent.get()?
EDIT:
The reason for getting around the agent.get() method is because I am trying to use EventMachine::Iterator to make concurrent EM-HTTP requests.
EventMachine.run do
EM::Iterator.new(urls, 3).each do |url,iter|
puts "giving #{url} to httprequest now"
http = EM::HttpRequest.new(url).get
http.callback { |resp|
uri = resp.send(:URI, url)
puts "inside callback of #{url}"
body = resp.response
page = agent.parse(uri, resp, body)
}
iter.next
end
end
But its not working. I am getting an error:
/usr/local/rvm/gems/ruby-1.9.3-p194/gems/mechanize-2.5.1/lib/mechanize.rb:1165:in`parse': undefined method `[]' for #<EventMachine::HttpClient:0x0000001c18eb30> (NoMethodError)
when I use the parse method for Net::HTTP it works fine and I get the Mechanize object:
uri = URI("http://www.example.com")
http = Net::HTTP.start(uri.host, uri.port, proxy_host, proxy_port)
request = Net::HTTP::Get.new uri.request_uri
response = http.request request # Net::HTTPResponse object
body = response.body
agent = Mechanize.new
page = agent.parse(uri, response, body)
Am I passing the wrong arguments for the parse method while using em-http?
I'm not sure why you think using Net::HTTP would be better. Mechanize will handle redirects and cookies, plus provides ready access to Nokogiri's parsed document.
require 'mechanize'
agent = Mechanize.new
page = agent.get('http://www.example.com')
# Use Nokogiri to find the content of the <h1> tag...
puts page.at('h1').content # => "Example Domains"
Note, setting the user_agent isn't necessary to reach example.com.
If you want to use a threaded engine to retrieve pages, take a look at Typhoeous and Hydra.
Looks like Mechanize has a parse method, so this could work:
mechanize_obj = Mechanize.parse(uri, response, body)

Resources