barx 0.1.0

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