Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to send binary data through a HTTP request using a Ruby gem?

Tags:

http

ruby

I'm trying to find out a way to reproduce a HTTP request that sends binary data in the payload as well as sets a Content-Type: binary header, like the following command with cURL:

echo -e '\x14\x00\x00\x00\x70\x69\x6e\x67\x00\x00' | curl -X POST \
-H 'Content-Type: binary' \
-H 'Accept: */*' \
-H 'Accept-Encoding: gzip,deflate,sdch' \
-H 'Accept-Language: en-US,en;q=0.8,pt;q=0.6' \
-H 'Cookie: JSESSIONID=m1q1hkaptxcqjuvruo5qugpf' \
--data-binary @- \
--url 'http://202.12.53.123' \
--trace-ascii /dev/stdout

I've already tried using the REST Client (https://github.com/rest-client/rest-client) and HTTPClient (https://github.com/nahi/httpclient), but unsuccessfully. Using the code below the server responded with HTTP 500. Has anyone done it before or is it not possible for the purpose to which the gems were designed?

Ruby code:

require 'rest-client'
request = RestClient::Request.new(
  :method => :post, 
  :url => 'http://202.12.53.123', 
  :payload => %w[14 00 00 00 70 69 6e 67 00 00], 
  :headers => {
    :content_type => :binary,
    :accept => '*/*',
    :accept_encoding => 'gzip,deflate,sdch',
    :accept_language => 'en-US,en;q=0.8,pt;q=0.6',
    :cookies => {'JSESSIONID' => 'm1q1hkaptxcqjuvruo5qugpf'}
  }
)
request.execute

UPDATE (w/ one possible solution)

I ended up running the request with the HTTParty (following the direction given by @DemonKingPiccolo) and it worked. Here's the code:

require 'httparty'
hex_data = "14 00 00 00 70 69 6e 67 00 00"
response = HTTParty.post(
  'http://202.12.53.123', 
  :headers => {
    'Content-Type' => 'binary',
    'Accept-Encoding' => 'gzip,deflate,sdch',
    'Accept-Language' => 'en-US,en;q=0.8,pt;q=0.6'
  },
  :cookies => {'JSESSIONID' => 'm1q1hkaptxcqjuvruo5qugpf'},
  :body => [hex_data.gsub(/\s+/,'')].pack('H*').force_encoding('ascii-8bit')
)
puts response.body, response.code, response.message, response.headers.inspect

The body can also be written as suggested by @gumbo:

%w[14 00 00 00 70 69 6e 67 00 00].map { |h| h.to_i(16) }.map(&:chr).join
like image 238
Igor de Lorenzi Avatar asked Jul 02 '14 16:07

Igor de Lorenzi


1 Answers

I just tried this and it worked like a charm:

require "net/http"

uri = URI("http://example.com/")

http = Net::HTTP.new(uri.host, uri.port)

req = Net::HTTP::Post.new(uri.path)
req.body = "\x14\x00\x00\x00\x70\x69\x6e\x67\x00\x00"
req.content_type = "application/octet-stream"

http.request(req)
# => #<Net::HTTPOK 200 OK readbody=true>

I verified that the data POSTed correctly using RequestBin.

Net::HTTP is really rough around the edges and not much fun to use (for example, you have to format your Cookie headers manually). Its main benefit is that it's in the standard library. A gem like RestClient or HTTParty might be a better choice, and I'm pretty sure any of them will handle binary data at least as easily.

like image 67
Jordan Running Avatar answered Sep 30 '22 12:09

Jordan Running