mechanize 2.7.7 → 2.8.0

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 (110) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci-test.yml +24 -4
  3. data/.yardopts +8 -0
  4. data/{CHANGELOG.rdoc → CHANGELOG.md} +81 -66
  5. data/Gemfile +1 -6
  6. data/{LICENSE.rdoc → LICENSE.txt} +4 -0
  7. data/README.md +79 -0
  8. data/Rakefile +18 -3
  9. data/lib/mechanize.rb +1 -0
  10. data/lib/mechanize/chunked_termination_error.rb +1 -0
  11. data/lib/mechanize/content_type_error.rb +1 -0
  12. data/lib/mechanize/cookie.rb +1 -13
  13. data/lib/mechanize/cookie_jar.rb +2 -10
  14. data/lib/mechanize/directory_saver.rb +1 -0
  15. data/lib/mechanize/download.rb +1 -0
  16. data/lib/mechanize/element_matcher.rb +1 -0
  17. data/lib/mechanize/element_not_found_error.rb +1 -0
  18. data/lib/mechanize/file.rb +1 -0
  19. data/lib/mechanize/file_connection.rb +5 -3
  20. data/lib/mechanize/file_request.rb +1 -0
  21. data/lib/mechanize/file_response.rb +3 -0
  22. data/lib/mechanize/file_saver.rb +1 -0
  23. data/lib/mechanize/form.rb +1 -9
  24. data/lib/mechanize/form/button.rb +1 -0
  25. data/lib/mechanize/form/check_box.rb +1 -0
  26. data/lib/mechanize/form/field.rb +1 -0
  27. data/lib/mechanize/form/file_upload.rb +1 -0
  28. data/lib/mechanize/form/hidden.rb +1 -0
  29. data/lib/mechanize/form/image_button.rb +1 -0
  30. data/lib/mechanize/form/keygen.rb +1 -0
  31. data/lib/mechanize/form/multi_select_list.rb +1 -0
  32. data/lib/mechanize/form/option.rb +1 -0
  33. data/lib/mechanize/form/radio_button.rb +1 -0
  34. data/lib/mechanize/form/reset.rb +1 -0
  35. data/lib/mechanize/form/select_list.rb +1 -0
  36. data/lib/mechanize/form/submit.rb +1 -0
  37. data/lib/mechanize/form/text.rb +1 -0
  38. data/lib/mechanize/form/textarea.rb +1 -0
  39. data/lib/mechanize/headers.rb +1 -0
  40. data/lib/mechanize/history.rb +1 -0
  41. data/lib/mechanize/http.rb +1 -0
  42. data/lib/mechanize/http/agent.rb +16 -8
  43. data/lib/mechanize/http/auth_challenge.rb +1 -0
  44. data/lib/mechanize/http/auth_realm.rb +1 -0
  45. data/lib/mechanize/http/auth_store.rb +1 -0
  46. data/lib/mechanize/http/content_disposition_parser.rb +14 -2
  47. data/lib/mechanize/http/www_authenticate_parser.rb +3 -3
  48. data/lib/mechanize/image.rb +1 -0
  49. data/lib/mechanize/page.rb +1 -0
  50. data/lib/mechanize/page/base.rb +1 -0
  51. data/lib/mechanize/page/frame.rb +1 -0
  52. data/lib/mechanize/page/image.rb +1 -0
  53. data/lib/mechanize/page/label.rb +1 -0
  54. data/lib/mechanize/page/link.rb +8 -1
  55. data/lib/mechanize/page/meta_refresh.rb +1 -0
  56. data/lib/mechanize/parser.rb +1 -0
  57. data/lib/mechanize/pluggable_parsers.rb +1 -0
  58. data/lib/mechanize/prependable.rb +1 -0
  59. data/lib/mechanize/redirect_limit_reached_error.rb +1 -0
  60. data/lib/mechanize/redirect_not_get_or_head_error.rb +1 -0
  61. data/lib/mechanize/response_code_error.rb +2 -1
  62. data/lib/mechanize/response_read_error.rb +1 -0
  63. data/lib/mechanize/robots_disallowed_error.rb +1 -0
  64. data/lib/mechanize/test_case.rb +32 -27
  65. data/lib/mechanize/test_case/bad_chunking_servlet.rb +1 -0
  66. data/lib/mechanize/test_case/basic_auth_servlet.rb +1 -0
  67. data/lib/mechanize/test_case/content_type_servlet.rb +1 -0
  68. data/lib/mechanize/test_case/digest_auth_servlet.rb +1 -0
  69. data/lib/mechanize/test_case/file_upload_servlet.rb +1 -0
  70. data/lib/mechanize/test_case/form_servlet.rb +1 -0
  71. data/lib/mechanize/test_case/gzip_servlet.rb +1 -0
  72. data/lib/mechanize/test_case/header_servlet.rb +1 -0
  73. data/lib/mechanize/test_case/http_refresh_servlet.rb +1 -0
  74. data/lib/mechanize/test_case/infinite_redirect_servlet.rb +1 -0
  75. data/lib/mechanize/test_case/infinite_refresh_servlet.rb +1 -0
  76. data/lib/mechanize/test_case/many_cookies_as_string_servlet.rb +1 -0
  77. data/lib/mechanize/test_case/many_cookies_servlet.rb +1 -0
  78. data/lib/mechanize/test_case/modified_since_servlet.rb +1 -0
  79. data/lib/mechanize/test_case/ntlm_servlet.rb +1 -0
  80. data/lib/mechanize/test_case/one_cookie_no_spaces_servlet.rb +1 -0
  81. data/lib/mechanize/test_case/one_cookie_servlet.rb +1 -0
  82. data/lib/mechanize/test_case/quoted_value_cookie_servlet.rb +1 -0
  83. data/lib/mechanize/test_case/redirect_servlet.rb +1 -0
  84. data/lib/mechanize/test_case/referer_servlet.rb +1 -0
  85. data/lib/mechanize/test_case/refresh_with_empty_url.rb +1 -0
  86. data/lib/mechanize/test_case/refresh_without_url.rb +1 -0
  87. data/lib/mechanize/test_case/response_code_servlet.rb +1 -0
  88. data/lib/mechanize/test_case/robots_txt_servlet.rb +1 -0
  89. data/lib/mechanize/test_case/send_cookies_servlet.rb +1 -0
  90. data/lib/mechanize/test_case/server.rb +1 -0
  91. data/lib/mechanize/test_case/servlets.rb +1 -0
  92. data/lib/mechanize/test_case/verb_servlet.rb +1 -0
  93. data/lib/mechanize/unauthorized_error.rb +1 -0
  94. data/lib/mechanize/unsupported_scheme_error.rb +1 -0
  95. data/lib/mechanize/util.rb +2 -1
  96. data/lib/mechanize/version.rb +2 -1
  97. data/lib/mechanize/xml_file.rb +1 -0
  98. data/mechanize.gemspec +38 -31
  99. data/test/htdocs/dir with spaces/foo.html +1 -0
  100. data/test/test_mechanize.rb +5 -4
  101. data/test/test_mechanize_cookie_jar.rb +2 -0
  102. data/test/test_mechanize_download.rb +1 -0
  103. data/test/test_mechanize_file.rb +1 -0
  104. data/test/test_mechanize_file_connection.rb +21 -3
  105. data/test/test_mechanize_file_response.rb +6 -0
  106. data/test/test_mechanize_http_agent.rb +47 -7
  107. data/test/test_mechanize_http_content_disposition_parser.rb +27 -0
  108. data/test/test_mechanize_link.rb +24 -0
  109. metadata +134 -52
  110. data/README.rdoc +0 -77
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class Mechanize::HTTP
2
3
 
3
4
  AuthChallenge = Struct.new :scheme, :params, :raw
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class Mechanize::HTTP::AuthRealm
2
3
 
3
4
  attr_reader :scheme
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  ##
2
3
  # A credential store for HTTP authentication.
3
4
  #
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  # coding: BINARY
2
3
 
3
4
  require 'strscan'
@@ -16,6 +17,7 @@ end
16
17
  # * Missing disposition-type
17
18
  # * Multiple semicolons
18
19
  # * Whitespace around semicolons
20
+ # * Dates in ISO 8601 format
19
21
 
20
22
  class Mechanize::HTTP::ContentDispositionParser
21
23
 
@@ -93,7 +95,17 @@ class Mechanize::HTTP::ContentDispositionParser
93
95
  when /^filename$/ then
94
96
  rfc_2045_value
95
97
  when /^(creation|modification|read)-date$/ then
96
- Time.rfc822 rfc_2045_quoted_string
98
+ date = rfc_2045_quoted_string
99
+
100
+ begin
101
+ Time.rfc822 date
102
+ rescue ArgumentError
103
+ begin
104
+ Time.iso8601 date
105
+ rescue ArgumentError
106
+ nil
107
+ end
108
+ end
97
109
  when /^size$/ then
98
110
  rfc_2045_value.to_i(10)
99
111
  else
@@ -125,7 +137,7 @@ class Mechanize::HTTP::ContentDispositionParser
125
137
  def rfc_2045_quoted_string
126
138
  return nil unless @scanner.scan(/"/)
127
139
 
128
- text = ''
140
+ text = String.new
129
141
 
130
142
  while true do
131
143
  chunk = @scanner.scan(/[\000-\014\016-\041\043-\133\135-\177]+/) # not \r "
@@ -1,4 +1,4 @@
1
- # coding: BINARY
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'strscan'
4
4
 
@@ -151,10 +151,10 @@ class Mechanize::HTTP::WWWAuthenticateParser
151
151
  def quoted_string
152
152
  return nil unless @scanner.scan(/"/)
153
153
 
154
- text = ''
154
+ text = String.new
155
155
 
156
156
  while true do
157
- chunk = @scanner.scan(/[\r\n \t\041\043-\176\200-\377]+/) # not "
157
+ chunk = @scanner.scan(/[\r\n \t\x21\x23-\x7e\u0080-\u00ff]+/) # not " which is \x22
158
158
 
159
159
  if chunk then
160
160
  text << chunk
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  ##
2
3
  # An Image holds downloaded data for an image/* response.
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  ##
2
3
  # This class encapsulates an HTML page. If Mechanize finds a content
3
4
  # type of 'text/html', this class will be instantiated and returned.
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  ##
2
3
  # A base element on an HTML page. Mechanize treats base tags just like 'a'
3
4
  # tags. Base objects will contain links, but most likely will have no text.
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  # A Frame object wraps a frame HTML element. Frame objects can be treated
2
3
  # just like Link objects. They contain #src, the #link they refer to and a
3
4
  # #name, the name of the frame they refer to. #src and #name are aliased to
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  ##
2
3
  # An image element on an HTML page
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  ##
2
3
  # A form label on an HTML page
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  ##
2
3
  # This class encapsulates links. It contains the text and the URI for
3
4
  # 'a' tags parsed out of an HTML page. If the link contains an image,
@@ -8,6 +9,8 @@
8
9
  # <a href="http://example">Hello World</a>
9
10
  # <a href="http://example"><img src="test.jpg" alt="Hello World"></a>
10
11
 
12
+ require 'addressable/uri'
13
+
11
14
  class Mechanize::Page::Link
12
15
  attr_reader :node
13
16
  attr_reader :href
@@ -94,7 +97,11 @@ class Mechanize::Page::Link
94
97
  begin
95
98
  URI.parse @href
96
99
  rescue URI::InvalidURIError
97
- URI.parse WEBrick::HTTPUtils.escape @href
100
+ begin
101
+ URI.parse(Addressable::URI.escape(@href))
102
+ rescue Addressable::URI::InvalidURIError
103
+ raise URI::InvalidURIError
104
+ end
98
105
  end
99
106
  end
100
107
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  ##
2
3
  # This class encapsulates a meta element with a refresh http-equiv. Mechanize
3
4
  # treats meta refresh elements just like 'a' tags. MetaRefresh objects will
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  ##
2
3
  # The parser module provides standard methods for accessing the headers and
3
4
  # content of a response that are shared across pluggable parsers.
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'mechanize/file'
2
3
  require 'mechanize/file_saver'
3
4
  require 'mechanize/page'
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  # Fake implementation of prepend(), which does not support overriding
2
3
  # inherited methods nor methods that are formerly overridden by
3
4
  # another invocation of prepend().
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  ##
2
3
  # Raised when too many redirects are sent
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  ##
2
3
  # Raised when a POST, PUT, or DELETE request results in a redirect
3
4
  # see RFC 2616 10.3.2, 10.3.3 http://www.ietf.org/rfc/rfc2616.txt
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  # This error is raised when Mechanize encounters a response code it does not
2
3
  # know how to handle. Currently, this exception will be thrown if Mechanize
3
4
  # encounters response codes other than 200, 301, or 302. Any other response
@@ -16,7 +17,7 @@ class Mechanize::ResponseCodeError < Mechanize::Error
16
17
 
17
18
  def to_s
18
19
  response_class = Net::HTTPResponse::CODE_TO_OBJ[@response_code]
19
- out = "#{@response_code} => #{response_class} "
20
+ out = String.new("#{@response_code} => #{response_class} ")
20
21
  out << "for #{@page.uri} " if @page.respond_to? :uri # may be HTTPResponse
21
22
  out << "-- #{super}"
22
23
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  ##
2
3
  # Raised when Mechanize encounters an error while reading the response body
3
4
  # from the server. Contains the response headers and the response body up to
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  # Exception that is raised when an access to a resource is disallowed by
2
3
  # robots.txt or by HTML document itself.
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'mechanize'
2
3
  require 'logger'
3
4
  require 'tempfile'
@@ -57,12 +58,12 @@ class Mechanize::TestCase < Minitest::Test
57
58
 
58
59
  def fake_page agent = @mech
59
60
  uri = URI 'http://fake.example/'
60
- html = <<-END
61
- <html>
62
- <body>
63
- <form><input type="submit" value="submit" /></form>
64
- </body>
65
- </html>
61
+ html = String.new(<<~END)
62
+ <html>
63
+ <body>
64
+ <form><input type="submit" value="submit" /></form>
65
+ </body>
66
+ </html>
66
67
  END
67
68
 
68
69
  Mechanize::Page.new uri, nil, html, 200, agent
@@ -87,11 +88,9 @@ class Mechanize::TestCase < Minitest::Test
87
88
  # Creates a Mechanize::CookieJar by parsing the given +str+
88
89
 
89
90
  def cookie_jar str, uri = URI('http://example')
90
- jar = Mechanize::CookieJar.new
91
-
92
- jar.parse str, uri
93
-
94
- jar
91
+ Mechanize::CookieJar.new.tap do |jar|
92
+ jar.parse str, uri
93
+ end
95
94
  end
96
95
 
97
96
  ##
@@ -109,22 +108,18 @@ class Mechanize::TestCase < Minitest::Test
109
108
  # Creates a Nokogiri Node +element+ with the given +attributes+
110
109
 
111
110
  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
111
+ Nokogiri::XML::Node.new(element, Nokogiri::HTML::Document.new).tap do |node|
112
+ attributes.each do |name, value|
113
+ node[name] = value
114
+ end
118
115
  end
119
-
120
- node
121
116
  end
122
117
 
123
118
  ##
124
119
  # Creates a Mechanize::Page for the given +uri+ with the given
125
120
  # +content_type+, response +body+ and HTTP status +code+
126
121
 
127
- def page uri, content_type = 'text/html', body = '', code = 200
122
+ def page uri, content_type = 'text/html', body = String.new, code = 200
128
123
  uri = URI uri unless URI::Generic === uri
129
124
 
130
125
  Mechanize::Page.new(uri, { 'content-type' => content_type }, body, code,
@@ -173,15 +168,25 @@ UQIBATANBgkqhkiG9w0BAQUFAANBAAAB////////////////////////////////
173
168
  # Creates a Tempfile with +content+ that is immediately unlinked
174
169
 
175
170
  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
171
+ Tempfile.new(@NAME).tap do |body_io|
172
+ body_io.unlink
173
+ body_io.write content
174
+ body_io.flush
175
+ body_io.rewind
176
+ end
177
+ end
181
178
 
182
- body_io
179
+ ##
180
+ # Returns true if the current platform is a Windows platform
181
+ def windows?
182
+ ::RUBY_PLATFORM =~ /mingw|mswin/
183
183
  end
184
184
 
185
+ ##
186
+ # Return the contents of the file without Windows carriage returns
187
+ def file_contents_without_cr(path)
188
+ File.read(path).gsub(/\r\n/, "\n")
189
+ end
185
190
  end
186
191
 
187
192
  require 'mechanize/test_case/servlets'
@@ -312,7 +317,7 @@ class Response # :nodoc:
312
317
 
313
318
  def initialize
314
319
  @header = {}
315
- @body = ''
320
+ @body = String.new
316
321
  @code = nil
317
322
  @query = nil
318
323
  @cookies = []
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class BadChunkingServlet < WEBrick::HTTPServlet::AbstractServlet
2
3
  def do_GET req, res
3
4
  res.keep_alive = false if res.respond_to? :keep_alive=
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class BasicAuthServlet < WEBrick::HTTPServlet::AbstractServlet
2
3
  def do_GET(req,res)
3
4
  htpd = nil
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class ContentTypeServlet < WEBrick::HTTPServlet::AbstractServlet
2
3
  def do_GET(req, res)
3
4
  ct = req.query['ct'] || "text/html; charset=utf-8"
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'logger'
2
3
 
3
4
  class DigestAuthServlet < WEBrick::HTTPServlet::AbstractServlet
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class FileUploadServlet < WEBrick::HTTPServlet::AbstractServlet
2
3
  def do_POST req, res
3
4
  res.body = req.body
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class FormServlet < 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 'stringio'
2
3
  require 'zlib'
3
4
 
@@ -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,3 +1,4 @@
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"
@@ -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,3 +1,4 @@
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}"
@@ -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)