rack-test 0.6.3 → 2.1.0

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