Ruby undefined method `bytesize' for #<Hash:0x2954fe8> - ruby

i have the following Ruby Code, for a tracking website in sandbox mode:
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="00340433836536550280"></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 'xpackageWP', 'hidden'
response = nhttp.start {|http|
http.request(request, xml:xml)
}
puts response.body
I always get the error :
d:/Ruby200/lib/ruby/2.0.0/net/http/generic_request.rb:179:in `send_request_with_body' undefined method `bytesize' for #<Hash:0x2954fe8> (NoMethodError)
from d:/Ruby200/lib/ruby/2.0.0/net/http/generic_request.rb:130:in `exec'
from d:/Ruby200/lib/ruby/2.0.0/net/http.rb:1404:in `block in transport_request'
from d:/Ruby200/lib/ruby/2.0.0/net/http.rb:1403:in `catch'
from d:/Ruby200/lib/ruby/2.0.0/net/http.rb:1403:in `transport_request'
from d:/Ruby200/lib/ruby/2.0.0/net/http.rb:1376:in `request'
from D:/Dropbox_5BHIF/Dropbox/TempDHL/Main.rb:17:in `block in <main>'
from d:/Ruby200/lib/ruby/2.0.0/net/http.rb:852:in `start'
from D:/Dropbox_5BHIF/Dropbox/TempDHL/Main.rb:16:in `<main>'
I tried really hard to solve this, but i cannot think of any problem.
When i test it in the Browser with the Link and then a ?xml= it works perfectly, so it seems to be a problem with my Ruby Code.

You're sending post data as a hash. You should encode it as string.
For example Using URI::encode_www_form:
request = Net::HTTP::Post.new(uri)
...
response = nhttp.start do |http|
post_data = URI.encode_www_form({xml: xml})
http.request(request, post_data)
end
UPDATE If you want GET request, append the query string to the url.
post_data = URI.encode_www_form({xml: xml})
uri = URI('https://cig.dhl.de/services/sandbox/rest/sendungsverfolgung?' +
post_data)
...
response = nhttp.start do |http|
http.request(request)
end

request expects a string for its second argument, on which it invokes bytesize. You're giving it a hash, which doesn't respond to bytesize.

Use POST and not GET request
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="00340433836536550280"></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::Post.new(uri)
request.body = xml
request.basic_auth 'xpackageWP', 'hidden'
response = nhttp.start {|http|
http.request(request)
}

I solved by using .to_s, it returns a 200.
#client.job.create_or_update(job_name, job_xml.get_xml.to_s)
This is Jenkins API client what I'm currently using:
https://github.com/arangamani/jenkins_api_client

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 Net::HTTP Get request Error when using https

I have a web server that i need to get some data from. I want to reuse the connection, that's why i chose HTTP.new
require "net/http"
require "openssl"
uri = URI.parse("https://example.com")
path = "/index.html"
http = Net::HTTP.new(uri.host, uri.port,
:use_ssl => uri.scheme == 'https')
request = Net::HTTP::Get.new "/index.html"
response = http.request(request)
When issuing the request (response = http.request(request)) ruby throws a TypeError:
TypeError: no implicit conversion of Hash into String
from /usr/local/Cellar/ruby/2.2.2/lib/ruby/2.2.0/net/http.rb:879:in `initialize'
from /usr/local/Cellar/ruby/2.2.2/lib/ruby/2.2.0/net/http.rb:879:in `open'
from /usr/local/Cellar/ruby/2.2.2/lib/ruby/2.2.0/net/http.rb:879:in `block in connect'
from /usr/local/Cellar/ruby/2.2.2/lib/ruby/2.2.0/timeout.rb:74:in `timeout'
from /usr/local/Cellar/ruby/2.2.2/lib/ruby/2.2.0/net/http.rb:878:in `connect'
from /usr/local/Cellar/ruby/2.2.2/lib/ruby/2.2.0/net/http.rb:863:in `do_start'
from /usr/local/Cellar/ruby/2.2.2/lib/ruby/2.2.0/net/http.rb:852:in `start'
from /usr/local/Cellar/ruby/2.2.2/lib/ruby/2.2.0/net/http.rb:1375:in `request'
from (irb):14
from /usr/local/bin/irb:11:in `<main>'
The same request works when i use http
I'm not sure you aren't overcomplicating the invocation. Why not just use:
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
I'm basing this on the assumption that you already know whether or not your target server requires HTTPS or not.

HTTPS request error: undefined method `set_body_internal'

The following code fails to execute:
require 'net/http'
uri = URI('https://example.com:8443')
http = Net::HTTP.new(uri.host, uri.port)
# Enable SSL/TLS ?
if uri.scheme == "https"
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
http.ca_file = File.join(File.dirname(__FILE__), "ca-rsa-cert.pem")
end
http.start {
http.request(uri)
}
The error is:
$ ./TestCert.rb
/usr/lib/ruby/1.9.1/net/http.rb:1292:in `request': undefined method `set_body_internal'
for #<URI::HTTPS:0x00000001a47fd0 URL:https://example.com:8443> (NoMethodError)
from ./TestCert.rb:16:in `block in <main>'
from /usr/lib/ruby/1.9.1/net/http.rb:745:in `start'
from ./TestCert.rb:15:in `<main>'
Unlike Ruby NoMethodError (undefined method `set_body_internal') with HTTP get, I'm using HTTPS and I don't care about a response. I simply need Ruby to make the connection to test the SSL/TLS server.
I did try to capture a response per the related question, but that had the same error:
http.start {
response = http.request uri
}
And this had the same error:
response = http.start {
http.request uri
}
And http.get failed too (but with a different error - undefined method 'empty?'):
response = http.start {
http.get uri
}
And another failure (but with a different error - undefined method 'empty?'):
http.start {
response = http.get uri
}
If it matters, this is a Debian 7.3 (x64) system running Ruby 1.9.3p194.
How do I make a HTTP request over SSL/TLS using Ruby?
I think your call http.request(uri) is wrong, you should pass a kind of request object like Net::HTTP::Get instead of the uri. Try with the following code:
require 'net/http'
uri = URI('https://example.com:8443')
http = Net::HTTP.new(uri.host, uri.port)
# Enable SSL/TLS ?
if uri.scheme == "https"
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
http.ca_file = File.join(File.dirname(__FILE__), "ca-rsa-cert.pem")
end
req = Net::HTTP::Get.new('/')
http.request(req)
Or call directly request_get('/'). That method will create the Get object for you, like the documentation explain:
def request_get(path, initheader = nil, &block) # :yield: +response+
request(Get.new(path, initheader), &block)
end

Sending http post request in Ruby by Net::HTTP

I'm sending a request with custom headers to a web service.
require 'uri'
require 'net/http'
uri = URI("https://api.site.com/api.dll")
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = true
headers =
{
'HEADER1' => "VALUE1",
'HEADER2' => "HEADER2"
}
response = https.post(uri.path, headers)
puts response
It's not working, I'm receiving an error of:
/usr/lib/ruby/1.9.1/net/http.rb:1932:in `send_request_with_body': undefined method `bytesize' for #<Hash:0x00000001b93a10> (NoMethodError)
How do I solve this?
P.S. Ruby 1.9.3
Try this:
For detailed documentation, take a look at:
http://www.rubyinside.com/nethttp-cheat-sheet-2940.html
require 'uri'
require 'net/http'
uri = URI('https://api.site.com/api.dll')
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = true
request = Net::HTTP::Post.new(uri.path)
request['HEADER1'] = 'VALUE1'
request['HEADER2'] = 'VALUE2'
response = https.request(request)
puts response
The second argument of Net::HTTP#post needs to be a String containing the data to post (often form data), the headers would be in the optional third argument.
As qqx mentioned, the second argument of Net::HTTP#post needs to be a String
Luckily there's a neat function that converts a hash into the required string:
response = https.post(uri.path, URI.encode_www_form(headers))

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