1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
# frozen_string_literal: true
module Rack
module Test
module Utils # :nodoc:
include Rack::Utils
extend self
# Build a query string for the given value and prefix. The value
# can be an array or hash of parameters.
def build_nested_query(value, prefix = nil)
case value
when Array
if value.empty?
"#{prefix}[]="
else
prefix += "[]" unless unescape(prefix).end_with?('[]')
value.map do |v|
build_nested_query(v, prefix.to_s)
end.join('&')
end
when Hash
value.map do |k, v|
build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k))
end.join('&')
when NilClass
prefix.to_s
else
"#{prefix}=#{escape(value)}"
end
end
# Build a multipart body for the given params.
def build_multipart(params, _first = true, multipart = false)
raise ArgumentError, 'value must be a Hash' unless params.is_a?(Hash)
unless multipart
query = lambda { |value|
case value
when Array
value.each(&query)
when Hash
value.values.each(&query)
when UploadedFile
multipart = true
end
}
params.values.each(&query)
return nil unless multipart
end
params = normalize_multipart_params(params, true)
buffer = String.new
build_parts(buffer, params)
buffer
end
private
# Return a flattened hash of parameter values based on the given params.
def normalize_multipart_params(params, first=false)
flattened_params = {}
params.each do |key, value|
k = first ? key.to_s : "[#{key}]"
case value
when Array
value.map do |v|
if v.is_a?(Hash)
nested_params = {}
normalize_multipart_params(v).each do |subkey, subvalue|
nested_params[subkey] = subvalue
end
(flattened_params["#{k}[]"] ||= []) << nested_params
else
flattened_params["#{k}[]"] = value
end
end
when Hash
normalize_multipart_params(value).each do |subkey, subvalue|
flattened_params[k + subkey] = subvalue
end
else
flattened_params[k] = value
end
end
flattened_params
end
# Build the multipart content for uploading.
def build_parts(buffer, parameters)
_build_parts(buffer, parameters)
buffer << END_BOUNDARY
end
# Append each multipart parameter value to the buffer.
def _build_parts(buffer, parameters)
parameters.map do |name, value|
if name =~ /\[\]\Z/ && value.is_a?(Array) && value.all? { |v| v.is_a?(Hash) }
value.each do |hash|
new_value = {}
hash.each { |k, v| new_value[name + k] = v }
_build_parts(buffer, new_value)
end
else
[value].flatten.map do |v|
if v.respond_to?(:original_filename)
build_file_part(buffer, name, v)
else
build_primitive_part(buffer, name, v)
end
end
end
end
end
# Append the multipart fragment for a parameter that isn't a file upload to the buffer.
def build_primitive_part(buffer, parameter_name, value)
buffer <<
START_BOUNDARY <<
"content-disposition: form-data; name=\"" <<
parameter_name.to_s.b <<
"\"\r\n\r\n" <<
value.to_s.b <<
"\r\n"
buffer
end
# Append the multipart fragment for a parameter that is a file upload to the buffer.
def build_file_part(buffer, parameter_name, uploaded_file)
buffer <<
START_BOUNDARY <<
"content-disposition: form-data; name=\"" <<
parameter_name.to_s.b <<
"\"; filename=\"" <<
escape_path(uploaded_file.original_filename).b <<
"\"\r\ncontent-type: " <<
uploaded_file.content_type.to_s.b <<
"\r\ncontent-length: " <<
uploaded_file.size.to_s.b <<
"\r\n\r\n"
# Handle old versions of Capybara::RackTest::Form::NilUploadedFile
if uploaded_file.respond_to?(:set_encoding)
uploaded_file.set_encoding(Encoding::BINARY)
uploaded_file.append_to(buffer)
end
buffer << "\r\n"
end
end
end
end
|