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.
- checksums.yaml +5 -5
- data/.github/dependabot.yml +11 -0
- data/.github/workflows/ci.yml +43 -0
- data/.github/workflows/upstream.yml +51 -0
- data/.yardopts +8 -0
- data/{CHANGELOG.rdoc → CHANGELOG.md} +221 -96
- data/EXAMPLES.rdoc +1 -24
- data/Gemfile +10 -4
- data/{LICENSE.rdoc → LICENSE.txt} +4 -0
- data/README.md +77 -0
- data/Rakefile +18 -3
- data/examples/latest_user_agents.rb +100 -0
- data/examples/rubygems.rb +2 -2
- data/examples/wikipedia_links_to_philosophy.rb +5 -6
- data/lib/mechanize/chunked_termination_error.rb +1 -0
- data/lib/mechanize/content_type_error.rb +1 -0
- data/lib/mechanize/cookie.rb +3 -15
- data/lib/mechanize/cookie_jar.rb +13 -9
- data/lib/mechanize/directory_saver.rb +1 -0
- data/lib/mechanize/download.rb +2 -1
- data/lib/mechanize/element_matcher.rb +1 -0
- data/lib/mechanize/element_not_found_error.rb +1 -0
- data/lib/mechanize/file.rb +2 -1
- data/lib/mechanize/file_connection.rb +5 -3
- data/lib/mechanize/file_request.rb +1 -0
- data/lib/mechanize/file_response.rb +4 -1
- data/lib/mechanize/file_saver.rb +1 -0
- data/lib/mechanize/form/button.rb +1 -0
- data/lib/mechanize/form/check_box.rb +1 -0
- data/lib/mechanize/form/field.rb +1 -0
- data/lib/mechanize/form/file_upload.rb +1 -0
- data/lib/mechanize/form/hidden.rb +1 -0
- data/lib/mechanize/form/image_button.rb +1 -0
- data/lib/mechanize/form/keygen.rb +1 -0
- data/lib/mechanize/form/multi_select_list.rb +2 -1
- data/lib/mechanize/form/option.rb +1 -0
- data/lib/mechanize/form/radio_button.rb +1 -0
- data/lib/mechanize/form/reset.rb +1 -0
- data/lib/mechanize/form/select_list.rb +1 -0
- data/lib/mechanize/form/submit.rb +1 -0
- data/lib/mechanize/form/text.rb +1 -0
- data/lib/mechanize/form/textarea.rb +1 -0
- data/lib/mechanize/form.rb +5 -13
- data/lib/mechanize/headers.rb +1 -0
- data/lib/mechanize/history.rb +1 -0
- data/lib/mechanize/http/agent.rb +83 -10
- data/lib/mechanize/http/auth_challenge.rb +1 -0
- data/lib/mechanize/http/auth_realm.rb +1 -0
- data/lib/mechanize/http/auth_store.rb +1 -0
- data/lib/mechanize/http/content_disposition_parser.rb +15 -4
- data/lib/mechanize/http/www_authenticate_parser.rb +3 -3
- data/lib/mechanize/http.rb +1 -0
- data/lib/mechanize/image.rb +1 -0
- data/lib/mechanize/page/base.rb +1 -0
- data/lib/mechanize/page/frame.rb +1 -0
- data/lib/mechanize/page/image.rb +1 -0
- data/lib/mechanize/page/label.rb +1 -0
- data/lib/mechanize/page/link.rb +8 -1
- data/lib/mechanize/page/meta_refresh.rb +1 -0
- data/lib/mechanize/page.rb +6 -8
- data/lib/mechanize/parser.rb +1 -0
- data/lib/mechanize/pluggable_parsers.rb +2 -1
- data/lib/mechanize/prependable.rb +1 -0
- data/lib/mechanize/redirect_limit_reached_error.rb +1 -0
- data/lib/mechanize/redirect_not_get_or_head_error.rb +1 -0
- data/lib/mechanize/response_code_error.rb +2 -1
- data/lib/mechanize/response_read_error.rb +1 -0
- data/lib/mechanize/robots_disallowed_error.rb +1 -0
- data/lib/mechanize/test_case/bad_chunking_servlet.rb +1 -0
- data/lib/mechanize/test_case/basic_auth_servlet.rb +1 -0
- data/lib/mechanize/test_case/content_type_servlet.rb +1 -0
- data/lib/mechanize/test_case/digest_auth_servlet.rb +1 -0
- data/lib/mechanize/test_case/file_upload_servlet.rb +1 -0
- data/lib/mechanize/test_case/form_servlet.rb +1 -0
- data/lib/mechanize/test_case/gzip_servlet.rb +4 -3
- data/lib/mechanize/test_case/header_servlet.rb +1 -0
- data/lib/mechanize/test_case/http_refresh_servlet.rb +1 -0
- data/lib/mechanize/test_case/infinite_redirect_servlet.rb +1 -0
- data/lib/mechanize/test_case/infinite_refresh_servlet.rb +1 -0
- data/lib/mechanize/test_case/many_cookies_as_string_servlet.rb +1 -0
- data/lib/mechanize/test_case/many_cookies_servlet.rb +1 -0
- data/lib/mechanize/test_case/modified_since_servlet.rb +1 -0
- data/lib/mechanize/test_case/ntlm_servlet.rb +1 -0
- data/lib/mechanize/test_case/one_cookie_no_spaces_servlet.rb +1 -0
- data/lib/mechanize/test_case/one_cookie_servlet.rb +1 -0
- data/lib/mechanize/test_case/quoted_value_cookie_servlet.rb +1 -0
- data/lib/mechanize/test_case/redirect_servlet.rb +1 -0
- data/lib/mechanize/test_case/referer_servlet.rb +1 -0
- data/lib/mechanize/test_case/refresh_with_empty_url.rb +1 -0
- data/lib/mechanize/test_case/refresh_without_url.rb +1 -0
- data/lib/mechanize/test_case/response_code_servlet.rb +1 -0
- data/lib/mechanize/test_case/robots_txt_servlet.rb +1 -0
- data/lib/mechanize/test_case/send_cookies_servlet.rb +1 -0
- data/lib/mechanize/test_case/server.rb +1 -0
- data/lib/mechanize/test_case/servlets.rb +1 -0
- data/lib/mechanize/test_case/verb_servlet.rb +5 -6
- data/lib/mechanize/test_case.rb +34 -34
- data/lib/mechanize/unauthorized_error.rb +1 -0
- data/lib/mechanize/unsupported_scheme_error.rb +1 -0
- data/lib/mechanize/util.rb +2 -1
- data/lib/mechanize/version.rb +2 -1
- data/lib/mechanize/xml_file.rb +1 -0
- data/lib/mechanize.rb +56 -37
- data/mechanize.gemspec +43 -35
- data/test/htdocs/dir with spaces/foo.html +1 -0
- data/test/htdocs/tc_links.html +1 -1
- data/test/test_mechanize.rb +21 -8
- data/test/test_mechanize_cookie.rb +38 -26
- data/test/test_mechanize_cookie_jar.rb +87 -54
- data/test/test_mechanize_directory_saver.rb +1 -0
- data/test/test_mechanize_download.rb +14 -1
- data/test/test_mechanize_element_not_found_error.rb +1 -0
- data/test/test_mechanize_file.rb +11 -0
- data/test/test_mechanize_file_connection.rb +23 -4
- data/test/test_mechanize_file_request.rb +1 -0
- data/test/test_mechanize_file_response.rb +26 -1
- data/test/test_mechanize_file_saver.rb +1 -0
- data/test/test_mechanize_form.rb +14 -1
- data/test/test_mechanize_form_check_box.rb +1 -0
- data/test/test_mechanize_form_encoding.rb +2 -1
- data/test/test_mechanize_form_field.rb +1 -0
- data/test/test_mechanize_form_file_upload.rb +1 -0
- data/test/test_mechanize_form_image_button.rb +1 -0
- data/test/test_mechanize_form_keygen.rb +2 -0
- data/test/test_mechanize_form_multi_select_list.rb +1 -0
- data/test/test_mechanize_form_option.rb +1 -0
- data/test/test_mechanize_form_radio_button.rb +1 -0
- data/test/test_mechanize_form_select_list.rb +1 -0
- data/test/test_mechanize_form_textarea.rb +1 -0
- data/test/test_mechanize_headers.rb +1 -0
- data/test/test_mechanize_history.rb +1 -0
- data/test/test_mechanize_http_agent.rb +187 -26
- data/test/test_mechanize_http_auth_challenge.rb +1 -0
- data/test/test_mechanize_http_auth_realm.rb +1 -0
- data/test/test_mechanize_http_auth_store.rb +1 -0
- data/test/test_mechanize_http_content_disposition_parser.rb +28 -0
- data/test/test_mechanize_http_www_authenticate_parser.rb +1 -0
- data/test/test_mechanize_image.rb +1 -0
- data/test/test_mechanize_link.rb +25 -0
- data/test/test_mechanize_page.rb +15 -0
- data/test/test_mechanize_page_encoding.rb +33 -5
- data/test/test_mechanize_page_frame.rb +1 -0
- data/test/test_mechanize_page_image.rb +1 -0
- data/test/test_mechanize_page_link.rb +27 -23
- data/test/test_mechanize_page_meta_refresh.rb +1 -0
- data/test/test_mechanize_parser.rb +1 -0
- data/test/test_mechanize_pluggable_parser.rb +1 -0
- data/test/test_mechanize_redirect_limit_reached_error.rb +1 -0
- data/test/test_mechanize_redirect_not_get_or_head_error.rb +1 -0
- data/test/test_mechanize_response_read_error.rb +1 -0
- data/test/test_mechanize_subclass.rb +1 -0
- data/test/test_mechanize_util.rb +4 -3
- data/test/test_mechanize_xml_file.rb +1 -0
- data/test/test_multi_select.rb +1 -0
- metadata +106 -86
- data/.travis.yml +0 -36
- data/README.rdoc +0 -77
|
@@ -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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
|
data/lib/mechanize/test_case.rb
CHANGED
|
@@ -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 =
|
|
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
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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 =
|
|
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
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
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
|
-
|
|
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')
|
|
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 = []
|
data/lib/mechanize/util.rb
CHANGED
|
@@ -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? ?
|
|
19
|
+
(s.nil? ? String.new : s << '&') << [CGI.escape(k.to_s), CGI.escape(v.to_s)].join('=')
|
|
19
20
|
} || ''
|
|
20
21
|
end
|
|
21
22
|
|
data/lib/mechanize/version.rb
CHANGED
data/lib/mechanize/xml_file.rb
CHANGED
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
|
-
#
|
|
90
|
-
#
|
|
91
|
-
# *
|
|
92
|
-
#
|
|
93
|
-
#
|
|
94
|
-
#
|
|
95
|
-
# *
|
|
96
|
-
# *
|
|
97
|
-
# *
|
|
98
|
-
#
|
|
99
|
-
#
|
|
100
|
-
#
|
|
101
|
-
# *
|
|
102
|
-
# *
|
|
103
|
-
# *
|
|
104
|
-
# *
|
|
105
|
-
#
|
|
106
|
-
#
|
|
107
|
-
#
|
|
108
|
-
# *
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
124
|
-
|
|
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
|
-
|
|
134
|
-
'
|
|
135
|
-
'iPad' => 'Mozilla/5.0 (iPad; CPU OS
|
|
136
|
-
'
|
|
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.
|
|
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
|
|
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
|
|
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
|
-
|
|
720
|
+
c = caller_locations(1,1).first
|
|
702
721
|
|
|
703
722
|
warn <<-WARNING
|
|
704
|
-
At #{
|
|
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
|
|
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
|
-
|
|
3
|
-
|
|
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
|
|
8
|
-
spec.version
|
|
9
|
-
spec.homepage
|
|
10
|
-
spec.summary
|
|
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
|
-
'
|
|
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.
|
|
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
|
|
41
|
-
spec.test_files
|
|
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.
|
|
44
|
-
spec.
|
|
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
|
-
|
|
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
|
|
49
|
-
|
|
50
|
-
|
|
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.
|
|
63
|
-
spec.
|
|
64
|
-
spec.
|
|
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
|
data/test/htdocs/tc_links.html
CHANGED
|
@@ -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://
|
|
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>
|
data/test/test_mechanize.rb
CHANGED
|
@@ -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
|
-
|
|
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, :>,
|
|
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, :>,
|
|
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, :>,
|
|
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
|
|
1187
|
+
contents = File.binread(__FILE__).gsub(/\r\n/, "\n")
|
|
1175
1188
|
basename = File.basename __FILE__
|
|
1176
1189
|
|
|
1177
1190
|
assert_match(
|