From a869485199f33fc209cfad0db3292078194fba8e Mon Sep 17 00:00:00 2001 From: Nikita Misharin Date: Tue, 30 Jan 2018 20:06:03 +0300 Subject: [PATCH] Generate proper multipart body --- lib/httparty/request/body.rb | 24 +++++++++++--- spec/fixtures/tiny.gif | Bin 0 -> 26 bytes spec/httparty/request/body_spec.rb | 50 +++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 spec/fixtures/tiny.gif create mode 100644 spec/httparty/request/body_spec.rb diff --git a/lib/httparty/request/body.rb b/lib/httparty/request/body.rb index 008d9bd..78136db 100644 --- a/lib/httparty/request/body.rb +++ b/lib/httparty/request/body.rb @@ -17,9 +17,27 @@ module HTTParty end end + def boundary + @boundary ||= "------------------------c772861a5109d5ef" + end + private def generate_multipart + normalized_params = params.flat_map { |key, value| HashConversions.normalize_keys(key, value) } + + multipart = normalized_params.inject('') do |memo, (key, value)| + memo += "--#{boundary}\n" + memo += "Content-Disposition: form-data; name='#{key}'" + memo += "; filename='#{File.basename(value)}'" if file?(value) + memo += "\n" + memo += "Content-Type: application/octet-stream\n" if file?(value) + memo += "\n" + memo += file?(value) ? value.read : value + memo += "\n" + end + + multipart += "--#{boundary}--\n" end def multipart? @@ -39,7 +57,7 @@ module HTTParty end def file?(object) - object.respond_to?(:path) && object.respond_to?(:read) + object.respond_to?(:path) && object.respond_to?(:read) # add memoization end def includes_hash?(object) @@ -54,10 +72,6 @@ module HTTParty end end - def boundary - @boundary ||= "--------------------------#{SecureRandom.urlsafe_base64(12)}" - end - attr_reader :params, :query_string_normalizer, :options end end diff --git a/spec/fixtures/tiny.gif b/spec/fixtures/tiny.gif new file mode 100644 index 0000000000000000000000000000000000000000..264e471abd04356be068ad9cc24fc181fde8ae7a GIT binary patch literal 26 ccmZ?wbhEHbWMp7uVEE6V!vF+eHWPz2062yN6#xJL literal 0 HcmV?d00001 diff --git a/spec/httparty/request/body_spec.rb b/spec/httparty/request/body_spec.rb new file mode 100644 index 0000000..4004a9d --- /dev/null +++ b/spec/httparty/request/body_spec.rb @@ -0,0 +1,50 @@ +require_relative '../../spec_helper' + +RSpec.describe HTTParty::Request::Body do + describe '#call' do + subject { described_class.new(params).call } + + context 'when params is string' do + let(:params) { 'name=Bob%20Jones' } + + it { is_expected.to eq params } + end + + context 'when params is hash' do + let(:params) { { people: ["Bob Jones", "Mike Smith"] } } + let(:converted_params) { "people[]=Bob%20Jones&people[]=Mike%20Smith"} + + it { is_expected.to eq converted_params } + + context 'when params has file' do + let(:params) do + { + user: { + avatar: File.open('spec/fixtures/tiny.gif'), + first_name: 'John', + last_name: 'Doe' + } + } + end + let(:multipart_params) do + "--------------------------c772861a5109d5ef\n" \ + "Content-Disposition: form-data; name='user[avatar]'; filename='tiny.gif'\n" \ + "Content-Type: application/octet-stream\n" \ + "\n" \ + "GIF89a\u0001\u0000\u0001\u0000\u0000\xFF\u0000,\u0000\u0000\u0000\u0000\u0001\u0000\u0001\u0000\u0000\u0002\u0000;\n" \ + "--------------------------c772861a5109d5ef\n" \ + "Content-Disposition: form-data; name='user[first_name]'\n" \ + "\n" \ + "John\n" \ + "--------------------------c772861a5109d5ef\n" \ + "Content-Disposition: form-data; name='user[last_name]'\n" \ + "\n" \ + "Doe\n" \ + "--------------------------c772861a5109d5ef--\n" + end + + it { is_expected.to eq multipart_params } + end + end + end +end