strelka 0.0.1.pre129 → 0.0.1.pre148
Sign up to get free protection for your applications and to get access to all the features.
- data/IDEAS.rdoc +26 -32
- data/Manifest.txt +27 -12
- data/README.rdoc +29 -33
- data/Rakefile +2 -1
- data/bin/leash +2 -1
- data/contrib/hoetemplate/README.rdoc.erb +18 -0
- data/contrib/hoetemplate/data/{file_name → project}/apps/file_name_app +0 -0
- data/contrib/hoetemplate/data/{file_name → project}/templates/layout.tmpl.erb +0 -0
- data/contrib/hoetemplate/data/{file_name → project}/templates/top.tmpl.erb +0 -0
- data/examples/config.yml +3 -0
- data/examples/gen-config.rb +48 -0
- data/examples/sessions-demo.rb +43 -0
- data/lib/strelka/app/errors.rb +59 -17
- data/lib/strelka/app/filters.rb +3 -1
- data/lib/strelka/app/negotiation.rb +5 -3
- data/lib/strelka/app/parameters.rb +33 -31
- data/lib/strelka/app/plugins.rb +14 -8
- data/lib/strelka/app/restresources.rb +3 -1
- data/lib/strelka/app/routing.rb +9 -7
- data/lib/strelka/app/sessions.rb +175 -0
- data/lib/strelka/app/templating.rb +6 -3
- data/lib/strelka/app.rb +19 -11
- data/lib/strelka/behavior/plugin.rb +4 -2
- data/lib/strelka/constants.rb +9 -0
- data/lib/strelka/cookie.rb +357 -0
- data/lib/strelka/cookieset.rb +117 -0
- data/lib/strelka/httprequest/acceptparams.rb +12 -10
- data/lib/strelka/httprequest/negotiation.rb +4 -2
- data/lib/strelka/httprequest/session.rb +71 -0
- data/lib/strelka/httprequest.rb +19 -7
- data/lib/strelka/httpresponse/negotiation.rb +17 -15
- data/lib/strelka/httpresponse/session.rb +101 -0
- data/lib/strelka/httpresponse.rb +26 -4
- data/lib/strelka/logging.rb +3 -1
- data/lib/strelka/mixins.rb +174 -2
- data/lib/strelka/{app/paramvalidator.rb → paramvalidator.rb} +25 -22
- data/lib/strelka/{app/defaultrouter.rb → router/default.rb} +6 -4
- data/lib/strelka/{app/exclusiverouter.rb → router/exclusive.rb} +6 -4
- data/lib/strelka/{app/router.rb → router.rb} +9 -7
- data/lib/strelka/session/default.rb +209 -0
- data/lib/strelka/session.rb +178 -0
- data/lib/strelka.rb +6 -4
- data/spec/lib/constants.rb +3 -1
- data/spec/lib/helpers.rb +7 -0
- data/spec/strelka/app/errors_spec.rb +32 -52
- data/spec/strelka/app/filters_spec.rb +3 -1
- data/spec/strelka/app/negotiation_spec.rb +3 -1
- data/spec/strelka/app/parameters_spec.rb +5 -3
- data/spec/strelka/app/plugins_spec.rb +5 -3
- data/spec/strelka/app/restresources_spec.rb +3 -1
- data/spec/strelka/app/routing_spec.rb +6 -4
- data/spec/strelka/app/sessions_spec.rb +109 -0
- data/spec/strelka/app/templating_spec.rb +3 -1
- data/spec/strelka/app_spec.rb +11 -2
- data/spec/strelka/cookie_spec.rb +194 -0
- data/spec/strelka/cookieset_spec.rb +159 -0
- data/spec/strelka/exceptions_spec.rb +3 -1
- data/spec/strelka/httprequest/acceptparams_spec.rb +3 -1
- data/spec/strelka/httprequest/negotiation_spec.rb +3 -1
- data/spec/strelka/httprequest/session_spec.rb +43 -0
- data/spec/strelka/httprequest_spec.rb +28 -1
- data/spec/strelka/httpresponse/negotiation_spec.rb +3 -3
- data/spec/strelka/httpresponse_spec.rb +13 -0
- data/spec/strelka/logging_spec.rb +3 -1
- data/spec/strelka/mixins_spec.rb +125 -1
- data/spec/strelka/{app/paramvalidator_spec.rb → paramvalidator_spec.rb} +4 -4
- data/spec/strelka/{app/defaultrouter_spec.rb → router/default_spec.rb} +6 -4
- data/spec/strelka/{app/exclusiverouter_spec.rb → router/exclusive_spec.rb} +6 -4
- data/spec/strelka/{app/router_spec.rb → router_spec.rb} +9 -7
- data/spec/strelka/session/default_spec.rb +210 -0
- data/spec/strelka/session_spec.rb +101 -0
- data.tar.gz.sig +1 -1
- metadata +64 -47
- metadata.gz.sig +0 -0
- data/contrib/hoetemplate/.autotest.erb +0 -23
@@ -0,0 +1,357 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
# vim: set nosta noet ts=4 sw=4:
|
3
|
+
# encoding: utf-8
|
4
|
+
|
5
|
+
require 'date'
|
6
|
+
require 'time'
|
7
|
+
require 'uri'
|
8
|
+
|
9
|
+
require 'strelka' unless defined?( Strelka )
|
10
|
+
require 'strelka/mixins'
|
11
|
+
|
12
|
+
# The Strelka::Cookie class, a class for parsing and generating HTTP cookies.
|
13
|
+
#
|
14
|
+
# Large parts of this code were copied from the Webrick::Cookie class
|
15
|
+
# in the Ruby standard library. The copyright statements for that module
|
16
|
+
# are:
|
17
|
+
#
|
18
|
+
# Author: IPR -- Internet Programming with Ruby -- writers
|
19
|
+
# Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
|
20
|
+
# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
|
21
|
+
# reserved.
|
22
|
+
#
|
23
|
+
class Strelka::Cookie
|
24
|
+
include Strelka::Loggable
|
25
|
+
|
26
|
+
# The format of the date field
|
27
|
+
COOKIE_DATE_FORMAT = '%a, %d-%b-%Y %H:%M:%S GMT'
|
28
|
+
|
29
|
+
### RFC 2109: HTTP State Management Mechanism
|
30
|
+
# When it sends a request to an origin server, the user agent sends a
|
31
|
+
# Cookie request header to the origin server if it has cookies that are
|
32
|
+
# applicable to the request, based on
|
33
|
+
#
|
34
|
+
# * the request-host;
|
35
|
+
# * the request-URI;
|
36
|
+
# * the cookie's age.
|
37
|
+
#
|
38
|
+
# The syntax for the header is:
|
39
|
+
#
|
40
|
+
# cookie = "Cookie:" cookie-version
|
41
|
+
# 1*((";" | ",") cookie-value)
|
42
|
+
# cookie-value = NAME "=" VALUE [";" path] [";" domain]
|
43
|
+
# cookie-version = "$Version" "=" value
|
44
|
+
# NAME = attr
|
45
|
+
# VALUE = value
|
46
|
+
# path = "$Path" "=" value
|
47
|
+
# domain = "$Domain" "=" value
|
48
|
+
|
49
|
+
# Parser constants
|
50
|
+
COOKIE_VERSION = /\$Version\s*=\s*(.+)\s*[,;]/
|
51
|
+
COOKIE_PATH = /\$Path/i
|
52
|
+
COOKIE_DOMAIN = /\$Domain/i
|
53
|
+
|
54
|
+
### RFC2068: Hypertext Transfer Protocol -- HTTP/1.1
|
55
|
+
# CTL = <any US-ASCII control character
|
56
|
+
# (octets 0 - 31) and DEL (127)>
|
57
|
+
# token = 1*<any CHAR except CTLs or tspecials>
|
58
|
+
#
|
59
|
+
# tspecials = "(" | ")" | "<" | ">" | "@"
|
60
|
+
# | "," | ";" | ":" | "\" | <">
|
61
|
+
# | "/" | "[" | "]" | "?" | "="
|
62
|
+
# | "{" | "}" | SP | HT
|
63
|
+
|
64
|
+
# Cookie-value parser constants
|
65
|
+
CTLs = "[:cntrl:]"
|
66
|
+
TSPECIALS = Regexp.quote( ' "(),/:;<=>?@[\\]{}' )
|
67
|
+
NON_TOKEN_CHAR = /[#{CTLs}#{TSPECIALS}]/s
|
68
|
+
HTTP_TOKEN = /\A[^#{CTLs}#{TSPECIALS}]+\z/s
|
69
|
+
|
70
|
+
# Number of seconds in the various offset types
|
71
|
+
UNIT_SECONDS = {
|
72
|
+
's' => 1,
|
73
|
+
'm' => 60,
|
74
|
+
'h' => 60*60,
|
75
|
+
'd' => 60*60*24,
|
76
|
+
'M' => 60*60*24*30,
|
77
|
+
'y' => 60*60*24*365,
|
78
|
+
}
|
79
|
+
|
80
|
+
|
81
|
+
### Strip surrounding double quotes from a copy of the specified string
|
82
|
+
### and return it.
|
83
|
+
def self::dequote( string )
|
84
|
+
/^"((?:[^"]+|\\.)*)"/.match( string ) ? $1 : string.dup
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
### Parse a cookie value string, returning an Array of Strings
|
89
|
+
def self::parse_valuestring( valstr )
|
90
|
+
return [] unless valstr
|
91
|
+
valstr = dequote( valstr )
|
92
|
+
|
93
|
+
return valstr.split('&').collect{|str| URI.decode_www_form_component(str) }
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
### Parse the specified 'Cookie:' +header+ value and return a Hash of
|
98
|
+
### one or more new Strelka::Cookie objects, keyed by name.
|
99
|
+
def self::parse( header )
|
100
|
+
return {} if header.nil? or header.empty?
|
101
|
+
Strelka.log.debug "Parsing cookie header: %p" % [ header ]
|
102
|
+
cookies = []
|
103
|
+
version = 0
|
104
|
+
header = header.strip
|
105
|
+
|
106
|
+
# "$Version" = value
|
107
|
+
if COOKIE_VERSION.match( header )
|
108
|
+
Strelka.log.debug " Found cookie version %p" % [ $1 ]
|
109
|
+
version = Integer( dequote($1) )
|
110
|
+
header.slice!( COOKIE_VERSION )
|
111
|
+
end
|
112
|
+
|
113
|
+
# 1*((";" | ",") NAME "=" VALUE [";" path] [";" domain])
|
114
|
+
header.split( /[,;]\s*/ ).each do |pair|
|
115
|
+
Strelka.log.debug " Found pair %p" % [ pair ]
|
116
|
+
key, valstr = pair.split( /=/, 2 ).collect {|s| s.strip }
|
117
|
+
|
118
|
+
case key
|
119
|
+
when COOKIE_PATH
|
120
|
+
Strelka.log.debug " -> cookie-path %p" % [ valstr ]
|
121
|
+
cookies.last.path = dequote( valstr ) unless cookies.empty?
|
122
|
+
|
123
|
+
when COOKIE_DOMAIN
|
124
|
+
Strelka.log.debug " -> cookie-domain %p" % [ valstr ]
|
125
|
+
cookies.last.domain = dequote( valstr ) unless cookies.empty?
|
126
|
+
|
127
|
+
when HTTP_TOKEN
|
128
|
+
values = parse_valuestring( valstr )
|
129
|
+
Strelka.log.debug " -> cookie-values %p" % [ values ]
|
130
|
+
cookies << new( key, values, :version => version )
|
131
|
+
|
132
|
+
else
|
133
|
+
Strelka.log.warn \
|
134
|
+
"Malformed cookie header %p: %p is not a valid token; ignoring" %
|
135
|
+
[ header, key ]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# Turn the array into a Hash, ignoring all but the first instance of
|
140
|
+
# a cookie with the same name
|
141
|
+
return cookies.inject({}) do |hash,cookie|
|
142
|
+
hash[cookie.name] = cookie unless hash.key?( cookie.name )
|
143
|
+
hash
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
#################################################################
|
149
|
+
### I N S T A N C E M E T H O D S
|
150
|
+
#################################################################
|
151
|
+
|
152
|
+
### Create a new Strelka::Cookie object with the specified +name+ and
|
153
|
+
### +values+.
|
154
|
+
def initialize( name, values, options={} )
|
155
|
+
values = [ values ] unless values.is_a?( Array )
|
156
|
+
@name = name
|
157
|
+
@values = values
|
158
|
+
|
159
|
+
@domain = nil
|
160
|
+
@path = nil
|
161
|
+
@secure = false
|
162
|
+
@comment = nil
|
163
|
+
@max_age = nil
|
164
|
+
@expires = nil
|
165
|
+
@version = 0
|
166
|
+
|
167
|
+
options.each do |meth, val|
|
168
|
+
self.__send__( "#{meth}=", val )
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
|
173
|
+
|
174
|
+
######
|
175
|
+
public
|
176
|
+
######
|
177
|
+
|
178
|
+
# The name of the cookie
|
179
|
+
attr_accessor :name
|
180
|
+
|
181
|
+
# The Array of cookie values
|
182
|
+
attr_accessor :values
|
183
|
+
|
184
|
+
# The cookie version. 0 (the default) is fine for most uses
|
185
|
+
attr_accessor :version
|
186
|
+
|
187
|
+
# The domain the cookie belongs to
|
188
|
+
attr_reader :domain
|
189
|
+
|
190
|
+
# The path the cookie applies to
|
191
|
+
attr_accessor :path
|
192
|
+
|
193
|
+
# The cookie's 'secure' flag.
|
194
|
+
attr_writer :secure
|
195
|
+
|
196
|
+
# The cookie's expiration (a Time object)
|
197
|
+
attr_reader :expires
|
198
|
+
|
199
|
+
# The lifetime of the cookie, in seconds.
|
200
|
+
attr_reader :max_age
|
201
|
+
|
202
|
+
# Because cookies can contain private information about a
|
203
|
+
# user, the Cookie attribute allows an origin server to document its
|
204
|
+
# intended use of a cookie. The user can inspect the information to
|
205
|
+
# decide whether to initiate or continue a session with this cookie.
|
206
|
+
attr_accessor :comment
|
207
|
+
|
208
|
+
|
209
|
+
### Return the first value stored in the cookie as a String.
|
210
|
+
def value
|
211
|
+
return @values.first
|
212
|
+
end
|
213
|
+
|
214
|
+
|
215
|
+
### Returns +true+ if the secure flag is set
|
216
|
+
def secure?
|
217
|
+
return @secure ? true : false
|
218
|
+
end
|
219
|
+
|
220
|
+
# Set the lifetime of the cookie. The value is a decimal non-negative
|
221
|
+
# integer. After +delta_seconds+ seconds elapse, the client should
|
222
|
+
# discard the cookie. A value of zero means the cookie should be
|
223
|
+
# discarded immediately.
|
224
|
+
def max_age=( delta_seconds )
|
225
|
+
@max_age = Integer( delta_seconds )
|
226
|
+
end
|
227
|
+
|
228
|
+
|
229
|
+
### Set the domain for which the cookie is valid.
|
230
|
+
def domain=( newdomain )
|
231
|
+
newdomain = ".#{newdomain}" unless newdomain[0] == ?.
|
232
|
+
@domain = newdomain.dup
|
233
|
+
end
|
234
|
+
|
235
|
+
|
236
|
+
### Set the cookie's expires field. The value can be either a Time object
|
237
|
+
### or a String in any of the following formats:
|
238
|
+
### +30s::
|
239
|
+
### 30 seconds from now
|
240
|
+
### +10m::
|
241
|
+
### ten minutes from now
|
242
|
+
### +1h::
|
243
|
+
### one hour from now
|
244
|
+
### -1d::
|
245
|
+
### yesterday (i.e. "ASAP!")
|
246
|
+
### now::
|
247
|
+
### immediately
|
248
|
+
### +3M::
|
249
|
+
### in three months
|
250
|
+
### +10y::
|
251
|
+
### in ten years time
|
252
|
+
### Thursday, 25-Apr-1999 00:40:33 GMT::
|
253
|
+
### at the indicated time & date
|
254
|
+
def expires=( time )
|
255
|
+
case time
|
256
|
+
when NilClass
|
257
|
+
@expires = nil
|
258
|
+
|
259
|
+
when Date
|
260
|
+
@expires = Time.parse( time.ctime )
|
261
|
+
|
262
|
+
when Time
|
263
|
+
@expires = time
|
264
|
+
|
265
|
+
else
|
266
|
+
@expires = parse_time_delta( time )
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
|
271
|
+
### Set the cookie expiration to a time in the past
|
272
|
+
def expire!
|
273
|
+
self.expires = Time.at(0)
|
274
|
+
end
|
275
|
+
|
276
|
+
|
277
|
+
### Return the cookie as a String
|
278
|
+
def to_s
|
279
|
+
rval = "%s=%s" % [ self.name, make_valuestring(self.values) ]
|
280
|
+
|
281
|
+
rval << make_field( "Version", self.version ) if self.version.nonzero?
|
282
|
+
rval << make_field( "Domain", self.domain )
|
283
|
+
rval << make_field( "Expires", make_cookiedate(self.expires) ) if self.expires
|
284
|
+
rval << make_field( "Max-Age", self.max_age )
|
285
|
+
rval << make_field( "Comment", self.comment )
|
286
|
+
rval << make_field( "Path", self.path )
|
287
|
+
|
288
|
+
rval << "; " << "Secure" if self.secure?
|
289
|
+
|
290
|
+
return rval
|
291
|
+
end
|
292
|
+
|
293
|
+
|
294
|
+
### Return +true+ if other_cookie has the same name as the receiver.
|
295
|
+
def eql?( other_cookie )
|
296
|
+
self.log.debug "Comparing %p with other cookie: %p" % [ self, other_cookie ]
|
297
|
+
return (self.name == other_cookie.name) ? true : false
|
298
|
+
end
|
299
|
+
|
300
|
+
|
301
|
+
### Generate a Fixnum hash value for this object. Uses the hash of the cookie's name.
|
302
|
+
def hash
|
303
|
+
return self.name.to_s.hash
|
304
|
+
end
|
305
|
+
|
306
|
+
|
307
|
+
|
308
|
+
#######
|
309
|
+
private
|
310
|
+
#######
|
311
|
+
|
312
|
+
### Make a cookie field for appending to the outgoing header for the
|
313
|
+
### specified +value+ and +field_name+. If +value+ is nil, an empty
|
314
|
+
### string will be returned.
|
315
|
+
def make_field( field_name, value )
|
316
|
+
return '' if value.nil? || (value.is_a?(String) && value.empty?)
|
317
|
+
|
318
|
+
return "; %s=%s" % [
|
319
|
+
field_name.capitalize,
|
320
|
+
value
|
321
|
+
]
|
322
|
+
end
|
323
|
+
|
324
|
+
|
325
|
+
### Parse a time delta like those accepted by #expires= into a Time
|
326
|
+
### object.
|
327
|
+
def parse_time_delta( time )
|
328
|
+
return Time.now if time.nil? || time == 'now'
|
329
|
+
return Time.at( Integer(time) ) if /^\d+$/.match( time )
|
330
|
+
|
331
|
+
if /^([+-]?(?:\d+|\d*\.\d*))([mhdMy]?)/.match( time )
|
332
|
+
offset = (UNIT_SECONDS[$2] || 1) * Integer($1)
|
333
|
+
return Time.now + offset
|
334
|
+
end
|
335
|
+
|
336
|
+
return Time.parse( time )
|
337
|
+
end
|
338
|
+
|
339
|
+
|
340
|
+
### Make a uri-escaped value string for the given +values+
|
341
|
+
def make_valuestring( values )
|
342
|
+
return values.collect {|val| URI.encode_www_form_component(val) }.join('&')
|
343
|
+
end
|
344
|
+
|
345
|
+
|
346
|
+
### Make an RFC2109-formatted date out of +date+.
|
347
|
+
def make_cookiedate( date )
|
348
|
+
return date.gmtime.strftime( COOKIE_DATE_FORMAT )
|
349
|
+
end
|
350
|
+
|
351
|
+
|
352
|
+
### Quote a copy of the given string and return it.
|
353
|
+
def quote( val )
|
354
|
+
return %q{"%s"} % [ val.to_s.gsub(/"/, '\\"') ]
|
355
|
+
end
|
356
|
+
|
357
|
+
end # class Strelka::Cookie
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
# vim: set nosta noet ts=4 sw=4:
|
3
|
+
# encoding: utf-8
|
4
|
+
|
5
|
+
require 'strelka' unless defined?( Strelka )
|
6
|
+
require 'strelka/cookie'
|
7
|
+
require 'set'
|
8
|
+
require 'forwardable'
|
9
|
+
|
10
|
+
|
11
|
+
# An object class which provides a convenient way of accessing a set of Strelka::Cookies.
|
12
|
+
#
|
13
|
+
# == Synopsis
|
14
|
+
#
|
15
|
+
# cset = Strelka::CookieSet.new()
|
16
|
+
# cset = Strelka::CookieSet.new( cookies )
|
17
|
+
#
|
18
|
+
# cset['cookiename'] # => Strelka::Cookie
|
19
|
+
#
|
20
|
+
# cset['cookiename'] = cookie_object
|
21
|
+
# cset['cookiename'] = 'cookievalue'
|
22
|
+
# cset[:cookiename] = 'cookievalue'
|
23
|
+
# cset << Strelka::Cookie.new( *args )
|
24
|
+
#
|
25
|
+
# cset.include?( 'cookiename' )
|
26
|
+
# cset.include?( cookie_object )
|
27
|
+
#
|
28
|
+
# cset.each do |cookie|
|
29
|
+
# ...
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# == Authors
|
33
|
+
#
|
34
|
+
# * Michael Granger <ged@FaerieMUD.org>
|
35
|
+
# * Jeremiah Jordan <phaedrus@FaerieMUD.org>
|
36
|
+
#
|
37
|
+
class Strelka::CookieSet
|
38
|
+
extend Forwardable
|
39
|
+
include Enumerable
|
40
|
+
|
41
|
+
|
42
|
+
### Parse the Cookie header of the specified +request+ into Strelka::Cookie objects
|
43
|
+
### and return them in a new CookieSet.
|
44
|
+
def self::parse( request )
|
45
|
+
Strelka.log.debug "Parsing cookies from header: %p" % [ request.header.cookie ]
|
46
|
+
cookies = Strelka::Cookie.parse( request.header.cookie )
|
47
|
+
Strelka.log.debug " found %d cookies: %p" % [ cookies.length, cookies ]
|
48
|
+
return new( cookies.values )
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
#################################################################
|
53
|
+
### I N S T A N C E M E T H O D S
|
54
|
+
#################################################################
|
55
|
+
|
56
|
+
### Create a new CookieSet prepopulated with the given cookies
|
57
|
+
def initialize( *cookies )
|
58
|
+
@cookie_set = Set.new( cookies.flatten )
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
######
|
63
|
+
public
|
64
|
+
######
|
65
|
+
|
66
|
+
def_delegators :@cookie_set, :each
|
67
|
+
|
68
|
+
|
69
|
+
### Returns the number of cookies in the cookieset
|
70
|
+
def length
|
71
|
+
return @cookie_set.length
|
72
|
+
end
|
73
|
+
alias_method :size, :length
|
74
|
+
|
75
|
+
|
76
|
+
### Index operator method: returns the Strelka::Cookie with the given +name+ if it
|
77
|
+
### exists in the cookieset.
|
78
|
+
def []( name )
|
79
|
+
name = name.to_s
|
80
|
+
return @cookie_set.find {|cookie| cookie.name == name }
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
### Index set operator method: set the cookie that corresponds to the given +name+
|
85
|
+
### to +value+. If +value+ is not an Strelka::Cookie, one with be created and its
|
86
|
+
### value set to +value+.
|
87
|
+
def []=( name, value )
|
88
|
+
value = Strelka::Cookie.new( name.to_s, value ) unless value.is_a?( Strelka::Cookie )
|
89
|
+
raise ArgumentError, "cannot set a cookie named '%s' with a key of '%s'" %
|
90
|
+
[ value.name, name ] if value.name.to_s != name.to_s
|
91
|
+
|
92
|
+
self << value
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
### Returns +true+ if the CookieSet includes either a cookie with the given name or
|
97
|
+
### an Strelka::Cookie object.
|
98
|
+
def include?( name_or_cookie )
|
99
|
+
return true if @cookie_set.include?( name_or_cookie )
|
100
|
+
name = name_or_cookie.to_s
|
101
|
+
return self[name] ? true : false
|
102
|
+
end
|
103
|
+
alias_method :key?, :include?
|
104
|
+
|
105
|
+
|
106
|
+
### Append operator: Add the given +cookie+ to the set, replacing an existing
|
107
|
+
### cookie with the same name if one exists.
|
108
|
+
def <<( cookie )
|
109
|
+
@cookie_set.delete( cookie )
|
110
|
+
@cookie_set.add( cookie )
|
111
|
+
|
112
|
+
return self
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
end # class Strelka::CookieSet
|
117
|
+
|
@@ -1,12 +1,14 @@
|
|
1
|
-
|
1
|
+
# -*- ruby -*-
|
2
|
+
# vim: set nosta noet ts=4 sw=4:
|
3
|
+
# encoding: utf-8
|
2
4
|
|
3
5
|
require 'strelka/mixins'
|
4
6
|
require 'strelka/httprequest'
|
5
7
|
|
6
8
|
class Strelka::HTTPRequest
|
7
9
|
|
8
|
-
# A parser for request Accept, Accept-encoding, Accept-charset, and Accept-language
|
9
|
-
# header values. They provide weighted and wildcard comparisions between two values
|
10
|
+
# A parser for request Accept, Accept-encoding, Accept-charset, and Accept-language
|
11
|
+
# header values. They provide weighted and wildcard comparisions between two values
|
10
12
|
# of the same field.
|
11
13
|
#
|
12
14
|
# require 'strelka/httprequest/acceptparam'
|
@@ -200,7 +202,7 @@ class Strelka::HTTPRequest
|
|
200
202
|
# A mediatype parameter such as one you'd find in an Accept header.
|
201
203
|
class MediaType < Strelka::HTTPRequest::AcceptParam
|
202
204
|
|
203
|
-
### Parse the given +accept_param+ as a mediatype and return a
|
205
|
+
### Parse the given +accept_param+ as a mediatype and return a
|
204
206
|
### Strelka::HTTPRequest::MediaType object for it.
|
205
207
|
def self::parse( accept_param )
|
206
208
|
raise ArgumentError, "Bad Accept param: no media-range in %p" % [accept_param] unless
|
@@ -239,7 +241,7 @@ class Strelka::HTTPRequest
|
|
239
241
|
# Accept-Language header.
|
240
242
|
class Language < Strelka::HTTPRequest::AcceptParam
|
241
243
|
|
242
|
-
### Parse the given +accept_param+ as a language range and return a
|
244
|
+
### Parse the given +accept_param+ as a language range and return a
|
243
245
|
### Strelka::HTTPRequest::Language object for it.
|
244
246
|
def self::parse( accept_param )
|
245
247
|
language_range, *stuff = accept_param.split( /\s*;\s*/ )
|
@@ -262,7 +264,7 @@ class Strelka::HTTPRequest
|
|
262
264
|
return [ self.primary_tag, self.subtag ].compact.join( '-' )
|
263
265
|
end
|
264
266
|
|
265
|
-
### Return the parameter as a String suitable for inclusion in an
|
267
|
+
### Return the parameter as a String suitable for inclusion in an
|
266
268
|
### Accept-language header.
|
267
269
|
def to_s
|
268
270
|
return [
|
@@ -278,7 +280,7 @@ class Strelka::HTTPRequest
|
|
278
280
|
# A content encoding parameter, such as one you'd find in an Accept-Encoding header.
|
279
281
|
class Encoding < Strelka::HTTPRequest::AcceptParam
|
280
282
|
|
281
|
-
### Parse the given +accept_param+ as a content coding and return a
|
283
|
+
### Parse the given +accept_param+ as a content coding and return a
|
282
284
|
### Strelka::HTTPRequest::Encoding object for it.
|
283
285
|
def self::parse( accept_param )
|
284
286
|
content_coding, *stuff = accept_param.split( /\s*;\s*/ )
|
@@ -295,7 +297,7 @@ class Strelka::HTTPRequest
|
|
295
297
|
alias_method :content_coding, :type
|
296
298
|
|
297
299
|
|
298
|
-
### Return the parameter as a String suitable for inclusion in an
|
300
|
+
### Return the parameter as a String suitable for inclusion in an
|
299
301
|
### Accept-language header.
|
300
302
|
def to_s
|
301
303
|
return [
|
@@ -311,7 +313,7 @@ class Strelka::HTTPRequest
|
|
311
313
|
# A content character-set parameter, such as one you'd find in an Accept-Charset header.
|
312
314
|
class Charset < Strelka::HTTPRequest::AcceptParam
|
313
315
|
|
314
|
-
### Parse the given +accept_param+ as a charset and return a
|
316
|
+
### Parse the given +accept_param+ as a charset and return a
|
315
317
|
### Strelka::HTTPRequest::Charset object for it.
|
316
318
|
def self::parse( accept_param )
|
317
319
|
charset, *stuff = accept_param.split( /\s*;\s*/ )
|
@@ -328,7 +330,7 @@ class Strelka::HTTPRequest
|
|
328
330
|
alias_method :name, :type
|
329
331
|
|
330
332
|
|
331
|
-
### Return the parameter as a String suitable for inclusion in an
|
333
|
+
### Return the parameter as a String suitable for inclusion in an
|
332
334
|
### Accept-language header.
|
333
335
|
def to_s
|
334
336
|
return [
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# -*- ruby -*-
|
2
|
+
# vim: set nosta noet ts=4 sw=4:
|
3
|
+
# encoding: utf-8
|
2
4
|
|
3
5
|
require 'strelka/constants'
|
4
6
|
require 'strelka/httprequest' unless defined?( Strelka::HTTPRequest )
|
@@ -19,7 +21,7 @@ require 'strelka/httprequest/acceptparams'
|
|
19
21
|
module Strelka::HTTPRequest::Negotiation
|
20
22
|
include Strelka::Constants
|
21
23
|
|
22
|
-
### Extension callback -- add instance variables to extended objects.
|
24
|
+
### Extension callback -- add instance variables to extended objects.
|
23
25
|
def initialize( * )
|
24
26
|
super
|
25
27
|
@accepted_mediatypes = nil
|
@@ -0,0 +1,71 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'configurability'
|
4
|
+
|
5
|
+
require 'strelka/constants'
|
6
|
+
require 'strelka/session' unless defined?( Strelka::Session )
|
7
|
+
require 'strelka/httprequest' unless defined?( Strelka::HTTPRequest )
|
8
|
+
|
9
|
+
|
10
|
+
# The mixin that adds methods to Strelka::HTTPRequest for session management.
|
11
|
+
#
|
12
|
+
# request.session?
|
13
|
+
# request.session
|
14
|
+
#
|
15
|
+
module Strelka::HTTPRequest::Session
|
16
|
+
extend Configurability
|
17
|
+
include Strelka::Constants
|
18
|
+
|
19
|
+
|
20
|
+
### Extension callback -- add instance variables to extended objects.
|
21
|
+
def initialize( * )
|
22
|
+
super
|
23
|
+
@session_namespace = nil
|
24
|
+
@session = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
######
|
29
|
+
public
|
30
|
+
######
|
31
|
+
|
32
|
+
# The current session namespace
|
33
|
+
attr_reader :session_namespace
|
34
|
+
|
35
|
+
|
36
|
+
### The namespace that will be used when creating a session for this request
|
37
|
+
def session_namespace=( namespace )
|
38
|
+
self.log.debug "Setting session namespace to %p" % [ namespace ]
|
39
|
+
@session_namespace = namespace
|
40
|
+
|
41
|
+
# If the session has already been created, switch its current namespace
|
42
|
+
@session.namespace = namespace if @session
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
### Returns +true+ if the request already has an associated session object.
|
47
|
+
def session?
|
48
|
+
return !@session.nil?
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
### Return the session associated with the request, creating it if necessary.
|
53
|
+
def session
|
54
|
+
unless @session
|
55
|
+
@session = Strelka::App::Sessions.session_class.load_or_create( self )
|
56
|
+
@session.namespace = self.session_namespace
|
57
|
+
end
|
58
|
+
|
59
|
+
return @session
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
### Set the request's session object.
|
64
|
+
def session=( new_session )
|
65
|
+
new_session.namespace = self.session_namespace
|
66
|
+
@session = new_session
|
67
|
+
end
|
68
|
+
|
69
|
+
end # module Strelka::HTTPRequest::Session
|
70
|
+
|
71
|
+
|
data/lib/strelka/httprequest.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# -*- ruby -*-
|
2
|
+
# vim: set nosta noet ts=4 sw=4:
|
3
|
+
# encoding: utf-8
|
2
4
|
|
3
5
|
require 'yajl'
|
4
6
|
require 'yaml'
|
@@ -7,6 +9,7 @@ require 'uri'
|
|
7
9
|
require 'mongrel2/httprequest'
|
8
10
|
require 'strelka' unless defined?( Strelka )
|
9
11
|
require 'strelka/httpresponse'
|
12
|
+
require 'strelka/cookieset'
|
10
13
|
|
11
14
|
# An HTTP request class.
|
12
15
|
class Strelka::HTTPRequest < Mongrel2::HTTPRequest
|
@@ -30,10 +33,11 @@ class Strelka::HTTPRequest < Mongrel2::HTTPRequest
|
|
30
33
|
### Initialize some additional stuff for Strelka requests.
|
31
34
|
def initialize( * ) # :notnew:
|
32
35
|
super
|
33
|
-
@uri
|
34
|
-
@verb
|
35
|
-
@params
|
36
|
-
@notes
|
36
|
+
@uri = nil
|
37
|
+
@verb = self.headers[:method].to_sym
|
38
|
+
@params = nil
|
39
|
+
@notes = Hash.new( &method(:autovivify) )
|
40
|
+
@cookies = nil
|
37
41
|
end
|
38
42
|
|
39
43
|
|
@@ -114,7 +118,7 @@ class Strelka::HTTPRequest < Mongrel2::HTTPRequest
|
|
114
118
|
|
115
119
|
|
116
120
|
### Parse the request parameters and return them as a Hash. For GET requests, these are
|
117
|
-
### take from the query arguments, and for POST requests, from the
|
121
|
+
### take from the query arguments, and for POST requests, from the
|
118
122
|
###
|
119
123
|
### # For a handler with a route of '/user', for the request:
|
120
124
|
### # "GET /user/1/profile?checkbox=1&checkbox=2&text=foo HTTP/1.1"
|
@@ -136,11 +140,19 @@ class Strelka::HTTPRequest < Mongrel2::HTTPRequest
|
|
136
140
|
end
|
137
141
|
|
138
142
|
|
143
|
+
### Fetch any cookies that accompanied the request as a Strelka::CookieSet, creating
|
144
|
+
### it if necessary.
|
145
|
+
def cookies
|
146
|
+
@cookies = Strelka::CookieSet.parse( self ) unless @cookies
|
147
|
+
return @cookies
|
148
|
+
end
|
149
|
+
|
150
|
+
|
139
151
|
#########
|
140
152
|
protected
|
141
153
|
#########
|
142
154
|
|
143
|
-
### Return a Hash of request query arguments.
|
155
|
+
### Return a Hash of request query arguments.
|
144
156
|
### ?arg1=yes&arg2=no&arg3 #=> {'arg1' => 'yes', 'arg2' => 'no', 'arg3' => nil}
|
145
157
|
def parse_query_args
|
146
158
|
return {} if self.uri.query.nil?
|