mechanize 2.7.6 → 2.8.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 (119) hide show
  1. checksums.yaml +5 -5
  2. data/.github/dependabot.yml +11 -0
  3. data/.github/workflows/ci-test.yml +53 -0
  4. data/.yardopts +8 -0
  5. data/{CHANGELOG.rdoc → CHANGELOG.md} +136 -87
  6. data/EXAMPLES.rdoc +1 -24
  7. data/Gemfile +1 -4
  8. data/{LICENSE.rdoc → LICENSE.txt} +4 -0
  9. data/README.md +77 -0
  10. data/Rakefile +18 -3
  11. data/examples/rubygems.rb +2 -2
  12. data/lib/mechanize.rb +3 -2
  13. data/lib/mechanize/chunked_termination_error.rb +1 -0
  14. data/lib/mechanize/content_type_error.rb +1 -0
  15. data/lib/mechanize/cookie.rb +1 -13
  16. data/lib/mechanize/cookie_jar.rb +4 -12
  17. data/lib/mechanize/directory_saver.rb +1 -0
  18. data/lib/mechanize/download.rb +2 -1
  19. data/lib/mechanize/element_matcher.rb +1 -0
  20. data/lib/mechanize/element_not_found_error.rb +1 -0
  21. data/lib/mechanize/file.rb +2 -1
  22. data/lib/mechanize/file_connection.rb +5 -3
  23. data/lib/mechanize/file_request.rb +1 -0
  24. data/lib/mechanize/file_response.rb +4 -1
  25. data/lib/mechanize/file_saver.rb +1 -0
  26. data/lib/mechanize/form.rb +2 -10
  27. data/lib/mechanize/form/button.rb +1 -0
  28. data/lib/mechanize/form/check_box.rb +1 -0
  29. data/lib/mechanize/form/field.rb +1 -0
  30. data/lib/mechanize/form/file_upload.rb +1 -0
  31. data/lib/mechanize/form/hidden.rb +1 -0
  32. data/lib/mechanize/form/image_button.rb +1 -0
  33. data/lib/mechanize/form/keygen.rb +1 -0
  34. data/lib/mechanize/form/multi_select_list.rb +1 -0
  35. data/lib/mechanize/form/option.rb +1 -0
  36. data/lib/mechanize/form/radio_button.rb +1 -0
  37. data/lib/mechanize/form/reset.rb +1 -0
  38. data/lib/mechanize/form/select_list.rb +1 -0
  39. data/lib/mechanize/form/submit.rb +1 -0
  40. data/lib/mechanize/form/text.rb +1 -0
  41. data/lib/mechanize/form/textarea.rb +1 -0
  42. data/lib/mechanize/headers.rb +1 -0
  43. data/lib/mechanize/history.rb +1 -0
  44. data/lib/mechanize/http.rb +1 -0
  45. data/lib/mechanize/http/agent.rb +16 -8
  46. data/lib/mechanize/http/auth_challenge.rb +1 -0
  47. data/lib/mechanize/http/auth_realm.rb +1 -0
  48. data/lib/mechanize/http/auth_store.rb +1 -0
  49. data/lib/mechanize/http/content_disposition_parser.rb +14 -2
  50. data/lib/mechanize/http/www_authenticate_parser.rb +3 -3
  51. data/lib/mechanize/image.rb +1 -0
  52. data/lib/mechanize/page.rb +4 -3
  53. data/lib/mechanize/page/base.rb +1 -0
  54. data/lib/mechanize/page/frame.rb +1 -0
  55. data/lib/mechanize/page/image.rb +1 -0
  56. data/lib/mechanize/page/label.rb +1 -0
  57. data/lib/mechanize/page/link.rb +8 -1
  58. data/lib/mechanize/page/meta_refresh.rb +1 -0
  59. data/lib/mechanize/parser.rb +1 -0
  60. data/lib/mechanize/pluggable_parsers.rb +1 -0
  61. data/lib/mechanize/prependable.rb +1 -0
  62. data/lib/mechanize/redirect_limit_reached_error.rb +1 -0
  63. data/lib/mechanize/redirect_not_get_or_head_error.rb +1 -0
  64. data/lib/mechanize/response_code_error.rb +2 -1
  65. data/lib/mechanize/response_read_error.rb +1 -0
  66. data/lib/mechanize/robots_disallowed_error.rb +1 -0
  67. data/lib/mechanize/test_case.rb +34 -29
  68. data/lib/mechanize/test_case/bad_chunking_servlet.rb +1 -0
  69. data/lib/mechanize/test_case/basic_auth_servlet.rb +1 -0
  70. data/lib/mechanize/test_case/content_type_servlet.rb +1 -0
  71. data/lib/mechanize/test_case/digest_auth_servlet.rb +1 -0
  72. data/lib/mechanize/test_case/file_upload_servlet.rb +1 -0
  73. data/lib/mechanize/test_case/form_servlet.rb +1 -0
  74. data/lib/mechanize/test_case/gzip_servlet.rb +4 -3
  75. data/lib/mechanize/test_case/header_servlet.rb +1 -0
  76. data/lib/mechanize/test_case/http_refresh_servlet.rb +1 -0
  77. data/lib/mechanize/test_case/infinite_redirect_servlet.rb +1 -0
  78. data/lib/mechanize/test_case/infinite_refresh_servlet.rb +1 -0
  79. data/lib/mechanize/test_case/many_cookies_as_string_servlet.rb +1 -0
  80. data/lib/mechanize/test_case/many_cookies_servlet.rb +1 -0
  81. data/lib/mechanize/test_case/modified_since_servlet.rb +1 -0
  82. data/lib/mechanize/test_case/ntlm_servlet.rb +1 -0
  83. data/lib/mechanize/test_case/one_cookie_no_spaces_servlet.rb +1 -0
  84. data/lib/mechanize/test_case/one_cookie_servlet.rb +1 -0
  85. data/lib/mechanize/test_case/quoted_value_cookie_servlet.rb +1 -0
  86. data/lib/mechanize/test_case/redirect_servlet.rb +1 -0
  87. data/lib/mechanize/test_case/referer_servlet.rb +1 -0
  88. data/lib/mechanize/test_case/refresh_with_empty_url.rb +1 -0
  89. data/lib/mechanize/test_case/refresh_without_url.rb +1 -0
  90. data/lib/mechanize/test_case/response_code_servlet.rb +1 -0
  91. data/lib/mechanize/test_case/robots_txt_servlet.rb +1 -0
  92. data/lib/mechanize/test_case/send_cookies_servlet.rb +1 -0
  93. data/lib/mechanize/test_case/server.rb +1 -0
  94. data/lib/mechanize/test_case/servlets.rb +1 -0
  95. data/lib/mechanize/test_case/verb_servlet.rb +5 -6
  96. data/lib/mechanize/unauthorized_error.rb +1 -0
  97. data/lib/mechanize/unsupported_scheme_error.rb +1 -0
  98. data/lib/mechanize/util.rb +2 -1
  99. data/lib/mechanize/version.rb +2 -1
  100. data/lib/mechanize/xml_file.rb +1 -0
  101. data/mechanize.gemspec +45 -35
  102. data/test/htdocs/dir with spaces/foo.html +1 -0
  103. data/test/htdocs/tc_links.html +1 -1
  104. data/test/test_mechanize.rb +19 -7
  105. data/test/test_mechanize_cookie.rb +19 -19
  106. data/test/test_mechanize_cookie_jar.rb +85 -53
  107. data/test/test_mechanize_download.rb +13 -1
  108. data/test/test_mechanize_file.rb +10 -0
  109. data/test/test_mechanize_file_connection.rb +21 -3
  110. data/test/test_mechanize_file_response.rb +25 -1
  111. data/test/test_mechanize_form.rb +12 -0
  112. data/test/test_mechanize_form_keygen.rb +1 -0
  113. data/test/test_mechanize_http_agent.rb +53 -8
  114. data/test/test_mechanize_http_content_disposition_parser.rb +27 -0
  115. data/test/test_mechanize_link.rb +24 -0
  116. data/test/test_mechanize_page_encoding.rb +28 -1
  117. metadata +117 -71
  118. data/.travis.yml +0 -36
  119. data/README.rdoc +0 -77
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class Mechanize::Form::Hidden < Mechanize::Form::Field
2
3
  end
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  ##
2
3
  # This class represents an image button in a form. Use the x and y methods to
3
4
  # set the x and y positions for where the mouse "clicked".
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  ##
2
3
  # This class represents a keygen (public / private key generator) found in a
3
4
  # Form. The field will automatically generate a key pair and compute its own
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  ##
2
3
  # This class represents a select list where multiple values can be selected.
3
4
  # MultiSelectList#value= accepts an array, and those values are used as
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  ##
2
3
  # This class contains an option found within SelectList. A SelectList can
3
4
  # have many Option classes associated with it. An option can be selected by
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  ##
2
3
  # This class represents a radio button found in a Form. To activate the
3
4
  # RadioButton in the Form, set the checked method to true.
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class Mechanize::Form::Reset < Mechanize::Form::Button
2
3
  end
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  # This class represents a select list or drop down box in a Form. Set the
2
3
  # value for the list by calling SelectList#value=. SelectList contains a list
3
4
  # of Option that were found. After finding the correct option, set the select
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class Mechanize::Form::Submit < Mechanize::Form::Button
2
3
  end
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class Mechanize::Form::Text < Mechanize::Form::Field
2
3
  end
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class Mechanize::Form::Textarea < Mechanize::Form::Field
2
3
  end
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class Mechanize::Headers < Hash
2
3
  def [](key)
3
4
  super(key.downcase)
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  ##
2
3
  # This class manages history for your mechanize object.
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  ##
2
3
  # Mechanize::HTTP contains classes for communicated with HTTP servers. All
3
4
  # API under this namespace is considered private and is subject to change at
@@ -1,6 +1,6 @@
1
+ # frozen_string_literal: true
1
2
  require 'tempfile'
2
3
  require 'net/ntlm'
3
- require 'kconv'
4
4
  require 'webrobots'
5
5
 
6
6
  ##
@@ -9,6 +9,9 @@ require 'webrobots'
9
9
 
10
10
  class Mechanize::HTTP::Agent
11
11
 
12
+ CREDENTIAL_HEADERS = ['Authorization', 'Cookie']
13
+ POST_HEADERS = ['Content-Length', 'Content-MD5', 'Content-Type']
14
+
12
15
  # :section: Headers
13
16
 
14
17
  # Disables If-Modified-Since conditional requests (enabled by default)
@@ -838,7 +841,7 @@ class Mechanize::HTTP::Agent
838
841
 
839
842
  out_io
840
843
  rescue Zlib::Error => e
841
- message = "error handling content-encoding #{response['Content-Encoding']}:"
844
+ message = String.new("error handling content-encoding #{response['Content-Encoding']}:")
842
845
  message << " #{e.message} (#{e.class})"
843
846
  raise Mechanize::Error, message
844
847
  ensure
@@ -986,14 +989,20 @@ class Mechanize::HTTP::Agent
986
989
 
987
990
  redirect_method = method == :head ? :head : :get
988
991
 
992
+ new_uri = secure_resolve!(response['Location'].to_s, page)
993
+ @history.push(page, page.uri)
994
+
989
995
  # Make sure we are not copying over the POST headers from the original request
990
- ['Content-Length', 'Content-MD5', 'Content-Type'].each do |key|
991
- headers.delete key
996
+ POST_HEADERS.each do |key|
997
+ headers.delete_if { |h| h.casecmp?(key) }
992
998
  end
993
999
 
994
- new_uri = secure_resolve! response['Location'].to_s, page
995
-
996
- @history.push(page, page.uri)
1000
+ # Make sure we clear credential headers if being redirected to another site
1001
+ if new_uri.host != page.uri.host
1002
+ CREDENTIAL_HEADERS.each do |ch|
1003
+ headers.delete_if { |h| h.casecmp?(ch) }
1004
+ end
1005
+ end
997
1006
 
998
1007
  fetch new_uri, redirect_method, headers, [], referer, redirects + 1
999
1008
  end
@@ -1278,4 +1287,3 @@ class Mechanize::HTTP::Agent
1278
1287
  end
1279
1288
 
1280
1289
  require 'mechanize/http/auth_store'
1281
-
@@ -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.
@@ -103,9 +104,9 @@ class Mechanize::Page < Mechanize::File
103
104
  parser = self.parser unless parser
104
105
  return false if parser.errors.empty?
105
106
  parser.errors.any? do |error|
106
- error.message =~ /(indicate\ encoding)|
107
- (Invalid\ char)|
108
- (input\ conversion\ failed)/x
107
+ error.message.scrub =~ /(indicate\ encoding)|
108
+ (Invalid\ char)|
109
+ (input\ conversion\ failed)/x
109
110
  end
110
111
  end
111
112
 
@@ -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'
@@ -230,9 +235,9 @@ class Net::HTTP # :nodoc:
230
235
  else
231
236
  filename = "htdocs#{path.gsub(/[^\/\\.\w\s]/, '_')}"
232
237
  unless PAGE_CACHE[filename]
233
- open("#{Mechanize::TestCase::TEST_DIR}/#{filename}", 'rb') { |io|
238
+ ::File.open("#{Mechanize::TestCase::TEST_DIR}/#{filename}", 'rb') do |io|
234
239
  PAGE_CACHE[filename] = io.read
235
- }
240
+ end
236
241
  end
237
242
 
238
243
  res.body = PAGE_CACHE[filename]
@@ -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 = []