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.
- data.tar.gz.sig +0 -0
- data/CHANGELOG.rdoc +82 -0
- data/EXAMPLES.rdoc +1 -1
- data/FAQ.rdoc +9 -9
- data/Manifest.txt +35 -48
- data/README.rdoc +2 -1
- data/Rakefile +16 -3
- data/lib/mechanize.rb +809 -392
- data/lib/mechanize/content_type_error.rb +10 -11
- data/lib/mechanize/cookie.rb +193 -60
- data/lib/mechanize/cookie_jar.rb +39 -86
- data/lib/mechanize/download.rb +59 -0
- data/lib/mechanize/element_matcher.rb +1 -0
- data/lib/mechanize/file.rb +61 -76
- data/lib/mechanize/file_saver.rb +37 -35
- data/lib/mechanize/form.rb +475 -410
- data/lib/mechanize/form/button.rb +4 -7
- data/lib/mechanize/form/check_box.rb +10 -9
- data/lib/mechanize/form/field.rb +52 -42
- data/lib/mechanize/form/file_upload.rb +17 -19
- data/lib/mechanize/form/hidden.rb +3 -0
- data/lib/mechanize/form/image_button.rb +15 -16
- data/lib/mechanize/form/keygen.rb +34 -0
- data/lib/mechanize/form/multi_select_list.rb +20 -9
- data/lib/mechanize/form/option.rb +48 -47
- data/lib/mechanize/form/radio_button.rb +52 -45
- data/lib/mechanize/form/reset.rb +3 -0
- data/lib/mechanize/form/select_list.rb +10 -6
- data/lib/mechanize/form/submit.rb +3 -0
- data/lib/mechanize/form/text.rb +3 -0
- data/lib/mechanize/form/textarea.rb +3 -0
- data/lib/mechanize/headers.rb +17 -19
- data/lib/mechanize/history.rb +60 -61
- data/lib/mechanize/http.rb +5 -0
- data/lib/mechanize/http/agent.rb +485 -218
- data/lib/mechanize/http/auth_challenge.rb +59 -0
- data/lib/mechanize/http/auth_realm.rb +31 -0
- data/lib/mechanize/http/content_disposition_parser.rb +188 -0
- data/lib/mechanize/http/www_authenticate_parser.rb +155 -0
- data/lib/mechanize/monkey_patch.rb +14 -35
- data/lib/mechanize/page.rb +34 -2
- data/lib/mechanize/page/base.rb +6 -7
- data/lib/mechanize/page/frame.rb +5 -5
- data/lib/mechanize/page/image.rb +23 -23
- data/lib/mechanize/page/label.rb +16 -16
- data/lib/mechanize/page/link.rb +16 -0
- data/lib/mechanize/page/meta_refresh.rb +19 -7
- data/lib/mechanize/parser.rb +173 -0
- data/lib/mechanize/pluggable_parsers.rb +126 -83
- data/lib/mechanize/redirect_limit_reached_error.rb +16 -13
- data/lib/mechanize/redirect_not_get_or_head_error.rb +18 -16
- data/lib/mechanize/response_code_error.rb +16 -17
- data/lib/mechanize/robots_disallowed_error.rb +22 -23
- data/lib/mechanize/test_case.rb +659 -0
- data/lib/mechanize/unauthorized_error.rb +3 -0
- data/lib/mechanize/unsupported_scheme_error.rb +4 -6
- data/lib/mechanize/util.rb +0 -12
- data/test/htdocs/form_order_test.html +11 -0
- data/test/htdocs/form_test.html +2 -2
- data/test/htdocs/tc_links.html +1 -0
- data/test/test_mechanize.rb +367 -59
- data/test/test_mechanize_cookie.rb +69 -4
- data/test/test_mechanize_cookie_jar.rb +200 -124
- data/test/test_mechanize_download.rb +43 -0
- data/test/test_mechanize_file.rb +53 -45
- data/test/{test_mechanize_file_response.rb → test_mechanize_file_connection.rb} +2 -2
- data/test/test_mechanize_file_request.rb +2 -2
- data/test/test_mechanize_file_saver.rb +21 -0
- data/test/test_mechanize_form.rb +345 -46
- data/test/test_mechanize_form_check_box.rb +5 -4
- data/test/test_mechanize_form_encoding.rb +10 -16
- data/test/test_mechanize_form_field.rb +45 -3
- data/test/test_mechanize_form_file_upload.rb +20 -0
- data/test/test_mechanize_form_image_button.rb +2 -2
- data/test/test_mechanize_form_keygen.rb +32 -0
- data/test/test_mechanize_form_multi_select_list.rb +84 -0
- data/test/test_mechanize_form_option.rb +55 -0
- data/test/test_mechanize_form_radio_button.rb +78 -0
- data/test/test_mechanize_form_select_list.rb +76 -0
- data/test/test_mechanize_form_textarea.rb +8 -7
- data/test/{test_headers.rb → test_mechanize_headers.rb} +4 -2
- data/test/test_mechanize_history.rb +103 -0
- data/test/test_mechanize_http_agent.rb +525 -17
- data/test/test_mechanize_http_auth_challenge.rb +39 -0
- data/test/test_mechanize_http_auth_realm.rb +49 -0
- data/test/test_mechanize_http_content_disposition_parser.rb +118 -0
- data/test/test_mechanize_http_www_authenticate_parser.rb +146 -0
- data/test/test_mechanize_link.rb +10 -14
- data/test/test_mechanize_page.rb +118 -0
- data/test/test_mechanize_page_encoding.rb +48 -13
- data/test/test_mechanize_page_frame.rb +16 -0
- data/test/test_mechanize_page_link.rb +27 -19
- data/test/test_mechanize_page_meta_refresh.rb +26 -14
- data/test/test_mechanize_parser.rb +289 -0
- data/test/test_mechanize_pluggable_parser.rb +52 -0
- data/test/test_mechanize_redirect_limit_reached_error.rb +24 -0
- data/test/test_mechanize_redirect_not_get_or_head_error.rb +3 -7
- data/test/test_mechanize_subclass.rb +2 -2
- data/test/test_mechanize_util.rb +24 -13
- data/test/test_multi_select.rb +23 -22
- metadata +145 -114
- metadata.gz.sig +0 -0
- data/lib/mechanize/inspect.rb +0 -88
- data/test/helper.rb +0 -175
- data/test/htdocs/form_select_all.html +0 -16
- data/test/htdocs/form_select_none.html +0 -17
- data/test/htdocs/form_select_noopts.html +0 -10
- data/test/htdocs/iframe_test.html +0 -16
- data/test/htdocs/nofollow.html +0 -9
- data/test/htdocs/norobots.html +0 -8
- data/test/htdocs/rel_nofollow.html +0 -8
- data/test/htdocs/tc_base_images.html +0 -10
- data/test/htdocs/tc_images.html +0 -8
- data/test/htdocs/tc_no_attributes.html +0 -16
- data/test/htdocs/tc_radiobuttons.html +0 -17
- data/test/htdocs/test_bad_encoding.html +0 -52
- data/test/servlets.rb +0 -402
- data/test/ssl_server.rb +0 -48
- data/test/test_cookies.rb +0 -129
- data/test/test_form_action.rb +0 -52
- data/test/test_form_as_hash.rb +0 -59
- data/test/test_form_button.rb +0 -46
- data/test/test_frames.rb +0 -34
- data/test/test_history.rb +0 -118
- data/test/test_history_added.rb +0 -16
- data/test/test_html_unscape_forms.rb +0 -46
- data/test/test_if_modified_since.rb +0 -20
- data/test/test_images.rb +0 -19
- data/test/test_no_attributes.rb +0 -13
- data/test/test_option.rb +0 -18
- data/test/test_pluggable_parser.rb +0 -136
- data/test/test_post_form.rb +0 -37
- data/test/test_pretty_print.rb +0 -22
- data/test/test_radiobutton.rb +0 -75
- data/test/test_redirect_limit_reached.rb +0 -39
- data/test/test_referer.rb +0 -81
- data/test/test_relative_links.rb +0 -40
- data/test/test_request.rb +0 -13
- data/test/test_response_code.rb +0 -53
- data/test/test_robots.rb +0 -72
- data/test/test_save_file.rb +0 -48
- data/test/test_scheme.rb +0 -48
- data/test/test_select.rb +0 -119
- data/test/test_select_all.rb +0 -15
- data/test/test_select_none.rb +0 -15
- data/test/test_select_noopts.rb +0 -18
- data/test/test_set_fields.rb +0 -44
- data/test/test_ssl_server.rb +0 -20
@@ -1,14 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
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
|
-
|
11
|
-
|
12
|
-
|
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
|
+
|
data/lib/mechanize/cookie.rb
CHANGED
@@ -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
|
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
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
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
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
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
|
-
|
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
|
data/lib/mechanize/cookie_jar.rb
CHANGED
@@ -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
|
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
|
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
|
-
|
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
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
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
|
61
|
+
def each
|
62
|
+
block_given? or return enum_for(__method__)
|
65
63
|
cleanup
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
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
|
-
|
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(
|
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
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
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
|
|