mechanize 2.0.1 → 2.1.pre.1

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 (148) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG.rdoc +82 -0
  3. data/EXAMPLES.rdoc +1 -1
  4. data/FAQ.rdoc +9 -9
  5. data/Manifest.txt +35 -48
  6. data/README.rdoc +2 -1
  7. data/Rakefile +16 -3
  8. data/lib/mechanize.rb +809 -392
  9. data/lib/mechanize/content_type_error.rb +10 -11
  10. data/lib/mechanize/cookie.rb +193 -60
  11. data/lib/mechanize/cookie_jar.rb +39 -86
  12. data/lib/mechanize/download.rb +59 -0
  13. data/lib/mechanize/element_matcher.rb +1 -0
  14. data/lib/mechanize/file.rb +61 -76
  15. data/lib/mechanize/file_saver.rb +37 -35
  16. data/lib/mechanize/form.rb +475 -410
  17. data/lib/mechanize/form/button.rb +4 -7
  18. data/lib/mechanize/form/check_box.rb +10 -9
  19. data/lib/mechanize/form/field.rb +52 -42
  20. data/lib/mechanize/form/file_upload.rb +17 -19
  21. data/lib/mechanize/form/hidden.rb +3 -0
  22. data/lib/mechanize/form/image_button.rb +15 -16
  23. data/lib/mechanize/form/keygen.rb +34 -0
  24. data/lib/mechanize/form/multi_select_list.rb +20 -9
  25. data/lib/mechanize/form/option.rb +48 -47
  26. data/lib/mechanize/form/radio_button.rb +52 -45
  27. data/lib/mechanize/form/reset.rb +3 -0
  28. data/lib/mechanize/form/select_list.rb +10 -6
  29. data/lib/mechanize/form/submit.rb +3 -0
  30. data/lib/mechanize/form/text.rb +3 -0
  31. data/lib/mechanize/form/textarea.rb +3 -0
  32. data/lib/mechanize/headers.rb +17 -19
  33. data/lib/mechanize/history.rb +60 -61
  34. data/lib/mechanize/http.rb +5 -0
  35. data/lib/mechanize/http/agent.rb +485 -218
  36. data/lib/mechanize/http/auth_challenge.rb +59 -0
  37. data/lib/mechanize/http/auth_realm.rb +31 -0
  38. data/lib/mechanize/http/content_disposition_parser.rb +188 -0
  39. data/lib/mechanize/http/www_authenticate_parser.rb +155 -0
  40. data/lib/mechanize/monkey_patch.rb +14 -35
  41. data/lib/mechanize/page.rb +34 -2
  42. data/lib/mechanize/page/base.rb +6 -7
  43. data/lib/mechanize/page/frame.rb +5 -5
  44. data/lib/mechanize/page/image.rb +23 -23
  45. data/lib/mechanize/page/label.rb +16 -16
  46. data/lib/mechanize/page/link.rb +16 -0
  47. data/lib/mechanize/page/meta_refresh.rb +19 -7
  48. data/lib/mechanize/parser.rb +173 -0
  49. data/lib/mechanize/pluggable_parsers.rb +126 -83
  50. data/lib/mechanize/redirect_limit_reached_error.rb +16 -13
  51. data/lib/mechanize/redirect_not_get_or_head_error.rb +18 -16
  52. data/lib/mechanize/response_code_error.rb +16 -17
  53. data/lib/mechanize/robots_disallowed_error.rb +22 -23
  54. data/lib/mechanize/test_case.rb +659 -0
  55. data/lib/mechanize/unauthorized_error.rb +3 -0
  56. data/lib/mechanize/unsupported_scheme_error.rb +4 -6
  57. data/lib/mechanize/util.rb +0 -12
  58. data/test/htdocs/form_order_test.html +11 -0
  59. data/test/htdocs/form_test.html +2 -2
  60. data/test/htdocs/tc_links.html +1 -0
  61. data/test/test_mechanize.rb +367 -59
  62. data/test/test_mechanize_cookie.rb +69 -4
  63. data/test/test_mechanize_cookie_jar.rb +200 -124
  64. data/test/test_mechanize_download.rb +43 -0
  65. data/test/test_mechanize_file.rb +53 -45
  66. data/test/{test_mechanize_file_response.rb → test_mechanize_file_connection.rb} +2 -2
  67. data/test/test_mechanize_file_request.rb +2 -2
  68. data/test/test_mechanize_file_saver.rb +21 -0
  69. data/test/test_mechanize_form.rb +345 -46
  70. data/test/test_mechanize_form_check_box.rb +5 -4
  71. data/test/test_mechanize_form_encoding.rb +10 -16
  72. data/test/test_mechanize_form_field.rb +45 -3
  73. data/test/test_mechanize_form_file_upload.rb +20 -0
  74. data/test/test_mechanize_form_image_button.rb +2 -2
  75. data/test/test_mechanize_form_keygen.rb +32 -0
  76. data/test/test_mechanize_form_multi_select_list.rb +84 -0
  77. data/test/test_mechanize_form_option.rb +55 -0
  78. data/test/test_mechanize_form_radio_button.rb +78 -0
  79. data/test/test_mechanize_form_select_list.rb +76 -0
  80. data/test/test_mechanize_form_textarea.rb +8 -7
  81. data/test/{test_headers.rb → test_mechanize_headers.rb} +4 -2
  82. data/test/test_mechanize_history.rb +103 -0
  83. data/test/test_mechanize_http_agent.rb +525 -17
  84. data/test/test_mechanize_http_auth_challenge.rb +39 -0
  85. data/test/test_mechanize_http_auth_realm.rb +49 -0
  86. data/test/test_mechanize_http_content_disposition_parser.rb +118 -0
  87. data/test/test_mechanize_http_www_authenticate_parser.rb +146 -0
  88. data/test/test_mechanize_link.rb +10 -14
  89. data/test/test_mechanize_page.rb +118 -0
  90. data/test/test_mechanize_page_encoding.rb +48 -13
  91. data/test/test_mechanize_page_frame.rb +16 -0
  92. data/test/test_mechanize_page_link.rb +27 -19
  93. data/test/test_mechanize_page_meta_refresh.rb +26 -14
  94. data/test/test_mechanize_parser.rb +289 -0
  95. data/test/test_mechanize_pluggable_parser.rb +52 -0
  96. data/test/test_mechanize_redirect_limit_reached_error.rb +24 -0
  97. data/test/test_mechanize_redirect_not_get_or_head_error.rb +3 -7
  98. data/test/test_mechanize_subclass.rb +2 -2
  99. data/test/test_mechanize_util.rb +24 -13
  100. data/test/test_multi_select.rb +23 -22
  101. metadata +145 -114
  102. metadata.gz.sig +0 -0
  103. data/lib/mechanize/inspect.rb +0 -88
  104. data/test/helper.rb +0 -175
  105. data/test/htdocs/form_select_all.html +0 -16
  106. data/test/htdocs/form_select_none.html +0 -17
  107. data/test/htdocs/form_select_noopts.html +0 -10
  108. data/test/htdocs/iframe_test.html +0 -16
  109. data/test/htdocs/nofollow.html +0 -9
  110. data/test/htdocs/norobots.html +0 -8
  111. data/test/htdocs/rel_nofollow.html +0 -8
  112. data/test/htdocs/tc_base_images.html +0 -10
  113. data/test/htdocs/tc_images.html +0 -8
  114. data/test/htdocs/tc_no_attributes.html +0 -16
  115. data/test/htdocs/tc_radiobuttons.html +0 -17
  116. data/test/htdocs/test_bad_encoding.html +0 -52
  117. data/test/servlets.rb +0 -402
  118. data/test/ssl_server.rb +0 -48
  119. data/test/test_cookies.rb +0 -129
  120. data/test/test_form_action.rb +0 -52
  121. data/test/test_form_as_hash.rb +0 -59
  122. data/test/test_form_button.rb +0 -46
  123. data/test/test_frames.rb +0 -34
  124. data/test/test_history.rb +0 -118
  125. data/test/test_history_added.rb +0 -16
  126. data/test/test_html_unscape_forms.rb +0 -46
  127. data/test/test_if_modified_since.rb +0 -20
  128. data/test/test_images.rb +0 -19
  129. data/test/test_no_attributes.rb +0 -13
  130. data/test/test_option.rb +0 -18
  131. data/test/test_pluggable_parser.rb +0 -136
  132. data/test/test_post_form.rb +0 -37
  133. data/test/test_pretty_print.rb +0 -22
  134. data/test/test_radiobutton.rb +0 -75
  135. data/test/test_redirect_limit_reached.rb +0 -39
  136. data/test/test_referer.rb +0 -81
  137. data/test/test_relative_links.rb +0 -40
  138. data/test/test_request.rb +0 -13
  139. data/test/test_response_code.rb +0 -53
  140. data/test/test_robots.rb +0 -72
  141. data/test/test_save_file.rb +0 -48
  142. data/test/test_scheme.rb +0 -48
  143. data/test/test_select.rb +0 -119
  144. data/test/test_select_all.rb +0 -15
  145. data/test/test_select_none.rb +0 -15
  146. data/test/test_select_noopts.rb +0 -18
  147. data/test/test_set_fields.rb +0 -44
  148. data/test/test_ssl_server.rb +0 -20
@@ -1,14 +1,13 @@
1
- class Mechanize
2
- # =Synopsis
3
- # This class contains an error for when a pluggable parser tries to
4
- # parse a content type that it does not know how to handle. For example
5
- # if Mechanize::Page were to try to parse a PDF, a ContentTypeError
6
- # would be thrown.
7
- class ContentTypeError < Mechanize::Error
8
- attr_reader :content_type
1
+ ##
2
+ # This error is raised when a pluggable parser tries to parse a content type
3
+ # that it does not know how to handle. For example if Mechanize::Page were to
4
+ # try to parse a PDF, a ContentTypeError would be thrown.
9
5
 
10
- def initialize(content_type)
11
- @content_type = content_type
12
- end
6
+ class Mechanize::ContentTypeError < Mechanize::Error
7
+ attr_reader :content_type
8
+
9
+ def initialize(content_type)
10
+ @content_type = content_type
13
11
  end
14
12
  end
13
+
@@ -1,77 +1,170 @@
1
1
  require 'time'
2
2
  require 'webrick/cookie'
3
+ require 'domain_name'
3
4
 
4
5
  # This class is used to represent an HTTP Cookie.
5
- class Mechanize::Cookie < WEBrick::Cookie
6
+ class Mechanize::Cookie
7
+ attr_reader :name
8
+ attr_accessor :value, :version
9
+ attr_accessor :domain, :path, :secure
10
+ attr_accessor :comment, :max_age
6
11
 
7
12
  attr_accessor :session
8
13
 
9
- def self.parse(uri, str, log = Mechanize.log)
10
- return str.split(/,(?=[^;,]*=)|,$/).map { |c|
11
- cookie_elem = c.split(/;+/)
12
- first_elem = cookie_elem.shift
13
- first_elem.strip!
14
- key, value = first_elem.split(/\=/, 2)
15
-
16
- cookie = nil
17
- begin
18
- cookie = new(key, value.dup)
19
- rescue
20
- log.warn("Couldn't parse key/value: #{first_elem}") if log
14
+ attr_accessor :created_at
15
+ attr_accessor :accessed_at
16
+
17
+ # :call-seq:
18
+ # new(name, value)
19
+ # new(name, value, attr_hash)
20
+ # new(attr_hash)
21
+ #
22
+ # Creates a cookie object. For each key of +attr_hash+, the setter
23
+ # is called if defined. Each key can be either a symbol or a
24
+ # string, downcased or not.
25
+ #
26
+ # e.g.
27
+ # new("uid", "a12345")
28
+ # new("uid", "a12345", :domain => 'example.org',
29
+ # :for_domain => true, :expired => Time.now + 7*86400)
30
+ # new("name" => "uid", "value" => "a12345", "Domain" => 'www.example.org')
31
+ #
32
+ def initialize(*args)
33
+ @version = 0 # Netscape Cookie
34
+
35
+ @domain = @path = @secure = @comment = @max_age =
36
+ @expires = @comment_url = @discard = @port = nil
37
+
38
+ @created_at = @accessed_at = Time.now
39
+ case args.size
40
+ when 2
41
+ @name, @value = *args
42
+ @for_domain = false
43
+ return
44
+ when 3
45
+ @name, @value, attr_hash = *args
46
+ when 1
47
+ attr_hash = args.first
48
+ else
49
+ raise ArgumentError, "wrong number of arguments (#{args.size} for 1-3)"
50
+ end
51
+ for_domain = false
52
+ attr_hash.each_pair { |key, val|
53
+ skey = key.to_s.downcase
54
+ skey.sub!(/[!?]\z/, '')
55
+ case skey
56
+ when 'for_domain'
57
+ for_domain = !!val
58
+ when 'name'
59
+ @name = val
60
+ when 'value'
61
+ @value = val
62
+ else
63
+ setter = :"#{skey}="
64
+ send(setter, val) if respond_to?(setter)
21
65
  end
66
+ }
67
+ @for_domain = for_domain
68
+ end
22
69
 
23
- next unless cookie
24
-
25
- cookie_elem.each do |pair|
26
- pair.strip!
27
- key, value = pair.split(/\=/, 2)
28
- next unless key
29
- value = WEBrick::HTTPUtils.dequote(value.strip) if value
30
-
31
- case key.downcase
32
- when "domain" then
33
- value = ".#{value}" unless value =~ /^\./
34
- cookie.domain = value
35
- when "path" then
36
- cookie.path = value
37
- when 'expires'
38
- if value.empty? then
39
- cookie.session = true
40
- next
41
- end
70
+ # If this flag is true, this cookie will be sent to any host in the
71
+ # +domain+. If it is false, this cookie will be sent only to the
72
+ # host indicated by the +domain+.
73
+ attr_accessor :for_domain
74
+ alias for_domain? for_domain
42
75
 
43
- begin
44
- cookie.expires = Time::parse(value)
45
- rescue
46
- log.warn("Couldn't parse expires: #{value}") if log
47
- end
48
- when "max-age" then
49
- begin
50
- cookie.max_age = Integer(value)
51
- rescue
52
- log.warn("Couldn't parse max age '#{value}'") if log
53
- cookie.max_age = nil
54
- end
55
- when "comment" then cookie.comment = value
56
- when "version" then
57
- begin
58
- cookie.version = Integer(value)
59
- rescue
60
- log.warn("Couldn't parse version '#{value}'") if log
61
- cookie.version = nil
76
+ class << self
77
+ def parse(uri, str, log = Mechanize.log)
78
+ return str.split(/,(?=[^;,]*=)|,$/).map { |c|
79
+ cookie_elem = c.split(/;+/)
80
+ first_elem = cookie_elem.shift
81
+ first_elem.strip!
82
+ key, value = first_elem.split(/\=/, 2)
83
+
84
+ begin
85
+ cookie = new(key, value.dup)
86
+ rescue
87
+ log.warn("Couldn't parse key/value: #{first_elem}") if log
88
+ next
89
+ end
90
+
91
+ cookie_elem.each do |pair|
92
+ pair.strip!
93
+ key, value = pair.split(/\=/, 2)
94
+ next unless key
95
+ value = WEBrick::HTTPUtils.dequote(value.strip) if value
96
+
97
+ case key.downcase
98
+ when 'domain'
99
+ cookie.domain = value
100
+ cookie.for_domain = true
101
+ when 'path'
102
+ cookie.path = value
103
+ when 'expires'
104
+ if value.empty?
105
+ cookie.session = true
106
+ next
107
+ end
108
+
109
+ begin
110
+ cookie.expires = Time::parse(value)
111
+ rescue
112
+ log.warn("Couldn't parse expires: #{value}") if log
113
+ end
114
+ when 'max-age'
115
+ begin
116
+ cookie.max_age = Integer(value)
117
+ rescue
118
+ log.warn("Couldn't parse max age '#{value}'") if log
119
+ end
120
+ when 'comment'
121
+ cookie.comment = value
122
+ when 'version'
123
+ begin
124
+ cookie.version = Integer(value)
125
+ rescue
126
+ log.warn("Couldn't parse version '#{value}'") if log
127
+ cookie.version = nil
128
+ end
129
+ when 'secure'
130
+ cookie.secure = true
62
131
  end
63
- when "secure" then cookie.secure = true
64
132
  end
65
- end
66
133
 
67
- cookie.path ||= uri.path.to_s.sub(%r%[^/]*$%, '')
68
- cookie.secure ||= false
69
- cookie.domain ||= uri.host
70
- # Move this in to the cookie jar
71
- yield cookie if block_given?
134
+ cookie.path ||= (uri + './').path
135
+ cookie.secure ||= false
136
+ cookie.domain ||= uri.host
137
+ # Move this in to the cookie jar
138
+ yield cookie if block_given?
72
139
 
73
- cookie
74
- }
140
+ cookie
141
+ }
142
+ end
143
+ end
144
+
145
+ alias set_domain domain=
146
+
147
+ # Sets the domain attribute. A leading dot in +domain+ implies
148
+ # turning the +for_domain?+ flag on.
149
+ def domain=(domain)
150
+ if domain.start_with?('.')
151
+ @for_domain = true
152
+ domain = domain[1..-1]
153
+ end
154
+ # Do we really need to support this?
155
+ if domain.match(/\A([^:]+):[0-9]+\z/)
156
+ domain = $1
157
+ end
158
+ @domain_name = DomainName.new(domain)
159
+ set_domain(@domain_name.hostname)
160
+ end
161
+
162
+ def expires=(t)
163
+ @expires = t && (t.is_a?(Time) ? t.httpdate : t.to_s)
164
+ end
165
+
166
+ def expires
167
+ @expires && Time.parse(@expires)
75
168
  end
76
169
 
77
170
  def expired?
@@ -79,7 +172,47 @@ class Mechanize::Cookie < WEBrick::Cookie
79
172
  Time.now > expires
80
173
  end
81
174
 
175
+ alias secure? secure
176
+
177
+ def acceptable_from_uri?(uri)
178
+ host = DomainName.new(uri.host)
179
+
180
+ # RFC 6265 5.3
181
+ # When the user agent "receives a cookie":
182
+ return host.hostname == domain unless @for_domain
183
+
184
+ if host.cookie_domain?(@domain_name)
185
+ true
186
+ elsif host.hostname == domain
187
+ @for_domain = false
188
+ true
189
+ else
190
+ false
191
+ end
192
+ end
193
+
194
+ def valid_for_uri?(uri)
195
+ return false if secure? && uri.scheme != 'https'
196
+ acceptable_from_uri?(uri) && uri.path.start_with?(path)
197
+ end
198
+
82
199
  def to_s
83
200
  "#{@name}=#{@value}"
84
201
  end
202
+
203
+ def init_with(coder)
204
+ yaml_initialize(coder.tag, coder.map)
205
+ end
206
+
207
+ def yaml_initialize(tag, map)
208
+ @for_domain = true # for forward compatibility
209
+ map.each { |key, value|
210
+ case key
211
+ when 'domain'
212
+ self.domain = value # ditto
213
+ else
214
+ instance_variable_set(:"@#{key}", value)
215
+ end
216
+ }
217
+ end
85
218
  end
@@ -3,11 +3,10 @@
3
3
  # any particular website.
4
4
 
5
5
  class Mechanize::CookieJar
6
+ include Enumerable
6
7
 
7
8
  # add_cookie wants something resembling a URI.
8
9
 
9
- FakeURI = Struct.new(:host) # :nodoc:
10
-
11
10
  attr_reader :jar
12
11
 
13
12
  def initialize
@@ -18,10 +17,17 @@ class Mechanize::CookieJar
18
17
  @jar = Marshal.load Marshal.dump other.jar
19
18
  end
20
19
 
21
- # Add a cookie to the Jar.
20
+ # Add a +cookie+ to the jar if it is considered acceptable from
21
+ # +uri+. Return nil if the cookie was not added, otherwise return
22
+ # the cookie added.
22
23
  def add(uri, cookie)
23
- return unless valid_cookie_for_uri?(uri, cookie)
24
+ return nil unless cookie.acceptable_from_uri?(uri)
25
+ add!(cookie)
26
+ cookie
27
+ end
24
28
 
29
+ # Add a +cookie+ to the jar and return self.
30
+ def add!(cookie)
25
31
  normal_domain = cookie.domain.downcase
26
32
 
27
33
  @jar[normal_domain] ||= {} unless @jar.has_key?(normal_domain)
@@ -29,46 +35,39 @@ class Mechanize::CookieJar
29
35
  @jar[normal_domain][cookie.path] ||= {}
30
36
  @jar[normal_domain][cookie.path][cookie.name] = cookie
31
37
 
32
- cookie
38
+ self
33
39
  end
40
+ alias << add!
34
41
 
35
42
  # Fetch the cookies that should be used for the URI object passed in.
36
43
  def cookies(url)
37
44
  cleanup
38
45
  url.path = '/' if url.path.empty?
46
+ now = Time.now
39
47
 
40
- domains = @jar.find_all { |domain, _|
41
- cookie_domain = self.class.strip_port(domain)
42
- if cookie_domain.start_with?('.')
43
- url.host =~ /#{Regexp.escape cookie_domain}$/i
44
- else
45
- url.host =~ /^#{Regexp.escape cookie_domain}$/i
46
- end
48
+ select { |cookie|
49
+ !cookie.expired? && cookie.valid_for_uri?(url) && (cookie.accessed_at = now)
50
+ }.sort_by { |cookie|
51
+ # RFC 6265 5.4
52
+ # Precedence: 1. longer path 2. older creation
53
+ [-cookie.path.length, cookie.created_at]
47
54
  }
48
-
49
- return [] unless domains.length > 0
50
-
51
- cookies = domains.map { |_,paths|
52
- paths.find_all { |path, _|
53
- url.path =~ /^#{Regexp.escape(path)}/
54
- }.map { |_,cookie| cookie.values }
55
- }.flatten
56
-
57
- cookies.find_all { |cookie| ! cookie.expired? }
58
55
  end
59
56
 
60
57
  def empty?(url)
61
58
  cookies(url).length > 0 ? false : true
62
59
  end
63
60
 
64
- def to_a
61
+ def each
62
+ block_given? or return enum_for(__method__)
65
63
  cleanup
66
-
67
- @jar.map do |domain, paths|
68
- paths.map do |path, names|
69
- names.values
70
- end
71
- end.flatten
64
+ @jar.each { |domain, paths|
65
+ paths.each { |path, hash|
66
+ hash.each_value { |cookie|
67
+ yield cookie
68
+ }
69
+ }
70
+ }
72
71
  end
73
72
 
74
73
  # Save the cookie jar to a file in the format specified.
@@ -151,15 +150,13 @@ class Mechanize::CookieJar
151
150
 
152
151
  c = Mechanize::Cookie.new(fields[5], fields[6])
153
152
  c.domain = fields[0]
154
- # Field 1 indicates whether the cookie can be read by other machines at
155
- # the same domain. This is computed by the cookie implementation, based
156
- # on the domain value.
153
+ c.for_domain = (fields[1] == "TRUE") # Whether this cookie is for domain
157
154
  c.path = fields[2] # Path for which the cookie is relevant
158
155
  c.secure = (fields[3] == "TRUE") # Requires a secure connection
159
156
  c.expires = expires # Time the cookie expires.
160
157
  c.version = 0 # Conforms to Netscape cookie spec.
161
158
 
162
- add(FakeURI.new(c.domain), c)
159
+ add!(c)
163
160
  end
164
161
 
165
162
  @jar
@@ -168,58 +165,18 @@ class Mechanize::CookieJar
168
165
  # Write cookies to Mozilla cookies.txt-style IO stream
169
166
  def dump_cookiestxt(io)
170
167
  to_a.each do |cookie|
171
- fields = []
172
- fields[0] = cookie.domain
173
-
174
- if cookie.domain =~ /^\./
175
- fields[1] = "TRUE"
176
- else
177
- fields[1] = "FALSE"
178
- end
179
-
180
- fields[2] = cookie.path
181
-
182
- if cookie.secure == true
183
- fields[3] = "TRUE"
184
- else
185
- fields[3] = "FALSE"
186
- end
187
-
188
- fields[4] = cookie.expires.to_i.to_s
189
-
190
- fields[5] = cookie.name
191
- fields[6] = cookie.value
192
- io.puts(fields.join("\t"))
168
+ io.puts([
169
+ cookie.domain,
170
+ cookie.for_domain? ? "TRUE" : "FALSE",
171
+ cookie.path,
172
+ cookie.secure ? "TRUE" : "FALSE",
173
+ cookie.expires.to_i.to_s,
174
+ cookie.name,
175
+ cookie.value
176
+ ].join("\t"))
193
177
  end
194
178
  end
195
179
 
196
- private
197
- # Determine if the cookie's domain and path are valid for
198
- # the uri.host based on the rules in RFC 2965
199
- def valid_cookie_for_uri?(uri, cookie)
200
- cookie_domain = self.class.strip_port(cookie.domain)
201
-
202
- # reject cookies whose domains do not contain an embedded dot
203
- # cookies for localhost and .local. are exempt from this rule
204
- return false if
205
- cookie_domain !~ /.\../ && cookie_domain !~ /(localhost|\.?local)\.?$/
206
-
207
- cookie_domain = if cookie_domain.start_with? '.' then
208
- ".?#{Regexp.escape cookie_domain[1..-1]}"
209
- else
210
- Regexp.escape cookie_domain
211
- end
212
-
213
- # Permitted: A Set-Cookie for x.foo.com for Domain=.foo.com
214
- # Not Permitted: A Set-Cookie for y.x.foo.com for Domain=.foo.com because
215
- # y.x contains a dot
216
- # Not Permitted: A Set-Cookie for foo.com for Domain=.bar.com
217
- match = uri.host.match(/#{cookie_domain}/i)
218
- return false if match.nil? || match.pre_match =~ /.\../
219
-
220
- true
221
- end
222
-
223
180
  protected
224
181
 
225
182
  # Remove expired cookies
@@ -233,9 +190,5 @@ class Mechanize::CookieJar
233
190
  end
234
191
  end
235
192
  end
236
-
237
- def self.strip_port(host)
238
- host.gsub(/:[0-9]+$/,'')
239
- end
240
193
  end
241
194