httpclient 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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