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
  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'
@@ -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
  require 'mechanize'
2
3
  require 'logger'
3
4
  require 'tempfile'
@@ -14,11 +15,6 @@ end
14
15
 
15
16
  require 'minitest/autorun'
16
17
 
17
- begin
18
- require 'minitest/pride'
19
- rescue LoadError
20
- end
21
-
22
18
  ##
23
19
  # A generic test case for testing mechanize. Using a subclass of
24
20
  # Mechanize::TestCase for your tests will create an isolated mechanize
@@ -57,12 +53,12 @@ class Mechanize::TestCase < Minitest::Test
57
53
 
58
54
  def fake_page agent = @mech
59
55
  uri = URI 'http://fake.example/'
60
- html = <<-END
61
- <html>
62
- <body>
63
- <form><input type="submit" value="submit" /></form>
64
- </body>
65
- </html>
56
+ html = String.new(<<~END)
57
+ <html>
58
+ <body>
59
+ <form><input type="submit" value="submit" /></form>
60
+ </body>
61
+ </html>
66
62
  END
67
63
 
68
64
  Mechanize::Page.new uri, nil, html, 200, agent
@@ -87,11 +83,9 @@ class Mechanize::TestCase < Minitest::Test
87
83
  # Creates a Mechanize::CookieJar by parsing the given +str+
88
84
 
89
85
  def cookie_jar str, uri = URI('http://example')
90
- jar = Mechanize::CookieJar.new
91
-
92
- jar.parse str, uri
93
-
94
- jar
86
+ Mechanize::CookieJar.new.tap do |jar|
87
+ jar.parse str, uri
88
+ end
95
89
  end
96
90
 
97
91
  ##
@@ -109,22 +103,18 @@ class Mechanize::TestCase < Minitest::Test
109
103
  # Creates a Nokogiri Node +element+ with the given +attributes+
110
104
 
111
105
  def node element, attributes = {}
112
- doc = Nokogiri::HTML::Document.new
113
-
114
- node = Nokogiri::XML::Node.new element, doc
115
-
116
- attributes.each do |name, value|
117
- node[name] = value
106
+ Nokogiri::XML::Node.new(element, Nokogiri::HTML::Document.new).tap do |node|
107
+ attributes.each do |name, value|
108
+ node[name] = value
109
+ end
118
110
  end
119
-
120
- node
121
111
  end
122
112
 
123
113
  ##
124
114
  # Creates a Mechanize::Page for the given +uri+ with the given
125
115
  # +content_type+, response +body+ and HTTP status +code+
126
116
 
127
- def page uri, content_type = 'text/html', body = '', code = 200
117
+ def page uri, content_type = 'text/html', body = String.new, code = 200
128
118
  uri = URI uri unless URI::Generic === uri
129
119
 
130
120
  Mechanize::Page.new(uri, { 'content-type' => content_type }, body, code,
@@ -173,15 +163,25 @@ UQIBATANBgkqhkiG9w0BAQUFAANBAAAB////////////////////////////////
173
163
  # Creates a Tempfile with +content+ that is immediately unlinked
174
164
 
175
165
  def tempfile content
176
- body_io = Tempfile.new @NAME
177
- body_io.unlink
178
- body_io.write content
179
- body_io.flush
180
- body_io.rewind
166
+ Tempfile.new(@NAME).tap do |body_io|
167
+ body_io.unlink
168
+ body_io.write content
169
+ body_io.flush
170
+ body_io.rewind
171
+ end
172
+ end
181
173
 
182
- body_io
174
+ ##
175
+ # Returns true if the current platform is a Windows platform
176
+ def windows?
177
+ ::RUBY_PLATFORM =~ /mingw|mswin/
183
178
  end
184
179
 
180
+ ##
181
+ # Return the contents of the file without Windows carriage returns
182
+ def file_contents_without_cr(path)
183
+ File.read(path).gsub(/\r\n/, "\n")
184
+ end
185
185
  end
186
186
 
187
187
  require 'mechanize/test_case/servlets'
@@ -230,9 +230,9 @@ class Net::HTTP # :nodoc:
230
230
  else
231
231
  filename = "htdocs#{path.gsub(/[^\/\\.\w\s]/, '_')}"
232
232
  unless PAGE_CACHE[filename]
233
- open("#{Mechanize::TestCase::TEST_DIR}/#{filename}", 'rb') { |io|
233
+ ::File.open("#{Mechanize::TestCase::TEST_DIR}/#{filename}", 'rb') do |io|
234
234
  PAGE_CACHE[filename] = io.read
235
- }
235
+ end
236
236
  end
237
237
 
238
238
  res.body = PAGE_CACHE[filename]
@@ -312,7 +312,7 @@ class Response # :nodoc:
312
312
 
313
313
  def initialize
314
314
  @header = {}
315
- @body = ''
315
+ @body = String.new
316
316
  @code = nil
317
317
  @query = nil
318
318
  @cookies = []
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class Mechanize::UnauthorizedError < Mechanize::ResponseCodeError
2
3
 
3
4
  attr_reader :challenges
@@ -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
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class Mechanize
2
- VERSION = "2.7.6"
3
+ VERSION = "2.12.2"
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/lib/mechanize.rb CHANGED
@@ -1,7 +1,7 @@
1
+ # frozen_string_literal: true
1
2
  require 'mechanize/version'
2
3
  require 'fileutils'
3
4
  require 'forwardable'
4
- require 'mutex_m'
5
5
  require 'net/http/digest_auth'
6
6
  require 'net/http/persistent'
7
7
  require 'nokogiri'
@@ -86,54 +86,73 @@ class Mechanize
86
86
  # description in parenthesis is for informative purposes and is not part of
87
87
  # the alias name.
88
88
  #
89
- # * Linux Firefox (43.0 on Ubuntu Linux)
90
- # * Linux Konqueror (3)
91
- # * Linux Mozilla
92
- # * Mac Firefox (43.0)
93
- # * Mac Mozilla
94
- # * Mac Safari (9.0 on OS X 10.11.2)
95
- # * Mac Safari 4
96
- # * Mechanize (default)
97
- # * Windows IE 6
98
- # * Windows IE 7
99
- # * Windows IE 8
100
- # * Windows IE 9
101
- # * Windows IE 10 (Windows 8 64bit)
102
- # * Windows IE 11 (Windows 8.1 64bit)
103
- # * Windows Edge
104
- # * Windows Mozilla
105
- # * Windows Firefox (43.0)
106
- # * iPhone (iOS 9.1)
107
- # * iPad (iOS 9.1)
108
- # * Android (5.1.1)
89
+ # The default User-Agent alias:
90
+ #
91
+ # * "Mechanize"
92
+ #
93
+ # Linux User-Agent aliases:
94
+ #
95
+ # * "Linux Firefox"
96
+ # * "Linux Konqueror"
97
+ # * "Linux Mozilla"
98
+ #
99
+ # Mac User-Agent aliases:
100
+ #
101
+ # * "Mac Firefox"
102
+ # * "Mac Mozilla"
103
+ # * "Mac Safari 4"
104
+ # * "Mac Safari"
105
+ #
106
+ # Windows User-Agent aliases:
107
+ #
108
+ # * "Windows Chrome"
109
+ # * "Windows Edge"
110
+ # * "Windows Firefox"
111
+ # * "Windows IE 6"
112
+ # * "Windows IE 7"
113
+ # * "Windows IE 8"
114
+ # * "Windows IE 9"
115
+ # * "Windows IE 10"
116
+ # * "Windows IE 11"
117
+ # * "Windows Mozilla"
118
+ #
119
+ # Mobile User-Agent aliases:
120
+ #
121
+ # * "Android"
122
+ # * "iPad"
123
+ # * "iPhone"
109
124
  #
110
125
  # Example:
111
126
  #
112
127
  # agent = Mechanize.new
113
128
  # agent.user_agent_alias = 'Mac Safari'
114
-
129
+ #
115
130
  AGENT_ALIASES = {
116
131
  'Mechanize' => "Mechanize/#{VERSION} Ruby/#{ruby_version} (http://github.com/sparklemotion/mechanize/)",
117
- 'Linux Firefox' => 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:43.0) Gecko/20100101 Firefox/43.0',
132
+
133
+ 'Linux Firefox' => 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/121.0',
118
134
  'Linux Konqueror' => 'Mozilla/5.0 (compatible; Konqueror/3; Linux)',
119
135
  'Linux Mozilla' => 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624',
120
- 'Mac Firefox' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:43.0) Gecko/20100101 Firefox/43.0',
136
+
137
+ 'Mac Firefox' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 14.2; rv:109.0) Gecko/20100101 Firefox/121.0',
121
138
  'Mac Mozilla' => 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.4a) Gecko/20030401',
122
139
  'Mac Safari 4' => 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; de-at) AppleWebKit/531.21.8 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10',
123
- 'Mac Safari' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/601.3.9 (KHTML, like Gecko) Version/9.0.2 Safari/601.3.9',
124
- 'Windows Chrome' => 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.125 Safari/537.36',
140
+ 'Mac Safari' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_2_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15',
141
+
142
+ 'Windows Chrome' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
143
+ 'Windows Edge' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.2210.133',
144
+ 'Windows Firefox' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/121.0',
125
145
  'Windows IE 6' => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
126
146
  'Windows IE 7' => 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)',
127
147
  'Windows IE 8' => 'Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727)',
128
148
  'Windows IE 9' => 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)',
129
149
  'Windows IE 10' => 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)',
130
150
  'Windows IE 11' => 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko',
131
- 'Windows Edge' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586',
132
151
  'Windows Mozilla' => 'Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6',
133
- 'Windows Firefox' => 'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0',
134
- 'iPhone' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B5110e Safari/601.1',
135
- 'iPad' => 'Mozilla/5.0 (iPad; CPU OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1',
136
- 'Android' => 'Mozilla/5.0 (Linux; Android 5.1.1; Nexus 7 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.76 Safari/537.36',
152
+
153
+ 'Android' => 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.210 Mobile Safari/537.36',
154
+ 'iPad' => 'Mozilla/5.0 (iPad; CPU OS 17_2_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Mobile/15E148 Safari/604.1',
155
+ 'iPhone' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_2_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Mobile/15E148 Safari/604.1',
137
156
  }
138
157
 
139
158
  AGENT_ALIASES.default_proc = proc { |hash, key|
@@ -175,13 +194,13 @@ class Mechanize
175
194
  # as SSL parameters or proxies:
176
195
  #
177
196
  # agent = Mechanize.new do |a|
178
- # a.proxy_host = 'proxy.example'
197
+ # a.proxy_addr = 'proxy.example'
179
198
  # a.proxy_port = 8080
180
199
  # end
181
200
  #
182
201
  # If you need segregated SSL connections give each agent a unique
183
202
  # name. Otherwise the connections will be shared. This is
184
- # particularly important if you are using certifcates.
203
+ # particularly important if you are using certificates.
185
204
  #
186
205
  # agent_1 = Mechanize.new 'conn1'
187
206
  # agent_2 = Mechanize.new 'conn2'
@@ -396,7 +415,7 @@ class Mechanize
396
415
  io = if io_or_filename.respond_to? :write then
397
416
  io_or_filename
398
417
  else
399
- open io_or_filename, 'wb'
418
+ ::File.open(io_or_filename, 'wb')
400
419
  end
401
420
 
402
421
  case page
@@ -698,10 +717,10 @@ class Mechanize
698
717
  # authentication.
699
718
 
700
719
  def auth user, password, domain = nil
701
- caller.first =~ /(.*?):(\d+).*?$/
720
+ c = caller_locations(1,1).first
702
721
 
703
722
  warn <<-WARNING
704
- At #{$1} line #{$2}
723
+ At #{c.absolute_path} line #{c.lineno}
705
724
 
706
725
  Use of #auth and #basic_auth are deprecated due to a security vulnerability.
707
726
 
@@ -937,7 +956,7 @@ Use of #auth and #basic_auth are deprecated due to a security vulnerability.
937
956
  # allowed:
938
957
  #
939
958
  # :all, true:: All 3xx redirects are followed (default)
940
- # :permanent:: Only 301 Moved Permanantly redirects are followed
959
+ # :permanent:: Only 301 Moved Permanently redirects are followed
941
960
  # false:: No redirects are followed
942
961
 
943
962
  def redirect_ok
data/mechanize.gemspec CHANGED
@@ -1,20 +1,19 @@
1
1
  # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'mechanize/version'
2
+ # frozen_string_literal: true
3
+ require_relative 'lib/mechanize/version'
5
4
 
6
5
  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 =
6
+ spec.name = "mechanize"
7
+ spec.version = Mechanize::VERSION
8
+ spec.homepage = "https://github.com/sparklemotion/mechanize"
9
+ spec.summary = 'The Mechanize library is used for automating interaction with websites'
10
+ spec.description =
12
11
  [
13
12
  "The Mechanize library is used for automating interaction with websites.",
14
13
  "Mechanize automatically stores and sends cookies, follows redirects,",
15
14
  "and can follow links and submit forms. Form fields can be populated and",
16
15
  "submitted. Mechanize also keeps track of the sites that you have visited as",
17
- "a history."
16
+ "a history.",
18
17
  ].join("\n")
19
18
 
20
19
  spec.authors =
@@ -23,44 +22,53 @@ Gem::Specification.new do |spec|
23
22
  'Aaron Patterson',
24
23
  'Mike Dalessio',
25
24
  'Akinori MUSHA',
26
- 'Lee Jarvis'
25
+ 'Lee Jarvis',
27
26
  ]
28
27
  spec.email =
29
28
  [
30
29
  'drbrain@segment7.net',
31
- 'aaronp@rubyforge.org',
30
+ 'aaron.patterson@gmail.com',
32
31
  'mike.dalessio@gmail.com',
33
32
  'knu@idaemons.org',
34
- 'ljjarvis@gmail.com'
33
+ 'ljjarvis@gmail.com',
35
34
  ]
36
35
 
37
- spec.license = "MIT"
36
+ spec.metadata = {
37
+ 'yard.run' => 'yard',
38
+ 'bug_tracker_uri' => 'https://github.com/sparklemotion/mechanize/issues',
39
+ 'changelog_uri' => 'https://github.com/sparklemotion/mechanize/blob/main/CHANGELOG.md',
40
+ 'documentation_uri' => 'https://www.rubydoc.info/gems/mechanize',
41
+ 'homepage_uri' => 'https://github.com/sparklemotion/mechanize',
42
+ 'source_code_uri' => 'https://github.com/sparklemotion/mechanize'
43
+ }
44
+
45
+ spec.license = "MIT"
38
46
 
39
47
  spec.require_paths = ["lib"]
40
- spec.files = `git ls-files`.split($/)
41
- spec.test_files = spec.files.grep(%r{^test/})
48
+ spec.files = %x(git ls-files).split($/)
49
+ spec.test_files = spec.files.grep(%r{^test/})
50
+
51
+ spec.extra_rdoc_files += Dir['*.rdoc', '*.md']
52
+ spec.rdoc_options = ["--main", "README.md"]
53
+
54
+ spec.required_ruby_version = ">= 2.6.0"
42
55
 
43
- spec.extra_rdoc_files += Dir['*.rdoc']
44
- spec.rdoc_options = ["--main", "README.rdoc"]
56
+ spec.add_runtime_dependency("addressable", "~> 2.8")
57
+ spec.add_runtime_dependency("domain_name", ">= 0.5.20190701", "~> 0.5")
58
+ spec.add_runtime_dependency("http-cookie", ">= 1.0.3", "~> 1.0")
59
+ spec.add_runtime_dependency("mime-types", "~> 3.3")
60
+ spec.add_runtime_dependency("net-http-digest_auth", ">= 1.4.1", "~> 1.4")
45
61
 
46
- spec.required_ruby_version = ">= 1.9.2"
62
+ # careful! some folks are relying on older versions of net-http-persistent
63
+ # - see the socks proxy patch in use at #507 and #464
64
+ # - see use of retry_change_requests that was removed at #558
65
+ spec.add_runtime_dependency("net-http-persistent", ">= 2.5.2", "< 5.0.dev")
47
66
 
48
- spec.add_runtime_dependency "net-http-digest_auth", [ ">= 1.1.1", "~> 1.1" ]
49
- if RUBY_VERSION >= "2.0"
50
- spec.add_runtime_dependency "mime-types", [ ">= 1.17.2" ]
51
- spec.add_runtime_dependency "net-http-persistent", [ ">= 2.5.2"]
52
- else
53
- spec.add_runtime_dependency "mime-types", [ ">= 1.17.2", "< 3" ]
54
- spec.add_runtime_dependency "net-http-persistent", [ ">= 2.5.2", "~> 2.5" ]
55
- end
56
- spec.add_runtime_dependency "http-cookie", [ "~> 1.0" ]
57
- spec.add_runtime_dependency "nokogiri", [ "~> 1.6" ]
58
- spec.add_runtime_dependency "ntlm-http", [ ">= 0.1.1", "~> 0.1" ]
59
- spec.add_runtime_dependency "webrobots", [ "< 0.2", ">= 0.0.9" ]
60
- spec.add_runtime_dependency "domain_name", [ ">= 0.5.1", "~> 0.5" ]
67
+ spec.add_runtime_dependency("nokogiri", ">= 1.11.2", "~> 1.11")
68
+ spec.add_runtime_dependency("webrick", "~> 1.7")
69
+ spec.add_runtime_dependency("webrobots", "~> 0.1.2")
61
70
 
62
- spec.add_development_dependency "rake"
63
- spec.add_development_dependency "bundler", "~> 1.3"
64
- spec.add_development_dependency "rdoc", "~> 4.0"
65
- spec.add_development_dependency "minitest", "~> 5.0"
71
+ spec.add_runtime_dependency("rubyntlm", ">= 0.6.3", "~> 0.6")
72
+ spec.add_runtime_dependency("base64") # removed from bundled gems in 3.4, and needed by rubyntlm (which doesn't declare this dependency)
73
+ spec.add_runtime_dependency("nkf") # removed from bundled gems in 3.4
66
74
  end
@@ -1 +1,2 @@
1
1
  HELLO
2
+
@@ -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>
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'mechanize/test_case'
4
5
 
@@ -345,6 +346,15 @@ but not <a href="/" rel="me nofollow">this</a>!
345
346
  end
346
347
  end
347
348
 
349
+ def test_download_does_not_allow_command_injection
350
+ skip if windows?
351
+ in_tmpdir do
352
+ @mech.download('http://example', '| ruby -rfileutils -e \'FileUtils.touch("vul.txt")\'')
353
+
354
+ refute_operator(File, :exist?, "vul.txt")
355
+ end
356
+ end
357
+
348
358
  def test_get
349
359
  uri = URI 'http://localhost'
350
360
 
@@ -689,9 +699,7 @@ but not <a href="/" rel="me nofollow">this</a>!
689
699
  end
690
700
 
691
701
  def test_get_space
692
- page = nil
693
-
694
- page = @mech.get("http://localhost/tc_bad_links.html ")
702
+ @mech.get("http://localhost/tc_bad_links.html ")
695
703
 
696
704
  assert_match(/tc_bad_links.html$/, @mech.history.last.uri.to_s)
697
705
 
@@ -943,7 +951,7 @@ but not <a href="/" rel="me nofollow">this</a>!
943
951
  "Content-Disposition: form-data; name=\"userfile1\"; filename=\"#{name}\"",
944
952
  page.body
945
953
  )
946
- assert_operator page.body.bytesize, :>, File.size(__FILE__)
954
+ assert_operator page.body.bytesize, :>, file_contents_without_cr(__FILE__).length
947
955
  end
948
956
 
949
957
  def test_post_file_upload_nonascii
@@ -958,11 +966,11 @@ but not <a href="/" rel="me nofollow">this</a>!
958
966
  })
959
967
 
960
968
  assert_match(
961
- "Content-Disposition: form-data; name=\"userfile1\"; filename=\"#{name}\"".force_encoding(Encoding::ASCII_8BIT),
969
+ "Content-Disposition: form-data; name=\"userfile1\"; filename=\"#{name}\"".dup.force_encoding(Encoding::ASCII_8BIT),
962
970
  page.body
963
971
  )
964
972
  assert_match("Content-Type: application/zip", page.body)
965
- assert_operator page.body.bytesize, :>, File.size(__FILE__)
973
+ assert_operator page.body.bytesize, :>, file_contents_without_cr(__FILE__).length
966
974
  end
967
975
 
968
976
  def test_post_file_upload
@@ -981,7 +989,7 @@ but not <a href="/" rel="me nofollow">this</a>!
981
989
  page.body
982
990
  )
983
991
  assert_match("Content-Type: application/zip", page.body)
984
- assert_operator page.body.bytesize, :>, File.size(__FILE__)
992
+ assert_operator page.body.bytesize, :>, file_contents_without_cr(__FILE__).length
985
993
  end
986
994
 
987
995
  def test_post_redirect
@@ -1056,6 +1064,11 @@ but not <a href="/" rel="me nofollow">this</a>!
1056
1064
  end
1057
1065
 
1058
1066
  def test_retry_change_requests_equals
1067
+ unless Gem::Requirement.new("< 4.0.0").satisfied_by?(Gem::Version.new(Net::HTTP::Persistent::VERSION))
1068
+ # see https://github.com/drbrain/net-http-persistent/pull/100
1069
+ skip("net-http-persistent 4.0.0 and later does not support retry_change_requests")
1070
+ end
1071
+
1059
1072
  refute @mech.retry_change_requests
1060
1073
 
1061
1074
  @mech.retry_change_requests = true
@@ -1171,7 +1184,7 @@ but not <a href="/" rel="me nofollow">this</a>!
1171
1184
 
1172
1185
  page = @mech.submit(form)
1173
1186
 
1174
- contents = File.binread __FILE__
1187
+ contents = File.binread(__FILE__).gsub(/\r\n/, "\n")
1175
1188
  basename = File.basename __FILE__
1176
1189
 
1177
1190
  assert_match(