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

10,077

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.

Share:
10,077
Igor de Lorenzi
Author by

Igor de Lorenzi

Updated on June 14, 2022

Comments

  • Igor de Lorenzi
    Igor de Lorenzi almost 2 years

    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
    
  • Igor de Lorenzi
    Igor de Lorenzi almost 10 years
    Thank you @jordan to present me the Net::HTTP. I edited the question description with other possible solutions I reached.
  • raskhadafi
    raskhadafi about 7 years
    Following row: req = NET::HTTP::Post.new(uri.path) has a typo correctly it is: req = Net::HTTP::Post.new(uri.path)