rack-test 0.6.3 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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