mechanize 2.7.2 → 2.7.7

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of mechanize might be problematic. Click here for more details.

Files changed (79) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ci-test.yml +25 -0
  3. data/.gitignore +15 -0
  4. data/CHANGELOG.rdoc +83 -0
  5. data/EXAMPLES.rdoc +2 -25
  6. data/Gemfile +8 -0
  7. data/README.rdoc +12 -18
  8. data/Rakefile +22 -38
  9. data/examples/{rubyforge.rb → rubygems.rb} +7 -6
  10. data/lib/mechanize.rb +85 -35
  11. data/lib/mechanize/cookie_jar.rb +2 -2
  12. data/lib/mechanize/directory_saver.rb +14 -2
  13. data/lib/mechanize/download.rb +6 -1
  14. data/lib/mechanize/element_matcher.rb +35 -14
  15. data/lib/mechanize/element_not_found_error.rb +19 -0
  16. data/lib/mechanize/file.rb +13 -3
  17. data/lib/mechanize/file_response.rb +2 -4
  18. data/lib/mechanize/form.rb +157 -46
  19. data/lib/mechanize/form/field.rb +46 -0
  20. data/lib/mechanize/form/multi_select_list.rb +13 -14
  21. data/lib/mechanize/form/option.rb +2 -1
  22. data/lib/mechanize/history.rb +1 -1
  23. data/lib/mechanize/http/agent.rb +104 -59
  24. data/lib/mechanize/http/auth_realm.rb +1 -1
  25. data/lib/mechanize/http/auth_store.rb +2 -0
  26. data/lib/mechanize/http/content_disposition_parser.rb +4 -1
  27. data/lib/mechanize/http/www_authenticate_parser.rb +2 -2
  28. data/lib/mechanize/page.rb +195 -49
  29. data/lib/mechanize/page/frame.rb +3 -1
  30. data/lib/mechanize/page/image.rb +2 -0
  31. data/lib/mechanize/page/link.rb +5 -0
  32. data/lib/mechanize/parser.rb +3 -3
  33. data/lib/mechanize/pluggable_parsers.rb +13 -1
  34. data/lib/mechanize/test_case.rb +7 -2
  35. data/lib/mechanize/test_case/gzip_servlet.rb +3 -3
  36. data/lib/mechanize/test_case/http_refresh_servlet.rb +1 -2
  37. data/lib/mechanize/test_case/infinite_refresh_servlet.rb +1 -2
  38. data/lib/mechanize/test_case/robots_txt_servlet.rb +14 -0
  39. data/lib/mechanize/test_case/servlets.rb +3 -0
  40. data/lib/mechanize/test_case/verb_servlet.rb +4 -6
  41. data/lib/mechanize/unauthorized_error.rb +1 -1
  42. data/lib/mechanize/unsupported_scheme_error.rb +4 -2
  43. data/lib/mechanize/util.rb +89 -43
  44. data/lib/mechanize/version.rb +3 -0
  45. data/mechanize.gemspec +62 -0
  46. data/test/htdocs/find_link.html +1 -4
  47. data/test/htdocs/tc_links.html +1 -1
  48. data/test/test_mechanize.rb +118 -55
  49. data/test/test_mechanize_cookie.rb +75 -60
  50. data/test/test_mechanize_cookie_jar.rb +110 -59
  51. data/test/test_mechanize_download.rb +40 -3
  52. data/test/test_mechanize_element_not_found_error.rb +15 -0
  53. data/test/test_mechanize_file.rb +29 -10
  54. data/test/test_mechanize_file_response.rb +21 -3
  55. data/test/test_mechanize_form.rb +69 -11
  56. data/test/test_mechanize_form_check_box.rb +10 -0
  57. data/test/test_mechanize_form_encoding.rb +3 -8
  58. data/test/test_mechanize_form_keygen.rb +1 -0
  59. data/test/test_mechanize_form_multi_select_list.rb +5 -1
  60. data/test/test_mechanize_http_agent.rb +139 -12
  61. data/test/test_mechanize_http_auth_challenge.rb +14 -0
  62. data/test/test_mechanize_http_auth_realm.rb +7 -1
  63. data/test/test_mechanize_http_auth_store.rb +37 -0
  64. data/test/test_mechanize_http_content_disposition_parser.rb +8 -1
  65. data/test/test_mechanize_http_www_authenticate_parser.rb +24 -0
  66. data/test/test_mechanize_link.rb +61 -3
  67. data/test/test_mechanize_page.rb +82 -7
  68. data/test/test_mechanize_page_encoding.rb +2 -3
  69. data/test/test_mechanize_page_image.rb +1 -1
  70. data/test/test_mechanize_page_link.rb +20 -5
  71. data/test/test_mechanize_page_meta_refresh.rb +1 -1
  72. data/test/test_mechanize_parser.rb +12 -2
  73. data/test/test_mechanize_util.rb +46 -11
  74. metadata +125 -111
  75. data/.gemtest +0 -0
  76. data/.travis.yml +0 -26
  77. data/Manifest.txt +0 -203
  78. data/lib/mechanize/monkey_patch.rb +0 -17
  79. data/test/htdocs/robots.txt +0 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 540e567d390aebe104b22b2c11c726c9bceef098
4
- data.tar.gz: c86f1051ac42694d9390856a53724a1b76019a35
2
+ SHA256:
3
+ metadata.gz: feff4acdf05edc4c615ab91f9ab0b7abfd1987dbd998ed07a36489189594edf2
4
+ data.tar.gz: efce735d57a4b2259f30a630829f432f270e3aa353fb9d4f5ad032df06387e84
5
5
  SHA512:
6
- metadata.gz: 949355d69adf7c58dfa355508e25044535f2880f7a7640d29ee8177d354850fb972dc625c4fac32c7b7e7496d5ca9eae94ad3fb47fc4ee37a45ad9d19f3a10d7
7
- data.tar.gz: c0a04825b124542b1d5eee4749402bfe64de7ba49b52952054f1fe92cd2d6607628174e76d8d2ca3f8be90b0da46871cb26db55be0fc3bf388ff0c266daf82f7
6
+ metadata.gz: f83a08c469e67045f58f3f3685cb17618db889dd85d1b7f2e56da1c9ae7744f36815a1f811f09bd99614c529b42f2038100a64fb06cdee1569d43bb831ea3fae
7
+ data.tar.gz: c01289d967e87c40e0936c2f973847da696bc92d9255a5c5f20099ff795ce57430f45a631a02a9395cfe7066e27731ec040a879fd255468b43cf9a1b5149c3eb
@@ -0,0 +1,25 @@
1
+ name: "ci"
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ "*" ]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ ruby-version: ["2.3", "2.4", "2.5", "2.6", "2.7", "3.0", "jruby"]
16
+
17
+ steps:
18
+ - uses: actions/checkout@v2
19
+ - name: Set up Ruby
20
+ uses: ruby/setup-ruby@v1
21
+ with:
22
+ ruby-version: ${{ matrix.ruby-version }}
23
+ bundler-cache: true
24
+ - name: Run tests
25
+ run: bundle exec rake
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ *.swp
2
+ *.gem
3
+ *.rbc
4
+ /.bundle
5
+ /.config
6
+ /Gemfile.lock
7
+ /TAGS
8
+ /pkg
9
+ /tags
10
+ /.rvmrc
11
+ digest.htpasswd
12
+ doc
13
+ rdoc
14
+ .yardoc
15
+ _yardoc
data/CHANGELOG.rdoc CHANGED
@@ -1,5 +1,88 @@
1
1
  = Mechanize CHANGELOG
2
2
 
3
+ === 2.7.7 / 2021-02-01
4
+
5
+ * Security fixes for CVE-2021-21289
6
+
7
+ Mechanize `>= v2.0`, `< v2.7.7` allows for OS commands to be injected into several classes'
8
+ methods via implicit use of Ruby's `Kernel.open` method. Exploitation is possible only if
9
+ untrusted input is used as a local filename and passed to any of these calls:
10
+
11
+ - `Mechanize::CookieJar#load`: since v2.0 (see 208e3ed)
12
+ - `Mechanize::CookieJar#save_as`: since v2.0 (see 5b776a4)
13
+ - `Mechanize#download`: since v2.2 (see dc91667)
14
+ - `Mechanize::Download#save` and `#save!` since v2.1 (see 98b2f51, bd62ff0)
15
+ - `Mechanize::File#save` and `#save_as`: since v2.1 (see 2bf7519)
16
+ - `Mechanize::FileResponse#read_body`: since v2.0 (see 01039f5)
17
+
18
+ See https://github.com/sparklemotion/mechanize/security/advisories/GHSA-qrqm-fpv6-6r8g for more
19
+ information.
20
+
21
+ Also see #547, #548. Thank you, @kyoshidajp!
22
+
23
+ * New Features
24
+ * Support for Ruby 3.0 by adding `webrick` as a runtime dependency. (#557) @pvalena
25
+
26
+ * Bug fix
27
+ * Ignore input fields with blank names (#542, #536)
28
+
29
+
30
+ === 2.7.6
31
+
32
+ * New Features
33
+ * Mechanize#set_proxy accepts an HTTP URL/URI. (#513)
34
+
35
+ * Bug fix
36
+ * Fix element(s)_with(search: selector) methods not working for forms, form fields and frames. (#444)
37
+ * Improve the filename parser for the `Content-Disposition` header. (#496, #517)
38
+ * Accept `Content-Encoding: identity`. (#515)
39
+ * Mechanize::Page#title no longer picks a title in an embeded SVG/RDF element. (#503)
40
+ * Make Mechanize::Form#has_field? boolean. (#501)
41
+
42
+ === 2.7.5
43
+
44
+ * New Features
45
+ * All 4xx responses and RedirectLimitReachedError when fetching robots.txt are treated as full allow just like Googlebot does.
46
+ * Enable support for mime-types > 3.
47
+
48
+ * Bug fix
49
+ * Don't cause infinite loop when `GET /robots.txt` redirects. (#457)
50
+ * Fix basic authentication for a realm that contains uppercase characters. (#458, #459)
51
+ * Fix encoding error when uploading a file which name is non-ASCII. (#333)
52
+
53
+ === 2.7.4
54
+
55
+ * New Features
56
+ * Accept array-like and hash-like values as query/parameter value.
57
+ A new utility method Mechanize::Util.each_parameter is added, and Mechanize::Util.build_query_string is enhanced
58
+ for this feature.
59
+ * Allow passing a `Form::FileUpload` instance to `#post`. #350 by Sam
60
+ Rawlins.
61
+ * Capture link when scheme is unsupported. #362 by Jon Rowe.
62
+ * Pre-defined User-Agent stings are updated to those of more recent versions, and new aliases for IE 10/11 and Edge are added.
63
+ * Support for mime-types 1.x is restored while keeping compatible with mime-types 2.x.
64
+ * Mechanize::Page now responds to #xpath, #css, #at_xpath, #at_css, and #%.
65
+ * element(s)_with methods now accept :xpath and :css options for doing xpath/css
66
+ selector searching.
67
+ * Pass URI information to Nokogiri where applicable. #405 @lulalala
68
+
69
+ * Bug fix
70
+ * Don't raise an exception if a connection has set a {read,open}_timeout and
71
+ a `file://` request is made. (#397)
72
+ * Fix whitespace bug in WWW-Authenticate. #451, #450, by Rasmus Bergholdt
73
+ * Don't allow redirect from a non-file URL to a file URL for security reasons. (#455)
74
+
75
+ === 2.7.3
76
+
77
+ * New Features
78
+ * Allow net-http-persistent instance to be named. #324, John Weir.
79
+ * #save and #save! return filename #340
80
+ * Updated mime-types requirement to 2.x versions. #348 by Jeff Nyman.
81
+
82
+ * Bug fix
83
+ * Ensure Download#save! defaults back to original filename if
84
+ none is provided (#300)
85
+
3
86
  === 2.7.2
4
87
 
5
88
  * Bug fix
data/EXAMPLES.rdoc CHANGED
@@ -15,7 +15,7 @@ example, <code>do ... end.submit</code> is the same as <code>{ ...
15
15
  }
16
16
 
17
17
  a.get('http://google.com/') do |page|
18
- search_result = page.form_with(:name => 'f') do |search|
18
+ search_result = page.form_with(:id => 'gbqf') do |search|
19
19
  search.q = 'Hello world'
20
20
  end.submit
21
21
 
@@ -24,29 +24,6 @@ example, <code>do ... end.submit</code> is the same as <code>{ ...
24
24
  end
25
25
  end
26
26
 
27
- == Rubyforge
28
-
29
- require 'rubygems'
30
- require 'mechanize'
31
-
32
- a = Mechanize.new
33
- a.get('http://rubyforge.org/') do |page|
34
- # Click the login link
35
- login_page = a.click(page.link_with(:text => /Log In/))
36
-
37
- # Submit the login form
38
- my_page = login_page.form_with(:action => '/account/login.php') do |f|
39
- f.form_loginname = ARGV[0]
40
- f.form_pw = ARGV[1]
41
- end.click_button
42
-
43
- my_page.links.each do |link|
44
- text = link.text.strip
45
- next unless text.length > 0
46
- puts text
47
- end
48
- end
49
-
50
27
  == File Upload
51
28
 
52
29
  Upload a file to flickr.
@@ -129,7 +106,7 @@ This example also demonstrates subclassing Mechanize.
129
106
 
130
107
  class TestMech < Mechanize
131
108
  def process
132
- get 'http://rubyforge.org/'
109
+ get 'http://rubygems.org/'
133
110
  search_form = page.forms.first
134
111
  search_form.words = 'WWW'
135
112
  submit search_form
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem "rake"
4
+ gem "bundler"
5
+ gem "rdoc"
6
+ gem "minitest"
7
+
8
+ gemspec
data/README.rdoc CHANGED
@@ -1,6 +1,6 @@
1
- = Mechanize {<img src="https://secure.travis-ci.org/sparklemotion/mechanize.png?rvm=1.9.3" />}[http://travis-ci.org/sparklemotion/mechanize]
1
+ = Mechanize {<img src="https://secure.travis-ci.org/sparklemotion/mechanize.svg?rvm=2.3.3" />}[http://travis-ci.org/sparklemotion/mechanize]
2
2
 
3
- * http://mechanize.rubyforge.org
3
+ * http://docs.seattlerb.org/mechanize
4
4
  * https://github.com/sparklemotion/mechanize
5
5
 
6
6
  == Description
@@ -14,32 +14,26 @@ a history.
14
14
  == Dependencies
15
15
 
16
16
  * ruby 1.9.2 or newer
17
- * nokogiri[http://nokogiri.rubyforge.org]
17
+ * nokogiri[https://github.com/sparklemotion/nokogiri]
18
18
 
19
19
  == Support:
20
20
 
21
- The mechanize mailing list is available here:
22
-
23
- * http://rubyforge.org/mailman/listinfo/mechanize-users
24
-
25
21
  The bug tracker is available here:
26
22
 
27
23
  * https://github.com/sparklemotion/mechanize/issues
28
24
 
29
25
  == Examples
30
26
 
31
- If you are just starting, check out the GUIDE[http://mechanize.rubyforge.org/GUIDE_rdoc.html] or
32
- the EXAMPLES[http://mechanize.rubyforge.org/EXAMPLES_rdoc.html] file.
27
+ If you are just starting, check out the GUIDE[http://docs.seattlerb.org/mechanize/GUIDE_rdoc.html] or
28
+ the EXAMPLES[http://docs.seattlerb.org/mechanize/EXAMPLES_rdoc.html] file.
33
29
 
34
30
  == Developers
35
31
 
36
- To run the tests for the first time:
32
+ Use bundler to install dependencies:
37
33
 
38
- gem install hoe rake
39
- rake newb
34
+ bundle install
40
35
 
41
- This will install all the required dependencies for running the tests. For
42
- subsequent test runs:
36
+ Run all tests with:
43
37
 
44
38
  rake test
45
39
 
@@ -54,14 +48,14 @@ Copyright (c) 2005 by Michael Neumann (mneumann@ntecs.de)
54
48
 
55
49
  Copyright (c) 2006-2011:
56
50
 
57
- * {Aaron Patterson}[http://tenderlovemaking.com] (aaronp@rubyforge.org)
51
+ * {Aaron Patterson}[http://tenderlovemaking.com] (aaron.patterson@gmail.com)
58
52
  * {Mike Dalessio}[http://mike.daless.io] (mike@csa.net)
59
53
 
60
- Copyright (c) 2011-2013:
54
+ Copyright (c) 2011-2015:
61
55
 
62
56
  * {Eric Hodel}[http://blog.segment7.net] (drbrain@segment7.net)
63
57
  * {Akinori MUSHA}[http://blog.akinori.org] (knu@idaemons.org)
64
- * {Lee Jarvis}[http://aeroproof.com] (ljjarvis@gmail.com)
58
+ * {Lee Jarvis}[http://twitter.com/lee_jarvis] (ljjarvis@gmail.com)
65
59
 
66
60
  This library comes with a shameless plug for employing me
67
61
  (Aaron[http://tenderlovemaking.com/]) programming Ruby, my favorite language!
@@ -79,5 +73,5 @@ library!
79
73
 
80
74
  == License
81
75
 
82
- This library is distributed under the MIT license. Please see the LICENSE[http://mechanize.rubyforge.org/LICENSE_rdoc.html] file.
76
+ This library is distributed under the MIT license. Please see the LICENSE[http://docs.seattlerb.org/mechanize/LICENSE_rdoc.html] file.
83
77
 
data/Rakefile CHANGED
@@ -1,38 +1,14 @@
1
1
  require 'rubygems'
2
- require 'hoe'
3
2
 
4
- Hoe.plugin :git
5
- Hoe.plugin :minitest
6
- Hoe.plugin :travis
7
-
8
- hoe = Hoe.spec 'mechanize' do
9
- developer 'Eric Hodel', 'drbrain@segment7.net'
10
- developer 'Aaron Patterson', 'aaronp@rubyforge.org'
11
- developer 'Mike Dalessio', 'mike.dalessio@gmail.com'
12
- developer 'Akinori MUSHA', 'knu@idaemons.org'
13
- developer 'Lee Jarvis', 'ljjarvis@gmail.com'
14
-
15
- self.readme_file = 'README.rdoc'
16
- self.history_file = 'CHANGELOG.rdoc'
17
- self.extra_rdoc_files += Dir['*.rdoc']
18
-
19
- rdoc_locations << 'rubyforge.org:/var/www/gforge-projects/mechanize/'
20
-
21
- self.extra_deps << ['net-http-digest_auth', '~> 1.1', '>= 1.1.1']
22
- self.extra_deps << ['net-http-persistent', '~> 2.5', '>= 2.5.2']
23
- self.extra_deps << ['mime-types', '~> 1.17', '>= 1.17.2']
24
- self.extra_deps << ['http-cookie', '~> 1.0.0']
25
- self.extra_deps << ['nokogiri', '~> 1.4']
26
- self.extra_deps << ['ntlm-http', '~> 0.1', '>= 0.1.1']
27
- self.extra_deps << ['webrobots', '< 0.2', '>= 0.0.9']
28
- self.extra_deps << ['domain_name', '~> 0.5', '>= 0.5.1']
29
-
30
- self.extra_dev_deps << ['minitest', '~> 5.0']
31
-
32
- self.spec_extras[:required_ruby_version] = '>= 1.8.7'
3
+ begin
4
+ require "bundler/gem_tasks"
5
+ rescue LoadError
33
6
  end
34
7
 
35
- task :prerelease => [:clobber, :check_manifest, :test]
8
+ require 'rdoc/task'
9
+ require 'rake/testtask'
10
+
11
+ task :prerelease => [:clobber_rdoc, :test]
36
12
 
37
13
  desc "Update SSL Certificate"
38
14
  task('ssl_cert') do |p|
@@ -46,12 +22,20 @@ task('ssl_cert') do |p|
46
22
  sh "rm server.key.org"
47
23
  end
48
24
 
49
- desc 'Install deps for travis to work around Hoe/RubyGems bug'
50
- task 'travis_deps' do
51
- hoe.spec.dependencies.each do |dep|
52
- first_requirement = dep.requirement.requirements.first.join ' '
53
- system('gem', 'install', dep.name, '-v', first_requirement,
54
- '--no-rdoc', '--no-ri')
55
- end
25
+ RDoc::Task.new do |rdoc|
26
+ rdoc.main = "README.rdoc"
27
+ rdoc.rdoc_dir = 'doc'
28
+ rdoc.rdoc_files.include( "CHANGELOG.rdoc", "EXAMPLES.rdoc", "GUIDE.rdoc", "LICENSE.rdoc", "README.rdoc", "lib/**/*.rb")
29
+ end
30
+
31
+ desc "Run tests"
32
+ Rake::TestTask.new { |t|
33
+ t.test_files = Dir['test/**/test*.rb']
34
+ t.verbose = true
35
+ }
36
+
37
+ task publish_docs: %w[rdoc] do
38
+ sh 'rsync', '-avzO', '--delete', 'doc/', 'docs-push.seattlerb.org:/data/www/docs.seattlerb.org/mechanize/'
56
39
  end
57
40
 
41
+ task default: :test
@@ -1,4 +1,4 @@
1
- # This example logs a user in to rubyforge and prints out the body of the
1
+ # This example logs a user in to rubygems and prints out the body of the
2
2
  # page after logging the user in.
3
3
  require 'rubygems'
4
4
  require 'mechanize'
@@ -9,12 +9,13 @@ mech = Mechanize.new
9
9
  mech.log = Logger.new $stderr
10
10
  mech.agent.http.debug_output = $stderr
11
11
 
12
- # Load the rubyforge website
13
- page = mech.get('http://rubyforge.org/')
14
- page = mech.click page.link_with(:text => /Log In/) # Click the login link
12
+ # Load the rubygems website
13
+ page = mech.get('https://rubygems.org/')
14
+ page = mech.click page.link_with(:text => /Sign in/) # Click the login link
15
15
  form = page.forms[1] # Select the first form
16
- form.form_loginname = ARGV[0]
17
- form.form_pw = ARGV[1]
16
+ form["session[who]"] = ARGV[0]
17
+ form["session[password]"] = ARGV[1]
18
+ form["commit"] = "Sign in"
18
19
 
19
20
  # Submit the form
20
21
  page = form.submit form.buttons.first
data/lib/mechanize.rb CHANGED
@@ -1,7 +1,6 @@
1
+ require 'mechanize/version'
1
2
  require 'fileutils'
2
3
  require 'forwardable'
3
- require 'iconv' if RUBY_VERSION < '1.9.2'
4
- require 'mime/types'
5
4
  require 'mutex_m'
6
5
  require 'net/http/digest_auth'
7
6
  require 'net/http/persistent'
@@ -70,11 +69,6 @@ require 'zlib'
70
69
 
71
70
  class Mechanize
72
71
 
73
- ##
74
- # The version of Mechanize you are using.
75
-
76
- VERSION = '2.7.2'
77
-
78
72
  ##
79
73
  # Base mechanize error class
80
74
 
@@ -92,22 +86,26 @@ class Mechanize
92
86
  # description in parenthesis is for informative purposes and is not part of
93
87
  # the alias name.
94
88
  #
95
- # * Linux Firefox (3.6.1)
89
+ # * Linux Firefox (43.0 on Ubuntu Linux)
96
90
  # * Linux Konqueror (3)
97
91
  # * Linux Mozilla
98
- # * Mac Firefox (3.6)
92
+ # * Mac Firefox (43.0)
99
93
  # * Mac Mozilla
100
- # * Mac Safari (5)
94
+ # * Mac Safari (9.0 on OS X 10.11.2)
101
95
  # * Mac Safari 4
102
96
  # * Mechanize (default)
103
97
  # * Windows IE 6
104
98
  # * Windows IE 7
105
99
  # * Windows IE 8
106
100
  # * Windows IE 9
101
+ # * Windows IE 10 (Windows 8 64bit)
102
+ # * Windows IE 11 (Windows 8.1 64bit)
103
+ # * Windows Edge
107
104
  # * Windows Mozilla
108
- # * iPhone (3.0)
109
- # * iPad
110
- # * Android (Motorola Xoom)
105
+ # * Windows Firefox (43.0)
106
+ # * iPhone (iOS 9.1)
107
+ # * iPad (iOS 9.1)
108
+ # * Android (5.1.1)
111
109
  #
112
110
  # Example:
113
111
  #
@@ -116,26 +114,37 @@ class Mechanize
116
114
 
117
115
  AGENT_ALIASES = {
118
116
  'Mechanize' => "Mechanize/#{VERSION} Ruby/#{ruby_version} (http://github.com/sparklemotion/mechanize/)",
119
- 'Linux Firefox' => 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.1) Gecko/20100122 firefox/3.6.1',
117
+ 'Linux Firefox' => 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:43.0) Gecko/20100101 Firefox/43.0',
120
118
  'Linux Konqueror' => 'Mozilla/5.0 (compatible; Konqueror/3; Linux)',
121
119
  'Linux Mozilla' => 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624',
122
- 'Mac Firefox' => 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6',
120
+ 'Mac Firefox' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:43.0) Gecko/20100101 Firefox/43.0',
123
121
  'Mac Mozilla' => 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.4a) Gecko/20030401',
124
122
  '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',
125
- 'Mac Safari' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/534.51.22 (KHTML, like Gecko) Version/5.1.1 Safari/534.51.22',
126
- 'Windows Chrome' => 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.32 Safari/537.36',
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',
127
125
  'Windows IE 6' => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
128
126
  'Windows IE 7' => 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)',
129
127
  '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)',
130
128
  'Windows IE 9' => 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)',
129
+ 'Windows IE 10' => 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)',
130
+ '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',
131
132
  'Windows Mozilla' => 'Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6',
132
- 'iPhone' => 'Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1C28 Safari/419.3',
133
- 'iPad' => 'Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B334b Safari/531.21.10',
134
- 'Android' => 'Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13'
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',
135
137
  }
136
138
 
137
- AGENT_ALIASES['Mac FireFox'] = AGENT_ALIASES['Mac Firefox']
138
- AGENT_ALIASES['Linux FireFox'] = AGENT_ALIASES['Linux Firefox']
139
+ AGENT_ALIASES.default_proc = proc { |hash, key|
140
+ case key
141
+ when /FireFox/
142
+ if ua = hash[nkey = key.sub(/FireFox/, 'Firefox')]
143
+ warn "Mechanize#user_agent_alias: #{key.inspect} should be spelled as #{nkey.inspect}"
144
+ ua
145
+ end
146
+ end
147
+ }
139
148
 
140
149
  def self.inherited(child) # :nodoc:
141
150
  child.html_parser = html_parser
@@ -166,12 +175,20 @@ class Mechanize
166
175
  # as SSL parameters or proxies:
167
176
  #
168
177
  # agent = Mechanize.new do |a|
169
- # a.proxy_host = 'proxy.example'
178
+ # a.proxy_addr = 'proxy.example'
170
179
  # a.proxy_port = 8080
171
180
  # end
181
+ #
182
+ # If you need segregated SSL connections give each agent a unique
183
+ # name. Otherwise the connections will be shared. This is
184
+ # particularly important if you are using certifcates.
185
+ #
186
+ # agent_1 = Mechanize.new 'conn1'
187
+ # agent_2 = Mechanize.new 'conn2'
188
+ #
172
189
 
173
- def initialize
174
- @agent = Mechanize::HTTP::Agent.new
190
+ def initialize(connection_name = 'mechanize')
191
+ @agent = Mechanize::HTTP::Agent.new(connection_name)
175
192
  @agent.context = self
176
193
  @log = nil
177
194
 
@@ -334,12 +351,21 @@ class Mechanize
334
351
  click real_link
335
352
  else
336
353
  button = nil
354
+ # Note that this will not work if we have since navigated to a different page.
355
+ # Should rather make each button aware of its parent form.
337
356
  form = page.forms.find do |f|
338
357
  button = f.button_with(:value => link)
339
358
  button.is_a? Form::Submit
340
359
  end
341
360
  submit form, button if form
342
361
  end
362
+ when Form::Submit, Form::ImageButton then
363
+ # Note that this will not work if we have since navigated to a different page.
364
+ # Should rather make each button aware of its parent form.
365
+ form = page.forms.find do |f|
366
+ f.buttons.include?(link)
367
+ end
368
+ submit form, link if form
343
369
  else
344
370
  referer = current_page()
345
371
  href = link.respond_to?(:href) ? link.href :
@@ -370,7 +396,7 @@ class Mechanize
370
396
  io = if io_or_filename.respond_to? :write then
371
397
  io_or_filename
372
398
  else
373
- open io_or_filename, 'wb'
399
+ ::File.open(io_or_filename, 'wb')
374
400
  end
375
401
 
376
402
  case page
@@ -392,6 +418,9 @@ class Mechanize
392
418
  ##
393
419
  # DELETE +uri+ with +query_params+, and setting +headers+:
394
420
  #
421
+ # +query_params+ is formatted into a query string using
422
+ # Mechanize::Util.build_query_string, which see.
423
+ #
395
424
  # delete('http://example/', {'q' => 'foo'}, {})
396
425
 
397
426
  def delete(uri, query_params = {}, headers = {})
@@ -405,6 +434,9 @@ class Mechanize
405
434
  # +headers+.
406
435
  #
407
436
  # The +referer+ may be a URI or a page.
437
+ #
438
+ # +parameters+ is formatted into a query string using
439
+ # Mechanize::Util.build_query_string, which see.
408
440
 
409
441
  def get(uri, parameters = [], referer = nil, headers = {})
410
442
  method = :get
@@ -445,6 +477,9 @@ class Mechanize
445
477
  ##
446
478
  # HEAD +uri+ with +query_params+ and +headers+:
447
479
  #
480
+ # +query_params+ is formatted into a query string using
481
+ # Mechanize::Util.build_query_string, which see.
482
+ #
448
483
  # head('http://example/', {'q' => 'foo'}, {})
449
484
 
450
485
  def head(uri, query_params = {}, headers = {})
@@ -456,9 +491,13 @@ class Mechanize
456
491
  end
457
492
 
458
493
  ##
459
- # POST to the given +uri+ with the given +query+. The query is specified by
460
- # either a string, or a list of key-value pairs represented by a hash or an
461
- # array of arrays.
494
+ # POST to the given +uri+ with the given +query+.
495
+ #
496
+ # +query+ is processed using Mechanize::Util.each_parameter (which
497
+ # see), and then encoded into an entity body. If any IO/FileUpload
498
+ # object is specified as a field value the "enctype" will be
499
+ # multipart/form-data, or application/x-www-form-urlencoded
500
+ # otherwise.
462
501
  #
463
502
  # Examples:
464
503
  # agent.post 'http://example.com/', "foo" => "bar"
@@ -481,12 +520,15 @@ class Mechanize
481
520
 
482
521
  form = Form.new(node)
483
522
 
484
- query.each { |k, v|
523
+ Mechanize::Util.each_parameter(query) { |k, v|
485
524
  if v.is_a?(IO)
486
525
  form.enctype = 'multipart/form-data'
487
526
  ul = Form::FileUpload.new({'name' => k.to_s},::File.basename(v.path))
488
527
  ul.file_data = v.read
489
528
  form.file_uploads << ul
529
+ elsif v.is_a?(Form::FileUpload)
530
+ form.enctype = 'multipart/form-data'
531
+ form.file_uploads << v
490
532
  else
491
533
  form.fields << Form::Field.new({'name' => k.to_s},v)
492
534
  end
@@ -510,6 +552,8 @@ class Mechanize
510
552
  def request_with_entity(verb, uri, entity, headers = {})
511
553
  cur_page = current_page || Page.new
512
554
 
555
+ log.debug("query: #{ entity.inspect }") if log
556
+
513
557
  headers = {
514
558
  'Content-Type' => 'application/octet-stream',
515
559
  'Content-Length' => entity.size.to_s,
@@ -926,6 +970,12 @@ Use of #auth and #basic_auth are deprecated due to a security vulnerability.
926
970
  @agent.redirection_limit = limit
927
971
  end
928
972
 
973
+ ##
974
+ # Resolve the full path of a link / uri
975
+ def resolve link
976
+ @agent.resolve link
977
+ end
978
+
929
979
  ##
930
980
  # A hash of custom request headers that will be sent on every request
931
981
 
@@ -1130,19 +1180,19 @@ Use of #auth and #basic_auth are deprecated due to a security vulnerability.
1130
1180
  end
1131
1181
 
1132
1182
  ##
1133
- # SSL version to use. Ruby 1.9 and newer only.
1183
+ # SSL version to use.
1134
1184
 
1135
1185
  def ssl_version
1136
1186
  @agent.ssl_version
1137
- end if RUBY_VERSION > '1.9'
1187
+ end
1138
1188
 
1139
1189
  ##
1140
1190
  # Sets the SSL version to use to +version+ without client/server
1141
- # negotiation. Ruby 1.9 and newer only.
1191
+ # negotiation.
1142
1192
 
1143
1193
  def ssl_version= ssl_version
1144
1194
  @agent.ssl_version = ssl_version
1145
- end if RUBY_VERSION > '1.9'
1195
+ end
1146
1196
 
1147
1197
  ##
1148
1198
  # A callback for additional certificate verification. See
@@ -1285,6 +1335,7 @@ Use of #auth and #basic_auth are deprecated due to a security vulnerability.
1285
1335
 
1286
1336
  end
1287
1337
 
1338
+ require 'mechanize/element_not_found_error'
1288
1339
  require 'mechanize/response_read_error'
1289
1340
  require 'mechanize/chunked_termination_error'
1290
1341
  require 'mechanize/content_type_error'
@@ -1307,7 +1358,6 @@ require 'mechanize/http/content_disposition_parser'
1307
1358
  require 'mechanize/http/www_authenticate_parser'
1308
1359
  require 'mechanize/image'
1309
1360
  require 'mechanize/page'
1310
- require 'mechanize/monkey_patch'
1311
1361
  require 'mechanize/pluggable_parsers'
1312
1362
  require 'mechanize/redirect_limit_reached_error'
1313
1363
  require 'mechanize/redirect_not_get_or_head_error'