nitro 0.1.2
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/AUTHORS +8 -0
- data/ChangeLog +1546 -0
- data/LICENCE +32 -0
- data/README +278 -0
- data/RELEASES +7 -0
- data/Rakefile +79 -0
- data/bin/cluster.rb +219 -0
- data/doc/architecture.txt +28 -0
- data/doc/bugs.txt +7 -0
- data/doc/css.txt +20 -0
- data/doc/ideas.txt +120 -0
- data/doc/pg.txt +47 -0
- data/doc/svn.txt +82 -0
- data/doc/todo.txt +30 -0
- data/etc/new-project.rb +18 -0
- data/examples/simple/README +15 -0
- data/examples/simple/app.rb +31 -0
- data/examples/simple/conf/apache.conf +100 -0
- data/examples/simple/conf/config.rb +89 -0
- data/examples/simple/conf/debug-config.rb +53 -0
- data/examples/simple/conf/live-config.rb +48 -0
- data/examples/simple/conf/overrides.rb +9 -0
- data/examples/simple/conf/requires.rb +51 -0
- data/examples/simple/ctl +32 -0
- data/examples/simple/env.rb +33 -0
- data/examples/simple/install.rb +12 -0
- data/examples/simple/lib/articles/entities.rb +35 -0
- data/examples/simple/lib/articles/lc-en.rb +36 -0
- data/examples/simple/lib/articles/methods.rb +55 -0
- data/examples/simple/lib/articles/part.rb +58 -0
- data/examples/simple/logs/access_log +2 -0
- data/examples/simple/logs/apache.log +3 -0
- data/examples/simple/logs/app.log +1 -0
- data/examples/simple/logs/events.log +1 -0
- data/examples/simple/root/add-article.sx +15 -0
- data/examples/simple/root/article-form.ss +20 -0
- data/examples/simple/root/comments-form.ss +16 -0
- data/examples/simple/root/comments.si +30 -0
- data/examples/simple/root/index.sx +44 -0
- data/examples/simple/root/shader/shader.xsl +100 -0
- data/examples/simple/root/shader/style.css +9 -0
- data/examples/simple/root/view-article.sx +30 -0
- data/examples/tiny/app.rb +30 -0
- data/examples/tiny/conf/apache.conf +100 -0
- data/examples/tiny/conf/config.rb +67 -0
- data/examples/tiny/conf/requires.rb +40 -0
- data/examples/tiny/ctl +31 -0
- data/examples/tiny/logs/access_log +9 -0
- data/examples/tiny/logs/apache.log +9 -0
- data/examples/tiny/root/index.sx +35 -0
- data/lib/n/app/cluster.rb +219 -0
- data/lib/n/app/cookie.rb +86 -0
- data/lib/n/app/filters/autologin.rb +50 -0
- data/lib/n/app/fragment.rb +67 -0
- data/lib/n/app/handlers.rb +120 -0
- data/lib/n/app/handlers/code-handler.rb +184 -0
- data/lib/n/app/handlers/page-handler.rb +612 -0
- data/lib/n/app/request-part.rb +59 -0
- data/lib/n/app/request.rb +653 -0
- data/lib/n/app/script.rb +398 -0
- data/lib/n/app/server.rb +53 -0
- data/lib/n/app/session.rb +224 -0
- data/lib/n/app/user.rb +47 -0
- data/lib/n/app/webrick-servlet.rb +213 -0
- data/lib/n/app/webrick.rb +70 -0
- data/lib/n/application.rb +187 -0
- data/lib/n/config.rb +31 -0
- data/lib/n/db.rb +217 -0
- data/lib/n/db/README +232 -0
- data/lib/n/db/connection.rb +369 -0
- data/lib/n/db/make-release.sh +26 -0
- data/lib/n/db/managed.rb +235 -0
- data/lib/n/db/mixins.rb +282 -0
- data/lib/n/db/mysql.rb +342 -0
- data/lib/n/db/psql.rb +378 -0
- data/lib/n/db/tools.rb +110 -0
- data/lib/n/db/utils.rb +99 -0
- data/lib/n/events.rb +118 -0
- data/lib/n/l10n.rb +22 -0
- data/lib/n/logger.rb +33 -0
- data/lib/n/macros.rb +53 -0
- data/lib/n/mixins.rb +46 -0
- data/lib/n/parts.rb +154 -0
- data/lib/n/properties.rb +194 -0
- data/lib/n/server.rb +61 -0
- data/lib/n/server/PLAYBACK.txt +8 -0
- data/lib/n/server/RESEARCH.txt +13 -0
- data/lib/n/server/filter.rb +77 -0
- data/lib/n/shaders.rb +167 -0
- data/lib/n/sitemap.rb +188 -0
- data/lib/n/std.rb +69 -0
- data/lib/n/sync/clc.rb +108 -0
- data/lib/n/sync/handler.rb +221 -0
- data/lib/n/sync/server.rb +170 -0
- data/lib/n/tools/README +11 -0
- data/lib/n/ui/date-select.rb +74 -0
- data/lib/n/ui/pager.rb +187 -0
- data/lib/n/ui/popup.rb +45 -0
- data/lib/n/ui/select.rb +41 -0
- data/lib/n/ui/tabs.rb +34 -0
- data/lib/n/utils/array.rb +92 -0
- data/lib/n/utils/cache.rb +144 -0
- data/lib/n/utils/gfx.rb +108 -0
- data/lib/n/utils/hash.rb +148 -0
- data/lib/n/utils/html.rb +147 -0
- data/lib/n/utils/http.rb +98 -0
- data/lib/n/utils/mail.rb +28 -0
- data/lib/n/utils/number.rb +31 -0
- data/lib/n/utils/pool.rb +66 -0
- data/lib/n/utils/string.rb +297 -0
- data/lib/n/utils/template.rb +38 -0
- data/lib/n/utils/time.rb +91 -0
- data/lib/n/utils/uri.rb +193 -0
- data/lib/xsl/base.xsl +205 -0
- data/lib/xsl/ce.xsl +30 -0
- data/lib/xsl/localization.xsl +23 -0
- data/lib/xsl/xforms.xsl +26 -0
- data/test/run.rb +95 -0
- metadata +187 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# = RequestPart
|
|
2
|
+
#
|
|
3
|
+
# Encapsulates a multipart part.
|
|
4
|
+
#
|
|
5
|
+
# code:
|
|
6
|
+
# George Moschovitis <gm@navel.gr>
|
|
7
|
+
#
|
|
8
|
+
# (c) 2004 Navel, all rights reserved.
|
|
9
|
+
# $Id: request-part.rb 71 2004-10-18 10:50:22Z gmosx $
|
|
10
|
+
|
|
11
|
+
require "cgi"
|
|
12
|
+
require "ftools"
|
|
13
|
+
|
|
14
|
+
require "n/utils/string"
|
|
15
|
+
require "n/utils/uri"
|
|
16
|
+
require "n/utils/http"
|
|
17
|
+
require "n/app/cookie"
|
|
18
|
+
|
|
19
|
+
module N; module App
|
|
20
|
+
|
|
21
|
+
# RequestPart
|
|
22
|
+
#
|
|
23
|
+
# This class encapsulates a part in a multipart request.
|
|
24
|
+
# A part is typically an uploaded files.
|
|
25
|
+
#
|
|
26
|
+
class RequestPart
|
|
27
|
+
# the filename of the part
|
|
28
|
+
attr_accessor :filename
|
|
29
|
+
|
|
30
|
+
# the original filename path
|
|
31
|
+
attr_accessor :original_path
|
|
32
|
+
|
|
33
|
+
# the temp filename path
|
|
34
|
+
attr_accessor :body
|
|
35
|
+
|
|
36
|
+
# the content-type
|
|
37
|
+
attr_accessor :content_type
|
|
38
|
+
|
|
39
|
+
def initialize(original_path, body, content_type = nil)
|
|
40
|
+
@original_path = original_path
|
|
41
|
+
@body = body
|
|
42
|
+
@content_type = content_type
|
|
43
|
+
# handle dos + unix separators.
|
|
44
|
+
@filename = @original_path.split(/\/|\\/).last
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# gmosx:
|
|
48
|
+
# Hack fixed save for webrick!
|
|
49
|
+
#
|
|
50
|
+
def save(prefix, forced_filename = nil, forced_extension = nil)
|
|
51
|
+
# ARGH!! local path is used for something else, FIXME!!
|
|
52
|
+
::FileUtils.mkdir_p(prefix)
|
|
53
|
+
save_path = "#{prefix}/#{@filename}"
|
|
54
|
+
::File.open(save_path, "wb") {|f| f.write @body }
|
|
55
|
+
return save_path
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end; end # module
|
|
@@ -0,0 +1,653 @@
|
|
|
1
|
+
# = Request
|
|
2
|
+
#
|
|
3
|
+
# Will use params with symbols for args. use uppercase for system
|
|
4
|
+
# 'args'.
|
|
5
|
+
#
|
|
6
|
+
# === INVESTIGATE:
|
|
7
|
+
# extend request from hash? to make more compatible with irb?
|
|
8
|
+
#
|
|
9
|
+
# code: gmosx, drak
|
|
10
|
+
#
|
|
11
|
+
# (c) 2004 Navel, all rights reserved.
|
|
12
|
+
# $Id: request.rb 71 2004-10-18 10:50:22Z gmosx $
|
|
13
|
+
|
|
14
|
+
require "cgi"
|
|
15
|
+
require "ftools"
|
|
16
|
+
|
|
17
|
+
require "n/utils/string"
|
|
18
|
+
require "n/utils/uri"
|
|
19
|
+
require "n/utils/http"
|
|
20
|
+
require "n/app/cookie"
|
|
21
|
+
require "n/app/request-part"
|
|
22
|
+
|
|
23
|
+
module N; module App
|
|
24
|
+
|
|
25
|
+
# = RequestUtils
|
|
26
|
+
#
|
|
27
|
+
# A collection of Request utility methods. Factored out from the
|
|
28
|
+
# Request object in a separate module to allow for inclusion in generic
|
|
29
|
+
# request objects (for example WEBrick).
|
|
30
|
+
#
|
|
31
|
+
module RequestUtils
|
|
32
|
+
|
|
33
|
+
# Full URI
|
|
34
|
+
#
|
|
35
|
+
def full_uri
|
|
36
|
+
if @query_string
|
|
37
|
+
return "#{@translated_uri}?#{@query_string}"
|
|
38
|
+
else
|
|
39
|
+
return @translated_uri
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Expand URI
|
|
44
|
+
# Calculates a new uri based on the request.uri that includes
|
|
45
|
+
# the additional parameters suplied.
|
|
46
|
+
#
|
|
47
|
+
def expand_uri(params)
|
|
48
|
+
hash = @parameters.dup()
|
|
49
|
+
hash.update(params)
|
|
50
|
+
|
|
51
|
+
pairs = []
|
|
52
|
+
hash.each { |param, value|
|
|
53
|
+
pairs << "#{param}=#{value}"
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
# gmosx: hash is ALWAYS non empty!
|
|
57
|
+
return "#{@translated_uri}?#{pairs.join(';')}"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Uses the passed oid_param to load a managed object (entity).
|
|
61
|
+
# Enforces some form of security by checking the klass of the
|
|
62
|
+
# requested entity.
|
|
63
|
+
#
|
|
64
|
+
def get_entity(oid_param, klass = nil)
|
|
65
|
+
if oid = self[oid_param]
|
|
66
|
+
obj = $db.get(oid, klass)
|
|
67
|
+
|
|
68
|
+
if klass
|
|
69
|
+
if obj.is_a?(klass)
|
|
70
|
+
return obj
|
|
71
|
+
else
|
|
72
|
+
return nil
|
|
73
|
+
end
|
|
74
|
+
else
|
|
75
|
+
return obj
|
|
76
|
+
end
|
|
77
|
+
else
|
|
78
|
+
# $log.error "request.get_object('#{oid_param}') failed!"
|
|
79
|
+
return nil
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Uses the passed name_param to load a managed object (entity)
|
|
84
|
+
# by name.
|
|
85
|
+
# Enforces some form of security by checking the klass of the
|
|
86
|
+
# requested entity.
|
|
87
|
+
#
|
|
88
|
+
def get_entity_by_name(name_param, klass)
|
|
89
|
+
if name = self[name_param]
|
|
90
|
+
obj = $db.get_by_name(name, klass)
|
|
91
|
+
|
|
92
|
+
if klass
|
|
93
|
+
if obj.is_a?(klass)
|
|
94
|
+
return obj
|
|
95
|
+
else
|
|
96
|
+
return nil
|
|
97
|
+
end
|
|
98
|
+
else
|
|
99
|
+
# $log.error "request.get_object_by_name('#{name_param}') failed!"
|
|
100
|
+
return obj
|
|
101
|
+
end
|
|
102
|
+
else
|
|
103
|
+
return nil
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# = Request
|
|
110
|
+
#
|
|
111
|
+
# Encapsulates an http protocol request. Generally clones
|
|
112
|
+
# the Apache Request passed by mod_ruby.
|
|
113
|
+
#
|
|
114
|
+
# === Todo:
|
|
115
|
+
#
|
|
116
|
+
# - USE libapreq!
|
|
117
|
+
# - Dont use env_table (arghhhh!)
|
|
118
|
+
# - dont use a separate path and real path
|
|
119
|
+
# - MEGA: unify request and request (like a socket, io
|
|
120
|
+
# stream,etc). Evan subclass IO!
|
|
121
|
+
#
|
|
122
|
+
# === Design:
|
|
123
|
+
#
|
|
124
|
+
# - uri: the original uri entered to the browser (INCLUDES qs)
|
|
125
|
+
# gmosx: i included the qs and removed full_uri (always forgot
|
|
126
|
+
# to use it anyway, was very error prone)
|
|
127
|
+
# - translated_uri: as translated by the web server (no query string)
|
|
128
|
+
# - path: the path to the actual script (or object)
|
|
129
|
+
#
|
|
130
|
+
# Example:
|
|
131
|
+
#
|
|
132
|
+
# http://www.site.com/faq/?id=1
|
|
133
|
+
# ->
|
|
134
|
+
# uri: /faq/?id=1
|
|
135
|
+
# translated_uri: /faq/index.sx
|
|
136
|
+
# path: base/site/root/faq/index.sx
|
|
137
|
+
# query_string: id=1
|
|
138
|
+
#
|
|
139
|
+
# - querystring should probably include the ?
|
|
140
|
+
# - Encapsulate ModRuby/Apache requests
|
|
141
|
+
# - Based on resin3.0 excellent code:
|
|
142
|
+
# com/caucho/server/http/HttpRequest.java
|
|
143
|
+
# - use as much of ruby's default cgi/http code as
|
|
144
|
+
# possible (why reinvent the wheel?)
|
|
145
|
+
#
|
|
146
|
+
#
|
|
147
|
+
class Request
|
|
148
|
+
# include usefull query parsing code from the standard
|
|
149
|
+
# lib. ARGHHH cgi.rb sucks!
|
|
150
|
+
include CGI::QueryExtension
|
|
151
|
+
include RequestUtils
|
|
152
|
+
|
|
153
|
+
# request methods enumeration
|
|
154
|
+
METHOD_GET = 0
|
|
155
|
+
METHOD_POST = 1
|
|
156
|
+
METHOD_HEAD = 2
|
|
157
|
+
|
|
158
|
+
# request method
|
|
159
|
+
attr_accessor :method
|
|
160
|
+
|
|
161
|
+
# content type
|
|
162
|
+
attr_accessor :content_type
|
|
163
|
+
|
|
164
|
+
# the uri for the request. For sub-requests keeps the
|
|
165
|
+
# uri of the top level request.
|
|
166
|
+
# gmosx: the writer is needed for injects.
|
|
167
|
+
attr_accessor :uri
|
|
168
|
+
|
|
169
|
+
# the uri as translated by the web server. For sub-requests keeps
|
|
170
|
+
# the usri of the top level request.
|
|
171
|
+
attr_accessor :translated_uri
|
|
172
|
+
|
|
173
|
+
# the path to the actual object (script)
|
|
174
|
+
# gets overriden by sub-requests, is not needed in scripts.
|
|
175
|
+
attr_accessor :path
|
|
176
|
+
|
|
177
|
+
# path info (extra parameters in the uri)
|
|
178
|
+
#
|
|
179
|
+
attr_accessor :path_info
|
|
180
|
+
|
|
181
|
+
# the query string part of the uri
|
|
182
|
+
attr_accessor :query_string
|
|
183
|
+
|
|
184
|
+
# The query string is parsed to the parameters
|
|
185
|
+
# hash.
|
|
186
|
+
attr_accessor :parameters
|
|
187
|
+
alias_method :query, :parameters
|
|
188
|
+
|
|
189
|
+
# the session this request is part-of
|
|
190
|
+
attr_accessor :session
|
|
191
|
+
|
|
192
|
+
# The parts attached to this request.
|
|
193
|
+
# A part is typically an uploaded file. By using
|
|
194
|
+
# a separate hash instead of the parameters hash one
|
|
195
|
+
# can easily enumerate parts.
|
|
196
|
+
attr_accessor :parts
|
|
197
|
+
|
|
198
|
+
# the level of the request (0 = toplevel)
|
|
199
|
+
attr_accessor :level
|
|
200
|
+
|
|
201
|
+
# the remote address for this request
|
|
202
|
+
attr_accessor :remote_addr
|
|
203
|
+
|
|
204
|
+
# Is the request cacheable?
|
|
205
|
+
# Set this attribute to 'true' to avoid caching the request
|
|
206
|
+
# fragment. Used to avoid caching 'action' requests.
|
|
207
|
+
attr_accessor :uncacheable
|
|
208
|
+
|
|
209
|
+
# the locale hash for this request.
|
|
210
|
+
attr_accessor :locale
|
|
211
|
+
|
|
212
|
+
# the shader for this request.
|
|
213
|
+
attr_accessor :shader
|
|
214
|
+
|
|
215
|
+
# the script hash for this request
|
|
216
|
+
attr_accessor :tag
|
|
217
|
+
|
|
218
|
+
# keep the original handler process uri, usefull as a cache key.
|
|
219
|
+
# Typically updated in subrequests only. Investigate if we could
|
|
220
|
+
# use a hash here!
|
|
221
|
+
attr_accessor :fragment_hash
|
|
222
|
+
|
|
223
|
+
# Keep all errors to present them in-page when in admin mode.
|
|
224
|
+
attr_accessor :error_log
|
|
225
|
+
|
|
226
|
+
# The top level script for this request.
|
|
227
|
+
attr_accessor :top_script
|
|
228
|
+
|
|
229
|
+
# last modified cache
|
|
230
|
+
attr_accessor :lm
|
|
231
|
+
|
|
232
|
+
# request:
|
|
233
|
+
|
|
234
|
+
# the incoming headers
|
|
235
|
+
# gmosx: writer needed for inject (sub-req cloning)
|
|
236
|
+
attr_accessor :in
|
|
237
|
+
|
|
238
|
+
# the incoming cookies
|
|
239
|
+
attr_accessor :in_cookies
|
|
240
|
+
|
|
241
|
+
# request:
|
|
242
|
+
|
|
243
|
+
# the outgoing headers
|
|
244
|
+
attr_accessor :out
|
|
245
|
+
|
|
246
|
+
# the outgoing cookies
|
|
247
|
+
attr_accessor :out_cookies
|
|
248
|
+
|
|
249
|
+
# the outgoing buffer
|
|
250
|
+
attr_accessor :out_buffer
|
|
251
|
+
|
|
252
|
+
# request content type, default: text/html
|
|
253
|
+
attr_accessor :content_type
|
|
254
|
+
|
|
255
|
+
# HTTP request status
|
|
256
|
+
attr_accessor :status
|
|
257
|
+
|
|
258
|
+
# HTTP request message
|
|
259
|
+
attr_accessor :message
|
|
260
|
+
|
|
261
|
+
def initialize
|
|
262
|
+
# set to 0 (== top level). When including fragments
|
|
263
|
+
# the level is incremented.
|
|
264
|
+
@level = 0
|
|
265
|
+
|
|
266
|
+
# gmosx: it would be good to defere the hash creation,
|
|
267
|
+
# but having the hash always created saves as a LOT of
|
|
268
|
+
# checks in client code, so we create it here.
|
|
269
|
+
#
|
|
270
|
+
# FIXME: WE SHOULD NOT CREATE unneeded hash objects.
|
|
271
|
+
#
|
|
272
|
+
# @parts = {}
|
|
273
|
+
|
|
274
|
+
# request:
|
|
275
|
+
# provide some fair initialization values.
|
|
276
|
+
set_status(200)
|
|
277
|
+
@content_type = "text/html; charset=iso-8859-7"
|
|
278
|
+
@out = {}
|
|
279
|
+
@out_cookies = {}
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
#-----------------------------------------------------------------------
|
|
283
|
+
# Headers
|
|
284
|
+
|
|
285
|
+
# Return the referer to this resource. For the initial page in the
|
|
286
|
+
# clickstream there is no referer, set "/" by default.
|
|
287
|
+
|
|
288
|
+
def referer
|
|
289
|
+
return @in["REFERER"] || "/"
|
|
290
|
+
end
|
|
291
|
+
alias_method :referrer, :referer
|
|
292
|
+
|
|
293
|
+
#-----------------------------------------------------------------------
|
|
294
|
+
# Cookies
|
|
295
|
+
|
|
296
|
+
# this method is also usefull for probing (testing) the request class.
|
|
297
|
+
# FIXME: optimize this (libapreq)
|
|
298
|
+
|
|
299
|
+
def parse_cookies(cookie_string)
|
|
300
|
+
@cookies = Cookie.parse(cookie_string)
|
|
301
|
+
end
|
|
302
|
+
alias_method :parse_cookie_string, :parse_cookies
|
|
303
|
+
|
|
304
|
+
# === Input:
|
|
305
|
+
# the cookie name
|
|
306
|
+
#
|
|
307
|
+
# === Output:
|
|
308
|
+
# - the cookie value, or an array of values for multivalued cookies.
|
|
309
|
+
# - nil if the cookie doesnt exist.
|
|
310
|
+
#
|
|
311
|
+
# === Example:
|
|
312
|
+
# nsid = request.get_cookie("nsid")
|
|
313
|
+
#
|
|
314
|
+
def get_cookie(cookie_name)
|
|
315
|
+
return nil unless @in_cookies
|
|
316
|
+
cookie = @in_cookies[cookie_name]
|
|
317
|
+
return nil unless cookie
|
|
318
|
+
return CGI.unescape(cookie.value)
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
# Removes a cookie from the client by seting the expire
|
|
322
|
+
# time to the past (epoch).
|
|
323
|
+
#
|
|
324
|
+
def del_cookie(name)
|
|
325
|
+
cookie = N::App::Cookie.new(name, "nil")
|
|
326
|
+
cookie.path = "/"
|
|
327
|
+
cookie.expires = Time.at(0)
|
|
328
|
+
@out_cookies[name] = cookie
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
#-------------------------------------------------------------------------------
|
|
332
|
+
# Query
|
|
333
|
+
|
|
334
|
+
def parse_query_string
|
|
335
|
+
return N::UriUtils.query_string_to_hash(@query_string)
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
# Return the value of a query parameter
|
|
339
|
+
|
|
340
|
+
def [](name)
|
|
341
|
+
return @parameters[name]
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
# Same as [] but enforces a default value to!
|
|
345
|
+
# Also tries to guess the parameters type from the default
|
|
346
|
+
# value. It works like delete (ie returns nil for 'empty'
|
|
347
|
+
# String parameters).
|
|
348
|
+
#
|
|
349
|
+
def get(key, default=nil)
|
|
350
|
+
val = @parameters[key]
|
|
351
|
+
|
|
352
|
+
if !val or (val.is_a?(String) and (not N::StringUtils.valid?(val)))
|
|
353
|
+
@parameters[key] = default
|
|
354
|
+
return default
|
|
355
|
+
elsif default.is_a?(Integer)
|
|
356
|
+
return val.to_i
|
|
357
|
+
else
|
|
358
|
+
return val
|
|
359
|
+
end
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
# Set the value of a query parameter
|
|
363
|
+
#
|
|
364
|
+
# === FIXME:
|
|
365
|
+
# - handle multivalued parameters!
|
|
366
|
+
|
|
367
|
+
def []=(name, value)
|
|
368
|
+
@parameters[name] = value
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
#-----------------------------------------------------------------------
|
|
372
|
+
# Utilities
|
|
373
|
+
|
|
374
|
+
# Returns true for the top-level request, but false for
|
|
375
|
+
# any inject or forward
|
|
376
|
+
#
|
|
377
|
+
def is_top?
|
|
378
|
+
return 0 == @level
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
# Is this an admin request?
|
|
382
|
+
# FIXME: no longer valid, recode.
|
|
383
|
+
#
|
|
384
|
+
def admin?
|
|
385
|
+
return @parameters.include?("*admin")
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
# Shorthand for request.session.user
|
|
389
|
+
#
|
|
390
|
+
def user
|
|
391
|
+
return @session.user
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
# Shorthand for request.session.user.anonymous?
|
|
395
|
+
#
|
|
396
|
+
def anonymous?
|
|
397
|
+
return @session.user.anonymous?
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
# Set errors as a transaction entity.
|
|
401
|
+
# Returns the txid for the errors
|
|
402
|
+
def set_errors(errors)
|
|
403
|
+
new_tx_entity!(errors, "errid") unless errors.empty?
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
# Shorthand
|
|
407
|
+
#
|
|
408
|
+
# Output:
|
|
409
|
+
# nil if no errors.
|
|
410
|
+
#
|
|
411
|
+
def errors
|
|
412
|
+
return del_tx_entity!("errid")
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
# Returns the errors as an array.
|
|
416
|
+
#
|
|
417
|
+
def errors_to_a
|
|
418
|
+
if errors = del_tx_entity!("errid")
|
|
419
|
+
return errors.values
|
|
420
|
+
end
|
|
421
|
+
return nil
|
|
422
|
+
end
|
|
423
|
+
alias_method :errors_list, :errors_to_a
|
|
424
|
+
|
|
425
|
+
# Check if a parameter is valid
|
|
426
|
+
#
|
|
427
|
+
def param?(param)
|
|
428
|
+
return N::StringUtils.valid?(self[param])
|
|
429
|
+
end
|
|
430
|
+
alias_method :action?, :param?
|
|
431
|
+
|
|
432
|
+
# Check if a parameter exists!
|
|
433
|
+
# Example:
|
|
434
|
+
# url:www.mysite.com/page.sx?admin
|
|
435
|
+
# request.include?(admin) => true
|
|
436
|
+
#
|
|
437
|
+
def include?(param)
|
|
438
|
+
return @parameters.include?(param)
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
def update(*params)
|
|
442
|
+
@parameters.update(*params)
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
# Use the delete name to make the request compatible with
|
|
446
|
+
# hashes.
|
|
447
|
+
# Tests is a parameter is passed to the request and removes it!
|
|
448
|
+
# Used in action handlers.
|
|
449
|
+
#
|
|
450
|
+
def delete(param)
|
|
451
|
+
oparam = param
|
|
452
|
+
if param = @parameters.delete(param)
|
|
453
|
+
# gmosx: remove from querystring too! NEEDED.
|
|
454
|
+
# perhaps kinda slow but happens seldom and optimizes
|
|
455
|
+
# another frequent case
|
|
456
|
+
@query_string = @parameters.collect { |k, v| (v && k.is_a?(String)) ? "#{k}=#{v}" : k }.join(";")
|
|
457
|
+
|
|
458
|
+
# If the parameter exist this is an action request, so
|
|
459
|
+
# do NOT cache the fragment.
|
|
460
|
+
@uncacheable = true
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
# gmosx: to avoid using param?
|
|
464
|
+
if param.is_a?(String) and (not N::StringUtils.valid?(param))
|
|
465
|
+
return nil
|
|
466
|
+
else
|
|
467
|
+
return param
|
|
468
|
+
end
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
# exclude those parameters for security
|
|
472
|
+
EXCLUDED_PARAMETERS = %w{ oid pid name }
|
|
473
|
+
|
|
474
|
+
# gmosx: hmm this is a really dangerous method, the EXCLUDED params
|
|
475
|
+
# above dont seem enough :(
|
|
476
|
+
#
|
|
477
|
+
def update_entity(entity)
|
|
478
|
+
@parameters.each { |param, val|
|
|
479
|
+
begin
|
|
480
|
+
# gmosx: DO NOT escape by default !!!
|
|
481
|
+
# gmosx: We need to get non valid params
|
|
482
|
+
if (not EXCLUDED_PARAMETERS.include?(param))
|
|
483
|
+
entity.send("__force_#{param}", val)
|
|
484
|
+
end
|
|
485
|
+
rescue NameError
|
|
486
|
+
next
|
|
487
|
+
end
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
return entity
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
# --------------------------------------------------------------------
|
|
494
|
+
|
|
495
|
+
# The tx sequence increases, the count of transactions / session
|
|
496
|
+
# is usually bounded.
|
|
497
|
+
#
|
|
498
|
+
def new_tx_entity!(entity, txparam = "txid")
|
|
499
|
+
unless seq = @session["TXSEQ"]
|
|
500
|
+
seq = 0
|
|
501
|
+
end
|
|
502
|
+
seq += 1
|
|
503
|
+
@session["TXSEQ"] = seq
|
|
504
|
+
txid = "TX#{seq}"
|
|
505
|
+
@session[txid] = entity
|
|
506
|
+
@parameters[txparam] = txid
|
|
507
|
+
return txid
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
# Set (update) an existing tx entity. Does NOT increase the
|
|
511
|
+
# tx sequence.
|
|
512
|
+
#
|
|
513
|
+
def set_tx_entity!(entity, txparam = "txid")
|
|
514
|
+
if txid = @parameters[txparam]
|
|
515
|
+
@session[txid] = entity
|
|
516
|
+
end
|
|
517
|
+
end
|
|
518
|
+
alias_method :update_tx_entity!, :set_tx_entity!
|
|
519
|
+
|
|
520
|
+
#
|
|
521
|
+
#
|
|
522
|
+
def get_tx_entity(txparam = "txid")
|
|
523
|
+
if txid = @parameters[txparam]
|
|
524
|
+
return @session[txid]
|
|
525
|
+
end
|
|
526
|
+
return nil
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
#
|
|
530
|
+
#
|
|
531
|
+
def del_tx_entity!(txparam = "txid")
|
|
532
|
+
if txid = @parameters[txparam]
|
|
533
|
+
@session.delete(txid)
|
|
534
|
+
end
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
# --------------------------------------------------------------------
|
|
538
|
+
# Debugging helper
|
|
539
|
+
|
|
540
|
+
#
|
|
541
|
+
#
|
|
542
|
+
def log_error(str)
|
|
543
|
+
@error_log = [] unless @error_log
|
|
544
|
+
@error_log << str if @error_log.size < 200 # gmosx: dod attack!
|
|
545
|
+
$log.error str
|
|
546
|
+
end
|
|
547
|
+
|
|
548
|
+
# ====================================================================
|
|
549
|
+
# Request
|
|
550
|
+
|
|
551
|
+
# TODO: add status codes, messages
|
|
552
|
+
|
|
553
|
+
# Set the request HTTP status and lookup the
|
|
554
|
+
# corresponding request status message.
|
|
555
|
+
|
|
556
|
+
def set_status(status = 200)
|
|
557
|
+
@status = status
|
|
558
|
+
@message = HTTP::STATUS_STRINGS[status]
|
|
559
|
+
end
|
|
560
|
+
|
|
561
|
+
# Set the HTTP NOT_MODIFIED status code.
|
|
562
|
+
# Usefull for HTTP Caching.
|
|
563
|
+
#
|
|
564
|
+
def set_not_modified!
|
|
565
|
+
@status = 304
|
|
566
|
+
@message = N::HTTP::STATUS_STRINGS[status]
|
|
567
|
+
end
|
|
568
|
+
|
|
569
|
+
# 302 is the redirect status!
|
|
570
|
+
#
|
|
571
|
+
# === Status 303:
|
|
572
|
+
#
|
|
573
|
+
# The request to the request can be found
|
|
574
|
+
# under a different URI and SHOULD be retrieved using
|
|
575
|
+
# a GET method on that resource. This method exists
|
|
576
|
+
# primarily to allow the output of a POST-activated script
|
|
577
|
+
# to redirect the user agent to a selected resource. The new
|
|
578
|
+
# URI is not a substitute reference for the originally
|
|
579
|
+
# requested resource. The 303 request MUST NOT be cached,
|
|
580
|
+
# but the request to the second (redirected) request might
|
|
581
|
+
# be cacheable.
|
|
582
|
+
#
|
|
583
|
+
# Note: Many pre-HTTP/1.1 user agents do not understand the
|
|
584
|
+
# 303 status. When interoperability with such clients is a
|
|
585
|
+
# concern, the 302 status code may be used instead, since
|
|
586
|
+
# most user agents react to a 302 request as described
|
|
587
|
+
# here for 303.
|
|
588
|
+
#
|
|
589
|
+
# === WARNING:
|
|
590
|
+
#
|
|
591
|
+
# Konqueror always performs a 307 redirect ARGH!
|
|
592
|
+
#
|
|
593
|
+
# === Redesign:
|
|
594
|
+
#
|
|
595
|
+
# Use one redirect method with an optional status
|
|
596
|
+
# parameter, that reads messages from the status
|
|
597
|
+
# constants.
|
|
598
|
+
#
|
|
599
|
+
# === Input:
|
|
600
|
+
#
|
|
601
|
+
# - url to redirect to
|
|
602
|
+
# - if force_exit == true raises a ScriptExitException
|
|
603
|
+
# - status (303 or 307) default = 303
|
|
604
|
+
#
|
|
605
|
+
def redirect(url = nil, force_exit = false, status = 302)
|
|
606
|
+
# FIXME: normalize the url
|
|
607
|
+
# url = $srv_url + url if url =~ /^\//om
|
|
608
|
+
# FIXME: check arguments
|
|
609
|
+
|
|
610
|
+
# enforce a meaningfull default
|
|
611
|
+
url ||= self["_go"] || referer()
|
|
612
|
+
|
|
613
|
+
# the url should have a leading "/"
|
|
614
|
+
# enforce it to be sure. FIXME: optimize this!
|
|
615
|
+
url = "/#{url}".squeeze("/") unless url =~ /^http/
|
|
616
|
+
|
|
617
|
+
@out["Location"] = url
|
|
618
|
+
# gmosx: NOT needed? see the exceprt from the spec.
|
|
619
|
+
# @out['Cache-Control'] = "max-age=1"
|
|
620
|
+
|
|
621
|
+
set_status(status)
|
|
622
|
+
@out_buffer = "The URL has moved <a href='#{url}'>here</a>"
|
|
623
|
+
|
|
624
|
+
if force_exit
|
|
625
|
+
# Stop rendering the script immediately!
|
|
626
|
+
# This is the default behaviour!
|
|
627
|
+
raise N::ScriptExitException
|
|
628
|
+
end
|
|
629
|
+
|
|
630
|
+
# for unit testing
|
|
631
|
+
return url
|
|
632
|
+
end
|
|
633
|
+
|
|
634
|
+
# Internal redirect
|
|
635
|
+
#
|
|
636
|
+
# FIXME: implement me
|
|
637
|
+
#
|
|
638
|
+
def internal_redirect(url)
|
|
639
|
+
end
|
|
640
|
+
|
|
641
|
+
# Utility method to set the expires header.
|
|
642
|
+
#
|
|
643
|
+
def expires!(exp_time)
|
|
644
|
+
@out["Expires"] = N::HttpUtils.time_to_string(exp_time)
|
|
645
|
+
end
|
|
646
|
+
|
|
647
|
+
def expires?
|
|
648
|
+
return @out["Expires"]
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
end
|
|
652
|
+
|
|
653
|
+
end; end # module
|