mirror of
https://github.com/HoneyryderChuck/httpx.git
synced 2025-09-14 00:00:44 -04:00
allowing nested params also when posting multipart requests
This commit is contained in:
parent
0bb18ad500
commit
65f5e86f3f
@ -11,7 +11,7 @@ Metrics/ModuleLength:
|
||||
Max: 325
|
||||
|
||||
Metrics/BlockLength:
|
||||
Max: 100
|
||||
Max: 200
|
||||
|
||||
Metrics/BlockNesting:
|
||||
Enabled: False
|
||||
|
@ -23,12 +23,26 @@ module HTTPX
|
||||
def_delegator :@raw, :read
|
||||
|
||||
def initialize(form)
|
||||
@raw = HTTP::FormData.create(form)
|
||||
@raw = if multipart?(form)
|
||||
HTTP::FormData::Multipart.new(Hash[*form.map { |k, v| Transcoder.enum_for(:normalize_keys, k, v).to_a }])
|
||||
else
|
||||
HTTP::FormData::Urlencoded.new(form, :encoder => Transcoder::Form.method(:encode))
|
||||
end
|
||||
end
|
||||
|
||||
def bytesize
|
||||
@raw.content_length
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def multipart?(data)
|
||||
data.any? do |_, v|
|
||||
v.is_a?(HTTP::FormData::Part) ||
|
||||
(v.respond_to?(:to_ary) && v.to_ary.any? { |e| e.is_a?(HTTP::FormData::Part) }) ||
|
||||
(v.respond_to?(:to_hash) && v.to_hash.any? { |_, e| e.is_a?(HTTP::FormData::Part) })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def encode(form)
|
||||
|
@ -3,6 +3,24 @@
|
||||
module HTTPX
|
||||
module Transcoder
|
||||
extend Registry
|
||||
|
||||
def self.normalize_keys(key, value, &block)
|
||||
if value.respond_to?(:to_ary)
|
||||
if value.empty?
|
||||
block.call("#{key}[]")
|
||||
else
|
||||
value.to_ary.each do |element|
|
||||
normalize_keys("#{key}[]", element, &block)
|
||||
end
|
||||
end
|
||||
elsif value.respond_to?(:to_hash)
|
||||
value.to_hash.each do |child_key, child_value|
|
||||
normalize_keys("#{key}[#{child_key}]", child_value, &block)
|
||||
end
|
||||
else
|
||||
block.call(key.to_s, value)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -12,13 +12,16 @@ module HTTPX::Transcoder
|
||||
|
||||
def_delegator :@raw, :to_s
|
||||
|
||||
def_delegator :@raw, :to_str
|
||||
|
||||
def_delegator :@raw, :bytesize
|
||||
|
||||
def initialize(form)
|
||||
@raw = form.each_with_object("".b) do |(key, val), buf|
|
||||
normalize_keys(key, val) do |k, v|
|
||||
HTTPX::Transcoder.normalize_keys(key, val) do |k, v|
|
||||
buf << "&" unless buf.empty?
|
||||
buf << "#{URI.encode_www_form_component(k)}=#{URI.encode_www_form_component(v.to_s)}"
|
||||
buf << URI.encode_www_form_component(k)
|
||||
buf << "=#{URI.encode_www_form_component(v.to_s)}" unless v.nil?
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -26,26 +29,6 @@ module HTTPX::Transcoder
|
||||
def content_type
|
||||
"application/x-www-form-urlencoded"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def normalize_keys(key, value, &block)
|
||||
if value.respond_to?(:to_ary)
|
||||
if value.empty?
|
||||
block.call("#{key}[]", "")
|
||||
else
|
||||
value.to_ary.each do |element|
|
||||
normalize_keys("#{key}[]", element, &block)
|
||||
end
|
||||
end
|
||||
elsif value.respond_to?(:to_hash)
|
||||
value.to_hash.each do |child_key, child_value|
|
||||
normalize_keys("#{key}[#{child_key}]", child_value, &block)
|
||||
end
|
||||
else
|
||||
block.call(key.to_s, value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def encode(form)
|
||||
|
@ -12,7 +12,9 @@ module HTTPX
|
||||
|
||||
private
|
||||
|
||||
def initalize: (Hash[Symbol | string, HTTP::FormData::Part | string] multipart_data) -> untyped
|
||||
def initialize: (Hash[Symbol | string, HTTP::FormData::Part | string] multipart_data) -> untyped
|
||||
|
||||
def multipart?: (top) -> bool
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -4,6 +4,9 @@ module HTTPX
|
||||
module Transcoder
|
||||
extend HTTPX::Registry[String, Class]
|
||||
|
||||
def self.normalize_keys: (string | Symbol, top) { (string, top) -> void } -> void
|
||||
| (string | Symbol, top) { (string) -> void } -> void
|
||||
|
||||
interface _Encoder
|
||||
def bytesize: () -> Numeric
|
||||
end
|
||||
|
@ -11,8 +11,6 @@ module HTTPX::Transcoder
|
||||
private
|
||||
|
||||
def initialize: (urlencoded_input form) -> untyped
|
||||
|
||||
def normalize_keys: (string, untyped) { (string, untyped) -> void } -> void
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -16,6 +16,16 @@ module Requests
|
||||
verify_uploaded(body, "form", "foo" => "bar")
|
||||
end
|
||||
|
||||
define_method :"test_plugin_multipart_nested_urlencoded_#{meth}" do
|
||||
uri = build_uri("/#{meth}")
|
||||
response = HTTPX.plugin(:multipart)
|
||||
.send(meth, uri, form: { "q" => { "a" => "z" }, "a" => %w[1 2] })
|
||||
verify_status(response, 200)
|
||||
body = json_body(response)
|
||||
verify_header(body["headers"], "Content-Type", "application/x-www-form-urlencoded")
|
||||
verify_uploaded(body, "form", "q[a]" => "z", "a[]" => %w[1 2])
|
||||
end
|
||||
|
||||
define_method :"test_plugin_multipart_formdata_#{meth}" do
|
||||
uri = build_uri("/#{meth}")
|
||||
response = HTTPX.plugin(:multipart)
|
||||
@ -25,6 +35,16 @@ module Requests
|
||||
verify_header(body["headers"], "Content-Type", "multipart/form-data")
|
||||
verify_uploaded_image(body)
|
||||
end
|
||||
|
||||
define_method :"test_plugin_multipart_nested_formdata_#{meth}" do
|
||||
uri = build_uri("/#{meth}")
|
||||
response = HTTPX.plugin(:multipart)
|
||||
.send(meth, uri, form: { q: { image: HTTP::FormData::File.new(fixture_file_path) } })
|
||||
verify_status(response, 200)
|
||||
body = json_body(response)
|
||||
verify_header(body["headers"], "Content-Type", "multipart/form-data")
|
||||
verify_uploaded_image(body, "q[image]")
|
||||
end
|
||||
end
|
||||
|
||||
def fixture
|
||||
@ -39,9 +59,9 @@ module Requests
|
||||
File.join("test", "support", "fixtures", "image.jpg")
|
||||
end
|
||||
|
||||
def verify_uploaded_image(body)
|
||||
def verify_uploaded_image(body, key = "image")
|
||||
assert body.key?("files"), "there were no files uploaded"
|
||||
assert body["files"].key?("image"), "there is no image in the file"
|
||||
assert body["files"].key?(key), "there is no image in the file"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -14,11 +14,11 @@ module Requests
|
||||
|
||||
define_method :"test_#{meth}_query_nested_params" do
|
||||
uri = build_uri("/#{meth}")
|
||||
response = HTTPX.send(meth, uri, params: { "q" => { "a" => "z" }, "a" => %w[1 2] })
|
||||
response = HTTPX.send(meth, uri, params: { "q" => { "a" => "z" }, "a" => %w[1 2], "b" => [] })
|
||||
verify_status(response, 200)
|
||||
body = json_body(response)
|
||||
verify_uploaded(body, "args", "q[a]" => "z", "a[]" => %w[1 2])
|
||||
verify_uploaded(body, "url", build_uri("/#{meth}?q[a]=z&a[]=1&a[]=2"))
|
||||
verify_uploaded(body, "args", "q[a]" => "z", "a[]" => %w[1 2], "b[]" => "")
|
||||
verify_uploaded(body, "url", build_uri("/#{meth}?q[a]=z&a[]=1&a[]=2&b[]"))
|
||||
end
|
||||
|
||||
define_method :"test_#{meth}_form_params" do
|
||||
@ -32,11 +32,11 @@ module Requests
|
||||
|
||||
define_method :"test_#{meth}_form_nested_params" do
|
||||
uri = build_uri("/#{meth}")
|
||||
response = HTTPX.send(meth, uri, form: { "q" => { "a" => "z" }, "a" => %w[1 2] })
|
||||
response = HTTPX.send(meth, uri, form: { "q" => { "a" => "z" }, "a" => %w[1 2], "b" => [] })
|
||||
verify_status(response, 200)
|
||||
body = json_body(response)
|
||||
verify_header(body["headers"], "Content-Type", "application/x-www-form-urlencoded")
|
||||
verify_uploaded(body, "form", "q[a]" => "z", "a[]" => %w[1 2])
|
||||
verify_uploaded(body, "form", "q[a]" => "z", "a[]" => %w[1 2], "b[]" => "")
|
||||
end
|
||||
|
||||
define_method :"test_#{meth}_expect_100_form_params" do
|
||||
|
Loading…
x
Reference in New Issue
Block a user