mechanize 2.7.6 → 2.12.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.
Files changed (157) hide show
  1. checksums.yaml +5 -5
  2. data/.github/dependabot.yml +11 -0
  3. data/.github/workflows/ci.yml +43 -0
  4. data/.github/workflows/upstream.yml +51 -0
  5. data/.yardopts +8 -0
  6. data/{CHANGELOG.rdoc → CHANGELOG.md} +221 -96
  7. data/EXAMPLES.rdoc +1 -24
  8. data/Gemfile +10 -4
  9. data/{LICENSE.rdoc → LICENSE.txt} +4 -0
  10. data/README.md +77 -0
  11. data/Rakefile +18 -3
  12. data/examples/latest_user_agents.rb +100 -0
  13. data/examples/rubygems.rb +2 -2
  14. data/examples/wikipedia_links_to_philosophy.rb +5 -6
  15. data/lib/mechanize/chunked_termination_error.rb +1 -0
  16. data/lib/mechanize/content_type_error.rb +1 -0
  17. data/lib/mechanize/cookie.rb +3 -15
  18. data/lib/mechanize/cookie_jar.rb +13 -9
  19. data/lib/mechanize/directory_saver.rb +1 -0
  20. data/lib/mechanize/download.rb +2 -1
  21. data/lib/mechanize/element_matcher.rb +1 -0
  22. data/lib/mechanize/element_not_found_error.rb +1 -0
  23. data/lib/mechanize/file.rb +2 -1
  24. data/lib/mechanize/file_connection.rb +5 -3
  25. data/lib/mechanize/file_request.rb +1 -0
  26. data/lib/mechanize/file_response.rb +4 -1
  27. data/lib/mechanize/file_saver.rb +1 -0
  28. data/lib/mechanize/form/button.rb +1 -0
  29. data/lib/mechanize/form/check_box.rb +1 -0
  30. data/lib/mechanize/form/field.rb +1 -0
  31. data/lib/mechanize/form/file_upload.rb +1 -0
  32. data/lib/mechanize/form/hidden.rb +1 -0
  33. data/lib/mechanize/form/image_button.rb +1 -0
  34. data/lib/mechanize/form/keygen.rb +1 -0
  35. data/lib/mechanize/form/multi_select_list.rb +2 -1
  36. data/lib/mechanize/form/option.rb +1 -0
  37. data/lib/mechanize/form/radio_button.rb +1 -0
  38. data/lib/mechanize/form/reset.rb +1 -0
  39. data/lib/mechanize/form/select_list.rb +1 -0
  40. data/lib/mechanize/form/submit.rb +1 -0
  41. data/lib/mechanize/form/text.rb +1 -0
  42. data/lib/mechanize/form/textarea.rb +1 -0
  43. data/lib/mechanize/form.rb +5 -13
  44. data/lib/mechanize/headers.rb +1 -0
  45. data/lib/mechanize/history.rb +1 -0
  46. data/lib/mechanize/http/agent.rb +83 -10
  47. data/lib/mechanize/http/auth_challenge.rb +1 -0
  48. data/lib/mechanize/http/auth_realm.rb +1 -0
  49. data/lib/mechanize/http/auth_store.rb +1 -0
  50. data/lib/mechanize/http/content_disposition_parser.rb +15 -4
  51. data/lib/mechanize/http/www_authenticate_parser.rb +3 -3
  52. data/lib/mechanize/http.rb +1 -0
  53. data/lib/mechanize/image.rb +1 -0
  54. data/lib/mechanize/page/base.rb +1 -0
  55. data/lib/mechanize/page/frame.rb +1 -0
  56. data/lib/mechanize/page/image.rb +1 -0
  57. data/lib/mechanize/page/label.rb +1 -0
  58. data/lib/mechanize/page/link.rb +8 -1
  59. data/lib/mechanize/page/meta_refresh.rb +1 -0
  60. data/lib/mechanize/page.rb +6 -8
  61. data/lib/mechanize/parser.rb +1 -0
  62. data/lib/mechanize/pluggable_parsers.rb +2 -1
  63. data/lib/mechanize/prependable.rb +1 -0
  64. data/lib/mechanize/redirect_limit_reached_error.rb +1 -0
  65. data/lib/mechanize/redirect_not_get_or_head_error.rb +1 -0
  66. data/lib/mechanize/response_code_error.rb +2 -1
  67. data/lib/mechanize/response_read_error.rb +1 -0
  68. data/lib/mechanize/robots_disallowed_error.rb +1 -0
  69. data/lib/mechanize/test_case/bad_chunking_servlet.rb +1 -0
  70. data/lib/mechanize/test_case/basic_auth_servlet.rb +1 -0
  71. data/lib/mechanize/test_case/content_type_servlet.rb +1 -0
  72. data/lib/mechanize/test_case/digest_auth_servlet.rb +1 -0
  73. data/lib/mechanize/test_case/file_upload_servlet.rb +1 -0
  74. data/lib/mechanize/test_case/form_servlet.rb +1 -0
  75. data/lib/mechanize/test_case/gzip_servlet.rb +4 -3
  76. data/lib/mechanize/test_case/header_servlet.rb +1 -0
  77. data/lib/mechanize/test_case/http_refresh_servlet.rb +1 -0
  78. data/lib/mechanize/test_case/infinite_redirect_servlet.rb +1 -0
  79. data/lib/mechanize/test_case/infinite_refresh_servlet.rb +1 -0
  80. data/lib/mechanize/test_case/many_cookies_as_string_servlet.rb +1 -0
  81. data/lib/mechanize/test_case/many_cookies_servlet.rb +1 -0
  82. data/lib/mechanize/test_case/modified_since_servlet.rb +1 -0
  83. data/lib/mechanize/test_case/ntlm_servlet.rb +1 -0
  84. data/lib/mechanize/test_case/one_cookie_no_spaces_servlet.rb +1 -0
  85. data/lib/mechanize/test_case/one_cookie_servlet.rb +1 -0
  86. data/lib/mechanize/test_case/quoted_value_cookie_servlet.rb +1 -0
  87. data/lib/mechanize/test_case/redirect_servlet.rb +1 -0
  88. data/lib/mechanize/test_case/referer_servlet.rb +1 -0
  89. data/lib/mechanize/test_case/refresh_with_empty_url.rb +1 -0
  90. data/lib/mechanize/test_case/refresh_without_url.rb +1 -0
  91. data/lib/mechanize/test_case/response_code_servlet.rb +1 -0
  92. data/lib/mechanize/test_case/robots_txt_servlet.rb +1 -0
  93. data/lib/mechanize/test_case/send_cookies_servlet.rb +1 -0
  94. data/lib/mechanize/test_case/server.rb +1 -0
  95. data/lib/mechanize/test_case/servlets.rb +1 -0
  96. data/lib/mechanize/test_case/verb_servlet.rb +5 -6
  97. data/lib/mechanize/test_case.rb +34 -34
  98. data/lib/mechanize/unauthorized_error.rb +1 -0
  99. data/lib/mechanize/unsupported_scheme_error.rb +1 -0
  100. data/lib/mechanize/util.rb +2 -1
  101. data/lib/mechanize/version.rb +2 -1
  102. data/lib/mechanize/xml_file.rb +1 -0
  103. data/lib/mechanize.rb +56 -37
  104. data/mechanize.gemspec +43 -35
  105. data/test/htdocs/dir with spaces/foo.html +1 -0
  106. data/test/htdocs/tc_links.html +1 -1
  107. data/test/test_mechanize.rb +21 -8
  108. data/test/test_mechanize_cookie.rb +38 -26
  109. data/test/test_mechanize_cookie_jar.rb +87 -54
  110. data/test/test_mechanize_directory_saver.rb +1 -0
  111. data/test/test_mechanize_download.rb +14 -1
  112. data/test/test_mechanize_element_not_found_error.rb +1 -0
  113. data/test/test_mechanize_file.rb +11 -0
  114. data/test/test_mechanize_file_connection.rb +23 -4
  115. data/test/test_mechanize_file_request.rb +1 -0
  116. data/test/test_mechanize_file_response.rb +26 -1
  117. data/test/test_mechanize_file_saver.rb +1 -0
  118. data/test/test_mechanize_form.rb +14 -1
  119. data/test/test_mechanize_form_check_box.rb +1 -0
  120. data/test/test_mechanize_form_encoding.rb +2 -1
  121. data/test/test_mechanize_form_field.rb +1 -0
  122. data/test/test_mechanize_form_file_upload.rb +1 -0
  123. data/test/test_mechanize_form_image_button.rb +1 -0
  124. data/test/test_mechanize_form_keygen.rb +2 -0
  125. data/test/test_mechanize_form_multi_select_list.rb +1 -0
  126. data/test/test_mechanize_form_option.rb +1 -0
  127. data/test/test_mechanize_form_radio_button.rb +1 -0
  128. data/test/test_mechanize_form_select_list.rb +1 -0
  129. data/test/test_mechanize_form_textarea.rb +1 -0
  130. data/test/test_mechanize_headers.rb +1 -0
  131. data/test/test_mechanize_history.rb +1 -0
  132. data/test/test_mechanize_http_agent.rb +187 -26
  133. data/test/test_mechanize_http_auth_challenge.rb +1 -0
  134. data/test/test_mechanize_http_auth_realm.rb +1 -0
  135. data/test/test_mechanize_http_auth_store.rb +1 -0
  136. data/test/test_mechanize_http_content_disposition_parser.rb +28 -0
  137. data/test/test_mechanize_http_www_authenticate_parser.rb +1 -0
  138. data/test/test_mechanize_image.rb +1 -0
  139. data/test/test_mechanize_link.rb +25 -0
  140. data/test/test_mechanize_page.rb +15 -0
  141. data/test/test_mechanize_page_encoding.rb +33 -5
  142. data/test/test_mechanize_page_frame.rb +1 -0
  143. data/test/test_mechanize_page_image.rb +1 -0
  144. data/test/test_mechanize_page_link.rb +27 -23
  145. data/test/test_mechanize_page_meta_refresh.rb +1 -0
  146. data/test/test_mechanize_parser.rb +1 -0
  147. data/test/test_mechanize_pluggable_parser.rb +1 -0
  148. data/test/test_mechanize_redirect_limit_reached_error.rb +1 -0
  149. data/test/test_mechanize_redirect_not_get_or_head_error.rb +1 -0
  150. data/test/test_mechanize_response_read_error.rb +1 -0
  151. data/test/test_mechanize_subclass.rb +1 -0
  152. data/test/test_mechanize_util.rb +4 -3
  153. data/test/test_mechanize_xml_file.rb +1 -0
  154. data/test/test_multi_select.rb +1 -0
  155. metadata +106 -86
  156. data/.travis.yml +0 -36
  157. data/README.rdoc +0 -77
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'mechanize/test_case'
2
3
 
3
4
  module Enumerable
@@ -141,7 +142,7 @@ class TestMechanizeCookie < Mechanize::TestCase
141
142
  def test_parse_date_fail
142
143
  url = URI.parse('http://localhost/')
143
144
 
144
- dates = [
145
+ dates = [
145
146
  "20/06/95 21:07",
146
147
  ]
147
148
 
@@ -290,18 +291,18 @@ class TestMechanizeCookie < Mechanize::TestCase
290
291
  end
291
292
 
292
293
  def test_parse_valid_cookie
293
- url = URI.parse('http://rubyforge.org/')
294
+ url = URI.parse('http://rubygems.org/')
294
295
  cookie_params = {}
295
296
  cookie_params['expires'] = 'expires=Sun, 27-Sep-2037 00:00:00 GMT'
296
297
  cookie_params['path'] = 'path=/'
297
- cookie_params['domain'] = 'domain=.rubyforge.org'
298
+ cookie_params['domain'] = 'domain=.rubygems.org'
298
299
  cookie_params['httponly'] = 'HttpOnly'
299
300
  cookie_value = '12345%7D=ASDFWEE345%3DASda'
300
301
 
301
302
  expires = Time.parse('Sun, 27-Sep-2037 00:00:00 GMT')
302
-
303
+
303
304
  cookie_params.keys.combine.each do |c|
304
- cookie_text = "#{cookie_value}; "
305
+ cookie_text = +"#{cookie_value}; "
305
306
  c.each_with_index do |key, idx|
306
307
  if idx == (c.length - 1)
307
308
  cookie_text << "#{cookie_params[key]}"
@@ -325,18 +326,18 @@ class TestMechanizeCookie < Mechanize::TestCase
325
326
  end
326
327
 
327
328
  def test_parse_valid_cookie_empty_value
328
- url = URI.parse('http://rubyforge.org/')
329
+ url = URI.parse('http://rubygems.org/')
329
330
  cookie_params = {}
330
331
  cookie_params['expires'] = 'expires=Sun, 27-Sep-2037 00:00:00 GMT'
331
332
  cookie_params['path'] = 'path=/'
332
- cookie_params['domain'] = 'domain=.rubyforge.org'
333
+ cookie_params['domain'] = 'domain=.rubygems.org'
333
334
  cookie_params['httponly'] = 'HttpOnly'
334
335
  cookie_value = '12345%7D='
335
336
 
336
337
  expires = Time.parse('Sun, 27-Sep-2037 00:00:00 GMT')
337
-
338
+
338
339
  cookie_params.keys.combine.each do |c|
339
- cookie_text = "#{cookie_value}; "
340
+ cookie_text = +"#{cookie_value}; "
340
341
  c.each_with_index do |key, idx|
341
342
  if idx == (c.length - 1)
342
343
  cookie_text << "#{cookie_params[key]}"
@@ -361,19 +362,19 @@ class TestMechanizeCookie < Mechanize::TestCase
361
362
 
362
363
  # If no path was given, use the one from the URL
363
364
  def test_cookie_using_url_path
364
- url = URI.parse('http://rubyforge.org/login.php')
365
+ url = URI.parse('http://rubygems.org/login.php')
365
366
  cookie_params = {}
366
367
  cookie_params['expires'] = 'expires=Sun, 27-Sep-2037 00:00:00 GMT'
367
368
  cookie_params['path'] = 'path=/'
368
- cookie_params['domain'] = 'domain=.rubyforge.org'
369
+ cookie_params['domain'] = 'domain=.rubygems.org'
369
370
  cookie_params['httponly'] = 'HttpOnly'
370
371
  cookie_value = '12345%7D=ASDFWEE345%3DASda'
371
372
 
372
373
  expires = Time.parse('Sun, 27-Sep-2037 00:00:00 GMT')
373
-
374
+
374
375
  cookie_params.keys.combine.each do |c|
375
376
  next if c.find { |k| k == 'path' }
376
- cookie_text = "#{cookie_value}; "
377
+ cookie_text = +"#{cookie_value}; "
377
378
  c.each_with_index do |key, idx|
378
379
  if idx == (c.length - 1)
379
380
  cookie_text << "#{cookie_params[key]}"
@@ -398,19 +399,19 @@ class TestMechanizeCookie < Mechanize::TestCase
398
399
 
399
400
  # Test using secure cookies
400
401
  def test_cookie_with_secure
401
- url = URI.parse('http://rubyforge.org/')
402
+ url = URI.parse('http://rubygems.org/')
402
403
  cookie_params = {}
403
404
  cookie_params['expires'] = 'expires=Sun, 27-Sep-2037 00:00:00 GMT'
404
405
  cookie_params['path'] = 'path=/'
405
- cookie_params['domain'] = 'domain=.rubyforge.org'
406
+ cookie_params['domain'] = 'domain=.rubygems.org'
406
407
  cookie_params['secure'] = 'secure'
407
408
  cookie_value = '12345%7D=ASDFWEE345%3DASda'
408
409
 
409
410
  expires = Time.parse('Sun, 27-Sep-2037 00:00:00 GMT')
410
-
411
+
411
412
  cookie_params.keys.combine.each do |c|
412
413
  next unless c.find { |k| k == 'secure' }
413
- cookie_text = "#{cookie_value}; "
414
+ cookie_text = +"#{cookie_value}; "
414
415
  c.each_with_index do |key, idx|
415
416
  if idx == (c.length - 1)
416
417
  cookie_text << "#{cookie_params[key]}"
@@ -435,18 +436,18 @@ class TestMechanizeCookie < Mechanize::TestCase
435
436
  end
436
437
 
437
438
  def test_parse_cookie_no_spaces
438
- url = URI.parse('http://rubyforge.org/')
439
+ url = URI.parse('http://rubygems.org/')
439
440
  cookie_params = {}
440
441
  cookie_params['expires'] = 'expires=Sun, 27-Sep-2037 00:00:00 GMT'
441
442
  cookie_params['path'] = 'path=/'
442
- cookie_params['domain'] = 'domain=.rubyforge.org'
443
+ cookie_params['domain'] = 'domain=.rubygems.org'
443
444
  cookie_params['httponly'] = 'HttpOnly'
444
445
  cookie_value = '12345%7D=ASDFWEE345%3DASda'
445
446
 
446
447
  expires = Time.parse('Sun, 27-Sep-2037 00:00:00 GMT')
447
-
448
+
448
449
  cookie_params.keys.combine.each do |c|
449
- cookie_text = "#{cookie_value};"
450
+ cookie_text = +"#{cookie_value};"
450
451
  c.each_with_index do |key, idx|
451
452
  if idx == (c.length - 1)
452
453
  cookie_text << "#{cookie_params[key]}"
@@ -502,24 +503,35 @@ class TestMechanizeCookie < Mechanize::TestCase
502
503
  cookie.domain = 'Dom.example.com'
503
504
  assert 'dom.example.com', cookie.domain
504
505
 
505
- cookie.domain = Object.new.tap { |o|
506
+ new_domain = Object.new.tap { |o|
506
507
  def o.to_str
507
508
  'Example.com'
508
509
  end
509
510
  }
511
+ cookie.domain = new_domain
510
512
  assert 'example.com', cookie.domain
513
+
514
+ new_domain = Object.new.tap { |o|
515
+ def o.to_str
516
+ 'Example2.com'
517
+ end
518
+ }
519
+ assert_output nil, /The call of Mechanize::Cookie#set_domain/ do
520
+ cookie.set_domain(new_domain)
521
+ end
522
+ assert 'example2.com', cookie.domain
511
523
  end
512
524
 
513
525
  def test_cookie_httponly
514
- url = URI.parse('http://rubyforge.org/')
526
+ url = URI.parse('http://rubygems.org/')
515
527
  cookie_params = {}
516
528
  cookie_params['httponly'] = 'HttpOnly'
517
529
  cookie_value = '12345%7D=ASDFWEE345%3DASda'
518
530
 
519
531
  expires = Time.parse('Sun, 27-Sep-2037 00:00:00 GMT')
520
-
532
+
521
533
  cookie_params.keys.combine.each do |c|
522
- cookie_text = "#{cookie_value}; "
534
+ cookie_text = +"#{cookie_value}; "
523
535
  c.each_with_index do |key, idx|
524
536
  if idx == (c.length - 1)
525
537
  cookie_text << "#{cookie_params[key]}"
@@ -532,7 +544,7 @@ class TestMechanizeCookie < Mechanize::TestCase
532
544
 
533
545
  assert_equal(true, cookie.httponly)
534
546
 
535
-
547
+
536
548
  # if expires was set, make sure we parsed it
537
549
  if c.find { |k| k == 'expires' }
538
550
  assert_equal(expires, cookie.expires)
@@ -1,4 +1,6 @@
1
+ # frozen_string_literal: true
1
2
  require 'mechanize/test_case'
3
+ require 'fileutils'
2
4
 
3
5
  class TestMechanizeCookieJar < Mechanize::TestCase
4
6
 
@@ -39,23 +41,23 @@ class TestMechanizeCookieJar < Mechanize::TestCase
39
41
  :path => '/',
40
42
  :expires => Time.now + (10 * 86400),
41
43
  :for_domain => true,
42
- :domain => 'rubyforge.org'
44
+ :domain => 'rubygems.org'
43
45
  }.merge(options)
44
46
  end
45
47
 
46
48
  def test_two_cookies_same_domain_and_name_different_paths
47
- url = URI 'http://rubyforge.org/'
49
+ url = URI 'http://rubygems.org/'
48
50
 
49
51
  cookie = Mechanize::Cookie.new(cookie_values)
50
52
  @jar.add(url, cookie)
51
53
  @jar.add(url, Mechanize::Cookie.new(cookie_values(:path => '/onetwo')))
52
54
 
53
55
  assert_equal(1, @jar.cookies(url).length)
54
- assert_equal 2, @jar.cookies(URI('http://rubyforge.org/onetwo')).length
56
+ assert_equal 2, @jar.cookies(URI('http://rubygems.org/onetwo')).length
55
57
  end
56
58
 
57
59
  def test_domain_case
58
- url = URI 'http://rubyforge.org/'
60
+ url = URI 'http://rubygems.org/'
59
61
 
60
62
  # Add one cookie with an expiration date in the future
61
63
  cookie = Mechanize::Cookie.new(cookie_values)
@@ -63,49 +65,49 @@ class TestMechanizeCookieJar < Mechanize::TestCase
63
65
  assert_equal(1, @jar.cookies(url).length)
64
66
 
65
67
  @jar.add(url, Mechanize::Cookie.new(
66
- cookie_values(:domain => 'RuByForge.Org', :name => 'aaron')))
68
+ cookie_values(:domain => 'rubygems.Org', :name => 'aaron')))
67
69
 
68
70
  assert_equal(2, @jar.cookies(url).length)
69
71
 
70
- url2 = URI 'http://RuByFoRgE.oRg/'
72
+ url2 = URI 'http://rubygems.oRg/'
71
73
  assert_equal(2, @jar.cookies(url2).length)
72
74
  end
73
75
 
74
76
  def test_host_only
75
- url = URI.parse('http://rubyforge.org/')
77
+ url = URI.parse('http://rubygems.org/')
76
78
 
77
79
  @jar.add(url, Mechanize::Cookie.new(
78
- cookie_values(:domain => 'rubyforge.org', :for_domain => false)))
80
+ cookie_values(:domain => 'rubygems.org', :for_domain => false)))
79
81
 
80
82
  assert_equal(1, @jar.cookies(url).length)
81
83
 
82
- assert_equal(1, @jar.cookies(URI('http://RubyForge.org/')).length)
84
+ assert_equal(1, @jar.cookies(URI('http://rubygems.org/')).length)
83
85
 
84
- assert_equal(1, @jar.cookies(URI('https://RubyForge.org/')).length)
86
+ assert_equal(1, @jar.cookies(URI('https://rubygems.org/')).length)
85
87
 
86
- assert_equal(0, @jar.cookies(URI('http://www.rubyforge.org/')).length)
88
+ assert_equal(0, @jar.cookies(URI('http://www.rubygems.org/')).length)
87
89
  end
88
90
 
89
91
  def test_empty_value
90
92
  values = cookie_values(:value => "")
91
- url = URI 'http://rubyforge.org/'
93
+ url = URI 'http://rubygems.org/'
92
94
 
93
95
  # Add one cookie with an expiration date in the future
94
96
  cookie = Mechanize::Cookie.new(values)
95
97
  @jar.add(url, cookie)
96
98
  assert_equal(1, @jar.cookies(url).length)
97
99
 
98
- @jar.add url, Mechanize::Cookie.new(values.merge(:domain => 'RuByForge.Org',
100
+ @jar.add url, Mechanize::Cookie.new(values.merge(:domain => 'rubygems.Org',
99
101
  :name => 'aaron'))
100
102
 
101
103
  assert_equal(2, @jar.cookies(url).length)
102
104
 
103
- url2 = URI 'http://RuByFoRgE.oRg/'
105
+ url2 = URI 'http://rubygems.oRg/'
104
106
  assert_equal(2, @jar.cookies(url2).length)
105
107
  end
106
108
 
107
109
  def test_add_future_cookies
108
- url = URI 'http://rubyforge.org/'
110
+ url = URI 'http://rubygems.org/'
109
111
 
110
112
  # Add one cookie with an expiration date in the future
111
113
  cookie = Mechanize::Cookie.new(cookie_values)
@@ -117,14 +119,14 @@ class TestMechanizeCookieJar < Mechanize::TestCase
117
119
  assert_equal(1, @jar.cookies(url).length)
118
120
 
119
121
  # Make sure we can get the cookie from different paths
120
- assert_equal(1, @jar.cookies(URI('http://rubyforge.org/login')).length)
122
+ assert_equal(1, @jar.cookies(URI('http://rubygems.org/login')).length)
121
123
 
122
124
  # Make sure we can't get the cookie from different domains
123
125
  assert_equal(0, @jar.cookies(URI('http://google.com/')).length)
124
126
  end
125
127
 
126
128
  def test_add_multiple_cookies
127
- url = URI 'http://rubyforge.org/'
129
+ url = URI 'http://rubygems.org/'
128
130
 
129
131
  # Add one cookie with an expiration date in the future
130
132
  cookie = Mechanize::Cookie.new(cookie_values)
@@ -136,14 +138,14 @@ class TestMechanizeCookieJar < Mechanize::TestCase
136
138
  assert_equal(2, @jar.cookies(url).length)
137
139
 
138
140
  # Make sure we can get the cookie from different paths
139
- assert_equal(2, @jar.cookies(URI('http://rubyforge.org/login')).length)
141
+ assert_equal(2, @jar.cookies(URI('http://rubygems.org/login')).length)
140
142
 
141
143
  # Make sure we can't get the cookie from different domains
142
144
  assert_equal(0, @jar.cookies(URI('http://google.com/')).length)
143
145
  end
144
146
 
145
147
  def test_add_rejects_cookies_that_do_not_contain_an_embedded_dot
146
- url = URI 'http://rubyforge.org/'
148
+ url = URI 'http://rubygems.org/'
147
149
 
148
150
  tld_cookie = Mechanize::Cookie.new(cookie_values(:domain => '.org'))
149
151
  @jar.add(url, tld_cookie)
@@ -196,43 +198,43 @@ class TestMechanizeCookieJar < Mechanize::TestCase
196
198
  end
197
199
 
198
200
  def test_cookie_without_leading_dot_does_not_cause_substring_match
199
- url = URI 'http://arubyforge.org/'
201
+ url = URI 'http://arubygems.org/'
200
202
 
201
- cookie = Mechanize::Cookie.new(cookie_values(:domain => 'rubyforge.org'))
203
+ cookie = Mechanize::Cookie.new(cookie_values(:domain => 'rubygems.org'))
202
204
  @jar.add(url, cookie)
203
205
 
204
206
  assert_equal(0, @jar.cookies(url).length)
205
207
  end
206
208
 
207
209
  def test_cookie_without_leading_dot_matches_subdomains
208
- url = URI 'http://admin.rubyforge.org/'
210
+ url = URI 'http://admin.rubygems.org/'
209
211
 
210
- cookie = Mechanize::Cookie.new(cookie_values(:domain => 'rubyforge.org'))
212
+ cookie = Mechanize::Cookie.new(cookie_values(:domain => 'rubygems.org'))
211
213
  @jar.add(url, cookie)
212
214
 
213
215
  assert_equal(1, @jar.cookies(url).length)
214
216
  end
215
217
 
216
218
  def test_cookies_with_leading_dot_match_subdomains
217
- url = URI 'http://admin.rubyforge.org/'
219
+ url = URI 'http://admin.rubygems.org/'
218
220
 
219
- @jar.add(url, Mechanize::Cookie.new(cookie_values(:domain => '.rubyforge.org')))
221
+ @jar.add(url, Mechanize::Cookie.new(cookie_values(:domain => '.rubygems.org')))
220
222
 
221
223
  assert_equal(1, @jar.cookies(url).length)
222
224
  end
223
225
 
224
226
  def test_cookies_with_leading_dot_match_parent_domains
225
- url = URI 'http://rubyforge.org/'
227
+ url = URI 'http://rubygems.org/'
226
228
 
227
- @jar.add(url, Mechanize::Cookie.new(cookie_values(:domain => '.rubyforge.org')))
229
+ @jar.add(url, Mechanize::Cookie.new(cookie_values(:domain => '.rubygems.org')))
228
230
 
229
231
  assert_equal(1, @jar.cookies(url).length)
230
232
  end
231
233
 
232
234
  def test_cookies_with_leading_dot_match_parent_domains_exactly
233
- url = URI 'http://arubyforge.org/'
235
+ url = URI 'http://arubygems.org/'
234
236
 
235
- @jar.add(url, Mechanize::Cookie.new(cookie_values(:domain => '.rubyforge.org')))
237
+ @jar.add(url, Mechanize::Cookie.new(cookie_values(:domain => '.rubygems.org')))
236
238
 
237
239
  assert_equal(0, @jar.cookies(url).length)
238
240
  end
@@ -275,7 +277,7 @@ class TestMechanizeCookieJar < Mechanize::TestCase
275
277
  end
276
278
 
277
279
  def test_clear_bang
278
- url = URI 'http://rubyforge.org/'
280
+ url = URI 'http://rubygems.org/'
279
281
 
280
282
  # Add one cookie with an expiration date in the future
281
283
  cookie = Mechanize::Cookie.new(cookie_values)
@@ -289,7 +291,7 @@ class TestMechanizeCookieJar < Mechanize::TestCase
289
291
  end
290
292
 
291
293
  def test_save_cookies_yaml
292
- url = URI 'http://rubyforge.org/'
294
+ url = URI 'http://rubygems.org/'
293
295
 
294
296
  # Add one cookie with an expiration date in the future
295
297
  cookie = Mechanize::Cookie.new(cookie_values)
@@ -315,7 +317,7 @@ class TestMechanizeCookieJar < Mechanize::TestCase
315
317
  end
316
318
 
317
319
  def test_save_session_cookies_yaml
318
- url = URI 'http://rubyforge.org/'
320
+ url = URI 'http://rubygems.org/'
319
321
 
320
322
  # Add one cookie with an expiration date in the future
321
323
  cookie = Mechanize::Cookie.new(cookie_values)
@@ -341,7 +343,7 @@ class TestMechanizeCookieJar < Mechanize::TestCase
341
343
 
342
344
 
343
345
  def test_save_cookies_cookiestxt
344
- url = URI 'http://rubyforge.org/'
346
+ url = URI 'http://rubygems.org/'
345
347
 
346
348
  # Add one cookie with an expiration date in the future
347
349
  cookie = Mechanize::Cookie.new(cookie_values)
@@ -378,7 +380,7 @@ class TestMechanizeCookieJar < Mechanize::TestCase
378
380
  end
379
381
 
380
382
  def test_expire_cookies
381
- url = URI 'http://rubyforge.org/'
383
+ url = URI 'http://rubygems.org/'
382
384
 
383
385
  # Add one cookie with an expiration date in the future
384
386
  cookie = Mechanize::Cookie.new(cookie_values)
@@ -390,7 +392,7 @@ class TestMechanizeCookieJar < Mechanize::TestCase
390
392
  assert_equal(2, @jar.cookies(url).length)
391
393
 
392
394
  # Make sure we can get the cookie from different paths
393
- assert_equal(2, @jar.cookies(URI('http://rubyforge.org/login')).length)
395
+ assert_equal(2, @jar.cookies(URI('http://rubygems.org/login')).length)
394
396
 
395
397
  # Expire the first cookie
396
398
  @jar.add(url, Mechanize::Cookie.new(
@@ -405,7 +407,7 @@ class TestMechanizeCookieJar < Mechanize::TestCase
405
407
 
406
408
  def test_session_cookies
407
409
  values = cookie_values(:expires => nil)
408
- url = URI 'http://rubyforge.org/'
410
+ url = URI 'http://rubygems.org/'
409
411
 
410
412
  # Add one cookie with an expiration date in the future
411
413
  cookie = Mechanize::Cookie.new(values)
@@ -417,7 +419,7 @@ class TestMechanizeCookieJar < Mechanize::TestCase
417
419
  assert_equal(2, @jar.cookies(url).length)
418
420
 
419
421
  # Make sure we can get the cookie from different paths
420
- assert_equal(2, @jar.cookies(URI('http://rubyforge.org/login')).length)
422
+ assert_equal(2, @jar.cookies(URI('http://rubygems.org/login')).length)
421
423
 
422
424
  # Expire the first cookie
423
425
  @jar.add(url, Mechanize::Cookie.new(values.merge(:expires => Time.now - (10 * 86400))))
@@ -430,7 +432,7 @@ class TestMechanizeCookieJar < Mechanize::TestCase
430
432
 
431
433
  # When given a URI with a blank path, CookieJar#cookies should return
432
434
  # cookies with the path '/':
433
- url = URI 'http://rubyforge.org'
435
+ url = URI 'http://rubygems.org'
434
436
  assert_equal '', url.path
435
437
  assert_equal(0, @jar.cookies(url).length)
436
438
  # Now add a cookie with the path set to '/':
@@ -441,7 +443,7 @@ class TestMechanizeCookieJar < Mechanize::TestCase
441
443
 
442
444
  def test_paths
443
445
  values = cookie_values(:path => "/login", :expires => nil)
444
- url = URI 'http://rubyforge.org/login'
446
+ url = URI 'http://rubygems.org/login'
445
447
 
446
448
  # Add one cookie with an expiration date in the future
447
449
  cookie = Mechanize::Cookie.new(values)
@@ -453,8 +455,8 @@ class TestMechanizeCookieJar < Mechanize::TestCase
453
455
  assert_equal(2, @jar.cookies(url).length)
454
456
 
455
457
  # Make sure we don't get the cookie in a different path
456
- assert_equal(0, @jar.cookies(URI('http://rubyforge.org/hello')).length)
457
- assert_equal(0, @jar.cookies(URI('http://rubyforge.org/')).length)
458
+ assert_equal(0, @jar.cookies(URI('http://rubygems.org/hello')).length)
459
+ assert_equal(0, @jar.cookies(URI('http://rubygems.org/')).length)
458
460
 
459
461
  # Expire the first cookie
460
462
  @jar.add(url, Mechanize::Cookie.new(values.merge( :expires => Time.now - (10 * 86400))))
@@ -467,7 +469,7 @@ class TestMechanizeCookieJar < Mechanize::TestCase
467
469
  end
468
470
 
469
471
  def test_save_and_read_cookiestxt
470
- url = URI 'http://rubyforge.org/'
472
+ url = URI 'http://rubygems.org/'
471
473
 
472
474
  # Add one cookie with an expiration date in the future
473
475
  cookie = Mechanize::Cookie.new(cookie_values)
@@ -486,7 +488,7 @@ class TestMechanizeCookieJar < Mechanize::TestCase
486
488
  end
487
489
 
488
490
  def test_save_and_read_cookiestxt_with_session_cookies
489
- url = URI 'http://rubyforge.org/'
491
+ url = URI 'http://rubygems.org/'
490
492
 
491
493
  @jar.add(url, Mechanize::Cookie.new(cookie_values(:expires => nil)))
492
494
 
@@ -500,22 +502,53 @@ class TestMechanizeCookieJar < Mechanize::TestCase
500
502
  assert_equal(0, @jar.cookies(url).length)
501
503
  end
502
504
 
505
+ def test_prevent_command_injection_when_saving
506
+ skip if windows?
507
+ url = URI 'http://rubygems.org/'
508
+ path = '| ruby -rfileutils -e \'FileUtils.touch("vul.txt")\''
509
+
510
+ @jar.add(url, Mechanize::Cookie.new(cookie_values))
511
+
512
+ in_tmpdir do
513
+ @jar.save_as(path, :cookiestxt)
514
+ assert_equal(false, File.exist?('vul.txt'))
515
+ end
516
+ end
517
+
518
+ def test_prevent_command_injection_when_loading
519
+ skip if windows?
520
+ url = URI 'http://rubygems.org/'
521
+ path = '| ruby -rfileutils -e \'FileUtils.touch("vul.txt")\''
522
+
523
+ @jar.add(url, Mechanize::Cookie.new(cookie_values))
524
+
525
+ in_tmpdir do
526
+ @jar.save_as("cookies.txt", :cookiestxt)
527
+ @jar.clear!
528
+
529
+ assert_raises Errno::ENOENT do
530
+ @jar.load(path, :cookiestxt)
531
+ end
532
+ assert_equal(false, File.exist?('vul.txt'))
533
+ end
534
+ end
535
+
503
536
  def test_save_and_read_expired_cookies
504
- url = URI 'http://rubyforge.org/'
537
+ url = URI 'http://rubygems.org/'
505
538
 
506
- @jar.jar['rubyforge.org'] = {}
539
+ @jar.jar['rubygems.org'] = {}
507
540
 
508
541
 
509
542
  @jar.add url, Mechanize::Cookie.new(cookie_values)
510
543
 
511
- # HACK no asertion
544
+ # HACK no assertion
512
545
  end
513
546
 
514
547
  def test_ssl_cookies
515
548
  # thanks to michal "ocher" ochman for reporting the bug responsible for this test.
516
549
  values = cookie_values(:expires => nil)
517
550
  values_ssl = values.merge(:name => 'Baz', :domain => "#{values[:domain]}:443")
518
- url = URI 'https://rubyforge.org/login'
551
+ url = URI 'https://rubygems.org/login'
519
552
 
520
553
  cookie = Mechanize::Cookie.new(values)
521
554
  @jar.add(url, cookie)
@@ -527,8 +560,8 @@ class TestMechanizeCookieJar < Mechanize::TestCase
527
560
  end
528
561
 
529
562
  def test_secure_cookie
530
- nurl = URI 'http://rubyforge.org/login'
531
- surl = URI 'https://rubyforge.org/login'
563
+ nurl = URI 'http://rubygems.org/login'
564
+ surl = URI 'https://rubygems.org/login'
532
565
 
533
566
  ncookie = Mechanize::Cookie.new(cookie_values(:name => 'Foo1'))
534
567
  scookie = Mechanize::Cookie.new(cookie_values(:name => 'Foo2', :secure => true))
@@ -543,10 +576,10 @@ class TestMechanizeCookieJar < Mechanize::TestCase
543
576
  end
544
577
 
545
578
  def test_save_cookies_cookiestxt_subdomain
546
- top_url = URI 'http://rubyforge.org/'
547
- subdomain_url = URI 'http://admin.rubyforge.org/'
579
+ top_url = URI 'http://rubygems.org/'
580
+ subdomain_url = URI 'http://admin.rubygems.org/'
548
581
 
549
- # cookie1 is for *.rubyforge.org; cookie2 is only for rubyforge.org, no subdomains
582
+ # cookie1 is for *.rubygems.org; cookie2 is only for rubygems.org, no subdomains
550
583
  cookie1 = Mechanize::Cookie.new(cookie_values)
551
584
  cookie2 = Mechanize::Cookie.new(cookie_values(:name => 'Boo', :for_domain => false))
552
585
 
@@ -572,8 +605,8 @@ class TestMechanizeCookieJar < Mechanize::TestCase
572
605
  # * Cookies that match subdomains may have a leading dot, and must have
573
606
  # TRUE as the second field.
574
607
  cookies_txt = File.readlines("cookies.txt")
575
- assert_equal(1, cookies_txt.grep( /^rubyforge\.org\tFALSE/ ).length)
576
- assert_equal(1, cookies_txt.grep( /^\.rubyforge\.org\tTRUE/ ).length)
608
+ assert_equal(1, cookies_txt.grep( /^rubygems\.org\tFALSE/ ).length)
609
+ assert_equal(1, cookies_txt.grep( /^\.rubygems\.org\tTRUE/ ).length)
577
610
  end
578
611
 
579
612
  assert_equal(2, @jar.cookies(top_url).length)
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'mechanize/test_case'
2
3
 
3
4
  class TestMechanizeDirectorySaver < Mechanize::TestCase
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'mechanize/test_case'
2
3
 
3
4
  class TestMechanizeDownload < Mechanize::TestCase
@@ -46,6 +47,19 @@ class TestMechanizeDownload < Mechanize::TestCase
46
47
  end
47
48
  end
48
49
 
50
+ def test_save_bang_does_not_allow_command_injection
51
+ skip if windows?
52
+ uri = URI.parse 'http://example/foo.html'
53
+ body_io = StringIO.new '0123456789'
54
+
55
+ download = @parser.new uri, nil, body_io
56
+
57
+ in_tmpdir do
58
+ download.save!('| ruby -rfileutils -e \'FileUtils.touch("vul.txt")\'')
59
+ refute_operator(File, :exist?, "vul.txt")
60
+ end
61
+ end
62
+
49
63
  def test_save_tempfile
50
64
  uri = URI.parse 'http://example/foo.html'
51
65
  Tempfile.open @NAME do |body_io|
@@ -84,6 +98,5 @@ class TestMechanizeDownload < Mechanize::TestCase
84
98
 
85
99
  assert_equal "foo.html", download.filename
86
100
  end
87
-
88
101
  end
89
102
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'mechanize/test_case'
2
3
 
3
4
  class TestMechanizeRedirectLimitReachedError < Mechanize::TestCase
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'mechanize/test_case'
2
3
 
3
4
  class TestMechanizeFile < Mechanize::TestCase
@@ -103,5 +104,15 @@ class TestMechanizeFile < Mechanize::TestCase
103
104
  end
104
105
  end
105
106
 
107
+ def test_save_bang_does_not_allow_command_injection
108
+ skip if windows?
109
+ uri = URI 'http://example/test.html'
110
+ page = Mechanize::File.new uri, nil, ''
111
+
112
+ in_tmpdir do
113
+ page.save!('| ruby -rfileutils -e \'FileUtils.touch("vul.txt")\'')
114
+ refute_operator(File, :exist?, "vul.txt")
115
+ end
116
+ end
106
117
  end
107
118
 
@@ -1,21 +1,40 @@
1
+ # frozen_string_literal: true
1
2
  require 'mechanize/test_case'
2
3
 
3
4
  class TestMechanizeFileConnection < Mechanize::TestCase
4
5
 
5
6
  def test_request
6
- uri = URI.parse "file://#{File.expand_path __FILE__}"
7
+ file_path = File.expand_path(__FILE__)
8
+ uri = URI.parse "file://#{file_path}"
7
9
  conn = Mechanize::FileConnection.new
8
10
 
9
- body = ''
11
+ body = +''
10
12
 
11
13
  conn.request uri, nil do |response|
14
+ assert_equal(file_path, response.file_path)
12
15
  response.read_body do |part|
13
16
  body << part
14
17
  end
15
18
  end
16
19
 
17
- assert_equal File.read(__FILE__), body
20
+ assert_equal File.read(__FILE__), body.gsub(/\r\n/, "\n")
18
21
  end
19
22
 
20
- end
23
+ def test_request_on_uri_with_windows_drive
24
+ uri_string = "file://C:/path/to/file.html"
25
+ expected_file_path = "C:/path/to/file.html"
26
+
27
+ uri = URI.parse(uri_string)
28
+ conn = Mechanize::FileConnection.new
21
29
 
30
+ called = false
31
+ yielded_file_path = nil
32
+ conn.request(uri, nil) do |response|
33
+ called = true
34
+ yielded_file_path = response.file_path
35
+ end
36
+
37
+ assert(called)
38
+ assert_equal(expected_file_path, yielded_file_path)
39
+ end
40
+ end