mechanize 2.7.4 → 2.8.1

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 (134) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ci-test.yml +45 -0
  3. data/.yardopts +8 -0
  4. data/{CHANGELOG.rdoc → CHANGELOG.md} +151 -86
  5. data/EXAMPLES.rdoc +1 -24
  6. data/Gemfile +1 -1
  7. data/{LICENSE.rdoc → LICENSE.txt} +4 -0
  8. data/README.md +77 -0
  9. data/Rakefile +18 -3
  10. data/examples/rubygems.rb +2 -2
  11. data/lib/mechanize.rb +3 -2
  12. data/lib/mechanize/chunked_termination_error.rb +1 -0
  13. data/lib/mechanize/content_type_error.rb +1 -0
  14. data/lib/mechanize/cookie.rb +1 -13
  15. data/lib/mechanize/cookie_jar.rb +4 -12
  16. data/lib/mechanize/directory_saver.rb +1 -0
  17. data/lib/mechanize/download.rb +2 -1
  18. data/lib/mechanize/element_matcher.rb +5 -1
  19. data/lib/mechanize/element_not_found_error.rb +1 -0
  20. data/lib/mechanize/file.rb +2 -1
  21. data/lib/mechanize/file_connection.rb +5 -3
  22. data/lib/mechanize/file_request.rb +1 -0
  23. data/lib/mechanize/file_response.rb +4 -1
  24. data/lib/mechanize/file_saver.rb +1 -0
  25. data/lib/mechanize/form.rb +112 -45
  26. data/lib/mechanize/form/button.rb +1 -0
  27. data/lib/mechanize/form/check_box.rb +1 -0
  28. data/lib/mechanize/form/field.rb +47 -0
  29. data/lib/mechanize/form/file_upload.rb +1 -0
  30. data/lib/mechanize/form/hidden.rb +1 -0
  31. data/lib/mechanize/form/image_button.rb +1 -0
  32. data/lib/mechanize/form/keygen.rb +1 -0
  33. data/lib/mechanize/form/multi_select_list.rb +8 -14
  34. data/lib/mechanize/form/option.rb +3 -1
  35. data/lib/mechanize/form/radio_button.rb +1 -0
  36. data/lib/mechanize/form/reset.rb +1 -0
  37. data/lib/mechanize/form/select_list.rb +1 -0
  38. data/lib/mechanize/form/submit.rb +1 -0
  39. data/lib/mechanize/form/text.rb +1 -0
  40. data/lib/mechanize/form/textarea.rb +1 -0
  41. data/lib/mechanize/headers.rb +1 -0
  42. data/lib/mechanize/history.rb +2 -1
  43. data/lib/mechanize/http.rb +1 -0
  44. data/lib/mechanize/http/agent.rb +81 -38
  45. data/lib/mechanize/http/auth_challenge.rb +1 -0
  46. data/lib/mechanize/http/auth_realm.rb +2 -1
  47. data/lib/mechanize/http/auth_store.rb +1 -0
  48. data/lib/mechanize/http/content_disposition_parser.rb +18 -3
  49. data/lib/mechanize/http/www_authenticate_parser.rb +4 -4
  50. data/lib/mechanize/image.rb +1 -0
  51. data/lib/mechanize/page.rb +8 -5
  52. data/lib/mechanize/page/base.rb +1 -0
  53. data/lib/mechanize/page/frame.rb +4 -1
  54. data/lib/mechanize/page/image.rb +1 -0
  55. data/lib/mechanize/page/label.rb +1 -0
  56. data/lib/mechanize/page/link.rb +8 -1
  57. data/lib/mechanize/page/meta_refresh.rb +1 -0
  58. data/lib/mechanize/parser.rb +4 -3
  59. data/lib/mechanize/pluggable_parsers.rb +1 -0
  60. data/lib/mechanize/prependable.rb +1 -0
  61. data/lib/mechanize/redirect_limit_reached_error.rb +1 -0
  62. data/lib/mechanize/redirect_not_get_or_head_error.rb +1 -0
  63. data/lib/mechanize/response_code_error.rb +2 -1
  64. data/lib/mechanize/response_read_error.rb +1 -0
  65. data/lib/mechanize/robots_disallowed_error.rb +1 -0
  66. data/lib/mechanize/test_case.rb +34 -29
  67. data/lib/mechanize/test_case/bad_chunking_servlet.rb +1 -0
  68. data/lib/mechanize/test_case/basic_auth_servlet.rb +1 -0
  69. data/lib/mechanize/test_case/content_type_servlet.rb +1 -0
  70. data/lib/mechanize/test_case/digest_auth_servlet.rb +1 -0
  71. data/lib/mechanize/test_case/file_upload_servlet.rb +1 -0
  72. data/lib/mechanize/test_case/form_servlet.rb +1 -0
  73. data/lib/mechanize/test_case/gzip_servlet.rb +4 -3
  74. data/lib/mechanize/test_case/header_servlet.rb +1 -0
  75. data/lib/mechanize/test_case/http_refresh_servlet.rb +2 -2
  76. data/lib/mechanize/test_case/infinite_redirect_servlet.rb +1 -0
  77. data/lib/mechanize/test_case/infinite_refresh_servlet.rb +2 -2
  78. data/lib/mechanize/test_case/many_cookies_as_string_servlet.rb +1 -0
  79. data/lib/mechanize/test_case/many_cookies_servlet.rb +1 -0
  80. data/lib/mechanize/test_case/modified_since_servlet.rb +1 -0
  81. data/lib/mechanize/test_case/ntlm_servlet.rb +1 -0
  82. data/lib/mechanize/test_case/one_cookie_no_spaces_servlet.rb +1 -0
  83. data/lib/mechanize/test_case/one_cookie_servlet.rb +1 -0
  84. data/lib/mechanize/test_case/quoted_value_cookie_servlet.rb +1 -0
  85. data/lib/mechanize/test_case/redirect_servlet.rb +1 -0
  86. data/lib/mechanize/test_case/referer_servlet.rb +1 -0
  87. data/lib/mechanize/test_case/refresh_with_empty_url.rb +1 -0
  88. data/lib/mechanize/test_case/refresh_without_url.rb +1 -0
  89. data/lib/mechanize/test_case/response_code_servlet.rb +1 -0
  90. data/lib/mechanize/test_case/robots_txt_servlet.rb +15 -0
  91. data/lib/mechanize/test_case/send_cookies_servlet.rb +1 -0
  92. data/lib/mechanize/test_case/server.rb +1 -0
  93. data/lib/mechanize/test_case/servlets.rb +4 -0
  94. data/lib/mechanize/test_case/verb_servlet.rb +5 -6
  95. data/lib/mechanize/unauthorized_error.rb +2 -1
  96. data/lib/mechanize/unsupported_scheme_error.rb +1 -0
  97. data/lib/mechanize/util.rb +5 -3
  98. data/lib/mechanize/version.rb +2 -1
  99. data/lib/mechanize/xml_file.rb +1 -0
  100. data/mechanize.gemspec +39 -31
  101. data/test/htdocs/dir with spaces/foo.html +1 -0
  102. data/test/htdocs/find_link.html +1 -4
  103. data/test/htdocs/tc_links.html +1 -1
  104. data/test/test_mechanize.rb +57 -15
  105. data/test/test_mechanize_cookie.rb +75 -60
  106. data/test/test_mechanize_cookie_jar.rb +112 -59
  107. data/test/test_mechanize_download.rb +13 -1
  108. data/test/test_mechanize_file.rb +10 -0
  109. data/test/test_mechanize_file_connection.rb +21 -3
  110. data/test/test_mechanize_file_response.rb +26 -2
  111. data/test/test_mechanize_form.rb +27 -11
  112. data/test/test_mechanize_form_check_box.rb +10 -0
  113. data/test/test_mechanize_form_encoding.rb +1 -1
  114. data/test/test_mechanize_form_keygen.rb +1 -0
  115. data/test/test_mechanize_form_multi_select_list.rb +5 -1
  116. data/test/test_mechanize_http_agent.rb +116 -8
  117. data/test/test_mechanize_http_auth_challenge.rb +14 -0
  118. data/test/test_mechanize_http_auth_realm.rb +7 -1
  119. data/test/test_mechanize_http_auth_store.rb +37 -0
  120. data/test/test_mechanize_http_content_disposition_parser.rb +35 -1
  121. data/test/test_mechanize_http_www_authenticate_parser.rb +16 -0
  122. data/test/test_mechanize_link.rb +47 -4
  123. data/test/test_mechanize_page.rb +29 -1
  124. data/test/test_mechanize_page_encoding.rb +23 -1
  125. data/test/test_mechanize_page_image.rb +1 -1
  126. data/test/test_mechanize_page_link.rb +3 -3
  127. data/test/test_mechanize_page_meta_refresh.rb +1 -1
  128. data/test/test_mechanize_parser.rb +12 -2
  129. data/test/test_mechanize_util.rb +1 -1
  130. metadata +105 -81
  131. data/.travis.yml +0 -25
  132. data/Manifest.txt +0 -204
  133. data/README.rdoc +0 -77
  134. data/test/htdocs/robots.txt +0 -2
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'stringio'
2
3
  require 'zlib'
3
4
 
@@ -13,8 +14,8 @@ class GzipServlet < WEBrick::HTTPServlet::AbstractServlet
13
14
  end
14
15
 
15
16
  if name = req.query['file'] then
16
- open "#{TEST_DIR}/htdocs/#{name}" do |io|
17
- string = ""
17
+ ::File.open("#{TEST_DIR}/htdocs/#{name}") do |io|
18
+ string = String.new
18
19
  zipped = StringIO.new string, 'w'
19
20
  Zlib::GzipWriter.wrap zipped do |gz|
20
21
  gz.write io.read
@@ -22,7 +23,7 @@ class GzipServlet < WEBrick::HTTPServlet::AbstractServlet
22
23
  res.body = string
23
24
  end
24
25
  else
25
- res.body = ''
26
+ res.body = String.new
26
27
  end
27
28
 
28
29
  res['Content-Encoding'] = req['X-ResponseContentEncoding'] || 'gzip'
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class HeaderServlet < WEBrick::HTTPServlet::AbstractServlet
2
3
  def do_GET(req, res)
3
4
  res.content_type = "text/plain"
@@ -1,9 +1,9 @@
1
+ # frozen_string_literal: true
1
2
  class HttpRefreshServlet < WEBrick::HTTPServlet::AbstractServlet
2
3
  def do_GET(req, res)
3
4
  res['Content-Type'] = req.query['ct'] || "text/html"
4
5
  refresh_time = req.query['refresh_time'] || 0
5
6
  refresh_url = req.query['refresh_url'] || '/'
6
- res['Refresh'] = " #{refresh_time};url=#{refresh_url}\r\n";
7
+ res['Refresh'] = " #{refresh_time};url=#{refresh_url}";
7
8
  end
8
9
  end
9
-
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class InfiniteRedirectServlet < WEBrick::HTTPServlet::AbstractServlet
2
3
  def do_GET(req, res)
3
4
  res['Content-Type'] = req.query['ct'] || "text/html"
@@ -1,10 +1,10 @@
1
+ # frozen_string_literal: true
1
2
  class InfiniteRefreshServlet < WEBrick::HTTPServlet::AbstractServlet
2
3
  def do_GET(req, res)
3
4
  address = "#{req.host}:#{req.port}"
4
5
  res['Content-Type'] = req.query['ct'] || "text/html"
5
6
  res.status = req.query['code'] ? req.query['code'].to_i : '302'
6
7
  number = req.query['q'] ? req.query['q'].to_i : 0
7
- res['Refresh'] = "0;url=http://#{address}/infinite_refresh?q=#{number + 1}\r\n";
8
+ res['Refresh'] = "0;url=http://#{address}/infinite_refresh?q=#{number + 1}";
8
9
  end
9
10
  end
10
-
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class ManyCookiesAsStringServlet < WEBrick::HTTPServlet::AbstractServlet
2
3
  def do_GET(req, res)
3
4
  cookies = []
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class ManyCookiesServlet < WEBrick::HTTPServlet::AbstractServlet
2
3
  def do_GET(req, res)
3
4
  name_cookie = WEBrick::Cookie.new("name", "Aaron")
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class ModifiedSinceServlet < WEBrick::HTTPServlet::AbstractServlet
2
3
  def do_GET(req, res)
3
4
  s_time = 'Fri, 04 May 2001 00:00:38 GMT'
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class NTLMServlet < WEBrick::HTTPServlet::AbstractServlet
2
3
 
3
4
  def do_GET(req, res)
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class OneCookieNoSpacesServlet < WEBrick::HTTPServlet::AbstractServlet
2
3
  def do_GET(req, res)
3
4
  cookie = WEBrick::Cookie.new("foo", "bar")
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class OneCookieServlet < WEBrick::HTTPServlet::AbstractServlet
2
3
  def do_GET(req, res)
3
4
  cookie = WEBrick::Cookie.new("foo", "bar")
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class QuotedValueCookieServlet < WEBrick::HTTPServlet::AbstractServlet
2
3
  def do_GET(req, res)
3
4
  cookie = WEBrick::Cookie.new("quoted", "\"value\"")
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class RedirectServlet < WEBrick::HTTPServlet::AbstractServlet
2
3
  def do_GET(req, res)
3
4
  res['Content-Type'] = req.query['ct'] || 'text/html'
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class RefererServlet < WEBrick::HTTPServlet::AbstractServlet
2
3
  def do_GET(req, res)
3
4
  res['Content-Type'] = "text/html"
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class RefreshWithEmptyUrl < WEBrick::HTTPServlet::AbstractServlet
2
3
  @@count = 0
3
4
  def do_GET(req, res)
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class RefreshWithoutUrl < WEBrick::HTTPServlet::AbstractServlet
2
3
  @@count = 0
3
4
  def do_GET(req, res)
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class ResponseCodeServlet < WEBrick::HTTPServlet::AbstractServlet
2
3
  def do_GET(req, res)
3
4
  res['Content-Type'] = req.query['ct'] || "text/html"
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+ class RobotsTxtServlet < WEBrick::HTTPServlet::AbstractServlet
3
+ def do_GET(req, res)
4
+ if /301/ === req['Host'] && req.path == '/robots.txt'
5
+ res['Location'] = 'http://301/robots_txt'
6
+ res.code = 301
7
+ else
8
+ res['Content-Type'] = 'text/plain'
9
+ res.body = <<-'EOF'
10
+ User-Agent: *
11
+ Disallow: /norobots
12
+ EOF
13
+ end
14
+ end
15
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class SendCookiesServlet < WEBrick::HTTPServlet::AbstractServlet
2
3
  def do_GET(req, res)
3
4
  res.content_type = 'text/html'
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'webrick'
2
3
  require 'mechanize/test_case/servlets'
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'mechanize/test_case/bad_chunking_servlet'
2
3
  require 'mechanize/test_case/basic_auth_servlet'
3
4
  require 'mechanize/test_case/content_type_servlet'
@@ -21,6 +22,7 @@ require 'mechanize/test_case/referer_servlet'
21
22
  require 'mechanize/test_case/refresh_with_empty_url'
22
23
  require 'mechanize/test_case/refresh_without_url'
23
24
  require 'mechanize/test_case/response_code_servlet'
25
+ require 'mechanize/test_case/robots_txt_servlet'
24
26
  require 'mechanize/test_case/send_cookies_servlet'
25
27
  require 'mechanize/test_case/verb_servlet'
26
28
 
@@ -49,6 +51,8 @@ MECHANIZE_TEST_CASE_SERVLETS = {
49
51
  '/refresh_with_empty_url' => RefreshWithEmptyUrl,
50
52
  '/refresh_without_url' => RefreshWithoutUrl,
51
53
  '/response_code' => ResponseCodeServlet,
54
+ '/robots.txt' => RobotsTxtServlet,
55
+ '/robots_txt' => RobotsTxtServlet,
52
56
  '/send_cookies' => SendCookiesServlet,
53
57
  '/verb' => VerbServlet,
54
58
  }
@@ -1,11 +1,10 @@
1
+ # frozen_string_literal: true
1
2
  class VerbServlet < WEBrick::HTTPServlet::AbstractServlet
2
3
  %w[HEAD GET POST PUT DELETE].each do |verb|
3
- eval <<-METHOD
4
- def do_#{verb}(req, res)
5
- res.header['X-Request-Method'] = #{verb.dump}
6
- res.body = #{verb.dump}
7
- end
8
- METHOD
4
+ define_method "do_#{verb}" do |req, res|
5
+ res.header['X-Request-Method'] = verb
6
+ res.body = verb
7
+ end
9
8
  end
10
9
  end
11
10
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class Mechanize::UnauthorizedError < Mechanize::ResponseCodeError
2
3
 
3
4
  attr_reader :challenges
@@ -11,7 +12,7 @@ class Mechanize::UnauthorizedError < Mechanize::ResponseCodeError
11
12
  out = super
12
13
 
13
14
  if @challenges then
14
- realms = @challenges.map { |challenge| challenge.realm_name }.join ', '
15
+ realms = @challenges.map(&:realm_name).join ', '
15
16
  out << " -- available realms: #{realms}"
16
17
  end
17
18
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class Mechanize::UnsupportedSchemeError < Mechanize::Error
2
3
  attr_accessor :scheme, :uri
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'cgi'
2
3
  require 'nkf'
3
4
 
@@ -15,7 +16,7 @@ class Mechanize::Util
15
16
  def build_query_string(parameters, enc = nil)
16
17
  each_parameter(parameters).inject(nil) { |s, (k, v)|
17
18
  # WEBrick::HTTP.escape* has some problems about m17n on ruby-1.9.*.
18
- (s.nil? ? '' : s << '&') << [CGI.escape(k.to_s), CGI.escape(v.to_s)].join('=')
19
+ (s.nil? ? String.new : s << '&') << [CGI.escape(k.to_s), CGI.escape(v.to_s)].join('=')
19
20
  } || ''
20
21
  end
21
22
 
@@ -102,10 +103,11 @@ class Mechanize::Util
102
103
  case NKF::BINARY
103
104
  when Encoding
104
105
  def self.guess_encoding(src)
105
- NKF.guess(src)
106
+ # NKF.guess of JRuby may return nil
107
+ NKF.guess(src) || Encoding::US_ASCII
106
108
  end
107
109
  else
108
- # Old NKF from 1.8, still bundled with JRuby and Rubinius
110
+ # Old NKF from 1.8, still bundled with Rubinius
109
111
  NKF_ENCODING_MAP = {
110
112
  NKF::UNKNOWN => Encoding::US_ASCII,
111
113
  NKF::BINARY => Encoding::ASCII_8BIT,
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class Mechanize
2
- VERSION = "2.7.4"
3
+ VERSION = "2.8.1"
3
4
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  ##
2
3
  # This class encapsulates an XML file. If Mechanize finds a content-type
3
4
  # of 'text/xml' or 'application/xml' this class will be instantiated and
data/mechanize.gemspec CHANGED
@@ -1,20 +1,21 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
  lib = File.expand_path('../lib', __FILE__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
5
  require 'mechanize/version'
5
6
 
6
7
  Gem::Specification.new do |spec|
7
- spec.name = "mechanize"
8
- spec.version = Mechanize::VERSION
9
- spec.homepage = "http://docs.seattlerb.org/mechanize/"
10
- spec.summary = %q{The Mechanize library is used for automating interaction with websites}
11
- spec.description =
8
+ spec.name = "mechanize"
9
+ spec.version = Mechanize::VERSION
10
+ spec.homepage = "https://github.com/sparklemotion/mechanize"
11
+ spec.summary = 'The Mechanize library is used for automating interaction with websites'
12
+ spec.description =
12
13
  [
13
14
  "The Mechanize library is used for automating interaction with websites.",
14
15
  "Mechanize automatically stores and sends cookies, follows redirects,",
15
16
  "and can follow links and submit forms. Form fields can be populated and",
16
17
  "submitted. Mechanize also keeps track of the sites that you have visited as",
17
- "a history."
18
+ "a history.",
18
19
  ].join("\n")
19
20
 
20
21
  spec.authors =
@@ -23,39 +24,46 @@ Gem::Specification.new do |spec|
23
24
  'Aaron Patterson',
24
25
  'Mike Dalessio',
25
26
  'Akinori MUSHA',
26
- 'Lee Jarvis'
27
+ 'Lee Jarvis',
27
28
  ]
28
29
  spec.email =
29
30
  [
30
31
  'drbrain@segment7.net',
31
- 'aaronp@rubyforge.org',
32
+ 'aaron.patterson@gmail.com',
32
33
  'mike.dalessio@gmail.com',
33
34
  'knu@idaemons.org',
34
- 'ljjarvis@gmail.com'
35
+ 'ljjarvis@gmail.com',
35
36
  ]
36
37
 
37
- spec.license = "MIT"
38
+ spec.license = "MIT"
38
39
 
39
40
  spec.require_paths = ["lib"]
40
- spec.files = `git ls-files`.split($/)
41
- spec.test_files = spec.files.grep(%r{^test/})
42
-
43
- spec.extra_rdoc_files += Dir['*.rdoc']
44
- spec.rdoc_options = ["--main", "README.rdoc"]
45
-
46
- spec.required_ruby_version = ">= 1.9.2"
47
-
48
- spec.add_runtime_dependency "net-http-digest_auth", [ ">= 1.1.1", "~> 1.1" ]
49
- spec.add_runtime_dependency "net-http-persistent", [ ">= 2.5.2", "~> 2.5" ]
50
- spec.add_runtime_dependency "mime-types", [ ">= 1.17.2", "< 3" ]
51
- spec.add_runtime_dependency "http-cookie", [ "~> 1.0" ]
52
- spec.add_runtime_dependency "nokogiri", [ "~> 1.6" ]
53
- spec.add_runtime_dependency "ntlm-http", [ ">= 0.1.1", "~> 0.1" ]
54
- spec.add_runtime_dependency "webrobots", [ "< 0.2", ">= 0.0.9" ]
55
- spec.add_runtime_dependency "domain_name", [ ">= 0.5.1", "~> 0.5" ]
56
-
57
- spec.add_development_dependency "rake"
58
- spec.add_development_dependency "bundler", "~> 1.3"
59
- spec.add_development_dependency "rdoc", "~> 4.0"
60
- spec.add_development_dependency "minitest", "~> 5.0"
41
+ spec.files = %x(git ls-files).split($/)
42
+ spec.test_files = spec.files.grep(%r{^test/})
43
+
44
+ spec.extra_rdoc_files += Dir['*.rdoc', '*.md']
45
+ spec.rdoc_options = ["--main", "README.md"]
46
+
47
+ spec.required_ruby_version = ">= 2.5.0"
48
+
49
+ spec.add_runtime_dependency("addressable", "~> 2.7")
50
+ spec.add_runtime_dependency("domain_name", ">= 0.5.20190701", "~> 0.5")
51
+ spec.add_runtime_dependency("http-cookie", ">= 1.0.3", "~> 1.0")
52
+ spec.add_runtime_dependency("mime-types", "~> 3.0")
53
+ spec.add_runtime_dependency("net-http-digest_auth", ">= 1.4.1", "~> 1.4")
54
+
55
+ # careful! some folks are relying on older versions of net-http-persistent
56
+ # - see the socks proxy patch in use at #507 and #464
57
+ # - see use of retry_change_requests that was removed at #558
58
+ spec.add_runtime_dependency("net-http-persistent", ">= 2.5.2", "< 5.0.dev")
59
+
60
+ spec.add_runtime_dependency("nokogiri", ">= 1.11.2", "~> 1.11")
61
+ spec.add_runtime_dependency("rubyntlm", ">= 0.6.3", "~> 0.6")
62
+ spec.add_runtime_dependency("webrick", "~> 1.7")
63
+ spec.add_runtime_dependency("webrobots", "~> 0.1.2")
64
+
65
+ spec.add_development_dependency("minitest", "~> 5.14")
66
+ spec.add_development_dependency("rake", "~> 13.0")
67
+ spec.add_development_dependency("rdoc", "~> 6.3")
68
+ spec.add_development_dependency("rubocop", "~> 1.12")
61
69
  end
@@ -1 +1,2 @@
1
1
  HELLO
2
+
@@ -11,13 +11,10 @@
11
11
  <A HREF="http://blargle.com/">blargle</A>
12
12
  <A HREF="http://a.cpan.org/">CPAN A</A>
13
13
  <A HREF="http://b.cpan.org/">CPAN B</A>
14
- <FRAME SRC="foo.html">
15
- <FRAME SRC="bar.html">
16
14
  <A HREF="http://c.cpan.org/" NAME="bongo">CPAN C</A>
17
15
  <A HREF="http://d.cpan.org/">CPAN D</A>
18
16
 
19
17
  <A HREF="http://www.msnbc.com/">MSNBC</A>
20
- <FRAME SRC="http://www.oreilly.com/" NAME="wongo">
21
18
  <A HREF="http://www.cnn.com/">CNN</A>
22
19
  <A HREF="http://www.bbc.co.uk/" NAME="Wilma">BBC</A>
23
20
  <A HREF="http://www.msnbc.com/">News</A>
@@ -35,7 +32,7 @@
35
32
  <!-- new stuff -->
36
33
  <A HREF="http://nowhere.org/" Name="Here">NoWhere</A>
37
34
  <A HREF="http://nowhere.org/padded" Name=" Here "> NoWhere </A>
38
- <A HREF="blongo.html">Blongo!</A>
35
+ <A HREF="form_test.html" class="formtest">Form Test</A>
39
36
  </body>
40
37
  </html>
41
38
 
@@ -7,7 +7,7 @@
7
7
  <a href="thing.html" class="thing_link">Thing!</a>
8
8
  <a href="thing.html">Ruby <b>Rocks!</b></a>
9
9
  <!-- Testing a bug with escaped stuff in links:
10
- http://rubyforge.org/pipermail/mechanize-users/2006-September/000002.html
10
+ http://rubygems.org/pipermail/mechanize-users/2006-September/000002.html
11
11
  -->
12
12
  <a href="link%20with%20space.html">encoded space</a>
13
13
  <a href="link with space.html">not encoded space</a>
@@ -92,7 +92,7 @@ class TestMechanize < Mechanize::TestCase
92
92
 
93
93
  assert_equal("http://localhost/form_test.html",
94
94
  @mech.history.last.uri.to_s)
95
- end
95
+ end unless RUBY_ENGINE == 'jruby' # NekoHTML does not parse body of NOFRAMES
96
96
 
97
97
  def test_click_bogus_link_with_cookies
98
98
  @mech.cookie_jar = cookie_jar("a=b")
@@ -149,7 +149,7 @@ class TestMechanize < Mechanize::TestCase
149
149
 
150
150
  assert_equal("http://localhost/form_test.html",
151
151
  @mech.history.last.uri.to_s)
152
- end
152
+ end unless RUBY_ENGINE == 'jruby' # NekoHTML does not parse body of NOFRAMES
153
153
 
154
154
  def test_click_link
155
155
  link = node 'a', 'href' => '/index.html'
@@ -345,6 +345,15 @@ but not <a href="/" rel="me nofollow">this</a>!
345
345
  end
346
346
  end
347
347
 
348
+ def test_download_does_not_allow_command_injection
349
+ skip if windows?
350
+ in_tmpdir do
351
+ @mech.download('http://example', '| ruby -rfileutils -e \'FileUtils.touch("vul.txt")\'')
352
+
353
+ refute_operator(File, :exist?, "vul.txt")
354
+ end
355
+ end
356
+
348
357
  def test_get
349
358
  uri = URI 'http://localhost'
350
359
 
@@ -374,6 +383,14 @@ but not <a href="/" rel="me nofollow">this</a>!
374
383
  end
375
384
  end
376
385
 
386
+ def test_get_auth
387
+ @mech.add_auth @uri, 'user', 'pass'
388
+
389
+ page = @mech.get @uri + '/basic_auth'
390
+
391
+ assert_equal 'You are authenticated', page.body
392
+ end
393
+
377
394
  def test_get_auth_bad
378
395
  @mech.add_auth(@uri, 'aaron', 'aaron')
379
396
 
@@ -392,6 +409,14 @@ but not <a href="/" rel="me nofollow">this</a>!
392
409
  assert_equal("401", e.response_code)
393
410
  end
394
411
 
412
+ def test_get_auth_realm
413
+ @mech.add_auth @uri, 'user', 'pass', 'Blah'
414
+
415
+ page = @mech.get @uri + '/basic_auth'
416
+
417
+ assert_equal 'You are authenticated', page.body
418
+ end
419
+
395
420
  def test_get_conditional
396
421
  assert_empty @mech.history
397
422
 
@@ -673,9 +698,7 @@ but not <a href="/" rel="me nofollow">this</a>!
673
698
  end
674
699
 
675
700
  def test_get_space
676
- page = nil
677
-
678
- page = @mech.get("http://localhost/tc_bad_links.html ")
701
+ @mech.get("http://localhost/tc_bad_links.html ")
679
702
 
680
703
  assert_match(/tc_bad_links.html$/, @mech.history.last.uri.to_s)
681
704
 
@@ -927,7 +950,26 @@ but not <a href="/" rel="me nofollow">this</a>!
927
950
  "Content-Disposition: form-data; name=\"userfile1\"; filename=\"#{name}\"",
928
951
  page.body
929
952
  )
930
- assert page.body.length > File.read(__FILE__).length
953
+ assert_operator page.body.bytesize, :>, file_contents_without_cr(__FILE__).length
954
+ end
955
+
956
+ def test_post_file_upload_nonascii
957
+ name = 'ユーザファイル1'
958
+ file_upload = Mechanize::Form::FileUpload.new({'name' => 'userfile1'}, name)
959
+ file_upload.file_data = File.read(__FILE__)
960
+ file_upload.mime_type = 'application/zip'
961
+
962
+ page = @mech.post('http://localhost/file_upload', {
963
+ :name => 'Some file',
964
+ :userfile1 => file_upload
965
+ })
966
+
967
+ assert_match(
968
+ "Content-Disposition: form-data; name=\"userfile1\"; filename=\"#{name}\"".force_encoding(Encoding::ASCII_8BIT),
969
+ page.body
970
+ )
971
+ assert_match("Content-Type: application/zip", page.body)
972
+ assert_operator page.body.bytesize, :>, file_contents_without_cr(__FILE__).length
931
973
  end
932
974
 
933
975
  def test_post_file_upload
@@ -946,7 +988,7 @@ but not <a href="/" rel="me nofollow">this</a>!
946
988
  page.body
947
989
  )
948
990
  assert_match("Content-Type: application/zip", page.body)
949
- assert page.body.length > File.read(__FILE__).length
991
+ assert_operator page.body.bytesize, :>, file_contents_without_cr(__FILE__).length
950
992
  end
951
993
 
952
994
  def test_post_redirect
@@ -1021,6 +1063,11 @@ but not <a href="/" rel="me nofollow">this</a>!
1021
1063
  end
1022
1064
 
1023
1065
  def test_retry_change_requests_equals
1066
+ unless Gem::Requirement.new("< 4.0.0").satisfied_by?(Gem::Version.new(Net::HTTP::Persistent::VERSION))
1067
+ # see https://github.com/drbrain/net-http-persistent/pull/100
1068
+ skip("net-http-persistent 4.0.0 and later does not support retry_change_requests")
1069
+ end
1070
+
1024
1071
  refute @mech.retry_change_requests
1025
1072
 
1026
1073
  @mech.retry_change_requests = true
@@ -1052,25 +1099,21 @@ but not <a href="/" rel="me nofollow">this</a>!
1052
1099
 
1053
1100
  assert_match(/Hello World/, @mech.current_page.body)
1054
1101
  refute_empty @mech.cookies
1055
- refute_empty Thread.current[@mech.agent.http.request_key]
1056
1102
 
1057
1103
  @mech.shutdown
1058
1104
 
1059
- assert_nil Thread.current[@mech.agent.http.request_key]
1060
1105
  assert_empty @mech.history
1061
1106
  assert_empty @mech.cookies
1062
1107
  end
1063
1108
 
1064
1109
  def test_start
1065
- body, id = nil
1110
+ body = nil
1066
1111
 
1067
1112
  Mechanize.start do |m|
1068
1113
  body = m.get("http://localhost/").body
1069
- id = m.agent.http.request_key
1070
1114
  end
1071
1115
 
1072
1116
  assert_match(/Hello World/, body)
1073
- assert_nil Thread.current[id]
1074
1117
  end
1075
1118
 
1076
1119
  def test_submit_bad_form_method
@@ -1140,7 +1183,7 @@ but not <a href="/" rel="me nofollow">this</a>!
1140
1183
 
1141
1184
  page = @mech.submit(form)
1142
1185
 
1143
- contents = File.read __FILE__
1186
+ contents = File.binread(__FILE__).gsub(/\r\n/, "\n")
1144
1187
  basename = File.basename __FILE__
1145
1188
 
1146
1189
  assert_match(
@@ -1160,7 +1203,7 @@ but not <a href="/" rel="me nofollow">this</a>!
1160
1203
 
1161
1204
  page = @mech.submit(form)
1162
1205
 
1163
- contents = File.read __FILE__
1206
+ contents = File.binread __FILE__
1164
1207
  basename = File.basename __FILE__
1165
1208
  assert_match(
1166
1209
  "Content-Disposition: form-data; name=\"green[eggs]\"; filename=\"#{basename}\"",
@@ -1328,4 +1371,3 @@ but not <a href="/" rel="me nofollow">this</a>!
1328
1371
  end
1329
1372
  end
1330
1373
  end
1331
-