mechanize 2.14.1 → 2.14.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -1
- data/lib/mechanize/directory_saver.rb +2 -1
- data/lib/mechanize/file_saver.rb +2 -0
- data/lib/mechanize/parser.rb +33 -3
- data/lib/mechanize/test_case.rb +2 -9
- data/lib/mechanize/version.rb +1 -1
- metadata +3 -172
- data/.autotest +0 -6
- data/.github/dependabot.yml +0 -11
- data/.github/workflows/ci.yml +0 -43
- data/.github/workflows/upstream.yml +0 -51
- data/.gitignore +0 -15
- data/.yardopts +0 -8
- data/Gemfile +0 -12
- data/Rakefile +0 -56
- data/examples/flickr_upload.rb +0 -22
- data/examples/latest_user_agents.rb +0 -100
- data/examples/mech-dump.rb +0 -5
- data/examples/proxy_req.rb +0 -7
- data/examples/rubygems.rb +0 -23
- data/examples/spider.rb +0 -22
- data/examples/wikipedia_links_to_philosophy.rb +0 -158
- data/mechanize.gemspec +0 -74
- data/test/data/htpasswd +0 -1
- data/test/data/server.crt +0 -16
- data/test/data/server.csr +0 -12
- data/test/data/server.key +0 -15
- data/test/data/server.pem +0 -15
- data/test/test_mechanize.rb +0 -1382
- data/test/test_mechanize_cookie.rb +0 -559
- data/test/test_mechanize_cookie_jar.rb +0 -615
- data/test/test_mechanize_directory_saver.rb +0 -60
- data/test/test_mechanize_download.rb +0 -102
- data/test/test_mechanize_element_not_found_error.rb +0 -16
- data/test/test_mechanize_file.rb +0 -118
- data/test/test_mechanize_file_connection.rb +0 -40
- data/test/test_mechanize_file_request.rb +0 -26
- data/test/test_mechanize_file_response.rb +0 -48
- data/test/test_mechanize_file_saver.rb +0 -22
- data/test/test_mechanize_form.rb +0 -1025
- data/test/test_mechanize_form_check_box.rb +0 -49
- data/test/test_mechanize_form_encoding.rb +0 -110
- data/test/test_mechanize_form_field.rb +0 -78
- data/test/test_mechanize_form_file_upload.rb +0 -21
- data/test/test_mechanize_form_image_button.rb +0 -13
- data/test/test_mechanize_form_keygen.rb +0 -34
- data/test/test_mechanize_form_multi_select_list.rb +0 -98
- data/test/test_mechanize_form_option.rb +0 -60
- data/test/test_mechanize_form_radio_button.rb +0 -96
- data/test/test_mechanize_form_select_list.rb +0 -81
- data/test/test_mechanize_form_textarea.rb +0 -53
- data/test/test_mechanize_headers.rb +0 -36
- data/test/test_mechanize_history.rb +0 -104
- data/test/test_mechanize_http_agent.rb +0 -2145
- data/test/test_mechanize_http_auth_challenge.rb +0 -64
- data/test/test_mechanize_http_auth_realm.rb +0 -56
- data/test/test_mechanize_http_auth_store.rb +0 -233
- data/test/test_mechanize_http_content_disposition_parser.rb +0 -167
- data/test/test_mechanize_http_www_authenticate_parser.rb +0 -204
- data/test/test_mechanize_image.rb +0 -9
- data/test/test_mechanize_link.rb +0 -171
- data/test/test_mechanize_page.rb +0 -295
- data/test/test_mechanize_page_encoding.rb +0 -215
- data/test/test_mechanize_page_frame.rb +0 -17
- data/test/test_mechanize_page_image.rb +0 -191
- data/test/test_mechanize_page_link.rb +0 -377
- data/test/test_mechanize_page_meta_refresh.rb +0 -151
- data/test/test_mechanize_parser.rb +0 -316
- data/test/test_mechanize_pluggable_parser.rb +0 -68
- data/test/test_mechanize_redirect_limit_reached_error.rb +0 -25
- data/test/test_mechanize_redirect_not_get_or_head_error.rb +0 -15
- data/test/test_mechanize_response_read_error.rb +0 -29
- data/test/test_mechanize_subclass.rb +0 -23
- data/test/test_mechanize_util.rb +0 -144
- data/test/test_mechanize_xml_file.rb +0 -30
- data/test/test_multi_select.rb +0 -120
|
@@ -1,2145 +0,0 @@
|
|
|
1
|
-
# coding: utf-8
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
require 'mechanize/test_case'
|
|
5
|
-
unless RUBY_PLATFORM == 'java'
|
|
6
|
-
require 'brotli'
|
|
7
|
-
require 'zstd-ruby'
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
class TestMechanizeHttpAgent < Mechanize::TestCase
|
|
11
|
-
|
|
12
|
-
def setup
|
|
13
|
-
super
|
|
14
|
-
|
|
15
|
-
@agent = @mech.agent
|
|
16
|
-
|
|
17
|
-
@uri = URI.parse 'http://example/'
|
|
18
|
-
|
|
19
|
-
@req = Net::HTTP::Get.new '/'
|
|
20
|
-
@res = Net::HTTPOK.allocate
|
|
21
|
-
@res.instance_variable_set :@code, 200
|
|
22
|
-
@res.instance_variable_set :@header, {}
|
|
23
|
-
|
|
24
|
-
@headers = %w[accept accept-encoding user-agent]
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def auth_realm uri, scheme, type
|
|
28
|
-
base_uri = uri + '/'
|
|
29
|
-
realm = Mechanize::HTTP::AuthRealm.new scheme, base_uri, 'r'
|
|
30
|
-
@agent.authenticate_methods[base_uri][type] << realm
|
|
31
|
-
|
|
32
|
-
realm
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def skip_if_jruby_zlib
|
|
36
|
-
if RUBY_ENGINE == 'jruby'
|
|
37
|
-
meth = caller_locations(1,1).first.base_label
|
|
38
|
-
skip "#{meth}: skipped because how Zlib handles error is different in JRuby"
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def test_agent_is_named
|
|
43
|
-
assert_equal 'mechanize', Mechanize::HTTP::Agent.new.http.name
|
|
44
|
-
assert_equal 'unique', Mechanize::HTTP::Agent.new('unique').http.name
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def test_auto_io
|
|
48
|
-
Tempfile.open 'input' do |input_io|
|
|
49
|
-
input_io.binmode
|
|
50
|
-
input_io.write '12345'
|
|
51
|
-
input_io.rewind
|
|
52
|
-
|
|
53
|
-
out_io = @agent.auto_io @NAME, 1024, input_io
|
|
54
|
-
|
|
55
|
-
assert_equal '12345', out_io.string
|
|
56
|
-
|
|
57
|
-
assert_equal Encoding::BINARY, out_io.string.encoding if
|
|
58
|
-
Object.const_defined? :Encoding
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def test_auto_io_chunk
|
|
63
|
-
Tempfile.open 'input' do |input_io|
|
|
64
|
-
chunks = []
|
|
65
|
-
|
|
66
|
-
input_io.binmode
|
|
67
|
-
input_io.write '12345'
|
|
68
|
-
input_io.rewind
|
|
69
|
-
|
|
70
|
-
@agent.auto_io @NAME, 1, input_io do |chunk|
|
|
71
|
-
chunks << chunk
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
assert_equal %w[1 2 3 4 5], chunks
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def test_auto_io_tempfile
|
|
79
|
-
@agent.max_file_buffer = 3
|
|
80
|
-
|
|
81
|
-
Tempfile.open 'input' do |input_io|
|
|
82
|
-
input_io.binmode
|
|
83
|
-
input_io.write '12345'
|
|
84
|
-
input_io.rewind
|
|
85
|
-
|
|
86
|
-
out_io = @agent.auto_io @NAME, 1, input_io
|
|
87
|
-
|
|
88
|
-
result = out_io.read
|
|
89
|
-
assert_equal '12345', result
|
|
90
|
-
|
|
91
|
-
assert_equal Encoding::BINARY, result.encoding if
|
|
92
|
-
Object.const_defined? :Encoding
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def test_auto_io_yield
|
|
97
|
-
Tempfile.open 'input' do |input_io|
|
|
98
|
-
input_io.binmode
|
|
99
|
-
input_io.write '12345'
|
|
100
|
-
input_io.rewind
|
|
101
|
-
|
|
102
|
-
out_io = @agent.auto_io @NAME, 1024, input_io do |chunk|
|
|
103
|
-
"x#{chunk}"
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
assert_equal 'x12345', out_io.string
|
|
107
|
-
end
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def test_certificate_equals
|
|
111
|
-
cert_path = File.expand_path '../data/server.crt', __FILE__
|
|
112
|
-
cert = OpenSSL::X509::Certificate.new File.read cert_path
|
|
113
|
-
|
|
114
|
-
@agent.certificate = cert
|
|
115
|
-
|
|
116
|
-
assert_equal cert.to_pem, @agent.certificate.to_pem
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
def test_certificate_equals_file
|
|
120
|
-
cert_path = File.expand_path '../data/server.crt', __FILE__
|
|
121
|
-
|
|
122
|
-
cert = OpenSSL::X509::Certificate.new File.read cert_path
|
|
123
|
-
|
|
124
|
-
@agent.certificate = cert_path
|
|
125
|
-
|
|
126
|
-
assert_equal cert.to_pem, @agent.certificate.to_pem
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
def test_connection_for_file
|
|
130
|
-
uri = URI.parse 'file:///nonexistent'
|
|
131
|
-
conn = @agent.connection_for uri
|
|
132
|
-
|
|
133
|
-
assert_equal Mechanize::FileConnection.new, conn
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
def test_connection_for_http
|
|
137
|
-
conn = @agent.connection_for @uri
|
|
138
|
-
|
|
139
|
-
assert_equal @agent.http, conn
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
def test_disable_keep_alive
|
|
143
|
-
@agent.disable_keep_alive @req
|
|
144
|
-
|
|
145
|
-
refute @req['connection']
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
def test_disable_keep_alive_no
|
|
149
|
-
@agent.keep_alive = false
|
|
150
|
-
|
|
151
|
-
@agent.disable_keep_alive @req
|
|
152
|
-
|
|
153
|
-
assert_equal 'close', @req['connection']
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
def test_enable_gzip
|
|
157
|
-
@agent.enable_gzip @req
|
|
158
|
-
|
|
159
|
-
assert_equal 'gzip,deflate,identity', @req['accept-encoding']
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
def test_enable_gzip_no
|
|
163
|
-
@agent.gzip_enabled = false
|
|
164
|
-
|
|
165
|
-
@agent.enable_gzip @req
|
|
166
|
-
|
|
167
|
-
assert_equal 'identity', @req['accept-encoding']
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
def test_fetch_file_nonexistent
|
|
171
|
-
in_tmpdir do
|
|
172
|
-
nonexistent = File.join Dir.pwd, 'nonexistent'
|
|
173
|
-
|
|
174
|
-
uri = URI.parse "file:///#{nonexistent}"
|
|
175
|
-
|
|
176
|
-
e = assert_raises Mechanize::ResponseCodeError do
|
|
177
|
-
@agent.fetch uri
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
assert_match "404 => Net::HTTPNotFound for #{uri}", e.message
|
|
181
|
-
end
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
def test_fetch_file_plus
|
|
185
|
-
Tempfile.open '++plus++' do |io|
|
|
186
|
-
content = 'plusses +++'
|
|
187
|
-
io.write content
|
|
188
|
-
io.rewind
|
|
189
|
-
|
|
190
|
-
uri = URI.parse "file://#{Mechanize::Util.uri_escape io.path}"
|
|
191
|
-
|
|
192
|
-
page = @agent.fetch uri
|
|
193
|
-
|
|
194
|
-
assert_equal content, page.body
|
|
195
|
-
assert_kind_of Mechanize::File, page
|
|
196
|
-
end
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
def test_fetch_file_space
|
|
200
|
-
foo = File.expand_path("../htdocs/dir with spaces/foo.html", __FILE__)
|
|
201
|
-
|
|
202
|
-
uri = URI.parse "file://#{Mechanize::Util.uri_escape foo}"
|
|
203
|
-
|
|
204
|
-
page = @agent.fetch uri
|
|
205
|
-
|
|
206
|
-
assert_equal File.read(foo), page.body.gsub(/\r\n/, "\n")
|
|
207
|
-
assert_kind_of Mechanize::Page, page
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
def test_fetch_head_gzip
|
|
211
|
-
uri = @uri + '/gzip?file=index.html'
|
|
212
|
-
|
|
213
|
-
page = @agent.fetch uri, :head
|
|
214
|
-
|
|
215
|
-
assert_kind_of Mechanize::Page, page
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
def test_fetch_hooks
|
|
219
|
-
@agent.pre_connect_hooks << proc do |agent, request|
|
|
220
|
-
assert_equal '/index.html', request.path
|
|
221
|
-
assert_equal @agent, agent
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
@agent.post_connect_hooks << proc do |agent, uri, response, body|
|
|
225
|
-
assert_equal @agent, agent
|
|
226
|
-
assert_equal URI('http://example/index.html'), uri
|
|
227
|
-
assert_equal '200', response.code
|
|
228
|
-
assert_kind_of String, body
|
|
229
|
-
end
|
|
230
|
-
|
|
231
|
-
@agent.fetch URI 'http://example/index.html'
|
|
232
|
-
end
|
|
233
|
-
|
|
234
|
-
def test_fetch_ignore_bad_chunking
|
|
235
|
-
@agent.ignore_bad_chunking = true
|
|
236
|
-
|
|
237
|
-
file = @agent.fetch 'http://example/bad_chunking'
|
|
238
|
-
|
|
239
|
-
assert_equal '0123456789', file.content
|
|
240
|
-
end
|
|
241
|
-
|
|
242
|
-
def test_fetch_post_connect_hook
|
|
243
|
-
response = nil
|
|
244
|
-
@agent.post_connect_hooks << lambda { |_, _, res, _| response = res }
|
|
245
|
-
|
|
246
|
-
@agent.fetch 'http://localhost/'
|
|
247
|
-
|
|
248
|
-
assert response
|
|
249
|
-
end
|
|
250
|
-
|
|
251
|
-
def test_fetch_redirect_header
|
|
252
|
-
page = @agent.fetch('http://example/redirect', :get,
|
|
253
|
-
'X-Location' => '/http_headers',
|
|
254
|
-
'Range' => 'bytes=0-99999')
|
|
255
|
-
|
|
256
|
-
assert_match 'range|bytes=0-999', page.body
|
|
257
|
-
end
|
|
258
|
-
|
|
259
|
-
def test_fetch_server_error
|
|
260
|
-
e = assert_raises Mechanize::ResponseCodeError do
|
|
261
|
-
@mech.get 'http://localhost/response_code?code=500'
|
|
262
|
-
end
|
|
263
|
-
|
|
264
|
-
assert_equal '500', e.response_code
|
|
265
|
-
end
|
|
266
|
-
|
|
267
|
-
def test_fetch_allowed_error_codes
|
|
268
|
-
@agent.allowed_error_codes = ['500']
|
|
269
|
-
|
|
270
|
-
page = @mech.get 'http://localhost/response_code?code=500'
|
|
271
|
-
|
|
272
|
-
assert_equal '500', page.code
|
|
273
|
-
end
|
|
274
|
-
|
|
275
|
-
def test_fetch_allowed_error_codes_int
|
|
276
|
-
@agent.allowed_error_codes = [500]
|
|
277
|
-
|
|
278
|
-
page = @mech.get 'http://localhost/response_code?code=500'
|
|
279
|
-
|
|
280
|
-
assert_equal '500', page.code
|
|
281
|
-
end
|
|
282
|
-
|
|
283
|
-
def test_get_meta_refresh_header_follow_self
|
|
284
|
-
@agent.follow_meta_refresh = true
|
|
285
|
-
@agent.follow_meta_refresh_self = true
|
|
286
|
-
|
|
287
|
-
page = Mechanize::Page.new(@uri, nil, '', 200, @mech)
|
|
288
|
-
@res.instance_variable_set :@header, 'refresh' => ['0']
|
|
289
|
-
|
|
290
|
-
refresh = @agent.get_meta_refresh @res, @uri, page
|
|
291
|
-
|
|
292
|
-
assert_equal [0.0, URI('http://example/')], refresh
|
|
293
|
-
end
|
|
294
|
-
|
|
295
|
-
def test_get_meta_refresh_header_no_follow
|
|
296
|
-
page = Mechanize::Page.new(@uri, nil, '', 200, @mech)
|
|
297
|
-
@res.instance_variable_set :@header, 'refresh' => ['0']
|
|
298
|
-
|
|
299
|
-
refresh = @agent.get_meta_refresh @res, @uri, page
|
|
300
|
-
|
|
301
|
-
assert_nil refresh
|
|
302
|
-
end
|
|
303
|
-
|
|
304
|
-
def test_get_meta_refresh_header_no_follow_self
|
|
305
|
-
@agent.follow_meta_refresh = true
|
|
306
|
-
|
|
307
|
-
page = Mechanize::Page.new(@uri, nil, '', 200, @mech)
|
|
308
|
-
@res.instance_variable_set :@header, 'refresh' => ['0']
|
|
309
|
-
|
|
310
|
-
refresh = @agent.get_meta_refresh @res, @uri, page
|
|
311
|
-
|
|
312
|
-
assert_nil refresh
|
|
313
|
-
end
|
|
314
|
-
|
|
315
|
-
def test_get_meta_refresh_meta_follow_self
|
|
316
|
-
@agent.follow_meta_refresh = true
|
|
317
|
-
@agent.follow_meta_refresh_self = true
|
|
318
|
-
|
|
319
|
-
body = <<-BODY
|
|
320
|
-
<title></title>
|
|
321
|
-
<meta http-equiv="refresh" content="0">
|
|
322
|
-
BODY
|
|
323
|
-
|
|
324
|
-
page = Mechanize::Page.new(@uri, nil, body, 200, @mech)
|
|
325
|
-
|
|
326
|
-
refresh = @agent.get_meta_refresh @res, @uri, page
|
|
327
|
-
|
|
328
|
-
assert_equal [0, nil], refresh
|
|
329
|
-
end
|
|
330
|
-
|
|
331
|
-
def test_get_meta_refresh_meta_no_follow
|
|
332
|
-
body = <<-BODY
|
|
333
|
-
<title></title>
|
|
334
|
-
<meta http-equiv="refresh" content="0">
|
|
335
|
-
BODY
|
|
336
|
-
|
|
337
|
-
page = Mechanize::Page.new(@uri, nil, body, 200, @mech)
|
|
338
|
-
|
|
339
|
-
refresh = @agent.get_meta_refresh @res, @uri, page
|
|
340
|
-
|
|
341
|
-
assert_nil refresh
|
|
342
|
-
end
|
|
343
|
-
|
|
344
|
-
def test_get_meta_refresh_meta_no_follow_self
|
|
345
|
-
@agent.follow_meta_refresh = true
|
|
346
|
-
|
|
347
|
-
body = <<-BODY
|
|
348
|
-
<title></title>
|
|
349
|
-
<meta http-equiv="refresh" content="0">
|
|
350
|
-
BODY
|
|
351
|
-
|
|
352
|
-
page = Mechanize::Page.new(@uri, nil, body, 200, @mech)
|
|
353
|
-
|
|
354
|
-
refresh = @agent.get_meta_refresh @res, @uri, page
|
|
355
|
-
|
|
356
|
-
assert_nil refresh
|
|
357
|
-
end
|
|
358
|
-
|
|
359
|
-
def test_get_robots
|
|
360
|
-
robotstxt = @agent.get_robots 'http://localhost/robots.txt'
|
|
361
|
-
refute_equal '', robotstxt
|
|
362
|
-
|
|
363
|
-
robotstxt = @agent.get_robots 'http://localhost/response_code?code=404'
|
|
364
|
-
assert_equal '', robotstxt
|
|
365
|
-
end
|
|
366
|
-
|
|
367
|
-
def test_hook_content_encoding_response
|
|
368
|
-
@mech.content_encoding_hooks << lambda{|agent, uri, response, response_body_io|
|
|
369
|
-
response['content-encoding'] = 'gzip' if response['content-encoding'] == 'agzip'}
|
|
370
|
-
|
|
371
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[agzip]
|
|
372
|
-
body_io = StringIO.new 'part'
|
|
373
|
-
@agent.hook_content_encoding @res, @uri, body_io
|
|
374
|
-
|
|
375
|
-
assert_equal 'gzip', @res['content-encoding']
|
|
376
|
-
end
|
|
377
|
-
|
|
378
|
-
def test_http_request_file
|
|
379
|
-
uri = URI.parse 'file:///nonexistent'
|
|
380
|
-
request = @agent.http_request uri, :get
|
|
381
|
-
|
|
382
|
-
assert_kind_of Mechanize::FileRequest, request
|
|
383
|
-
assert_equal '/nonexistent', request.path
|
|
384
|
-
end
|
|
385
|
-
|
|
386
|
-
def test_http_request_get
|
|
387
|
-
request = @agent.http_request @uri, :get
|
|
388
|
-
|
|
389
|
-
assert_kind_of Net::HTTP::Get, request
|
|
390
|
-
assert_equal '/', request.path
|
|
391
|
-
end
|
|
392
|
-
|
|
393
|
-
def test_http_request_post
|
|
394
|
-
request = @agent.http_request @uri, :post
|
|
395
|
-
|
|
396
|
-
assert_kind_of Net::HTTP::Post, request
|
|
397
|
-
assert_equal '/', request.path
|
|
398
|
-
end
|
|
399
|
-
|
|
400
|
-
def test_idle_timeout_equals
|
|
401
|
-
@agent.idle_timeout = 1
|
|
402
|
-
|
|
403
|
-
assert_equal 1, @agent.http.idle_timeout
|
|
404
|
-
end
|
|
405
|
-
|
|
406
|
-
def test_inflate
|
|
407
|
-
body_io = StringIO.new "x\x9C+H,*\x01\x00\x04?\x01\xB8"
|
|
408
|
-
|
|
409
|
-
result = @agent.inflate body_io
|
|
410
|
-
|
|
411
|
-
assert_equal 'part', result.read
|
|
412
|
-
end
|
|
413
|
-
|
|
414
|
-
def test_post_connect
|
|
415
|
-
@agent.post_connect_hooks << proc { |agent, uri, response, body|
|
|
416
|
-
assert_equal @agent, agent
|
|
417
|
-
assert_equal @res, response
|
|
418
|
-
assert_equal 'body', body
|
|
419
|
-
throw :called
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
io = StringIO.new 'body'
|
|
423
|
-
|
|
424
|
-
assert_throws :called do
|
|
425
|
-
@agent.post_connect @uri, @res, io
|
|
426
|
-
end
|
|
427
|
-
|
|
428
|
-
assert_equal 0, io.pos
|
|
429
|
-
end
|
|
430
|
-
|
|
431
|
-
def test_pre_connect
|
|
432
|
-
@agent.pre_connect_hooks << proc { |agent, request|
|
|
433
|
-
assert_equal @agent, agent
|
|
434
|
-
assert_equal @req, request
|
|
435
|
-
throw :called
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
assert_throws :called do
|
|
439
|
-
@agent.pre_connect @req
|
|
440
|
-
end
|
|
441
|
-
end
|
|
442
|
-
|
|
443
|
-
def test_request_add_headers
|
|
444
|
-
@agent.request_add_headers @req, 'Content-Length' => 300
|
|
445
|
-
|
|
446
|
-
assert_equal '300', @req['content-length']
|
|
447
|
-
end
|
|
448
|
-
|
|
449
|
-
def test_request_add_headers_etag
|
|
450
|
-
@agent.request_add_headers @req, :etag => '300'
|
|
451
|
-
|
|
452
|
-
assert_equal '300', @req['etag']
|
|
453
|
-
end
|
|
454
|
-
|
|
455
|
-
def test_request_add_headers_if_modified_since
|
|
456
|
-
@agent.request_add_headers @req, :if_modified_since => 'some_date'
|
|
457
|
-
|
|
458
|
-
assert_equal 'some_date', @req['if-modified-since']
|
|
459
|
-
end
|
|
460
|
-
|
|
461
|
-
def test_request_add_headers_none
|
|
462
|
-
@agent.request_add_headers @req
|
|
463
|
-
|
|
464
|
-
assert_equal @headers, @req.to_hash.keys.sort
|
|
465
|
-
end
|
|
466
|
-
|
|
467
|
-
def test_fetch_accepts_symbol_names_in_request_headers
|
|
468
|
-
@agent.request_headers = { Authorization: 'Bearer tokensecret' }
|
|
469
|
-
|
|
470
|
-
page = @agent.fetch 'http://example/http_headers'
|
|
471
|
-
|
|
472
|
-
assert_match 'authorization|Bearer tokensecret', page.body
|
|
473
|
-
end
|
|
474
|
-
|
|
475
|
-
def test_fetch_lets_a_request_header_override_any_spelling_of_an_agent_header
|
|
476
|
-
@agent.request_headers = { 'Authorization' => 'agent-one', 'authorization' => 'agent-two' }
|
|
477
|
-
|
|
478
|
-
page = @agent.fetch 'http://example/http_headers', :get,
|
|
479
|
-
{ 'Authorization' => 'per-request' }
|
|
480
|
-
|
|
481
|
-
assert_match 'authorization|per-request', page.body
|
|
482
|
-
end
|
|
483
|
-
|
|
484
|
-
def test_meta_refresh_drops_entity_headers
|
|
485
|
-
@agent.follow_meta_refresh = true
|
|
486
|
-
|
|
487
|
-
uri = URI 'http://example/session'
|
|
488
|
-
response = Net::HTTPOK.new '1.1', '200', 'OK'
|
|
489
|
-
response['Refresh'] = '0;url=/http_headers'
|
|
490
|
-
page = Mechanize::Page.new uri, response, '', 200, @mech
|
|
491
|
-
|
|
492
|
-
@agent.response_follow_meta_refresh(response, uri, page, 0,
|
|
493
|
-
{ 'Content-Length' => '7',
|
|
494
|
-
'Content-Type' => 'text/plain',
|
|
495
|
-
'Content-MD5' => 'deadbeef' })
|
|
496
|
-
|
|
497
|
-
request = requests.last
|
|
498
|
-
|
|
499
|
-
assert_equal 'GET', request.method
|
|
500
|
-
assert_nil request['Content-Length']
|
|
501
|
-
assert_nil request['Content-Type']
|
|
502
|
-
assert_nil request['Content-MD5']
|
|
503
|
-
end
|
|
504
|
-
|
|
505
|
-
def test_fetch_applies_request_headers
|
|
506
|
-
@agent.request_headers['X-Foo'] = 'bar'
|
|
507
|
-
|
|
508
|
-
page = @agent.fetch 'http://example/http_headers'
|
|
509
|
-
|
|
510
|
-
assert_match 'x-foo|bar', page.body
|
|
511
|
-
end
|
|
512
|
-
|
|
513
|
-
def test_request_add_headers_symbol
|
|
514
|
-
e = assert_raises ArgumentError do
|
|
515
|
-
@agent.request_add_headers @req, :content_length => 300
|
|
516
|
-
end
|
|
517
|
-
|
|
518
|
-
assert_equal 'unknown header symbol content_length', e.message
|
|
519
|
-
end
|
|
520
|
-
|
|
521
|
-
def test_request_auth_basic
|
|
522
|
-
@agent.add_auth @uri, 'user', 'password'
|
|
523
|
-
|
|
524
|
-
auth_realm @uri, 'Basic', :basic
|
|
525
|
-
|
|
526
|
-
@agent.request_auth @req, @uri
|
|
527
|
-
|
|
528
|
-
assert_match %r%^Basic %, @req['Authorization']
|
|
529
|
-
end
|
|
530
|
-
|
|
531
|
-
def test_request_auth_digest
|
|
532
|
-
@agent.add_auth @uri, 'user', 'password'
|
|
533
|
-
|
|
534
|
-
realm = auth_realm @uri, 'Digest', :digest
|
|
535
|
-
@agent.digest_challenges[realm] = 'Digest realm=r, qop="auth"'
|
|
536
|
-
|
|
537
|
-
@agent.request_auth @req, @uri
|
|
538
|
-
|
|
539
|
-
assert_match %r%^Digest %, @req['Authorization']
|
|
540
|
-
assert_match %r%qop=auth%, @req['Authorization']
|
|
541
|
-
|
|
542
|
-
@req['Authorization'] = nil
|
|
543
|
-
@agent.request_auth @req, @uri
|
|
544
|
-
|
|
545
|
-
assert_match %r%^Digest %, @req['Authorization']
|
|
546
|
-
assert_match %r%qop=auth%, @req['Authorization']
|
|
547
|
-
end
|
|
548
|
-
|
|
549
|
-
def test_request_auth_iis_digest
|
|
550
|
-
@agent.add_auth @uri, 'user', 'password'
|
|
551
|
-
|
|
552
|
-
realm = auth_realm @uri, 'Digest', :digest
|
|
553
|
-
@agent.digest_challenges[realm] = 'Digest realm=r, qop="auth"'
|
|
554
|
-
|
|
555
|
-
@agent.request_auth @req, @uri
|
|
556
|
-
|
|
557
|
-
assert_match %r%^Digest %, @req['Authorization']
|
|
558
|
-
assert_match %r%qop=auth%, @req['Authorization']
|
|
559
|
-
end
|
|
560
|
-
|
|
561
|
-
def test_request_auth_none
|
|
562
|
-
@agent.request_auth @req, @uri
|
|
563
|
-
|
|
564
|
-
assert_nil @req['Authorization']
|
|
565
|
-
end
|
|
566
|
-
|
|
567
|
-
def test_request_cookies
|
|
568
|
-
uri = URI.parse 'http://host.example.com'
|
|
569
|
-
@agent.cookie_jar.parse 'hello=world domain=.example.com', uri
|
|
570
|
-
|
|
571
|
-
@agent.request_cookies @req, uri
|
|
572
|
-
|
|
573
|
-
assert_equal 'hello="world domain=.example.com"', @req['Cookie']
|
|
574
|
-
end
|
|
575
|
-
|
|
576
|
-
def test_request_cookies_many
|
|
577
|
-
uri = URI.parse 'http://host.example.com'
|
|
578
|
-
cookie_str = 'a=b domain=.example.com, c=d domain=.example.com'
|
|
579
|
-
@agent.cookie_jar.parse cookie_str, uri
|
|
580
|
-
|
|
581
|
-
@agent.request_cookies @req, uri
|
|
582
|
-
|
|
583
|
-
expected_variant1 = /a="b domain=\.example\.com"; c="d domain=\.example\.com"/
|
|
584
|
-
expected_variant2 = /c="d domain=\.example\.com"; a="b domain=\.example\.com"/
|
|
585
|
-
|
|
586
|
-
assert_match(/^(#{expected_variant1}|#{expected_variant2})$/, @req['Cookie'])
|
|
587
|
-
end
|
|
588
|
-
|
|
589
|
-
def test_request_cookies_none
|
|
590
|
-
@agent.request_cookies @req, @uri
|
|
591
|
-
|
|
592
|
-
assert_nil @req['Cookie']
|
|
593
|
-
end
|
|
594
|
-
|
|
595
|
-
def test_request_cookies_wrong_domain
|
|
596
|
-
uri = URI.parse 'http://host.example.com'
|
|
597
|
-
@agent.cookie_jar.parse 'hello=world domain=.example.com', uri
|
|
598
|
-
|
|
599
|
-
@agent.request_cookies @req, @uri
|
|
600
|
-
|
|
601
|
-
assert_nil @req['Cookie']
|
|
602
|
-
end
|
|
603
|
-
|
|
604
|
-
def test_request_host
|
|
605
|
-
@agent.request_host @req, @uri
|
|
606
|
-
|
|
607
|
-
assert_equal 'example', @req['host']
|
|
608
|
-
end
|
|
609
|
-
|
|
610
|
-
def test_request_host_nonstandard
|
|
611
|
-
@uri.port = 81
|
|
612
|
-
|
|
613
|
-
@agent.request_host @req, @uri
|
|
614
|
-
|
|
615
|
-
assert_equal 'example:81', @req['host']
|
|
616
|
-
end
|
|
617
|
-
|
|
618
|
-
def test_request_language_charset
|
|
619
|
-
@agent.request_language_charset @req
|
|
620
|
-
|
|
621
|
-
assert_equal('en-us,en;q=0.5', @req['accept-language'])
|
|
622
|
-
assert_nil(@req['accept-charset'])
|
|
623
|
-
end
|
|
624
|
-
|
|
625
|
-
def test_request_referer
|
|
626
|
-
referer = URI.parse 'http://old.example'
|
|
627
|
-
|
|
628
|
-
@agent.request_referer @req, @uri, referer
|
|
629
|
-
|
|
630
|
-
assert_equal 'http://old.example', @req['referer']
|
|
631
|
-
end
|
|
632
|
-
|
|
633
|
-
def test_request_referer_https
|
|
634
|
-
uri = URI.parse 'https://example'
|
|
635
|
-
referer = URI.parse 'https://old.example'
|
|
636
|
-
|
|
637
|
-
@agent.request_referer @req, uri, referer
|
|
638
|
-
|
|
639
|
-
assert_equal 'https://old.example', @req['referer']
|
|
640
|
-
end
|
|
641
|
-
|
|
642
|
-
def test_request_referer_https_downgrade
|
|
643
|
-
referer = URI.parse 'https://old.example'
|
|
644
|
-
|
|
645
|
-
@agent.request_referer @req, @uri, referer
|
|
646
|
-
|
|
647
|
-
assert_nil @req['referer']
|
|
648
|
-
end
|
|
649
|
-
|
|
650
|
-
def test_request_referer_https_downgrade_case
|
|
651
|
-
uri = URI.parse 'http://example'
|
|
652
|
-
referer = URI.parse 'httpS://old.example'
|
|
653
|
-
|
|
654
|
-
@agent.request_referer @req, uri, referer
|
|
655
|
-
|
|
656
|
-
assert_nil @req['referer']
|
|
657
|
-
end
|
|
658
|
-
|
|
659
|
-
def test_request_referer_https_upgrade
|
|
660
|
-
uri = URI.parse 'https://example'
|
|
661
|
-
referer = URI.parse 'http://old.example'
|
|
662
|
-
|
|
663
|
-
@agent.request_referer @req, uri, referer
|
|
664
|
-
|
|
665
|
-
assert_equal 'http://old.example', @req['referer']
|
|
666
|
-
end
|
|
667
|
-
|
|
668
|
-
def test_request_referer_none
|
|
669
|
-
@agent.request_referer @req, @uri, nil
|
|
670
|
-
|
|
671
|
-
assert_nil @req['referer']
|
|
672
|
-
end
|
|
673
|
-
|
|
674
|
-
def test_request_referer_strip
|
|
675
|
-
uri = URI.parse 'http://example.com/index.html'
|
|
676
|
-
|
|
677
|
-
host_path = "old.example/page.html?q=x"
|
|
678
|
-
referer = "http://#{host_path}"
|
|
679
|
-
|
|
680
|
-
[
|
|
681
|
-
"",
|
|
682
|
-
"@",
|
|
683
|
-
"user1@",
|
|
684
|
-
":@",
|
|
685
|
-
"user1:@",
|
|
686
|
-
":password1@",
|
|
687
|
-
"user1:password1@",
|
|
688
|
-
].each { |userinfo|
|
|
689
|
-
['', '#frag'].each { |frag|
|
|
690
|
-
url = URI.parse "http://#{userinfo}#{host_path}#{frag}"
|
|
691
|
-
|
|
692
|
-
@agent.request_referer @req, uri, url
|
|
693
|
-
|
|
694
|
-
assert_equal referer, @req['referer'], url
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
end
|
|
698
|
-
|
|
699
|
-
def test_request_user_agent
|
|
700
|
-
@agent.request_user_agent @req
|
|
701
|
-
|
|
702
|
-
assert_match %r%^Mechanize/#{Mechanize::VERSION}%, @req['user-agent']
|
|
703
|
-
|
|
704
|
-
ruby_version = if RUBY_PATCHLEVEL >= 0 then
|
|
705
|
-
"#{RUBY_VERSION}p#{RUBY_PATCHLEVEL}"
|
|
706
|
-
else
|
|
707
|
-
"#{RUBY_VERSION}dev#{RUBY_REVISION}"
|
|
708
|
-
end
|
|
709
|
-
|
|
710
|
-
assert_match %r%Ruby/#{ruby_version}%, @req['user-agent']
|
|
711
|
-
end
|
|
712
|
-
|
|
713
|
-
def test_resolve_bad_uri
|
|
714
|
-
e = assert_raises ArgumentError do
|
|
715
|
-
@agent.resolve 'google'
|
|
716
|
-
end
|
|
717
|
-
|
|
718
|
-
assert_equal 'absolute URL needed (not google)', e.message
|
|
719
|
-
end
|
|
720
|
-
|
|
721
|
-
def test_resolve_uri_without_path
|
|
722
|
-
e = assert_raises ArgumentError do
|
|
723
|
-
@agent.resolve 'http:%5C%5Cfoo'
|
|
724
|
-
end
|
|
725
|
-
|
|
726
|
-
assert_equal 'hierarchical URL needed (not http:%5C%5Cfoo)', e.message
|
|
727
|
-
end
|
|
728
|
-
|
|
729
|
-
def test_resolve_utf8
|
|
730
|
-
uri = 'http://example?q=ü'
|
|
731
|
-
|
|
732
|
-
resolved = @agent.resolve uri
|
|
733
|
-
|
|
734
|
-
assert_equal '/?q=%C3%BC', resolved.request_uri
|
|
735
|
-
end
|
|
736
|
-
|
|
737
|
-
def test_resolve_parameters_body
|
|
738
|
-
input_params = { :q => 'hello' }
|
|
739
|
-
|
|
740
|
-
uri, params = @agent.resolve_parameters @uri, :post, input_params
|
|
741
|
-
|
|
742
|
-
assert_equal 'http://example/', uri.to_s
|
|
743
|
-
assert_equal input_params, params
|
|
744
|
-
end
|
|
745
|
-
|
|
746
|
-
def test_resolve_parameters_query
|
|
747
|
-
uri, params = @agent.resolve_parameters @uri, :get, :q => 'hello'
|
|
748
|
-
|
|
749
|
-
assert_equal 'http://example/?q=hello', uri.to_s
|
|
750
|
-
assert_nil params
|
|
751
|
-
end
|
|
752
|
-
|
|
753
|
-
def test_resolve_parameters_query_append
|
|
754
|
-
input_params = { :q => 'hello' }
|
|
755
|
-
@uri.query = 'a=b'
|
|
756
|
-
|
|
757
|
-
uri, params = @agent.resolve_parameters @uri, :get, input_params
|
|
758
|
-
|
|
759
|
-
assert_equal 'http://example/?a=b&q=hello', uri.to_s
|
|
760
|
-
assert_nil params
|
|
761
|
-
end
|
|
762
|
-
|
|
763
|
-
def test_resolve_slashes
|
|
764
|
-
page = Mechanize::Page.new URI('http://example/foo/'), nil, '', 200, @mech
|
|
765
|
-
uri = '/bar/http://example/test/'
|
|
766
|
-
|
|
767
|
-
resolved = @agent.resolve uri, page
|
|
768
|
-
|
|
769
|
-
assert_equal 'http://example/bar/http://example/test/', resolved.to_s
|
|
770
|
-
end
|
|
771
|
-
|
|
772
|
-
def test_response_authenticate
|
|
773
|
-
@agent.add_auth @uri, 'user', 'password'
|
|
774
|
-
|
|
775
|
-
@res.instance_variable_set :@header, 'www-authenticate' => ['Basic realm=r']
|
|
776
|
-
|
|
777
|
-
@agent.response_authenticate @res, nil, @uri, @req, {}, nil, nil
|
|
778
|
-
|
|
779
|
-
base_uri = @uri + '/'
|
|
780
|
-
realm = Mechanize::HTTP::AuthRealm.new 'Basic', base_uri, 'r'
|
|
781
|
-
assert_equal [realm], @agent.authenticate_methods[base_uri][:basic]
|
|
782
|
-
end
|
|
783
|
-
|
|
784
|
-
def test_response_authenticate_digest
|
|
785
|
-
@agent.add_auth @uri, 'user', 'password'
|
|
786
|
-
|
|
787
|
-
@res.instance_variable_set(:@header,
|
|
788
|
-
'www-authenticate' => ['Digest realm=r'])
|
|
789
|
-
|
|
790
|
-
@agent.response_authenticate @res, nil, @uri, @req, {}, nil, nil
|
|
791
|
-
|
|
792
|
-
base_uri = @uri + '/'
|
|
793
|
-
realm = Mechanize::HTTP::AuthRealm.new 'Digest', base_uri, 'r'
|
|
794
|
-
assert_equal [realm], @agent.authenticate_methods[base_uri][:digest]
|
|
795
|
-
|
|
796
|
-
challenge = Mechanize::HTTP::AuthChallenge.new('Digest',
|
|
797
|
-
{ 'realm' => 'r' },
|
|
798
|
-
'Digest realm=r')
|
|
799
|
-
|
|
800
|
-
assert_equal challenge, @agent.digest_challenges[realm]
|
|
801
|
-
end
|
|
802
|
-
|
|
803
|
-
def test_response_authenticate_digest_iis
|
|
804
|
-
@agent.add_auth @uri, 'user', 'password'
|
|
805
|
-
|
|
806
|
-
@res.instance_variable_set(:@header,
|
|
807
|
-
'www-authenticate' => ['Digest realm=r'],
|
|
808
|
-
'server' => ['Microsoft-IIS'])
|
|
809
|
-
@agent.response_authenticate @res, nil, @uri, @req, {}, nil, nil
|
|
810
|
-
|
|
811
|
-
base_uri = @uri + '/'
|
|
812
|
-
realm = Mechanize::HTTP::AuthRealm.new 'Digest', base_uri, 'r'
|
|
813
|
-
assert_equal [realm], @agent.authenticate_methods[base_uri][:iis_digest]
|
|
814
|
-
end
|
|
815
|
-
|
|
816
|
-
def test_response_authenticate_multiple
|
|
817
|
-
@agent.add_auth @uri, 'user', 'password'
|
|
818
|
-
|
|
819
|
-
@res.instance_variable_set(:@header,
|
|
820
|
-
'www-authenticate' =>
|
|
821
|
-
['Basic realm=r, Digest realm=r'])
|
|
822
|
-
|
|
823
|
-
@agent.response_authenticate @res, nil, @uri, @req, {}, nil, nil
|
|
824
|
-
|
|
825
|
-
base_uri = @uri + '/'
|
|
826
|
-
realm = Mechanize::HTTP::AuthRealm.new 'Digest', base_uri, 'r'
|
|
827
|
-
assert_equal [realm], @agent.authenticate_methods[base_uri][:digest]
|
|
828
|
-
|
|
829
|
-
assert_empty @agent.authenticate_methods[base_uri][:basic]
|
|
830
|
-
end
|
|
831
|
-
|
|
832
|
-
def test_response_authenticate_no_credentials
|
|
833
|
-
@res.instance_variable_set :@header, 'www-authenticate' => ['Basic realm=r']
|
|
834
|
-
|
|
835
|
-
e = assert_raises Mechanize::UnauthorizedError do
|
|
836
|
-
@agent.response_authenticate @res, fake_page, @uri, @req, {}, nil, nil
|
|
837
|
-
end
|
|
838
|
-
|
|
839
|
-
assert_match 'no credentials', e.message
|
|
840
|
-
assert_match 'available realms: r', e.message
|
|
841
|
-
end
|
|
842
|
-
|
|
843
|
-
def test_response_authenticate_no_www_authenticate
|
|
844
|
-
@agent.add_auth @uri, 'user', 'password'
|
|
845
|
-
|
|
846
|
-
denied_uri = URI('http://example/denied')
|
|
847
|
-
|
|
848
|
-
denied = page denied_uri, 'text/html', '', 401
|
|
849
|
-
|
|
850
|
-
e = assert_raises Mechanize::UnauthorizedError do
|
|
851
|
-
@agent.response_authenticate @res, denied, @uri, @req, {}, nil, nil
|
|
852
|
-
end
|
|
853
|
-
|
|
854
|
-
assert_equal "401 => Net::HTTPUnauthorized for #{denied_uri} -- " \
|
|
855
|
-
"WWW-Authenticate header missing in response",
|
|
856
|
-
e.message
|
|
857
|
-
end
|
|
858
|
-
|
|
859
|
-
def test_response_authenticate_ntlm
|
|
860
|
-
@uri += '/ntlm'
|
|
861
|
-
@agent.add_auth @uri, 'user', 'password'
|
|
862
|
-
|
|
863
|
-
@res.instance_variable_set(:@header,
|
|
864
|
-
'www-authenticate' => ['Negotiate, NTLM'])
|
|
865
|
-
|
|
866
|
-
begin
|
|
867
|
-
page = @agent.response_authenticate @res, nil, @uri, @req, {}, nil, nil
|
|
868
|
-
rescue OpenSSL::Digest::DigestError
|
|
869
|
-
skip "It looks like OpenSSL is not configured to support MD4"
|
|
870
|
-
end
|
|
871
|
-
|
|
872
|
-
assert_equal 'ok', page.body # lame test
|
|
873
|
-
end
|
|
874
|
-
|
|
875
|
-
def test_response_authenticate_unknown
|
|
876
|
-
@agent.add_auth @uri, 'user', 'password'
|
|
877
|
-
|
|
878
|
-
page = Mechanize::File.new nil, nil, nil, 401
|
|
879
|
-
@res.instance_variable_set(:@header,
|
|
880
|
-
'www-authenticate' => ['Unknown realm=r'])
|
|
881
|
-
|
|
882
|
-
assert_raises Mechanize::UnauthorizedError do
|
|
883
|
-
@agent.response_authenticate @res, page, @uri, @req, nil, nil, nil
|
|
884
|
-
end
|
|
885
|
-
end
|
|
886
|
-
|
|
887
|
-
def test_response_content_encoding_7_bit
|
|
888
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[7bit]
|
|
889
|
-
|
|
890
|
-
body = @agent.response_content_encoding @res, StringIO.new('part')
|
|
891
|
-
|
|
892
|
-
assert_equal 'part', body.read
|
|
893
|
-
end
|
|
894
|
-
|
|
895
|
-
def test_response_content_encoding_deflate
|
|
896
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[deflate]
|
|
897
|
-
body_io = StringIO.new "x\x9C+H,*\x01\x00\x04?\x01\xB8"
|
|
898
|
-
|
|
899
|
-
body = @agent.response_content_encoding @res, body_io
|
|
900
|
-
|
|
901
|
-
assert_equal 'part', body.read
|
|
902
|
-
|
|
903
|
-
assert body_io.closed?
|
|
904
|
-
end
|
|
905
|
-
|
|
906
|
-
def test_response_content_encoding_deflate_chunked
|
|
907
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[deflate]
|
|
908
|
-
body_io = StringIO.new "x\x9C+H,*\x01\x00\x04?\x01\xB8"
|
|
909
|
-
|
|
910
|
-
body = @agent.response_content_encoding @res, body_io
|
|
911
|
-
|
|
912
|
-
assert_equal 'part', body.read
|
|
913
|
-
end
|
|
914
|
-
|
|
915
|
-
def test_response_content_encoding_deflate_corrupt
|
|
916
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[deflate]
|
|
917
|
-
body_io = StringIO.new "x\x9C+H,*\x01\x00\x04?\x01" # missing 1 byte
|
|
918
|
-
|
|
919
|
-
e = assert_raises Mechanize::Error do
|
|
920
|
-
@agent.response_content_encoding @res, body_io
|
|
921
|
-
end
|
|
922
|
-
|
|
923
|
-
assert_match %r%error handling content-encoding deflate:%, e.message
|
|
924
|
-
assert_match %r%Zlib%, e.message
|
|
925
|
-
|
|
926
|
-
assert body_io.closed?
|
|
927
|
-
end
|
|
928
|
-
|
|
929
|
-
def test_response_content_encoding_deflate_empty
|
|
930
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[deflate]
|
|
931
|
-
|
|
932
|
-
body = @agent.response_content_encoding @res, StringIO.new
|
|
933
|
-
|
|
934
|
-
assert_equal '', body.read
|
|
935
|
-
end
|
|
936
|
-
|
|
937
|
-
# IIS/6.0 ASP.NET/2.0.50727 does not wrap deflate with zlib, WTF?
|
|
938
|
-
def test_response_content_encoding_deflate_no_zlib
|
|
939
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[deflate]
|
|
940
|
-
|
|
941
|
-
body = @agent.response_content_encoding @res, StringIO.new("+H,*\001\000")
|
|
942
|
-
|
|
943
|
-
assert_equal 'part', body.read
|
|
944
|
-
end
|
|
945
|
-
|
|
946
|
-
def test_response_content_encoding_gzip
|
|
947
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[gzip]
|
|
948
|
-
body_io = StringIO.new \
|
|
949
|
-
"\037\213\b\0002\002\225M\000\003+H,*\001\000\306p\017I\004\000\000\000"
|
|
950
|
-
|
|
951
|
-
body = @agent.response_content_encoding @res, body_io
|
|
952
|
-
|
|
953
|
-
assert_equal 'part', body.read
|
|
954
|
-
|
|
955
|
-
assert body_io.closed?
|
|
956
|
-
end
|
|
957
|
-
|
|
958
|
-
def test_response_content_encoding_gzip_chunked
|
|
959
|
-
def @res.content_length() nil end
|
|
960
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[gzip]
|
|
961
|
-
body_io = StringIO.new \
|
|
962
|
-
"\037\213\b\0002\002\225M\000\003+H,*\001\000\306p\017I\004\000\000\000"
|
|
963
|
-
|
|
964
|
-
body = @agent.response_content_encoding @res, body_io
|
|
965
|
-
|
|
966
|
-
assert_equal 'part', body.read
|
|
967
|
-
end
|
|
968
|
-
|
|
969
|
-
def test_response_content_encoding_brotli_when_brotli_not_loaded
|
|
970
|
-
skip("only test this on jruby which doesn't have brotli support") unless RUBY_ENGINE == 'jruby'
|
|
971
|
-
|
|
972
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[br]
|
|
973
|
-
body_io = StringIO.new("content doesn't matter for this test")
|
|
974
|
-
|
|
975
|
-
e = assert_raises(Mechanize::Error) do
|
|
976
|
-
@agent.response_content_encoding(@res, body_io)
|
|
977
|
-
end
|
|
978
|
-
assert_includes(e.message, "cannot deflate brotli-encoded response")
|
|
979
|
-
|
|
980
|
-
assert(body_io.closed?)
|
|
981
|
-
end
|
|
982
|
-
|
|
983
|
-
def test_response_content_encoding_brotli
|
|
984
|
-
skip("jruby does not have brotli support") if RUBY_ENGINE == 'jruby'
|
|
985
|
-
|
|
986
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[br]
|
|
987
|
-
body_io = StringIO.new(Brotli.deflate("this is compressed by brotli"))
|
|
988
|
-
|
|
989
|
-
body = @agent.response_content_encoding(@res, body_io)
|
|
990
|
-
|
|
991
|
-
assert_equal("this is compressed by brotli", body.read)
|
|
992
|
-
assert(body_io.closed?)
|
|
993
|
-
end
|
|
994
|
-
|
|
995
|
-
def test_response_content_encoding_brotli_corrupt
|
|
996
|
-
skip("jruby does not have brotli support") if RUBY_ENGINE == 'jruby'
|
|
997
|
-
|
|
998
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[br]
|
|
999
|
-
body_io = StringIO.new("not a brotli payload")
|
|
1000
|
-
|
|
1001
|
-
e = assert_raises(Mechanize::Error) do
|
|
1002
|
-
@agent.response_content_encoding(@res, body_io)
|
|
1003
|
-
end
|
|
1004
|
-
assert_includes(e.message, "error inflating brotli-encoded response")
|
|
1005
|
-
assert_kind_of(Brotli::Error, e.cause)
|
|
1006
|
-
assert(body_io.closed?)
|
|
1007
|
-
end
|
|
1008
|
-
|
|
1009
|
-
def test_response_content_encoding_zstd_when_zstd_not_loaded
|
|
1010
|
-
skip("only test this on jruby which doesn't have zstd support") unless RUBY_ENGINE == 'jruby'
|
|
1011
|
-
|
|
1012
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[zstd]
|
|
1013
|
-
body_io = StringIO.new("content doesn't matter for this test")
|
|
1014
|
-
|
|
1015
|
-
e = assert_raises(Mechanize::Error) do
|
|
1016
|
-
@agent.response_content_encoding(@res, body_io)
|
|
1017
|
-
end
|
|
1018
|
-
assert_includes(e.message, 'cannot deflate zstd-encoded response')
|
|
1019
|
-
|
|
1020
|
-
assert(body_io.closed?)
|
|
1021
|
-
end
|
|
1022
|
-
|
|
1023
|
-
def test_response_content_encoding_zstd
|
|
1024
|
-
skip('jruby does not have zstd support') if RUBY_ENGINE == 'jruby'
|
|
1025
|
-
|
|
1026
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[zstd]
|
|
1027
|
-
body_io = StringIO.new(Zstd.compress('this is compressed by zstd'))
|
|
1028
|
-
|
|
1029
|
-
body = @agent.response_content_encoding(@res, body_io)
|
|
1030
|
-
|
|
1031
|
-
assert_equal('this is compressed by zstd', body.read)
|
|
1032
|
-
assert(body_io.closed?)
|
|
1033
|
-
end
|
|
1034
|
-
|
|
1035
|
-
def test_response_content_encoding_zstd_corrupt
|
|
1036
|
-
skip('jruby does not have zstd support') if RUBY_ENGINE == 'jruby'
|
|
1037
|
-
|
|
1038
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[zstd]
|
|
1039
|
-
body_io = StringIO.new('not a zstd payload')
|
|
1040
|
-
|
|
1041
|
-
e = assert_raises(Mechanize::Error) do
|
|
1042
|
-
@agent.response_content_encoding(@res, body_io)
|
|
1043
|
-
end
|
|
1044
|
-
assert_includes(e.message, 'error decompressing zstd-encoded response')
|
|
1045
|
-
assert_kind_of(RuntimeError, e.cause)
|
|
1046
|
-
assert(body_io.closed?)
|
|
1047
|
-
end
|
|
1048
|
-
|
|
1049
|
-
def test_response_content_encoding_gzip_corrupt
|
|
1050
|
-
log = StringIO.new
|
|
1051
|
-
logger = Logger.new log
|
|
1052
|
-
@agent.context.log = logger
|
|
1053
|
-
|
|
1054
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[gzip]
|
|
1055
|
-
body_io = StringIO.new \
|
|
1056
|
-
"\037\213\b\0002\002\225M\000\003+H,*\001"
|
|
1057
|
-
|
|
1058
|
-
skip_if_jruby_zlib
|
|
1059
|
-
|
|
1060
|
-
e = assert_raises Mechanize::Error do
|
|
1061
|
-
@agent.response_content_encoding @res, body_io
|
|
1062
|
-
end
|
|
1063
|
-
|
|
1064
|
-
assert_match %r%error handling content-encoding gzip:%, e.message
|
|
1065
|
-
assert_match %r%Zlib%, e.message
|
|
1066
|
-
|
|
1067
|
-
assert_match %r%unable to gunzip response: unexpected end of file%,
|
|
1068
|
-
log.string
|
|
1069
|
-
assert_match %r%unable to inflate response: buffer error%,
|
|
1070
|
-
log.string
|
|
1071
|
-
|
|
1072
|
-
assert body_io.closed?
|
|
1073
|
-
end
|
|
1074
|
-
|
|
1075
|
-
def test_response_content_encoding_gzip_checksum_corrupt_crc
|
|
1076
|
-
log = StringIO.new
|
|
1077
|
-
logger = Logger.new log
|
|
1078
|
-
@agent.context.log = logger
|
|
1079
|
-
|
|
1080
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[gzip]
|
|
1081
|
-
body_io = StringIO.new \
|
|
1082
|
-
"\037\213\b\0002\002\225M\000\003+H,*\001\000\306p\017J\004\000\000\000"
|
|
1083
|
-
|
|
1084
|
-
body = @agent.response_content_encoding @res, body_io
|
|
1085
|
-
|
|
1086
|
-
assert_equal 'part', body.read
|
|
1087
|
-
|
|
1088
|
-
assert body_io.closed?
|
|
1089
|
-
|
|
1090
|
-
assert_match %r%invalid compressed data -- crc error%, log.string
|
|
1091
|
-
rescue IOError
|
|
1092
|
-
skip_if_jruby_zlib
|
|
1093
|
-
raise
|
|
1094
|
-
end
|
|
1095
|
-
|
|
1096
|
-
def test_response_content_encoding_gzip_checksum_corrupt_length
|
|
1097
|
-
log = StringIO.new
|
|
1098
|
-
logger = Logger.new log
|
|
1099
|
-
@agent.context.log = logger
|
|
1100
|
-
|
|
1101
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[gzip]
|
|
1102
|
-
body_io = StringIO.new \
|
|
1103
|
-
"\037\213\b\0002\002\225M\000\003+H,*\001\000\306p\017I\005\000\000\000"
|
|
1104
|
-
|
|
1105
|
-
@agent.response_content_encoding @res, body_io
|
|
1106
|
-
|
|
1107
|
-
assert body_io.closed?
|
|
1108
|
-
|
|
1109
|
-
assert_match %r%invalid compressed data -- length error%, log.string
|
|
1110
|
-
rescue IOError
|
|
1111
|
-
skip_if_jruby_zlib
|
|
1112
|
-
raise
|
|
1113
|
-
end
|
|
1114
|
-
|
|
1115
|
-
def test_response_content_encoding_gzip_checksum_truncated
|
|
1116
|
-
log = StringIO.new
|
|
1117
|
-
logger = Logger.new log
|
|
1118
|
-
@agent.context.log = logger
|
|
1119
|
-
|
|
1120
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[gzip]
|
|
1121
|
-
body_io = StringIO.new \
|
|
1122
|
-
"\037\213\b\0002\002\225M\000\003+H,*\001\000\306p\017I\004\000\000"
|
|
1123
|
-
|
|
1124
|
-
@agent.response_content_encoding @res, body_io
|
|
1125
|
-
|
|
1126
|
-
assert body_io.closed?
|
|
1127
|
-
|
|
1128
|
-
assert_match %r%unable to gunzip response: footer is not found%, log.string
|
|
1129
|
-
rescue IOError
|
|
1130
|
-
skip_if_jruby_zlib
|
|
1131
|
-
raise
|
|
1132
|
-
end
|
|
1133
|
-
|
|
1134
|
-
def test_response_content_encoding_gzip_empty
|
|
1135
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[gzip]
|
|
1136
|
-
|
|
1137
|
-
body = @agent.response_content_encoding @res, StringIO.new
|
|
1138
|
-
|
|
1139
|
-
assert_equal '', body.read
|
|
1140
|
-
end
|
|
1141
|
-
|
|
1142
|
-
def test_response_content_encoding_gzip_encoding_bad
|
|
1143
|
-
@res.instance_variable_set(:@header,
|
|
1144
|
-
'content-encoding' => %w[gzip],
|
|
1145
|
-
'content-type' => 'text/html; charset=UTF-8')
|
|
1146
|
-
|
|
1147
|
-
# "test\xB2"
|
|
1148
|
-
body_io = StringIO.new \
|
|
1149
|
-
"\037\213\b\000*+\314N\000\003+I-.\331\004\000x\016\003\376\005\000\000\000"
|
|
1150
|
-
|
|
1151
|
-
body = @agent.response_content_encoding @res, body_io
|
|
1152
|
-
|
|
1153
|
-
expected = +"test\xB2"
|
|
1154
|
-
expected.force_encoding Encoding::BINARY if have_encoding?
|
|
1155
|
-
|
|
1156
|
-
content = body.read
|
|
1157
|
-
assert_equal expected, content
|
|
1158
|
-
assert_equal Encoding::BINARY, content.encoding if have_encoding?
|
|
1159
|
-
end
|
|
1160
|
-
|
|
1161
|
-
def test_response_content_encoding_gzip_no_footer
|
|
1162
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[gzip]
|
|
1163
|
-
body_io = StringIO.new \
|
|
1164
|
-
"\037\213\b\0002\002\225M\000\003+H,*\001\000"
|
|
1165
|
-
|
|
1166
|
-
body = @agent.response_content_encoding @res, body_io
|
|
1167
|
-
|
|
1168
|
-
assert_equal 'part', body.read
|
|
1169
|
-
|
|
1170
|
-
assert body_io.closed?
|
|
1171
|
-
rescue IOError
|
|
1172
|
-
skip_if_jruby_zlib
|
|
1173
|
-
raise
|
|
1174
|
-
end
|
|
1175
|
-
|
|
1176
|
-
def test_response_content_encoding_none
|
|
1177
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[none]
|
|
1178
|
-
|
|
1179
|
-
body = @agent.response_content_encoding @res, StringIO.new('part')
|
|
1180
|
-
|
|
1181
|
-
assert_equal 'part', body.read
|
|
1182
|
-
end
|
|
1183
|
-
|
|
1184
|
-
def test_response_content_encoding_empty_string
|
|
1185
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[]
|
|
1186
|
-
|
|
1187
|
-
body = @agent.response_content_encoding @res, StringIO.new('part')
|
|
1188
|
-
|
|
1189
|
-
assert_equal 'part', body.read
|
|
1190
|
-
end
|
|
1191
|
-
|
|
1192
|
-
def test_response_content_encoding_identity
|
|
1193
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[identity]
|
|
1194
|
-
|
|
1195
|
-
body = @agent.response_content_encoding @res, StringIO.new('part')
|
|
1196
|
-
|
|
1197
|
-
assert_equal 'part', body.read
|
|
1198
|
-
end
|
|
1199
|
-
|
|
1200
|
-
def test_response_content_encoding_tempfile_7_bit
|
|
1201
|
-
body_io = tempfile 'part'
|
|
1202
|
-
|
|
1203
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[7bit]
|
|
1204
|
-
|
|
1205
|
-
body = @agent.response_content_encoding @res, body_io
|
|
1206
|
-
|
|
1207
|
-
assert_equal 'part', body.read
|
|
1208
|
-
refute body_io.closed?
|
|
1209
|
-
ensure
|
|
1210
|
-
begin
|
|
1211
|
-
body_io.close! if body_io and not body_io.closed?
|
|
1212
|
-
rescue IOError
|
|
1213
|
-
# HACK for ruby 1.8
|
|
1214
|
-
end
|
|
1215
|
-
end
|
|
1216
|
-
|
|
1217
|
-
def test_response_content_encoding_tempfile_gzip
|
|
1218
|
-
body_io = tempfile "x\x9C+H,*\x01\x00\x04?\x01\xB8"
|
|
1219
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[deflate]
|
|
1220
|
-
|
|
1221
|
-
body = @agent.response_content_encoding @res, body_io
|
|
1222
|
-
|
|
1223
|
-
assert_equal 'part', body.read
|
|
1224
|
-
assert body_io.closed?
|
|
1225
|
-
ensure
|
|
1226
|
-
body_io.close! if body_io and not body_io.closed?
|
|
1227
|
-
end
|
|
1228
|
-
|
|
1229
|
-
def test_response_content_encoding_unknown
|
|
1230
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[unknown]
|
|
1231
|
-
body = StringIO.new 'part'
|
|
1232
|
-
|
|
1233
|
-
e = assert_raises Mechanize::Error do
|
|
1234
|
-
@agent.response_content_encoding @res, body
|
|
1235
|
-
end
|
|
1236
|
-
|
|
1237
|
-
assert_equal 'unsupported content-encoding: unknown', e.message
|
|
1238
|
-
end
|
|
1239
|
-
|
|
1240
|
-
def test_response_content_encoding_x_gzip
|
|
1241
|
-
@res.instance_variable_set :@header, 'content-encoding' => %w[x-gzip]
|
|
1242
|
-
body_io = StringIO.new \
|
|
1243
|
-
"\037\213\b\0002\002\225M\000\003+H,*\001\000\306p\017I\004\000\000\000"
|
|
1244
|
-
|
|
1245
|
-
body = @agent.response_content_encoding @res, body_io
|
|
1246
|
-
|
|
1247
|
-
assert_equal 'part', body.read
|
|
1248
|
-
end
|
|
1249
|
-
|
|
1250
|
-
def test_response_cookies
|
|
1251
|
-
uri = URI.parse 'http://host.example.com'
|
|
1252
|
-
cookie_str = 'a=b domain=.example.com'
|
|
1253
|
-
@res.instance_variable_set(:@header,
|
|
1254
|
-
'set-cookie' => [cookie_str],
|
|
1255
|
-
'content-type' => %w[text/html])
|
|
1256
|
-
page = Mechanize::Page.new uri, @res, '', 200, @mech
|
|
1257
|
-
|
|
1258
|
-
@agent.response_cookies @res, uri, page
|
|
1259
|
-
|
|
1260
|
-
assert_equal ['a="b domain=.example.com"'],
|
|
1261
|
-
@agent.cookie_jar.cookies(uri).map { |c| c.to_s }
|
|
1262
|
-
end
|
|
1263
|
-
|
|
1264
|
-
def test_response_cookies_many
|
|
1265
|
-
uri = URI.parse 'http://host.example.com'
|
|
1266
|
-
cookie1 = 'a=b domain=.example.com'
|
|
1267
|
-
cookie2 = 'c=d domain=.example.com'
|
|
1268
|
-
cookies = [cookie1, cookie2]
|
|
1269
|
-
@res.instance_variable_set(:@header,
|
|
1270
|
-
'set-cookie' => cookies,
|
|
1271
|
-
'content-type' => %w[text/html])
|
|
1272
|
-
page = Mechanize::Page.new uri, @res, '', 200, @mech
|
|
1273
|
-
|
|
1274
|
-
@agent.response_cookies @res, uri, page
|
|
1275
|
-
|
|
1276
|
-
cookies_from_jar = @agent.cookie_jar.cookies(uri)
|
|
1277
|
-
|
|
1278
|
-
assert_equal 2, cookies_from_jar.length
|
|
1279
|
-
assert_equal [
|
|
1280
|
-
'a="b domain=.example.com"',
|
|
1281
|
-
'c="d domain=.example.com"',
|
|
1282
|
-
], cookies_from_jar.sort_by { |c| c.name }.map(&:to_s)
|
|
1283
|
-
end
|
|
1284
|
-
|
|
1285
|
-
def test_response_cookies_meta
|
|
1286
|
-
uri = URI.parse 'http://host.example.com'
|
|
1287
|
-
cookie_str = 'a=b domain=.example.com'
|
|
1288
|
-
|
|
1289
|
-
body = <<-BODY
|
|
1290
|
-
<head>
|
|
1291
|
-
<meta http-equiv="Set-Cookie" content="#{cookie_str}">
|
|
1292
|
-
</head>"
|
|
1293
|
-
BODY
|
|
1294
|
-
|
|
1295
|
-
@res.instance_variable_set(:@header,
|
|
1296
|
-
'content-type' => %w[text/html])
|
|
1297
|
-
page = Mechanize::Page.new uri, @res, body, 200, @mech
|
|
1298
|
-
|
|
1299
|
-
@agent.response_cookies @res, uri, page
|
|
1300
|
-
|
|
1301
|
-
assert_equal ['a="b domain=.example.com"'],
|
|
1302
|
-
@agent.cookie_jar.cookies(uri).map { |c| c.to_s }
|
|
1303
|
-
end
|
|
1304
|
-
|
|
1305
|
-
def test_response_cookies_meta_bogus
|
|
1306
|
-
uri = URI.parse 'http://host.example.com'
|
|
1307
|
-
|
|
1308
|
-
body = <<-BODY
|
|
1309
|
-
<head>
|
|
1310
|
-
<meta http-equiv="Set-Cookie">
|
|
1311
|
-
</head>"
|
|
1312
|
-
BODY
|
|
1313
|
-
|
|
1314
|
-
@res.instance_variable_set(:@header,
|
|
1315
|
-
'content-type' => %w[text/html])
|
|
1316
|
-
page = Mechanize::Page.new uri, @res, body, 200, @mech
|
|
1317
|
-
|
|
1318
|
-
@agent.response_cookies @res, uri, page
|
|
1319
|
-
|
|
1320
|
-
assert_empty @agent.cookie_jar.cookies(uri)
|
|
1321
|
-
end
|
|
1322
|
-
|
|
1323
|
-
def test_response_follow_meta_refresh
|
|
1324
|
-
uri = URI.parse 'http://example/#id+1'
|
|
1325
|
-
|
|
1326
|
-
body = <<-BODY
|
|
1327
|
-
<title></title>
|
|
1328
|
-
<meta http-equiv="refresh" content="0">
|
|
1329
|
-
BODY
|
|
1330
|
-
|
|
1331
|
-
page = Mechanize::Page.new(uri, nil, body, 200, @mech)
|
|
1332
|
-
|
|
1333
|
-
@agent.follow_meta_refresh = true
|
|
1334
|
-
@agent.follow_meta_refresh_self = true
|
|
1335
|
-
|
|
1336
|
-
page = @agent.response_follow_meta_refresh @res, uri, page, 0
|
|
1337
|
-
|
|
1338
|
-
assert_equal uri, page.uri
|
|
1339
|
-
end
|
|
1340
|
-
|
|
1341
|
-
def test_response_follow_meta_refresh_to_cross_origin_drops_agent_request_headers
|
|
1342
|
-
uri = URI.parse 'http://example/'
|
|
1343
|
-
|
|
1344
|
-
body = <<-BODY
|
|
1345
|
-
<title></title>
|
|
1346
|
-
<meta http-equiv="refresh" content="0;url=http://trap/http_headers">
|
|
1347
|
-
BODY
|
|
1348
|
-
|
|
1349
|
-
page = Mechanize::Page.new(uri, nil, body, 200, @mech)
|
|
1350
|
-
|
|
1351
|
-
@agent.follow_meta_refresh = true
|
|
1352
|
-
@agent.request_headers = { 'Authorization' => 'Bearer tokensecret' }
|
|
1353
|
-
|
|
1354
|
-
page = @agent.response_follow_meta_refresh @res, uri, page, 0
|
|
1355
|
-
|
|
1356
|
-
refute_match("authorization|Bearer tokensecret", page.body)
|
|
1357
|
-
end
|
|
1358
|
-
|
|
1359
|
-
def test_meta_refresh_to_same_origin_keeps_agent_request_headers
|
|
1360
|
-
@agent.follow_meta_refresh = true
|
|
1361
|
-
@agent.request_headers = { 'Authorization' => 'Bearer tokensecret' }
|
|
1362
|
-
|
|
1363
|
-
page = @agent.fetch 'http://example/http_refresh?refresh_url=/http_headers'
|
|
1364
|
-
|
|
1365
|
-
assert_match("authorization|Bearer tokensecret", page.body)
|
|
1366
|
-
end
|
|
1367
|
-
|
|
1368
|
-
def test_response_follow_meta_refresh_limit
|
|
1369
|
-
uri = URI.parse 'http://example/#id+1'
|
|
1370
|
-
|
|
1371
|
-
body = <<-BODY
|
|
1372
|
-
<title></title>
|
|
1373
|
-
<meta http-equiv="refresh" content="0">
|
|
1374
|
-
BODY
|
|
1375
|
-
|
|
1376
|
-
page = Mechanize::Page.new(uri, nil, body, 200, @mech)
|
|
1377
|
-
|
|
1378
|
-
@agent.follow_meta_refresh = true
|
|
1379
|
-
@agent.follow_meta_refresh_self = true
|
|
1380
|
-
|
|
1381
|
-
assert_raises Mechanize::RedirectLimitReachedError do
|
|
1382
|
-
@agent.response_follow_meta_refresh(@res, uri, page,
|
|
1383
|
-
@agent.redirection_limit)
|
|
1384
|
-
end
|
|
1385
|
-
end
|
|
1386
|
-
|
|
1387
|
-
def test_response_meta_refresh_with_insecure_url
|
|
1388
|
-
uri = URI.parse 'http://example/#id+1'
|
|
1389
|
-
|
|
1390
|
-
body = <<-BODY
|
|
1391
|
-
<title></title>
|
|
1392
|
-
<meta http-equiv="refresh" content="0; url=file:///dev/zero">
|
|
1393
|
-
BODY
|
|
1394
|
-
|
|
1395
|
-
page = Mechanize::Page.new(uri, nil, body, 200, @mech)
|
|
1396
|
-
|
|
1397
|
-
@agent.follow_meta_refresh = true
|
|
1398
|
-
|
|
1399
|
-
assert_raises Mechanize::Error do
|
|
1400
|
-
@agent.response_follow_meta_refresh(@res, uri, page,
|
|
1401
|
-
@agent.redirection_limit)
|
|
1402
|
-
end
|
|
1403
|
-
end
|
|
1404
|
-
|
|
1405
|
-
def test_response_parse
|
|
1406
|
-
body = '<title>hi</title>'
|
|
1407
|
-
@res.instance_variable_set :@header, 'content-type' => %w[text/html]
|
|
1408
|
-
|
|
1409
|
-
page = @agent.response_parse @res, body, @uri
|
|
1410
|
-
|
|
1411
|
-
assert_instance_of Mechanize::Page, page
|
|
1412
|
-
assert_equal @mech, page.mech
|
|
1413
|
-
end
|
|
1414
|
-
|
|
1415
|
-
def test_response_parse_content_type_case
|
|
1416
|
-
body = '<title>hi</title>'
|
|
1417
|
-
@res.instance_variable_set(:@header, 'content-type' => %w[text/HTML])
|
|
1418
|
-
|
|
1419
|
-
page = @agent.response_parse @res, body, @uri
|
|
1420
|
-
|
|
1421
|
-
assert_instance_of Mechanize::Page, page
|
|
1422
|
-
|
|
1423
|
-
assert_equal 'text/HTML', page.content_type
|
|
1424
|
-
end
|
|
1425
|
-
|
|
1426
|
-
def test_response_parse_content_type_encoding
|
|
1427
|
-
body = '<title>hi</title>'
|
|
1428
|
-
@res.instance_variable_set(:@header,
|
|
1429
|
-
'content-type' =>
|
|
1430
|
-
%w[text/html;charset=ISO-8859-1])
|
|
1431
|
-
|
|
1432
|
-
page = @agent.response_parse @res, body, @uri
|
|
1433
|
-
|
|
1434
|
-
assert_instance_of Mechanize::Page, page
|
|
1435
|
-
assert_equal @mech, page.mech
|
|
1436
|
-
|
|
1437
|
-
assert_equal 'ISO-8859-1', page.encoding
|
|
1438
|
-
assert_equal 'ISO-8859-1', page.parser.encoding
|
|
1439
|
-
end
|
|
1440
|
-
|
|
1441
|
-
def test_response_parse_content_type_encoding_broken_iso_8859_1
|
|
1442
|
-
body = '<title>hi</title>'
|
|
1443
|
-
@res.instance_variable_set(:@header,
|
|
1444
|
-
'content-type' =>
|
|
1445
|
-
%w[text/html; charset=ISO_8859-1])
|
|
1446
|
-
|
|
1447
|
-
page = @agent.response_parse @res, body, @uri
|
|
1448
|
-
|
|
1449
|
-
assert_instance_of Mechanize::Page, page
|
|
1450
|
-
assert_equal 'ISO_8859-1', page.encoding
|
|
1451
|
-
end
|
|
1452
|
-
|
|
1453
|
-
def test_response_parse_content_type_encoding_broken_utf_8
|
|
1454
|
-
body = '<title>hi</title>'
|
|
1455
|
-
@res.instance_variable_set(:@header,
|
|
1456
|
-
'content-type' =>
|
|
1457
|
-
%w[text/html; charset=UTF8])
|
|
1458
|
-
|
|
1459
|
-
page = @agent.response_parse @res, body, @uri
|
|
1460
|
-
|
|
1461
|
-
assert_instance_of Mechanize::Page, page
|
|
1462
|
-
|
|
1463
|
-
# as of libxml 2.12.0, the result is dependent on how libiconv is built (which aliases are supported)
|
|
1464
|
-
# if the alias "UTF8" is defined, then the result will be "UTF-8".
|
|
1465
|
-
# if the alias "UTF8" is not defined, then the result will be "UTF8".
|
|
1466
|
-
# note that this alias may be defined by Nokogiri itself in its EncodingHandler class.
|
|
1467
|
-
assert_includes ["UTF8", "UTF-8"], page.encoding
|
|
1468
|
-
assert_includes ["UTF8", "UTF-8"], page.parser.encoding
|
|
1469
|
-
end
|
|
1470
|
-
|
|
1471
|
-
def test_response_parse_content_type_encoding_garbage
|
|
1472
|
-
body = '<title>hi</title>'
|
|
1473
|
-
@res.instance_variable_set(:@header,
|
|
1474
|
-
'content-type' =>
|
|
1475
|
-
%w[text/html; charset=garbage_charset])
|
|
1476
|
-
|
|
1477
|
-
page = @agent.response_parse @res, body, @uri
|
|
1478
|
-
|
|
1479
|
-
assert_instance_of Mechanize::Page, page
|
|
1480
|
-
assert_equal @mech, page.mech
|
|
1481
|
-
end
|
|
1482
|
-
|
|
1483
|
-
def test_response_parse_content_type_encoding_semicolon
|
|
1484
|
-
body = '<title>hi</title>'
|
|
1485
|
-
@res.instance_variable_set(:@header,
|
|
1486
|
-
'content-type' =>
|
|
1487
|
-
%w[text/html;charset=UTF-8;])
|
|
1488
|
-
|
|
1489
|
-
page = @agent.response_parse @res, body, @uri
|
|
1490
|
-
|
|
1491
|
-
assert_instance_of Mechanize::Page, page
|
|
1492
|
-
|
|
1493
|
-
assert_equal 'UTF-8', page.encoding
|
|
1494
|
-
end
|
|
1495
|
-
|
|
1496
|
-
def test_response_read
|
|
1497
|
-
def @res.read_body() yield 'part' end
|
|
1498
|
-
def @res.content_length() 4 end
|
|
1499
|
-
|
|
1500
|
-
io = @agent.response_read @res, @req, @uri
|
|
1501
|
-
|
|
1502
|
-
body = io.read
|
|
1503
|
-
|
|
1504
|
-
assert_equal 'part', body
|
|
1505
|
-
assert_equal Encoding::BINARY, body.encoding
|
|
1506
|
-
end
|
|
1507
|
-
|
|
1508
|
-
def test_response_read_chunked_no_trailer
|
|
1509
|
-
@res['Transfer-Encoding'] = 'chunked'
|
|
1510
|
-
def @res.content_length() end
|
|
1511
|
-
def @res.read_body
|
|
1512
|
-
yield 'a' * 10
|
|
1513
|
-
raise EOFError
|
|
1514
|
-
end
|
|
1515
|
-
|
|
1516
|
-
e = assert_raises Mechanize::ChunkedTerminationError do
|
|
1517
|
-
@agent.response_read @res, @req, @uri
|
|
1518
|
-
end
|
|
1519
|
-
|
|
1520
|
-
assert_equal 'aaaaaaaaaa', e.body_io.read
|
|
1521
|
-
end
|
|
1522
|
-
|
|
1523
|
-
def test_response_read_content_length_head
|
|
1524
|
-
req = Net::HTTP::Head.new '/'
|
|
1525
|
-
|
|
1526
|
-
def @res.content_length() end
|
|
1527
|
-
def @res.read_body() end
|
|
1528
|
-
|
|
1529
|
-
io = @agent.response_read @res, req, @uri
|
|
1530
|
-
|
|
1531
|
-
assert_equal '', io.read
|
|
1532
|
-
end
|
|
1533
|
-
|
|
1534
|
-
def test_response_read_content_length_mismatch
|
|
1535
|
-
def @res.content_length() 5 end
|
|
1536
|
-
def @res.read_body() yield 'part' end
|
|
1537
|
-
|
|
1538
|
-
e = assert_raises Mechanize::ResponseReadError do
|
|
1539
|
-
@agent.response_read @res, @req, @uri
|
|
1540
|
-
end
|
|
1541
|
-
|
|
1542
|
-
assert_equal 'Content-Length (5) does not match response body length (4)' \
|
|
1543
|
-
' (Mechanize::ResponseReadError)', e.message
|
|
1544
|
-
end
|
|
1545
|
-
|
|
1546
|
-
def test_response_read_content_length_redirect
|
|
1547
|
-
res = Net::HTTPFound.allocate
|
|
1548
|
-
def res.content_length() 5 end
|
|
1549
|
-
def res.code() 302 end
|
|
1550
|
-
def res.read_body() yield 'part' end
|
|
1551
|
-
res.instance_variable_set :@header, {}
|
|
1552
|
-
|
|
1553
|
-
io = @agent.response_read res, @req, @uri
|
|
1554
|
-
|
|
1555
|
-
assert_equal 'part', io.read
|
|
1556
|
-
end
|
|
1557
|
-
|
|
1558
|
-
def test_response_read_error
|
|
1559
|
-
def @res.read_body()
|
|
1560
|
-
yield 'part'
|
|
1561
|
-
raise Net::HTTP::Persistent::Error
|
|
1562
|
-
end
|
|
1563
|
-
|
|
1564
|
-
e = assert_raises Mechanize::ResponseReadError do
|
|
1565
|
-
@agent.response_read @res, @req, @uri
|
|
1566
|
-
end
|
|
1567
|
-
|
|
1568
|
-
assert_equal @res, e.response
|
|
1569
|
-
assert_equal 'part', e.body_io.read
|
|
1570
|
-
assert_kind_of Net::HTTP::Persistent::Error, e.error
|
|
1571
|
-
end
|
|
1572
|
-
|
|
1573
|
-
def test_response_read_file
|
|
1574
|
-
Tempfile.open 'pi.txt' do |tempfile|
|
|
1575
|
-
tempfile.write "π\n"
|
|
1576
|
-
tempfile.flush
|
|
1577
|
-
tempfile.rewind
|
|
1578
|
-
|
|
1579
|
-
uri = URI.parse "file://#{tempfile.path}"
|
|
1580
|
-
req = Mechanize::FileRequest.new uri
|
|
1581
|
-
res = Mechanize::FileResponse.new tempfile.path
|
|
1582
|
-
|
|
1583
|
-
io = @agent.response_read res, req, uri
|
|
1584
|
-
|
|
1585
|
-
expected = "π\n".dup.force_encoding(Encoding::BINARY)
|
|
1586
|
-
|
|
1587
|
-
# Ruby 1.8.7 doesn't let us set the write mode of the tempfile to binary,
|
|
1588
|
-
# so we should expect an inserted carriage return on some platforms
|
|
1589
|
-
expected_with_carriage_return = "π\r\n".dup.force_encoding(Encoding::BINARY)
|
|
1590
|
-
|
|
1591
|
-
body = io.read
|
|
1592
|
-
assert_match(/^(#{expected}|#{expected_with_carriage_return})$/m, body)
|
|
1593
|
-
assert_equal Encoding::BINARY, body.encoding
|
|
1594
|
-
end
|
|
1595
|
-
end
|
|
1596
|
-
|
|
1597
|
-
def test_response_read_large
|
|
1598
|
-
@agent.max_file_buffer = 10240
|
|
1599
|
-
|
|
1600
|
-
def @res.read_body() yield 'a' * 10241 end
|
|
1601
|
-
def @res.content_length() 10241 end
|
|
1602
|
-
|
|
1603
|
-
io = @agent.response_read @res, @req, @uri
|
|
1604
|
-
|
|
1605
|
-
assert_kind_of Tempfile, io
|
|
1606
|
-
assert_equal 10241, io.stat.size
|
|
1607
|
-
end
|
|
1608
|
-
|
|
1609
|
-
def test_response_read_large_chunked
|
|
1610
|
-
@agent.max_file_buffer = 10240
|
|
1611
|
-
|
|
1612
|
-
def @res.read_body
|
|
1613
|
-
11.times do yield 'a' * 1024 end
|
|
1614
|
-
end
|
|
1615
|
-
def @res.content_length() end
|
|
1616
|
-
|
|
1617
|
-
io = @agent.response_read @res, @req, @uri
|
|
1618
|
-
|
|
1619
|
-
assert_kind_of Tempfile, io
|
|
1620
|
-
assert_equal 11264, io.stat.size
|
|
1621
|
-
end
|
|
1622
|
-
|
|
1623
|
-
def test_response_read_no_body
|
|
1624
|
-
req = Net::HTTP::Options.new '/'
|
|
1625
|
-
|
|
1626
|
-
def @res.content_length() end
|
|
1627
|
-
def @res.read_body() end
|
|
1628
|
-
|
|
1629
|
-
io = @agent.response_read @res, req, @uri
|
|
1630
|
-
|
|
1631
|
-
assert_equal '', io.read
|
|
1632
|
-
end
|
|
1633
|
-
|
|
1634
|
-
def test_response_read_unknown_code
|
|
1635
|
-
res = Net::HTTPUnknownResponse.allocate
|
|
1636
|
-
res.instance_variable_set :@code, 9999
|
|
1637
|
-
res.instance_variable_set :@header, {}
|
|
1638
|
-
def res.read_body() yield 'part' end
|
|
1639
|
-
|
|
1640
|
-
e = assert_raises Mechanize::ResponseCodeError do
|
|
1641
|
-
@agent.response_read res, @req, @uri
|
|
1642
|
-
end
|
|
1643
|
-
|
|
1644
|
-
assert_equal res, e.page
|
|
1645
|
-
end
|
|
1646
|
-
|
|
1647
|
-
def test_response_redirect
|
|
1648
|
-
@agent.redirect_ok = true
|
|
1649
|
-
referer = page 'http://example/referer'
|
|
1650
|
-
|
|
1651
|
-
page = fake_page
|
|
1652
|
-
page = @agent.response_redirect({ 'Location' => '/index.html' }, :get,
|
|
1653
|
-
page, 0, {}, referer)
|
|
1654
|
-
|
|
1655
|
-
assert_equal URI('http://fake.example/index.html'), page.uri
|
|
1656
|
-
|
|
1657
|
-
assert_equal 'http://example/referer', requests.first['Referer']
|
|
1658
|
-
end
|
|
1659
|
-
|
|
1660
|
-
def test_response_redirect_header
|
|
1661
|
-
@agent.redirect_ok = true
|
|
1662
|
-
referer = page 'http://example/referer'
|
|
1663
|
-
|
|
1664
|
-
headers = {
|
|
1665
|
-
'Range' => 'bytes=0-9999',
|
|
1666
|
-
'Content-Type' => 'application/x-www-form-urlencoded',
|
|
1667
|
-
'CONTENT-LENGTH' => '9999',
|
|
1668
|
-
'content-md5' => '14758f1afd44c09b7992073ccf00b43d',
|
|
1669
|
-
}
|
|
1670
|
-
|
|
1671
|
-
page = fake_page
|
|
1672
|
-
page = @agent.response_redirect({ 'Location' => '/http_headers' }, :get,
|
|
1673
|
-
page, 0, headers, referer)
|
|
1674
|
-
|
|
1675
|
-
assert_equal URI('http://fake.example/http_headers'), page.uri
|
|
1676
|
-
|
|
1677
|
-
assert_match 'range|bytes=0-9999', page.body
|
|
1678
|
-
refute_match 'content-type|application/x-www-form-urlencoded', page.body
|
|
1679
|
-
refute_match 'content-length|9999', page.body
|
|
1680
|
-
refute_match 'content-md5|14758f1afd44c09b7992073ccf00b43d', page.body
|
|
1681
|
-
end
|
|
1682
|
-
|
|
1683
|
-
def test_response_redirect_malformed
|
|
1684
|
-
@agent.redirect_ok = true
|
|
1685
|
-
referer = page 'http://example/referer'
|
|
1686
|
-
|
|
1687
|
-
page = fake_page
|
|
1688
|
-
page = @agent.response_redirect({ 'Location' => '/index.html?q=あ' }, :get,
|
|
1689
|
-
page, 0, {}, referer)
|
|
1690
|
-
|
|
1691
|
-
assert_equal URI('http://fake.example/index.html?q=%E3%81%82'), page.uri
|
|
1692
|
-
|
|
1693
|
-
assert_equal 'http://example/referer', requests.first['Referer']
|
|
1694
|
-
end
|
|
1695
|
-
|
|
1696
|
-
def test_response_redirect_insecure
|
|
1697
|
-
@agent.redirect_ok = true
|
|
1698
|
-
referer = page 'http://example/referer'
|
|
1699
|
-
|
|
1700
|
-
assert_raises Mechanize::Error do
|
|
1701
|
-
@agent.response_redirect({ 'Location' => 'file:///etc/passwd' }, :get,
|
|
1702
|
-
fake_page, 0, {}, referer)
|
|
1703
|
-
end
|
|
1704
|
-
end
|
|
1705
|
-
|
|
1706
|
-
def test_response_redirect_limit
|
|
1707
|
-
@agent.redirect_ok = true
|
|
1708
|
-
referer = page 'http://example/referer'
|
|
1709
|
-
|
|
1710
|
-
assert_raises Mechanize::RedirectLimitReachedError do
|
|
1711
|
-
@agent.response_redirect({ 'Location' => '/index.html' }, :get,
|
|
1712
|
-
fake_page, @agent.redirection_limit, {}, referer)
|
|
1713
|
-
end
|
|
1714
|
-
end
|
|
1715
|
-
|
|
1716
|
-
def test_response_redirect_to_cross_site_with_credential
|
|
1717
|
-
@agent.redirect_ok = true
|
|
1718
|
-
|
|
1719
|
-
headers = {
|
|
1720
|
-
'Range' => 'bytes=0-9999',
|
|
1721
|
-
'AUTHORIZATION' => 'Basic xxx',
|
|
1722
|
-
'cookie' => 'name=value',
|
|
1723
|
-
}
|
|
1724
|
-
|
|
1725
|
-
page = html_page ''
|
|
1726
|
-
page = @agent.response_redirect({ 'Location' => 'http://trap/http_headers' }, :get,
|
|
1727
|
-
page, 0, headers)
|
|
1728
|
-
|
|
1729
|
-
refute_includes(headers.keys, "AUTHORIZATION")
|
|
1730
|
-
refute_includes(headers.keys, "cookie")
|
|
1731
|
-
|
|
1732
|
-
assert_match("range|bytes=0-9999", page.body)
|
|
1733
|
-
refute_match("authorization|Basic xxx", page.body)
|
|
1734
|
-
refute_match("cookie|name=value", page.body)
|
|
1735
|
-
end
|
|
1736
|
-
|
|
1737
|
-
def test_response_redirect_to_cross_site_strips_all_credential_headers
|
|
1738
|
-
@agent.redirect_ok = true
|
|
1739
|
-
|
|
1740
|
-
headers = {
|
|
1741
|
-
'Range' => 'bytes=0-9999',
|
|
1742
|
-
'Proxy-Authorization' => 'Basic proxysecret',
|
|
1743
|
-
'Cookie2' => 'version=1',
|
|
1744
|
-
}
|
|
1745
|
-
|
|
1746
|
-
page = html_page ''
|
|
1747
|
-
page = @agent.response_redirect({ 'Location' => 'http://trap/http_headers' }, :get,
|
|
1748
|
-
page, 0, headers)
|
|
1749
|
-
|
|
1750
|
-
refute_includes(headers.keys, "Proxy-Authorization")
|
|
1751
|
-
refute_includes(headers.keys, "Cookie2")
|
|
1752
|
-
|
|
1753
|
-
refute_match("proxy-authorization|Basic proxysecret", page.body)
|
|
1754
|
-
refute_match("cookie2|version=1", page.body)
|
|
1755
|
-
end
|
|
1756
|
-
|
|
1757
|
-
def test_response_redirect_to_same_site_keeps_all_credential_headers
|
|
1758
|
-
@agent.redirect_ok = true
|
|
1759
|
-
|
|
1760
|
-
headers = {
|
|
1761
|
-
'Proxy-Authorization' => 'Basic proxysecret',
|
|
1762
|
-
'Cookie2' => 'version=1',
|
|
1763
|
-
}
|
|
1764
|
-
|
|
1765
|
-
page = html_page ''
|
|
1766
|
-
page = @agent.response_redirect({ 'Location' => '/http_headers' }, :get,
|
|
1767
|
-
page, 0, headers)
|
|
1768
|
-
|
|
1769
|
-
assert_match("proxy-authorization|Basic proxysecret", page.body)
|
|
1770
|
-
assert_match("cookie2|version=1", page.body)
|
|
1771
|
-
end
|
|
1772
|
-
|
|
1773
|
-
def test_response_redirect_to_cross_site_drops_agent_request_headers
|
|
1774
|
-
@agent.redirect_ok = true
|
|
1775
|
-
@agent.request_headers = { 'Authorization' => 'Bearer tokensecret', 'Cookie' => 'name=value' }
|
|
1776
|
-
|
|
1777
|
-
page = html_page ''
|
|
1778
|
-
page = @agent.response_redirect({ 'Location' => 'http://trap/http_headers' }, :get,
|
|
1779
|
-
page, 0, {})
|
|
1780
|
-
|
|
1781
|
-
refute_match("authorization|Bearer tokensecret", page.body)
|
|
1782
|
-
refute_match("cookie|name=value", page.body)
|
|
1783
|
-
end
|
|
1784
|
-
|
|
1785
|
-
def test_redirect_to_cross_site_keeps_insensitive_agent_request_headers
|
|
1786
|
-
@agent.redirect_ok = true
|
|
1787
|
-
@agent.request_headers = { 'Authorization' => 'Bearer tokensecret', 'X-Api-Key' => 'apikey' }
|
|
1788
|
-
|
|
1789
|
-
page = @agent.fetch 'http://example/redirect', :get,
|
|
1790
|
-
{ 'X-Location' => 'http://trap/http_headers' }
|
|
1791
|
-
|
|
1792
|
-
refute_match("authorization|Bearer tokensecret", page.body)
|
|
1793
|
-
assert_match("x-api-key|apikey", page.body)
|
|
1794
|
-
end
|
|
1795
|
-
|
|
1796
|
-
def test_redirect_to_same_site_keeps_agent_request_headers
|
|
1797
|
-
@agent.redirect_ok = true
|
|
1798
|
-
@agent.request_headers = { 'Authorization' => 'Bearer tokensecret' }
|
|
1799
|
-
|
|
1800
|
-
page = @agent.fetch 'http://example/redirect', :get, { 'X-Location' => '/http_headers' }
|
|
1801
|
-
|
|
1802
|
-
assert_match("authorization|Bearer tokensecret", page.body)
|
|
1803
|
-
end
|
|
1804
|
-
|
|
1805
|
-
def test_response_redirect_to_downgraded_scheme_strips_credential
|
|
1806
|
-
@agent.redirect_ok = true
|
|
1807
|
-
|
|
1808
|
-
headers = { 'AUTHORIZATION' => 'Basic xxx', 'cookie' => 'name=value' }
|
|
1809
|
-
|
|
1810
|
-
page = page 'https://example:8443/', 'text/html'
|
|
1811
|
-
page = @agent.response_redirect({ 'Location' => 'http://example:8443/http_headers' }, :get,
|
|
1812
|
-
page, 0, headers)
|
|
1813
|
-
|
|
1814
|
-
refute_includes(headers.keys, "AUTHORIZATION")
|
|
1815
|
-
refute_includes(headers.keys, "cookie")
|
|
1816
|
-
|
|
1817
|
-
refute_match("authorization|Basic xxx", page.body)
|
|
1818
|
-
refute_match("cookie|name=value", page.body)
|
|
1819
|
-
end
|
|
1820
|
-
|
|
1821
|
-
def test_response_redirect_to_downgraded_scheme_drops_agent_request_headers
|
|
1822
|
-
@agent.redirect_ok = true
|
|
1823
|
-
@agent.request_headers = { 'Authorization' => 'Bearer tokensecret' }
|
|
1824
|
-
|
|
1825
|
-
page = page 'https://example:8443/', 'text/html'
|
|
1826
|
-
page = @agent.response_redirect({ 'Location' => 'http://example:8443/http_headers' }, :get,
|
|
1827
|
-
page, 0, {})
|
|
1828
|
-
|
|
1829
|
-
refute_match("authorization|Bearer tokensecret", page.body)
|
|
1830
|
-
end
|
|
1831
|
-
|
|
1832
|
-
def test_response_redirect_to_different_port_strips_cookie
|
|
1833
|
-
@agent.redirect_ok = true
|
|
1834
|
-
|
|
1835
|
-
headers = { 'cookie' => 'name=value' }
|
|
1836
|
-
|
|
1837
|
-
page = html_page ''
|
|
1838
|
-
page = @agent.response_redirect({ 'Location' => 'http://example:81/http_headers' }, :get,
|
|
1839
|
-
page, 0, headers)
|
|
1840
|
-
|
|
1841
|
-
refute_match("cookie|name=value", page.body)
|
|
1842
|
-
end
|
|
1843
|
-
|
|
1844
|
-
# Every request the agent made to a host other than the one the credential
|
|
1845
|
-
# was set for.
|
|
1846
|
-
def foreign_requests
|
|
1847
|
-
requests.reject { |request| request['host'] == 'example' }
|
|
1848
|
-
end
|
|
1849
|
-
|
|
1850
|
-
def test_second_redirect_hop_on_a_foreign_origin_does_not_restore_credentials
|
|
1851
|
-
@agent.redirect_ok = true
|
|
1852
|
-
@agent.redirection_limit = 2
|
|
1853
|
-
@agent.request_headers = { 'Authorization' => 'Bearer tokensecret' }
|
|
1854
|
-
|
|
1855
|
-
assert_raises Mechanize::RedirectLimitReachedError do
|
|
1856
|
-
@agent.fetch 'http://example/redirect', :get,
|
|
1857
|
-
{ 'X-Location' => 'http://trap/redirect' }
|
|
1858
|
-
end
|
|
1859
|
-
|
|
1860
|
-
assert_operator foreign_requests.length, :>, 1
|
|
1861
|
-
assert_empty foreign_requests.select { |r| r['Authorization'] }
|
|
1862
|
-
end
|
|
1863
|
-
|
|
1864
|
-
def test_authentication_retry_on_a_foreign_origin_does_not_restore_credentials
|
|
1865
|
-
@agent.redirect_ok = true
|
|
1866
|
-
@agent.request_headers = { 'Authorization' => 'Bearer tokensecret' }
|
|
1867
|
-
@agent.add_auth URI('http://trap/'), 'user', 'pass'
|
|
1868
|
-
|
|
1869
|
-
begin
|
|
1870
|
-
@agent.fetch 'http://example/redirect', :get,
|
|
1871
|
-
{ 'X-Location' => 'http://trap/basic_auth' }
|
|
1872
|
-
rescue Mechanize::UnauthorizedError
|
|
1873
|
-
# a leaked bearer token overwrites the Basic credential and the retry fails
|
|
1874
|
-
end
|
|
1875
|
-
|
|
1876
|
-
assert_operator foreign_requests.length, :>, 1
|
|
1877
|
-
assert_empty foreign_requests.select { |r| r['Authorization'] == 'Bearer tokensecret' }
|
|
1878
|
-
end
|
|
1879
|
-
|
|
1880
|
-
def test_meta_refresh_to_a_second_foreign_origin_does_not_restore_credentials
|
|
1881
|
-
@agent.redirect_ok = true
|
|
1882
|
-
@agent.follow_meta_refresh = true
|
|
1883
|
-
@agent.request_headers = { 'Authorization' => 'Bearer tokensecret' }
|
|
1884
|
-
|
|
1885
|
-
@agent.fetch 'http://example/redirect', :get,
|
|
1886
|
-
{ 'X-Location' => 'http://trap/http_refresh?refresh_url=/http_headers' }
|
|
1887
|
-
|
|
1888
|
-
assert_nil requests.find { |r| r.path == '/http_headers' }['Authorization']
|
|
1889
|
-
end
|
|
1890
|
-
|
|
1891
|
-
def test_robots_lookup_on_a_foreign_origin_does_not_send_credentials
|
|
1892
|
-
@agent.redirect_ok = true
|
|
1893
|
-
@agent.robots = true
|
|
1894
|
-
@agent.request_headers = { 'Authorization' => 'Bearer tokensecret' }
|
|
1895
|
-
|
|
1896
|
-
@agent.fetch 'http://example/redirect', :get,
|
|
1897
|
-
{ 'X-Location' => 'http://trap/http_headers' }
|
|
1898
|
-
|
|
1899
|
-
assert_nil requests.find { |r| r.path == '/robots.txt' }['Authorization']
|
|
1900
|
-
end
|
|
1901
|
-
|
|
1902
|
-
def test_response_redirect_to_same_site_with_credential
|
|
1903
|
-
@agent.redirect_ok = true
|
|
1904
|
-
|
|
1905
|
-
headers = {
|
|
1906
|
-
'Range' => 'bytes=0-9999',
|
|
1907
|
-
'AUTHORIZATION' => 'Basic xxx',
|
|
1908
|
-
'cookie' => 'name=value',
|
|
1909
|
-
}
|
|
1910
|
-
|
|
1911
|
-
page = html_page ''
|
|
1912
|
-
page = @agent.response_redirect({ 'Location' => '/http_headers' }, :get,
|
|
1913
|
-
page, 0, headers)
|
|
1914
|
-
|
|
1915
|
-
assert_includes(headers.keys, "AUTHORIZATION")
|
|
1916
|
-
assert_includes(headers.keys, "cookie")
|
|
1917
|
-
|
|
1918
|
-
assert_match("range|bytes=0-9999", page.body)
|
|
1919
|
-
assert_match("authorization|Basic xxx", page.body)
|
|
1920
|
-
assert_match("cookie|name=value", page.body)
|
|
1921
|
-
end
|
|
1922
|
-
|
|
1923
|
-
def test_response_redirect_to_same_site_diff_port_with_credential
|
|
1924
|
-
@agent.redirect_ok = true
|
|
1925
|
-
|
|
1926
|
-
headers = {
|
|
1927
|
-
'Range' => 'bytes=0-9999',
|
|
1928
|
-
'AUTHORIZATION' => 'Basic xxx',
|
|
1929
|
-
'cookie' => 'name=value',
|
|
1930
|
-
}
|
|
1931
|
-
|
|
1932
|
-
page = html_page ''
|
|
1933
|
-
page = @agent.response_redirect({ 'Location' => 'http://example:81/http_headers' }, :get,
|
|
1934
|
-
page, 0, headers)
|
|
1935
|
-
|
|
1936
|
-
refute_includes(headers.keys, "AUTHORIZATION")
|
|
1937
|
-
refute_includes(headers.keys, "cookie")
|
|
1938
|
-
|
|
1939
|
-
assert_match("range|bytes=0-9999", page.body)
|
|
1940
|
-
refute_match("authorization|Basic xxx", page.body)
|
|
1941
|
-
refute_match("cookie|name=value", page.body)
|
|
1942
|
-
end
|
|
1943
|
-
|
|
1944
|
-
def test_response_redirect_not_ok
|
|
1945
|
-
@agent.redirect_ok = false
|
|
1946
|
-
|
|
1947
|
-
page = fake_page
|
|
1948
|
-
page = @agent.response_redirect({ 'Location' => '/other' }, :get, page, 0,
|
|
1949
|
-
{}, page)
|
|
1950
|
-
|
|
1951
|
-
assert_equal URI('http://fake.example'), page.uri
|
|
1952
|
-
end
|
|
1953
|
-
|
|
1954
|
-
def test_response_redirect_permanent
|
|
1955
|
-
@agent.redirect_ok = :permanent
|
|
1956
|
-
|
|
1957
|
-
response = Net::HTTPMovedPermanently.allocate
|
|
1958
|
-
response.instance_variable_set :@header, { 'location' => %w[/index.html] }
|
|
1959
|
-
|
|
1960
|
-
page = fake_page
|
|
1961
|
-
page = @agent.response_redirect response, :get, page, 0, {}, page
|
|
1962
|
-
|
|
1963
|
-
assert_equal URI('http://fake.example/index.html'), page.uri
|
|
1964
|
-
end
|
|
1965
|
-
|
|
1966
|
-
def test_response_redirect_permanent_temporary
|
|
1967
|
-
@agent.redirect_ok = :permanent
|
|
1968
|
-
|
|
1969
|
-
response = Net::HTTPMovedTemporarily.allocate
|
|
1970
|
-
response.instance_variable_set :@header, { 'location' => %w[/index.html] }
|
|
1971
|
-
|
|
1972
|
-
page = fake_page
|
|
1973
|
-
page = @agent.response_redirect response, :get, page, 0, {}, page
|
|
1974
|
-
|
|
1975
|
-
assert_equal URI('http://fake.example/'), page.uri
|
|
1976
|
-
end
|
|
1977
|
-
|
|
1978
|
-
def test_retry_change_request_equals
|
|
1979
|
-
unless Gem::Requirement.new("< 4.0.0").satisfied_by?(Gem::Version.new(Net::HTTP::Persistent::VERSION))
|
|
1980
|
-
# see https://github.com/drbrain/net-http-persistent/pull/100
|
|
1981
|
-
skip("net-http-persistent 4.0.0 and later does not support retry_change_requests")
|
|
1982
|
-
end
|
|
1983
|
-
|
|
1984
|
-
refute @agent.http.retry_change_requests
|
|
1985
|
-
|
|
1986
|
-
@agent.retry_change_requests = true
|
|
1987
|
-
|
|
1988
|
-
assert @agent.http.retry_change_requests
|
|
1989
|
-
end
|
|
1990
|
-
|
|
1991
|
-
def test_robots_allowed_eh
|
|
1992
|
-
allowed = URI 'http://localhost/index.html'
|
|
1993
|
-
disallowed = URI 'http://localhost/norobots.html'
|
|
1994
|
-
|
|
1995
|
-
assert @agent.robots_allowed? allowed
|
|
1996
|
-
refute @agent.robots_allowed? disallowed
|
|
1997
|
-
|
|
1998
|
-
refute @agent.robots_disallowed? allowed
|
|
1999
|
-
assert @agent.robots_disallowed? disallowed
|
|
2000
|
-
end
|
|
2001
|
-
|
|
2002
|
-
def test_robots_allowed_eh_noindex
|
|
2003
|
-
@agent.robots = true
|
|
2004
|
-
|
|
2005
|
-
noindex = URI 'http://localhost/noindex.html'
|
|
2006
|
-
|
|
2007
|
-
assert @agent.robots_allowed? noindex
|
|
2008
|
-
|
|
2009
|
-
assert_raises Mechanize::RobotsDisallowedError do
|
|
2010
|
-
@agent.fetch noindex
|
|
2011
|
-
end
|
|
2012
|
-
end
|
|
2013
|
-
|
|
2014
|
-
def test_robots_infinite_loop
|
|
2015
|
-
@agent.robots = true
|
|
2016
|
-
@agent.redirect_ok = true
|
|
2017
|
-
|
|
2018
|
-
assert_raises Mechanize::RobotsDisallowedError do
|
|
2019
|
-
@agent.fetch URI('http://301/norobots.html')
|
|
2020
|
-
end
|
|
2021
|
-
|
|
2022
|
-
@agent.fetch URI('http://301/robots.html')
|
|
2023
|
-
end
|
|
2024
|
-
|
|
2025
|
-
def test_set_proxy
|
|
2026
|
-
@agent.set_proxy 'www.example.com', 9001, 'joe', 'lol'
|
|
2027
|
-
|
|
2028
|
-
assert_equal @agent.proxy_uri.host, 'www.example.com'
|
|
2029
|
-
assert_equal @agent.proxy_uri.port, 9001
|
|
2030
|
-
assert_equal @agent.proxy_uri.user, 'joe'
|
|
2031
|
-
assert_equal @agent.proxy_uri.password, 'lol'
|
|
2032
|
-
end
|
|
2033
|
-
|
|
2034
|
-
def test_set_proxy_port_string
|
|
2035
|
-
@agent.set_proxy 'www.example.com', '9001', 'joe', 'lol'
|
|
2036
|
-
|
|
2037
|
-
assert_equal @agent.proxy_uri.host, 'www.example.com'
|
|
2038
|
-
assert_equal @agent.proxy_uri.port, 9001
|
|
2039
|
-
assert_equal @agent.proxy_uri.user, 'joe'
|
|
2040
|
-
assert_equal @agent.proxy_uri.password, 'lol'
|
|
2041
|
-
end
|
|
2042
|
-
|
|
2043
|
-
def test_set_proxy_service_name
|
|
2044
|
-
@agent.set_proxy 'www.example.com', 'http', 'joe', 'lol'
|
|
2045
|
-
|
|
2046
|
-
assert_equal @agent.proxy_uri.host, 'www.example.com'
|
|
2047
|
-
assert_equal @agent.proxy_uri.port, 80
|
|
2048
|
-
assert_equal @agent.proxy_uri.user, 'joe'
|
|
2049
|
-
assert_equal @agent.proxy_uri.password, 'lol'
|
|
2050
|
-
end
|
|
2051
|
-
|
|
2052
|
-
def test_set_proxy_service_name_bad
|
|
2053
|
-
e = assert_raises ArgumentError do
|
|
2054
|
-
@agent.set_proxy 'www.example.com', 'nonexistent service', 'joe', 'lol'
|
|
2055
|
-
end
|
|
2056
|
-
|
|
2057
|
-
assert_equal 'invalid value for port: "nonexistent service"', e.message
|
|
2058
|
-
end
|
|
2059
|
-
|
|
2060
|
-
def test_set_proxy_with_scheme
|
|
2061
|
-
@agent.set_proxy 'http://www.example.com', 9001, 'joe', 'lol'
|
|
2062
|
-
|
|
2063
|
-
assert_equal @agent.proxy_uri.host, 'www.example.com'
|
|
2064
|
-
assert_equal @agent.proxy_uri.port, 9001
|
|
2065
|
-
assert_equal @agent.proxy_uri.user, 'joe'
|
|
2066
|
-
assert_equal @agent.proxy_uri.password, 'lol'
|
|
2067
|
-
end
|
|
2068
|
-
|
|
2069
|
-
def test_set_proxy_url
|
|
2070
|
-
@agent.set_proxy 'http://joe:lol@www.example.com:9001'
|
|
2071
|
-
|
|
2072
|
-
assert_equal @agent.proxy_uri.host, 'www.example.com'
|
|
2073
|
-
assert_equal @agent.proxy_uri.port, 9001
|
|
2074
|
-
assert_equal @agent.proxy_uri.user, 'joe'
|
|
2075
|
-
assert_equal @agent.proxy_uri.password, 'lol'
|
|
2076
|
-
end
|
|
2077
|
-
|
|
2078
|
-
def test_set_proxy_uri
|
|
2079
|
-
@agent.set_proxy URI('http://joe:lol@www.example.com:9001')
|
|
2080
|
-
|
|
2081
|
-
assert_equal @agent.proxy_uri.host, 'www.example.com'
|
|
2082
|
-
assert_equal @agent.proxy_uri.port, 9001
|
|
2083
|
-
assert_equal @agent.proxy_uri.user, 'joe'
|
|
2084
|
-
assert_equal @agent.proxy_uri.password, 'lol'
|
|
2085
|
-
end
|
|
2086
|
-
|
|
2087
|
-
def test_set_proxy_url_and_credentials
|
|
2088
|
-
@agent.set_proxy 'http://www.example.com:9001', nil, 'joe', 'lol'
|
|
2089
|
-
|
|
2090
|
-
assert_equal @agent.proxy_uri.host, 'www.example.com'
|
|
2091
|
-
assert_equal @agent.proxy_uri.port, 9001
|
|
2092
|
-
assert_equal @agent.proxy_uri.user, 'joe'
|
|
2093
|
-
assert_equal @agent.proxy_uri.password, 'lol'
|
|
2094
|
-
end
|
|
2095
|
-
|
|
2096
|
-
def test_setting_agent_name
|
|
2097
|
-
mech = Mechanize.new 'user-set-name'
|
|
2098
|
-
assert_equal 'user-set-name', mech.agent.http.name
|
|
2099
|
-
end
|
|
2100
|
-
|
|
2101
|
-
def test_ssl
|
|
2102
|
-
in_tmpdir do
|
|
2103
|
-
store = OpenSSL::X509::Store.new
|
|
2104
|
-
@agent.ca_file = '.'
|
|
2105
|
-
@agent.cert_store = store
|
|
2106
|
-
@agent.certificate = ssl_certificate
|
|
2107
|
-
@agent.private_key = ssl_private_key
|
|
2108
|
-
@agent.ssl_version = 'SSLv3'
|
|
2109
|
-
@agent.verify_callback = proc { |ok, context| }
|
|
2110
|
-
|
|
2111
|
-
http = @agent.http
|
|
2112
|
-
|
|
2113
|
-
assert_equal '.', http.ca_file
|
|
2114
|
-
assert_equal store, http.cert_store
|
|
2115
|
-
assert_equal ssl_certificate, http.certificate
|
|
2116
|
-
assert_equal ssl_private_key, http.private_key
|
|
2117
|
-
assert_equal 'SSLv3', http.ssl_version
|
|
2118
|
-
assert_equal OpenSSL::SSL::VERIFY_PEER, http.verify_mode
|
|
2119
|
-
assert http.verify_callback
|
|
2120
|
-
end
|
|
2121
|
-
end
|
|
2122
|
-
|
|
2123
|
-
def test_use_tempfile_eh
|
|
2124
|
-
refute @agent.use_tempfile? nil
|
|
2125
|
-
|
|
2126
|
-
@agent.max_file_buffer = 1
|
|
2127
|
-
|
|
2128
|
-
refute @agent.use_tempfile? 0
|
|
2129
|
-
assert @agent.use_tempfile? 1
|
|
2130
|
-
|
|
2131
|
-
@agent.max_file_buffer = nil
|
|
2132
|
-
|
|
2133
|
-
refute @agent.use_tempfile? 1
|
|
2134
|
-
end
|
|
2135
|
-
|
|
2136
|
-
def test_verify_none_equals
|
|
2137
|
-
@agent.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
2138
|
-
|
|
2139
|
-
http = @agent.http
|
|
2140
|
-
|
|
2141
|
-
assert_equal OpenSSL::SSL::VERIFY_NONE, http.verify_mode
|
|
2142
|
-
end
|
|
2143
|
-
|
|
2144
|
-
end
|
|
2145
|
-
|