3

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 ...
2
  • 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') Commented Oct 5, 2019 at 0: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 Commented Oct 6, 2019 at 8:34

3 Answers 3

2

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.

Sign up to request clarification or add additional context in comments.

Comments

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

1 Comment

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
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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.