2

I need to set Content-type = "application/pdf" to a parameter of a request with the method "set_form" from net/http class but it always shows me Content-Type = "application/octet-stream".

I already checked out the documentation for set_form but I don't know how to properly set the Content-Type.

    http = Net::HTTP.new(uri.host, uri.port)
    request = Net::HTTP::Post.new("#{path}")
    request.set_form([
        ["parameter1","#{parameter1}"],
        ["parameter2","#{parameter2}"],
        ["attachment", File.new("/home/name.pdf", "rb")]
    ], 'multipart/form-data')
    response = http.request(request)

I have tried this code to set opt hash like documentation but I have received the same response:

uri = URI.parse("#{host}")
    http = Net::HTTP.new(uri.host, uri.port)
    request = Net::HTTP::Post.new("#{path}")
    request.set_form([
        ["parameter1","#{parameter1}"],
        ["parameter2","#{parameter2}"],
        ["attachment", File.new("/home/name.pdf", "rb"), { "Content-Type" => "application/pdf" }]
    ], 'multipart/form-data')
    response = http.request(request)

The actual output is still Content-Type: application/octet-stream but I need:

... Content-Disposition: form-data; name=\"attachment\"; filename=\"name.pdf\"\r\nContent-Type: application/pdf\r\n\r\n%PDF-1.5\r%\xE2\xE ...
Christian
  • 4,902
  • 4
  • 24
  • 42
Jose Fdez
  • 23
  • 1
  • 4
  • Why do you need application/pdf? In the documentation there is a hint about the set_form form methods and multipart requests: `request.set_form([['upload', File.open("/home/name.pdf")]], 'multipart/form-data')` – Christian Oct 05 '19 at 00:19
  • Ruby sends by default files with Content-type = application/octet-stream so i need overwrite this value. I have a program that receives this value and if it has this extension the program doesnt recognize the file properly – Jose Fdez Oct 06 '19 at 08:34

3 Answers3

1

I have found this (https://dradisframework.com/blog/2017/04/dradis-attachments-api-using-ruby/), not sure if it helps.

This code builds individual body parts for the request.

require 'net/http'

uri = URI('http://dradis.ip/pro/api/nodes/18/attachments')

Net::HTTP.start(uri.host, uri.port) do |http|

  # Read attachments associated to a specific node:
  get_request = Net::HTTP::Get.new uri
  get_request['Authorization'] = 'Token token="iOEFCQDR-miTHNTjiBxObjWC"'
  get_request['Dradis-Project-Id'] = '8'
  get_response = http.request(get_request)
  puts get_response.body

  # Attach some other files to that node:
  BOUNDARY = "AaB03x"
  file1 = '/your/local/path/image1.png'
  file2 = '/your/local/path/image2.png'

  post_body = []

  post_body << "--#{BOUNDARY}\r\n"

  post_body << "Content-Disposition: form-data; name=\"files[]\"; filename=\"#{File.basename(file1)}\"\r\n"
  post_body << "Content-Type: image/png\r\n"
  post_body << "\r\n"
  post_body << File.read(file1)

  post_body << "\r\n--#{BOUNDARY}\r\n"

  post_body << "Content-Disposition: form-data; name=\"files[]\"; filename=\"#{File.basename(file2)}\"\r\n"
  post_body << "Content-Type: image/png\r\n"
  post_body << "\r\n"
  post_body << File.read(file2)

  post_body << "\r\n--#{BOUNDARY}--\r\n"

  post_request = Net::HTTP::Post.new uri
  post_request['Authorization'] = 'Token token="iOEFCQDR-miTHNTjiBxObjWC"'
  post_request['Dradis-Project-Id'] = '8'
  post_request.body = post_body.join
  post_request["Content-Type"] = "multipart/form-data, boundary=#{BOUNDARY}"

  post_response = http.request(post_request)
  puts post_response.body
end
Christian
  • 4,902
  • 4
  • 24
  • 42
  • Hi Christian, yes this code builds work fine, but i want to know how to use the method set_form. The documentation says that you can set optional values in formopt ( set_form(params, enctype='application/x-www-form-urlencoded', formopt={}) or opt (each item) but i don't know how to use it. thanks a lot – Jose Fdez Oct 09 '19 at 10:44
1

For those who are still looking for how to do it with Net::HTTP, you should be doing:

request.set_form(
  [
    ['attachment', File.open('myfile.pdf'), content_type: 'application/pdf', filename: 'my-better-filename.pdf']
  ],
  'multipart/form-data'
)

Options content_type and filename are optional. By default, content type is application/octet-stream and filename is the name of the file you are opening.

Aleksey Gureiev
  • 1,729
  • 15
  • 17
0

In my opinion this is not possible for multipart requests as you can see in the code for the set_form method, when a different content type is set it should raise an error.

# File net/http/header.rb, line 452
def set_form(params, enctype='application/x-www-form-urlencoded', formopt={})
  @body_data = params
  @body = nil
  @body_stream = nil
  @form_option = formopt
  case enctype
  when /\Aapplication\/x-www-form-urlencoded\z/i,
    /\Amultipart\/form-data\z/i
    self.content_type = enctype
  else
    raise ArgumentError, "invalid enctype: #{enctype}"
  end
end

There are surely workarounds as in my other answer or you can simply use different http clients like HTTParty which support a different content type for multipart requests, start reading the example here and continue in the source code on Github. I haven't found any better documentation.

Christian
  • 4,902
  • 4
  • 24
  • 42