arrow 1.0.7
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.
- data/ChangeLog +1590 -0
- data/LICENSE +28 -0
- data/README +75 -0
- data/Rakefile +366 -0
- data/Rakefile.local +63 -0
- data/data/arrow/applets/TEMPLATE.rb.tpl +53 -0
- data/data/arrow/applets/args.rb +50 -0
- data/data/arrow/applets/config.rb +55 -0
- data/data/arrow/applets/error.rb +63 -0
- data/data/arrow/applets/files.rb +46 -0
- data/data/arrow/applets/inspect.rb +46 -0
- data/data/arrow/applets/nosuchapplet.rb +31 -0
- data/data/arrow/applets/status.rb +92 -0
- data/data/arrow/applets/test.rb +133 -0
- data/data/arrow/applets/tutorial/counter.rb +96 -0
- data/data/arrow/applets/tutorial/dingus.rb +67 -0
- data/data/arrow/applets/tutorial/hello.rb +34 -0
- data/data/arrow/applets/tutorial/hello2.rb +73 -0
- data/data/arrow/applets/tutorial/imgtext.rb +90 -0
- data/data/arrow/applets/tutorial/imgtext2.rb +286 -0
- data/data/arrow/applets/tutorial/index.rb +36 -0
- data/data/arrow/applets/tutorial/logo.rb +98 -0
- data/data/arrow/applets/tutorial/memcache.rb +61 -0
- data/data/arrow/applets/tutorial/missing.rb +37 -0
- data/data/arrow/applets/tutorial/protected.rb +100 -0
- data/data/arrow/applets/tutorial/redirector.rb +52 -0
- data/data/arrow/applets/tutorial/rndimages.rb +159 -0
- data/data/arrow/applets/tutorial/sharenotes.rb +83 -0
- data/data/arrow/applets/tutorial/subclassed-hello.rb +32 -0
- data/data/arrow/applets/tutorial/superhello.rb +72 -0
- data/data/arrow/applets/tutorial/timeclock.rb +78 -0
- data/data/arrow/applets/view-applet.rb +123 -0
- data/data/arrow/applets/view-template.rb +85 -0
- data/data/arrow/applets/wiki.rb +274 -0
- data/data/arrow/templates/TEMPLATE.tmpl.tpl +36 -0
- data/data/arrow/templates/applet-status.tmpl +153 -0
- data/data/arrow/templates/args-display.tmpl +120 -0
- data/data/arrow/templates/config/display-table.tmpl +36 -0
- data/data/arrow/templates/config/display.tmpl +36 -0
- data/data/arrow/templates/counter-deleted.tmpl +33 -0
- data/data/arrow/templates/counter.tmpl +59 -0
- data/data/arrow/templates/dingus.tmpl +55 -0
- data/data/arrow/templates/enumtable.tmpl +8 -0
- data/data/arrow/templates/error-display.tmpl +92 -0
- data/data/arrow/templates/filemap.tmpl +89 -0
- data/data/arrow/templates/hello-world-src.tmpl +34 -0
- data/data/arrow/templates/hello-world.tmpl +60 -0
- data/data/arrow/templates/imgtext/fontlist.tmpl +46 -0
- data/data/arrow/templates/imgtext/form.tmpl +70 -0
- data/data/arrow/templates/imgtext/reload-error.tmpl +40 -0
- data/data/arrow/templates/imgtext/reload.tmpl +55 -0
- data/data/arrow/templates/inspect/display.tmpl +80 -0
- data/data/arrow/templates/loginform.tmpl +64 -0
- data/data/arrow/templates/logout.tmpl +32 -0
- data/data/arrow/templates/memcache/display.tmpl +41 -0
- data/data/arrow/templates/navbar.incl +27 -0
- data/data/arrow/templates/nosuchapplet.tmpl +32 -0
- data/data/arrow/templates/printsource.tmpl +35 -0
- data/data/arrow/templates/protected.tmpl +36 -0
- data/data/arrow/templates/rndimages.tmpl +38 -0
- data/data/arrow/templates/service-response.tmpl +13 -0
- data/data/arrow/templates/sharenotes/display.tmpl +38 -0
- data/data/arrow/templates/status.tmpl +120 -0
- data/data/arrow/templates/templateviewer.tmpl +43 -0
- data/data/arrow/templates/test/harness.tmpl +57 -0
- data/data/arrow/templates/test/list.tmpl +48 -0
- data/data/arrow/templates/test/problem.tmpl +42 -0
- data/data/arrow/templates/tutorial/index.tmpl +37 -0
- data/data/arrow/templates/tutorial/missingapplet.tmpl +29 -0
- data/data/arrow/templates/view-applet-nosuch.tmpl +32 -0
- data/data/arrow/templates/view-applet.tmpl +40 -0
- data/data/arrow/templates/view-template.tmpl +83 -0
- data/data/arrow/templates/wiki/formerror.tmpl +47 -0
- data/data/arrow/templates/wiki/markup_help.incl +6 -0
- data/data/arrow/templates/wiki/new.tmpl +56 -0
- data/data/arrow/templates/wiki/new_system.tmpl +122 -0
- data/data/arrow/templates/wiki/sectionlist.tmpl +43 -0
- data/data/arrow/templates/wiki/show.tmpl +34 -0
- data/docs/manual/layouts/default.page +43 -0
- data/docs/manual/lib/api-filter.rb +81 -0
- data/docs/manual/lib/editorial-filter.rb +64 -0
- data/docs/manual/lib/examples-filter.rb +244 -0
- data/docs/manual/lib/links-filter.rb +117 -0
- data/lib/apache/fakerequest.rb +448 -0
- data/lib/apache/logger.rb +33 -0
- data/lib/arrow.rb +51 -0
- data/lib/arrow/acceptparam.rb +207 -0
- data/lib/arrow/applet.rb +725 -0
- data/lib/arrow/appletmixins.rb +218 -0
- data/lib/arrow/appletregistry.rb +590 -0
- data/lib/arrow/applettestcase.rb +503 -0
- data/lib/arrow/broker.rb +255 -0
- data/lib/arrow/cache.rb +176 -0
- data/lib/arrow/config-loaders/yaml.rb +75 -0
- data/lib/arrow/config.rb +615 -0
- data/lib/arrow/constants.rb +24 -0
- data/lib/arrow/cookie.rb +359 -0
- data/lib/arrow/cookieset.rb +108 -0
- data/lib/arrow/dispatcher.rb +368 -0
- data/lib/arrow/dispatcherloader.rb +50 -0
- data/lib/arrow/exceptions.rb +61 -0
- data/lib/arrow/fallbackhandler.rb +48 -0
- data/lib/arrow/formvalidator.rb +631 -0
- data/lib/arrow/htmltokenizer.rb +343 -0
- data/lib/arrow/logger.rb +488 -0
- data/lib/arrow/logger/apacheoutputter.rb +69 -0
- data/lib/arrow/logger/arrayoutputter.rb +63 -0
- data/lib/arrow/logger/coloroutputter.rb +111 -0
- data/lib/arrow/logger/fileoutputter.rb +96 -0
- data/lib/arrow/logger/htmloutputter.rb +54 -0
- data/lib/arrow/logger/outputter.rb +123 -0
- data/lib/arrow/mixins.rb +425 -0
- data/lib/arrow/monkeypatches.rb +94 -0
- data/lib/arrow/object.rb +117 -0
- data/lib/arrow/path.rb +196 -0
- data/lib/arrow/service.rb +447 -0
- data/lib/arrow/session.rb +289 -0
- data/lib/arrow/session/dbstore.rb +100 -0
- data/lib/arrow/session/filelock.rb +160 -0
- data/lib/arrow/session/filestore.rb +132 -0
- data/lib/arrow/session/id.rb +98 -0
- data/lib/arrow/session/lock.rb +253 -0
- data/lib/arrow/session/md5id.rb +42 -0
- data/lib/arrow/session/nulllock.rb +42 -0
- data/lib/arrow/session/posixlock.rb +166 -0
- data/lib/arrow/session/sha1id.rb +54 -0
- data/lib/arrow/session/store.rb +366 -0
- data/lib/arrow/session/usertrackid.rb +52 -0
- data/lib/arrow/spechelpers.rb +73 -0
- data/lib/arrow/template.rb +713 -0
- data/lib/arrow/template/attr.rb +31 -0
- data/lib/arrow/template/call.rb +31 -0
- data/lib/arrow/template/comment.rb +33 -0
- data/lib/arrow/template/container.rb +118 -0
- data/lib/arrow/template/else.rb +41 -0
- data/lib/arrow/template/elsif.rb +44 -0
- data/lib/arrow/template/escape.rb +53 -0
- data/lib/arrow/template/export.rb +87 -0
- data/lib/arrow/template/for.rb +145 -0
- data/lib/arrow/template/if.rb +78 -0
- data/lib/arrow/template/import.rb +119 -0
- data/lib/arrow/template/include.rb +206 -0
- data/lib/arrow/template/iterator.rb +208 -0
- data/lib/arrow/template/nodes.rb +734 -0
- data/lib/arrow/template/parser.rb +571 -0
- data/lib/arrow/template/prettyprint.rb +53 -0
- data/lib/arrow/template/render.rb +191 -0
- data/lib/arrow/template/selectlist.rb +94 -0
- data/lib/arrow/template/set.rb +87 -0
- data/lib/arrow/template/timedelta.rb +81 -0
- data/lib/arrow/template/unless.rb +78 -0
- data/lib/arrow/template/urlencode.rb +51 -0
- data/lib/arrow/template/yield.rb +139 -0
- data/lib/arrow/templatefactory.rb +125 -0
- data/lib/arrow/testcase.rb +567 -0
- data/lib/arrow/transaction.rb +608 -0
- data/rake/191_compat.rb +26 -0
- data/rake/dependencies.rb +76 -0
- data/rake/documentation.rb +114 -0
- data/rake/helpers.rb +502 -0
- data/rake/hg.rb +282 -0
- data/rake/manual.rb +787 -0
- data/rake/packaging.rb +129 -0
- data/rake/publishing.rb +278 -0
- data/rake/style.rb +62 -0
- data/rake/svn.rb +668 -0
- data/rake/testing.rb +187 -0
- data/rake/verifytask.rb +64 -0
- data/spec/arrow/acceptparam_spec.rb +157 -0
- data/spec/arrow/applet_spec.rb +575 -0
- data/spec/arrow/appletmixins_spec.rb +409 -0
- data/spec/arrow/appletregistry_spec.rb +294 -0
- data/spec/arrow/broker_spec.rb +153 -0
- data/spec/arrow/config_spec.rb +224 -0
- data/spec/arrow/cookieset_spec.rb +164 -0
- data/spec/arrow/dispatcher_spec.rb +137 -0
- data/spec/arrow/dispatcherloader_spec.rb +65 -0
- data/spec/arrow/formvalidator_spec.rb +781 -0
- data/spec/arrow/logger_spec.rb +346 -0
- data/spec/arrow/mixins_spec.rb +120 -0
- data/spec/arrow/service_spec.rb +645 -0
- data/spec/arrow/session_spec.rb +121 -0
- data/spec/arrow/template/iterator_spec.rb +222 -0
- data/spec/arrow/templatefactory_spec.rb +185 -0
- data/spec/arrow/transaction_spec.rb +319 -0
- data/spec/arrow_spec.rb +37 -0
- data/spec/lib/appletmatchers.rb +281 -0
- data/spec/lib/constants.rb +77 -0
- data/spec/lib/helpers.rb +41 -0
- data/spec/lib/matchers.rb +44 -0
- data/tests/cookie.tests.rb +310 -0
- data/tests/path.tests.rb +157 -0
- data/tests/session.tests.rb +111 -0
- data/tests/session_id.tests.rb +82 -0
- data/tests/session_lock.tests.rb +191 -0
- data/tests/session_store.tests.rb +53 -0
- data/tests/template.tests.rb +1360 -0
- metadata +339 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
module Arrow
|
|
5
|
+
module Constants
|
|
6
|
+
|
|
7
|
+
# The domain to put Arrow objects into
|
|
8
|
+
YAML_DOMAIN = "rubycrafters.com,2003-10-22"
|
|
9
|
+
|
|
10
|
+
# The mimetype to use for XHTML content
|
|
11
|
+
XHTML_MIMETYPE = 'application/xhtml+xml'
|
|
12
|
+
|
|
13
|
+
# The mimetype to use for HTML content
|
|
14
|
+
HTML_MIMETYPE = 'text/html'
|
|
15
|
+
|
|
16
|
+
# The mimetype to use for marshalled Ruby objects
|
|
17
|
+
RUBY_MARSHALLED_MIMETYPE = 'application/x-ruby-marshalled-object'
|
|
18
|
+
|
|
19
|
+
# The mimetype to use for raw Ruby objects
|
|
20
|
+
RUBY_OBJECT_MIMETYPE = 'application/x-ruby-object'
|
|
21
|
+
|
|
22
|
+
end # module Constants
|
|
23
|
+
end # module Arrow
|
|
24
|
+
|
data/lib/arrow/cookie.rb
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'date'
|
|
4
|
+
require 'time'
|
|
5
|
+
require 'uri'
|
|
6
|
+
|
|
7
|
+
require 'arrow/object'
|
|
8
|
+
|
|
9
|
+
# The Arrow::Cookie class, a class for parsing and generating HTTP cookies.
|
|
10
|
+
#
|
|
11
|
+
# Large parts of this code were copied from the Webrick::Cookie class
|
|
12
|
+
# in the Ruby standard library. The copyright statements for that module
|
|
13
|
+
# are:
|
|
14
|
+
#
|
|
15
|
+
# Author: IPR -- Internet Programming with Ruby -- writers
|
|
16
|
+
# Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
|
|
17
|
+
# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
|
|
18
|
+
# reserved.
|
|
19
|
+
#
|
|
20
|
+
# == VCS Id
|
|
21
|
+
#
|
|
22
|
+
# $Id$
|
|
23
|
+
#
|
|
24
|
+
# == Authors
|
|
25
|
+
#
|
|
26
|
+
# * Michael Granger <ged@FaerieMUD.org>
|
|
27
|
+
#
|
|
28
|
+
# Please see the file LICENSE in the top-level directory for licensing details.
|
|
29
|
+
#
|
|
30
|
+
class Arrow::Cookie < Arrow::Object
|
|
31
|
+
|
|
32
|
+
CookieDateFormat = '%a, %d-%b-%Y %H:%M:%S GMT'
|
|
33
|
+
|
|
34
|
+
### Strip surrounding double quotes from a copy of the specified string
|
|
35
|
+
### and return it.
|
|
36
|
+
def self::dequote( string )
|
|
37
|
+
/^"((?:[^"]+|\\.)*)"/.match( string ) ? $1 : string.dup
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
### Parse a cookie value string, returning an Array of Strings
|
|
42
|
+
def self::parse_valuestring( valstr )
|
|
43
|
+
return [] unless valstr
|
|
44
|
+
valstr = dequote( valstr )
|
|
45
|
+
|
|
46
|
+
return valstr.split('&').collect{|str| URI.unescape(str) }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
### RFC 2109: HTTP State Management Mechanism
|
|
51
|
+
# When it sends a request to an origin server, the user agent sends a
|
|
52
|
+
# Cookie request header to the origin server if it has cookies that are
|
|
53
|
+
# applicable to the request, based on
|
|
54
|
+
#
|
|
55
|
+
# * the request-host;
|
|
56
|
+
# * the request-URI;
|
|
57
|
+
# * the cookie's age.
|
|
58
|
+
#
|
|
59
|
+
# The syntax for the header is:
|
|
60
|
+
#
|
|
61
|
+
# cookie = "Cookie:" cookie-version
|
|
62
|
+
# 1*((";" | ",") cookie-value)
|
|
63
|
+
# cookie-value = NAME "=" VALUE [";" path] [";" domain]
|
|
64
|
+
# cookie-version = "$Version" "=" value
|
|
65
|
+
# NAME = attr
|
|
66
|
+
# VALUE = value
|
|
67
|
+
# path = "$Path" "=" value
|
|
68
|
+
# domain = "$Domain" "=" value
|
|
69
|
+
|
|
70
|
+
CookieVersion = /\$Version\s*=\s*(.+)\s*[,;]/
|
|
71
|
+
CookiePath = /\$Path/i
|
|
72
|
+
CookieDomain = /\$Domain/i
|
|
73
|
+
|
|
74
|
+
### RFC2068: Hypertext Transfer Protocol -- HTTP/1.1
|
|
75
|
+
# CTL = <any US-ASCII control character
|
|
76
|
+
# (octets 0 - 31) and DEL (127)>
|
|
77
|
+
# token = 1*<any CHAR except CTLs or tspecials>
|
|
78
|
+
#
|
|
79
|
+
# tspecials = "(" | ")" | "<" | ">" | "@"
|
|
80
|
+
# | "," | ";" | ":" | "\" | <">
|
|
81
|
+
# | "/" | "[" | "]" | "?" | "="
|
|
82
|
+
# | "{" | "}" | SP | HT
|
|
83
|
+
CTLs = "[:cntrl:]"
|
|
84
|
+
TSpecials = Regexp.quote ' "(),/:;<=>?@[\\]{}'
|
|
85
|
+
NonTokenChar = /[#{CTLs}#{TSpecials}]/s
|
|
86
|
+
HTTPToken = /\A[^#{CTLs}#{TSpecials}]+\z/s
|
|
87
|
+
|
|
88
|
+
### Parse the specified 'Cookie:' +header+ value and return a Hash of
|
|
89
|
+
### one or more new Arrow::Cookie objects, keyed by name.
|
|
90
|
+
def self::parse( header )
|
|
91
|
+
return {} if header.nil? or header.empty?
|
|
92
|
+
Arrow::Logger[self].debug "Parsing cookie header: %p" % [ header ]
|
|
93
|
+
cookies = []
|
|
94
|
+
version = 0
|
|
95
|
+
header = header.strip
|
|
96
|
+
|
|
97
|
+
# "$Version" = value
|
|
98
|
+
if CookieVersion.match( header )
|
|
99
|
+
Arrow::Logger[self].debug " Found cookie version %p" % [ $1 ]
|
|
100
|
+
version = Integer( dequote($1) )
|
|
101
|
+
header.slice!( CookieVersion )
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# 1*((";" | ",") NAME "=" VALUE [";" path] [";" domain])
|
|
105
|
+
header.split( /[,;]\s*/ ).each do |pair|
|
|
106
|
+
Arrow::Logger[self].debug " Found pair %p" % [ pair ]
|
|
107
|
+
key, valstr = pair.split( /=/, 2 ).collect {|s| s.strip }
|
|
108
|
+
|
|
109
|
+
case key
|
|
110
|
+
when CookiePath
|
|
111
|
+
Arrow::Logger[self].debug " -> cookie-path %p" % [ valstr ]
|
|
112
|
+
cookies.last.path = dequote( valstr ) unless cookies.empty?
|
|
113
|
+
|
|
114
|
+
when CookieDomain
|
|
115
|
+
Arrow::Logger[self].debug " -> cookie-domain %p" % [ valstr ]
|
|
116
|
+
cookies.last.domain = dequote( valstr ) unless cookies.empty?
|
|
117
|
+
|
|
118
|
+
when HTTPToken
|
|
119
|
+
values = parse_valuestring( valstr )
|
|
120
|
+
Arrow::Logger[self].debug " -> cookie-values %p" % [ values ]
|
|
121
|
+
cookies << new( key, values, :version => version )
|
|
122
|
+
|
|
123
|
+
else
|
|
124
|
+
Arrow::Logger[self].warning \
|
|
125
|
+
"Malformed cookie header %p: %p is not a valid token; ignoring" %
|
|
126
|
+
[ header, key ]
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Turn the array into a Hash, ignoring all but the first instance of
|
|
131
|
+
# a cookie with the same name
|
|
132
|
+
return cookies.inject({}) do |hash,cookie|
|
|
133
|
+
hash[cookie.name] = cookie unless hash.key?( cookie.name )
|
|
134
|
+
hash
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
#################################################################
|
|
140
|
+
### I N S T A N C E M E T H O D S
|
|
141
|
+
#################################################################
|
|
142
|
+
|
|
143
|
+
### Create a new Arrow::Cookie object with the specified +name+ and
|
|
144
|
+
### +values+.
|
|
145
|
+
def initialize( name, values, options={} )
|
|
146
|
+
values = [ values ] unless values.is_a?( Array )
|
|
147
|
+
@name = name
|
|
148
|
+
@values = values
|
|
149
|
+
|
|
150
|
+
@domain = nil
|
|
151
|
+
@path = nil
|
|
152
|
+
@secure = false
|
|
153
|
+
@comment = nil
|
|
154
|
+
@max_age = nil
|
|
155
|
+
@expires = nil
|
|
156
|
+
@version = 0
|
|
157
|
+
|
|
158
|
+
options.each do |meth, val|
|
|
159
|
+
self.__send__( "#{meth}=", val )
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
######
|
|
166
|
+
public
|
|
167
|
+
######
|
|
168
|
+
|
|
169
|
+
# The name of the cookie
|
|
170
|
+
attr_accessor :name
|
|
171
|
+
|
|
172
|
+
# The Array of cookie values
|
|
173
|
+
attr_accessor :values
|
|
174
|
+
|
|
175
|
+
# The cookie version. 0 (the default) is fine for most uses
|
|
176
|
+
attr_accessor :version
|
|
177
|
+
|
|
178
|
+
# The domain the cookie belongs to
|
|
179
|
+
attr_reader :domain
|
|
180
|
+
|
|
181
|
+
# The path the cookie applies to
|
|
182
|
+
attr_accessor :path
|
|
183
|
+
|
|
184
|
+
# The cookie's 'secure' flag.
|
|
185
|
+
attr_writer :secure
|
|
186
|
+
|
|
187
|
+
# The cookie's expiration (a Time object)
|
|
188
|
+
attr_reader :expires
|
|
189
|
+
|
|
190
|
+
# The lifetime of the cookie, in seconds.
|
|
191
|
+
attr_reader :max_age
|
|
192
|
+
|
|
193
|
+
# Because cookies can contain private information about a
|
|
194
|
+
# user, the Cookie attribute allows an origin server to document its
|
|
195
|
+
# intended use of a cookie. The user can inspect the information to
|
|
196
|
+
# decide whether to initiate or continue a session with this cookie.
|
|
197
|
+
attr_accessor :comment
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
### Return the first value stored in the cookie as a String.
|
|
201
|
+
def value
|
|
202
|
+
@values.first
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
### Returns +true+ if the secure flag is set
|
|
207
|
+
def secure?
|
|
208
|
+
return @secure ? true : false
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# Set the lifetime of the cookie. The value is a decimal non-negative
|
|
212
|
+
# integer. After +delta_seconds+ seconds elapse, the client should
|
|
213
|
+
# discard the cookie. A value of zero means the cookie should be
|
|
214
|
+
# discarded immediately.
|
|
215
|
+
def max_age=( delta_seconds )
|
|
216
|
+
@max_age = Integer( delta_seconds )
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
### Set the domain for which the cookie is valid.
|
|
221
|
+
def domain=( newdomain )
|
|
222
|
+
newdomain = ".#{newdomain}" unless newdomain[0] == ?.
|
|
223
|
+
@domain = newdomain.dup
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
### Set the cookie's expires field. The value can be either a Time object
|
|
228
|
+
### or a String in any of the following formats:
|
|
229
|
+
### +30s::
|
|
230
|
+
### 30 seconds from now
|
|
231
|
+
### +10m::
|
|
232
|
+
### ten minutes from now
|
|
233
|
+
### +1h::
|
|
234
|
+
### one hour from now
|
|
235
|
+
### -1d::
|
|
236
|
+
### yesterday (i.e. "ASAP!")
|
|
237
|
+
### now::
|
|
238
|
+
### immediately
|
|
239
|
+
### +3M::
|
|
240
|
+
### in three months
|
|
241
|
+
### +10y::
|
|
242
|
+
### in ten years time
|
|
243
|
+
### Thursday, 25-Apr-1999 00:40:33 GMT::
|
|
244
|
+
### at the indicated time & date
|
|
245
|
+
def expires=( time )
|
|
246
|
+
case time
|
|
247
|
+
when NilClass
|
|
248
|
+
@expires = nil
|
|
249
|
+
|
|
250
|
+
when Date
|
|
251
|
+
@expires = Time.parse( time.ctime )
|
|
252
|
+
|
|
253
|
+
when Time
|
|
254
|
+
@expires = time
|
|
255
|
+
|
|
256
|
+
else
|
|
257
|
+
@expires = parse_time_delta( time )
|
|
258
|
+
end
|
|
259
|
+
rescue => err
|
|
260
|
+
raise err, caller(1)
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
### Set the cookie expiration to a time in the past
|
|
265
|
+
def expire!
|
|
266
|
+
self.expires = Time.at(0)
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
### Return the cookie as a String
|
|
272
|
+
def to_s
|
|
273
|
+
rval = "%s=%s" % [ self.name, make_valuestring(self.values) ]
|
|
274
|
+
|
|
275
|
+
rval << make_field( "Version", self.version ) if self.version.nonzero?
|
|
276
|
+
rval << make_field( "Domain", self.domain )
|
|
277
|
+
rval << make_field( "Expires", make_cookiedate(self.expires) ) if self.expires
|
|
278
|
+
rval << make_field( "Max-Age", self.max_age )
|
|
279
|
+
rval << make_field( "Comment", self.comment )
|
|
280
|
+
rval << make_field( "Path", self.path )
|
|
281
|
+
|
|
282
|
+
rval << "; " << "Secure" if self.secure?
|
|
283
|
+
|
|
284
|
+
return rval
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
### Return +true+ if other_cookie has the same name as the receiver.
|
|
289
|
+
def eql?( other_cookie )
|
|
290
|
+
return (self.name == other_cookie.name) ? true : false
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
### Generate a Fixnum hash value for this object. Uses the hash of the cookie's name.
|
|
295
|
+
def hash
|
|
296
|
+
return self.name.hash
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
#######
|
|
302
|
+
private
|
|
303
|
+
#######
|
|
304
|
+
|
|
305
|
+
### Make a cookie field for appending to the outgoing header for the
|
|
306
|
+
### specified +value+ and +field_name+. If +value+ is nil, an empty
|
|
307
|
+
### string will be returned.
|
|
308
|
+
def make_field( field_name, value )
|
|
309
|
+
return '' if value.nil? || (value.is_a?(String) && value.empty?)
|
|
310
|
+
|
|
311
|
+
return "; %s=%s" % [
|
|
312
|
+
field_name.capitalize,
|
|
313
|
+
value
|
|
314
|
+
]
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
# Number of seconds in the various offset types
|
|
319
|
+
Seconds = {
|
|
320
|
+
's' => 1,
|
|
321
|
+
'm' => 60,
|
|
322
|
+
'h' => 60*60,
|
|
323
|
+
'd' => 60*60*24,
|
|
324
|
+
'M' => 60*60*24*30,
|
|
325
|
+
'y' => 60*60*24*365,
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
### Parse a time delta like those accepted by #expires= into a Time
|
|
329
|
+
### object.
|
|
330
|
+
def parse_time_delta( time )
|
|
331
|
+
return Time.now if time.nil? || time == 'now'
|
|
332
|
+
return Time.at( Integer(time) ) if /^\d+$/.match( time )
|
|
333
|
+
|
|
334
|
+
if /^([+-]?(?:\d+|\d*\.\d*))([mhdMy]?)/.match( time )
|
|
335
|
+
offset = (Seconds[$2] || 1) * Integer($1)
|
|
336
|
+
return Time.now + offset
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
return Time.parse( time )
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
### Make a uri-escaped value string for the given +values+
|
|
343
|
+
def make_valuestring( values )
|
|
344
|
+
values.collect {|val| URI.escape(val, NonTokenChar) }.join('&')
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
### Make an RFC2109-formatted date out of +date+.
|
|
349
|
+
def make_cookiedate( date )
|
|
350
|
+
return date.gmtime.strftime( CookieDateFormat )
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
### Quote a copy of the given string and return it.
|
|
355
|
+
def quote( val )
|
|
356
|
+
%q{"%s"} % [ val.to_s.gsub(/"/, '\\"') ]
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
end # class Arrow::Cookie
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'arrow'
|
|
4
|
+
require 'arrow/cookie'
|
|
5
|
+
require 'set'
|
|
6
|
+
require 'forwardable'
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# An object class which provides a convenient way of accessing a set of Arrow::Cookies.
|
|
10
|
+
#
|
|
11
|
+
# == Synopsis
|
|
12
|
+
#
|
|
13
|
+
# cset = Arrow::CookieSet.new()
|
|
14
|
+
# cset = Arrow::CookieSet.new( cookies )
|
|
15
|
+
#
|
|
16
|
+
# cset['cookiename'] # => Arrow::Cookie
|
|
17
|
+
#
|
|
18
|
+
# cset['cookiename'] = cookie_object
|
|
19
|
+
# cset['cookiename'] = 'cookievalue'
|
|
20
|
+
# cset[:cookiename] = 'cookievalue'
|
|
21
|
+
# cset << Arrow::Cookie.new( *args )
|
|
22
|
+
#
|
|
23
|
+
# cset.include?( 'cookiename' )
|
|
24
|
+
# cset.include?( cookie_object )
|
|
25
|
+
#
|
|
26
|
+
# cset.each do |cookie|
|
|
27
|
+
# ...
|
|
28
|
+
# end
|
|
29
|
+
#
|
|
30
|
+
# == Authors
|
|
31
|
+
#
|
|
32
|
+
# * Michael Granger <ged@FaerieMUD.org>
|
|
33
|
+
# * Jeremiah Jordan <phaedrus@FaerieMUD.org>
|
|
34
|
+
#
|
|
35
|
+
# Please see the file LICENSE in the top-level directory for licensing details.
|
|
36
|
+
#
|
|
37
|
+
class Arrow::CookieSet < Arrow::Object
|
|
38
|
+
extend Forwardable
|
|
39
|
+
include Enumerable
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
#################################################################
|
|
44
|
+
### I N S T A N C E M E T H O D S
|
|
45
|
+
#################################################################
|
|
46
|
+
|
|
47
|
+
### Create a new CookieSet prepopulated with the given cookies
|
|
48
|
+
def initialize( *cookies )
|
|
49
|
+
@cookie_set = Set.new( cookies.flatten )
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
######
|
|
54
|
+
public
|
|
55
|
+
######
|
|
56
|
+
|
|
57
|
+
def_delegators :@cookie_set, :each
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
### Returns the number of cookies in the cookieset
|
|
61
|
+
def length
|
|
62
|
+
return @cookie_set.length
|
|
63
|
+
end
|
|
64
|
+
alias_method :size, :length
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
### Index operator method: returns the Arrow::Cookie with the given +name+ if it
|
|
68
|
+
### exists in the cookieset.
|
|
69
|
+
def []( name )
|
|
70
|
+
name = name.to_s
|
|
71
|
+
return @cookie_set.find() {|cookie| cookie.name == name }
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
### Index set operator method: set the cookie that corresponds to the given +name+
|
|
76
|
+
### to +value+. If +value+ is not an Arrow::Cookie, one with be created and its
|
|
77
|
+
### value set to +value+.
|
|
78
|
+
def []=( name, value )
|
|
79
|
+
value = Arrow::Cookie.new( name.to_s, value ) unless value.is_a?( Arrow::Cookie )
|
|
80
|
+
raise ArgumentError, "cannot set a cookie named '%s' with a key of '%s'" %
|
|
81
|
+
[ value.name, name ] if value.name.to_s != name.to_s
|
|
82
|
+
|
|
83
|
+
self << value
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
### Returns +true+ if the CookieSet includes either a cookie with the given name or
|
|
88
|
+
### an Arrow::Cookie object.
|
|
89
|
+
def include?( name_or_cookie )
|
|
90
|
+
return true if @cookie_set.include?( name_or_cookie )
|
|
91
|
+
name = name_or_cookie.to_s
|
|
92
|
+
return self[name] ? true : false
|
|
93
|
+
end
|
|
94
|
+
alias_method :key?, :include?
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
### Append operator: Add the given +cookie+ to the set, replacing an existing
|
|
98
|
+
### cookie with the same name if one exists.
|
|
99
|
+
def <<( cookie )
|
|
100
|
+
@cookie_set.delete( cookie )
|
|
101
|
+
@cookie_set.add( cookie )
|
|
102
|
+
|
|
103
|
+
return self
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
end # class Arrow::CookieSet
|
|
108
|
+
|