rubyforge 0.0.1 → 0.1.1

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.
@@ -0,0 +1,538 @@
1
+ # cookie.rb is redistributed file which is originally included in Webagent
2
+ # version 0.6.2 by TAKAHASHI `Maki' Masayoshi. And it contains some bug fixes.
3
+ # You can download the entire package of Webagent from
4
+ # http://www.rubycolor.org/arc/.
5
+
6
+
7
+ # Cookie class
8
+ #
9
+ # I refered to w3m's source to make these classes. Some comments
10
+ # are quoted from it. I'm thanksful for author(s) of it.
11
+ #
12
+ # w3m homepage: http://ei5nazha.yz.yamagata-u.ac.jp/~aito/w3m/eng/
13
+
14
+ require 'uri'
15
+
16
+ class WebAgent
17
+
18
+ module CookieUtils
19
+
20
+ def head_match?(str1, str2)
21
+ str1 == str2[0, str1.length]
22
+ end
23
+
24
+ def tail_match?(str1, str2)
25
+ if str1.length > 0
26
+ str1 == str2[-str1.length..-1].to_s
27
+ else
28
+ true
29
+ end
30
+ end
31
+
32
+ def domain_match(host, domain)
33
+ case domain
34
+ when /\d+\.\d+\.\d+\.\d+/
35
+ return (host == domain)
36
+ when '.'
37
+ return true
38
+ when /^\./
39
+ return tail_match?(domain, host)
40
+ else
41
+ return (host == domain)
42
+ end
43
+ end
44
+
45
+ def total_dot_num(string)
46
+ string.scan(/\./).length()
47
+ end
48
+
49
+ end
50
+
51
+ class Cookie
52
+ include CookieUtils
53
+
54
+ require 'parsedate'
55
+ include ParseDate
56
+
57
+ attr_accessor :name, :value
58
+ attr_accessor :domain, :path
59
+ attr_accessor :expires ## for Netscape Cookie
60
+ attr_accessor :url
61
+ attr_writer :use, :secure, :discard, :domain_orig, :path_orig, :override
62
+
63
+ USE = 1
64
+ SECURE = 2
65
+ DOMAIN = 4
66
+ PATH = 8
67
+ DISCARD = 16
68
+ OVERRIDE = 32
69
+ OVERRIDE_OK = 32
70
+
71
+ def initialize()
72
+ @discard = @use = @secure = @domain_orig = @path_orig = @override = nil
73
+ end
74
+
75
+ def discard?
76
+ @discard
77
+ end
78
+
79
+ def use?
80
+ @use
81
+ end
82
+
83
+ def secure?
84
+ @secure
85
+ end
86
+
87
+ def domain_orig?
88
+ @domain_orig
89
+ end
90
+
91
+ def path_orig?
92
+ @path_orig
93
+ end
94
+
95
+ def override?
96
+ @override
97
+ end
98
+
99
+ def flag
100
+ flg = 0
101
+ flg += USE if @use
102
+ flg += SECURE if @secure
103
+ flg += DOMAIN if @domain_orig
104
+ flg += PATH if @path_orig
105
+ flg += DISCARD if @discard
106
+ flg += OVERRIDE if @override
107
+ flg
108
+ end
109
+
110
+ def set_flag(flag)
111
+ flag = flag.to_i
112
+ @use = true if flag & USE > 0
113
+ @secure = true if flag & SECURE > 0
114
+ @domain_orig = true if flag & DOMAIN > 0
115
+ @path_orig = true if flag & PATH > 0
116
+ @discard = true if flag & DISCARD > 0
117
+ @override = true if flag & OVERRIDE > 0
118
+ end
119
+
120
+ def match?(url)
121
+ domainname = url.host
122
+ if (!domainname ||
123
+ !domain_match(domainname, @domain) ||
124
+ (@path && !head_match?(@path, url.path)) ||
125
+ (@secure && (url.scheme != 'https')) )
126
+ return false
127
+ else
128
+ return true
129
+ end
130
+ end
131
+
132
+ def join_quotedstr(array, sep)
133
+ ret = Array.new()
134
+ old_elem = nil
135
+ array.each{|elem|
136
+ if (elem.scan(/"/).length % 2) == 0
137
+ if old_elem
138
+ old_elem << sep << elem
139
+ else
140
+ ret << elem
141
+ old_elem = nil
142
+ end
143
+ else
144
+ if old_elem
145
+ old_elem << sep << elem
146
+ ret << old_elem
147
+ old_elem = nil
148
+ else
149
+ old_elem = elem.dup
150
+ end
151
+ end
152
+ }
153
+ ret
154
+ end
155
+
156
+ def parse(str, url)
157
+ @url = url
158
+ cookie_elem = str.split(/;/)
159
+ cookie_elem = join_quotedstr(cookie_elem, ';')
160
+ first_elem = cookie_elem.shift
161
+ if first_elem !~ /([^=]*)(\=(.*))?/
162
+ return
163
+ ## raise ArgumentError 'invalid cookie value'
164
+ end
165
+ @name = $1.strip
166
+ @value = $3
167
+ if @value
168
+ if @value =~ /^\s*"(.*)"\s*$/
169
+ @value = $1
170
+ else
171
+ @value.dup.strip!
172
+ end
173
+ end
174
+ cookie_elem.each{|pair|
175
+ key, value = pair.split(/=/) ## value may nil
176
+ key.strip!
177
+ if value
178
+ value = value.strip.sub(/\A"(.*)"\z/) { $1 }
179
+ end
180
+ case key.downcase
181
+ when 'domain'
182
+ @domain = value
183
+ when 'expires'
184
+ begin
185
+ @expires = Time.gm(*parsedate(value)[0,6])
186
+ rescue ArgumentError
187
+ @expires = nil
188
+ end
189
+ when 'path'
190
+ @path = value
191
+ when 'secure'
192
+ @secure = true ## value may nil, but must 'true'.
193
+ else
194
+ ## ignore
195
+ end
196
+ }
197
+ end
198
+
199
+ end
200
+
201
+ class CookieManager
202
+ include CookieUtils
203
+
204
+ ### errors
205
+ class Error < StandardError; end
206
+ class ErrorOverrideOK < Error; end
207
+ class SpecialError < Error; end
208
+ class NoDotError < ErrorOverrideOK; end
209
+
210
+ SPECIAL_DOMAIN = [".com",".edu",".gov",".mil",".net",".org",".int"]
211
+
212
+ attr_accessor :cookies
213
+ attr_accessor :cookies_file
214
+ attr_accessor :accept_domains, :reject_domains
215
+ attr_accessor :netscape_rule
216
+
217
+ def initialize(file=nil)
218
+ @cookies = Array.new()
219
+ @cookies_file = file
220
+ @is_saved = true
221
+ @reject_domains = Array.new()
222
+ @accept_domains = Array.new()
223
+ # for conformance to http://wp.netscape.com/newsref/std/cookie_spec.html
224
+ @netscape_rule = false
225
+ end
226
+
227
+ def save_all_cookies(force = nil, save_unused = true, save_discarded = true)
228
+ if @is_saved and !force
229
+ return
230
+ end
231
+ File.open(@cookies_file, 'w') do |f|
232
+ @cookies.each do |cookie|
233
+ if (cookie.use? or save_unused) and
234
+ (!cookie.discard? or save_discarded)
235
+ f.print(cookie.url.to_s,"\t",
236
+ cookie.name,"\t",
237
+ cookie.value,"\t",
238
+ cookie.expires.to_i,"\t",
239
+ cookie.domain,"\t",
240
+ cookie.path,"\t",
241
+ cookie.flag,"\n")
242
+ end
243
+ end
244
+ end
245
+ end
246
+
247
+ def save_cookies(force = nil)
248
+ save_all_cookies(force, false, false)
249
+ end
250
+
251
+ def check_expired_cookies()
252
+ @cookies.reject!{|cookie|
253
+ is_expired = (cookie.expires && (cookie.expires < Time.now.gmtime))
254
+ if is_expired && !cookie.discard?
255
+ @is_saved = false
256
+ end
257
+ is_expired
258
+ }
259
+ end
260
+
261
+ def parse(str, url)
262
+ cookie = WebAgent::Cookie.new()
263
+ cookie.parse(str, url)
264
+ add(cookie)
265
+ end
266
+
267
+ def make_cookie_str(cookie_list)
268
+ if cookie_list.empty?
269
+ return nil
270
+ end
271
+
272
+ ret = ''
273
+ c = cookie_list.shift
274
+ ret += "#{c.name}=#{c.value}"
275
+ cookie_list.each{|cookie|
276
+ ret += "; #{cookie.name}=#{cookie.value}"
277
+ }
278
+ return ret
279
+ end
280
+ private :make_cookie_str
281
+
282
+
283
+ def find(url)
284
+
285
+ check_expired_cookies()
286
+
287
+ cookie_list = Array.new()
288
+
289
+ @cookies.each{|cookie|
290
+ if cookie.use? && cookie.match?(url)
291
+ if cookie_list.select{|c1| c1.name == cookie.name}.empty?
292
+ cookie_list << cookie
293
+ end
294
+ end
295
+ }
296
+ return make_cookie_str(cookie_list)
297
+ end
298
+
299
+ def find_cookie_info(domain, path, name)
300
+ @cookies.find{|c|
301
+ c.domain == domain && c.path == path && c.name == name
302
+ }
303
+ end
304
+ private :find_cookie_info
305
+
306
+ def cookie_error(err, override)
307
+ if err.kind_of?(ErrorOverrideOK) || !override
308
+ raise err
309
+ end
310
+ end
311
+ private :cookie_error
312
+
313
+ def add(cookie)
314
+ url = cookie.url
315
+ name, value = cookie.name, cookie.value
316
+ expires, domain, path =
317
+ cookie.expires, cookie.domain, cookie.path
318
+ secure, domain_orig, path_orig =
319
+ cookie.secure?, cookie.domain_orig?, cookie.path_orig?
320
+ discard, override =
321
+ cookie.discard?, cookie.override?
322
+
323
+ domainname = url.host
324
+ domain_orig, path_orig = domain, path
325
+ use_security = override
326
+
327
+ if !domainname
328
+ cookie_error(NodotError.new(), override)
329
+ end
330
+
331
+ if domain
332
+
333
+ # [DRAFT 12] s. 4.2.2 (does not apply in the case that
334
+ # host name is the same as domain attribute for version 0
335
+ # cookie)
336
+ # I think that this rule has almost the same effect as the
337
+ # tail match of [NETSCAPE].
338
+ if domain !~ /^\./ && domainname != domain
339
+ domain = '.'+domain
340
+ end
341
+
342
+ n = total_dot_num(domain)
343
+ if n < 2
344
+ cookie_error(SpecialError.new(), override)
345
+ elsif @netscape_rule and n == 2
346
+ ## [NETSCAPE] rule
347
+ ok = SPECIAL_DOMAIN.select{|sdomain|
348
+ sdomain == domain[-(sdomain.length)..-1]
349
+ }
350
+ if ok.empty?
351
+ cookie_error(SpecialError.new(), override)
352
+ end
353
+ end
354
+
355
+ end
356
+
357
+ path ||= url.path.sub!(%r|/[^/]*|, '')
358
+ domain ||= domainname
359
+ cookie = find_cookie_info(domain, path, name)
360
+
361
+ if !cookie
362
+ cookie = WebAgent::Cookie.new()
363
+ cookie.use = true
364
+ @cookies << cookie
365
+ end
366
+
367
+ cookie.url = url
368
+ cookie.name = name
369
+ cookie.value = value
370
+ cookie.expires = expires
371
+ cookie.domain = domain
372
+ cookie.path = path
373
+
374
+ ## for flag
375
+ cookie.secure = secure
376
+ cookie.domain_orig = domain_orig
377
+ cookie.path_orig = path_orig
378
+ if discard || cookie.expires == nil
379
+ cookie.discard = true
380
+ else
381
+ cookie.discard = false
382
+ @is_saved = false
383
+ end
384
+
385
+ check_expired_cookies()
386
+ return false
387
+ end
388
+
389
+ def load_cookies()
390
+ return if !File.readable?(@cookies_file)
391
+ File.open(@cookies_file,'r'){|f|
392
+ while line = f.gets
393
+ cookie = WebAgent::Cookie.new()
394
+ @cookies << cookie
395
+ col = line.chomp.split(/\t/)
396
+ cookie.url = URI.parse(col[0])
397
+ cookie.name = col[1]
398
+ cookie.value = col[2]
399
+ cookie.expires = Time.at(col[3].to_i)
400
+ cookie.domain = col[4]
401
+ cookie.path = col[5]
402
+ cookie.set_flag(col[6])
403
+ end
404
+ }
405
+ end
406
+
407
+ def check_cookie_accept_domain(domain)
408
+ unless domain
409
+ return false
410
+ end
411
+ @accept_domains.each{|dom|
412
+ if domain_match(domain, dom)
413
+ return true
414
+ end
415
+ }
416
+ @reject_domains.each{|dom|
417
+ if domain_match(domain, dom)
418
+ return false
419
+ end
420
+ }
421
+ return true
422
+ end
423
+ end
424
+ end
425
+
426
+ __END__
427
+
428
+ =begin
429
+
430
+ == WebAgent::CookieManager Class
431
+
432
+ Load, save, parse and send cookies.
433
+
434
+ === Usage
435
+
436
+ ## initialize
437
+ cm = WebAgent::CookieManager.new("/home/foo/bar/cookie")
438
+
439
+ ## load cookie data
440
+ cm.load_cookies()
441
+
442
+ ## parse cookie from string (maybe "Set-Cookie:" header)
443
+ cm.parse(str)
444
+
445
+ ## send cookie data to url
446
+ f.write(cm.find(url))
447
+
448
+ ## save cookie to cookiefile
449
+ cm.save_cookies()
450
+
451
+
452
+ === Class Methods
453
+
454
+ -- CookieManager::new(file=nil)
455
+
456
+ create new CookieManager. If a file is provided,
457
+ use it as cookies' file.
458
+
459
+ === Methods
460
+
461
+ -- CookieManager#save_cookies(force = nil)
462
+
463
+ save cookies' data into file. if argument is true,
464
+ save data although data is not modified.
465
+
466
+ -- CookieManager#parse(str, url)
467
+
468
+ parse string and store cookie (to parse HTTP response header).
469
+
470
+ -- CookieManager#find(url)
471
+
472
+ get cookies and make into string (to send as HTTP request header).
473
+
474
+ -- CookieManager#add(cookie)
475
+
476
+ add new cookie.
477
+
478
+ -- CookieManager#load_cookies()
479
+
480
+ load cookies' data from file.
481
+
482
+
483
+ == WebAgent::CookieUtils Module
484
+
485
+ -- CookieUtils::head_match?(str1, str2)
486
+ -- CookieUtils::tail_match?(str1, str2)
487
+ -- CookieUtils::domain_match(host, domain)
488
+ -- CookieUtils::total_dot_num(str)
489
+
490
+
491
+ == WebAgent::Cookie Class
492
+
493
+ === Class Methods
494
+
495
+ -- Cookie::new()
496
+
497
+ create new cookie.
498
+
499
+ === Methods
500
+
501
+ -- Cookie#match?(url)
502
+
503
+ match cookie by url. if match, return true. otherwise,
504
+ return false.
505
+
506
+ -- Cookie#name
507
+ -- Cookie#name=(name)
508
+ -- Cookie#value
509
+ -- Cookie#value=(value)
510
+ -- Cookie#domain
511
+ -- Cookie#domain=(domain)
512
+ -- Cookie#path
513
+ -- Cookie#path=(path)
514
+ -- Cookie#expires
515
+ -- Cookie#expires=(expires)
516
+ -- Cookie#url
517
+ -- Cookie#url=(url)
518
+
519
+ accessor methods for cookie's items.
520
+
521
+ -- Cookie#discard?
522
+ -- Cookie#discard=(discard)
523
+ -- Cookie#use?
524
+ -- Cookie#use=(use)
525
+ -- Cookie#secure?
526
+ -- Cookie#secure=(secure)
527
+ -- Cookie#domain_orig?
528
+ -- Cookie#domain_orig=(domain_orig)
529
+ -- Cookie#path_orig?
530
+ -- Cookie#path_orig=(path_orig)
531
+ -- Cookie#override?
532
+ -- Cookie#override=(override)
533
+ -- Cookie#flag
534
+ -- Cookie#set_flag(flag_num)
535
+
536
+ accessor methods for flags.
537
+
538
+ =end