nitro 0.20.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +752 -543
- data/INSTALL +38 -38
- data/README +264 -225
- data/Rakefile +48 -49
- data/bin/nitro +3 -3
- data/bin/nitrogen +6 -6
- data/doc/AUTHORS +10 -10
- data/doc/CHANGELOG.1 +1939 -1939
- data/doc/CHANGELOG.2 +954 -954
- data/doc/LICENSE +3 -3
- data/doc/MIGRATION +28 -0
- data/doc/RELEASES +814 -643
- data/doc/config.txt +5 -5
- data/install.rb +7 -17
- data/lib/nitro.rb +38 -9
- data/lib/nitro/adapter/cgi.rb +311 -312
- data/lib/nitro/adapter/fastcgi.rb +18 -25
- data/lib/nitro/adapter/webrick.rb +128 -137
- data/lib/nitro/adapter/wee.rb +51 -0
- data/lib/nitro/caching.rb +20 -20
- data/lib/nitro/caching/actions.rb +43 -43
- data/lib/nitro/caching/fragments.rb +46 -46
- data/lib/nitro/caching/invalidation.rb +11 -11
- data/lib/nitro/caching/output.rb +65 -65
- data/lib/nitro/caching/stores.rb +67 -67
- data/lib/nitro/compiler.rb +262 -0
- data/lib/nitro/compiler/elements.rb +0 -0
- data/lib/nitro/compiler/errors.rb +65 -0
- data/lib/nitro/compiler/localization.rb +25 -0
- data/lib/nitro/compiler/markup.rb +19 -0
- data/lib/nitro/compiler/shaders.rb +206 -0
- data/lib/nitro/compiler/squeeze.rb +20 -0
- data/lib/nitro/compiler/xslt.rb +61 -0
- data/lib/nitro/context.rb +87 -88
- data/lib/nitro/controller.rb +151 -158
- data/lib/nitro/cookie.rb +34 -34
- data/lib/nitro/dispatcher.rb +195 -186
- data/lib/nitro/element.rb +132 -126
- data/lib/nitro/element/java_script.rb +6 -6
- data/lib/nitro/flash.rb +66 -66
- data/lib/nitro/mail.rb +192 -192
- data/lib/nitro/mixin/buffer.rb +66 -0
- data/lib/nitro/mixin/debug.rb +16 -16
- data/lib/nitro/mixin/form.rb +88 -0
- data/lib/nitro/mixin/helper.rb +2 -2
- data/lib/nitro/mixin/javascript.rb +108 -108
- data/lib/nitro/mixin/markup.rb +144 -0
- data/lib/nitro/mixin/pager.rb +202 -202
- data/lib/nitro/mixin/rss.rb +67 -0
- data/lib/nitro/mixin/table.rb +63 -0
- data/lib/nitro/mixin/xhtml.rb +75 -0
- data/lib/nitro/mixin/xml.rb +124 -0
- data/lib/nitro/render.rb +183 -359
- data/lib/nitro/request.rb +140 -140
- data/lib/nitro/response.rb +27 -27
- data/lib/nitro/routing.rb +21 -21
- data/lib/nitro/scaffold.rb +124 -118
- data/lib/nitro/server.rb +117 -80
- data/lib/nitro/server/runner.rb +341 -0
- data/lib/nitro/service.rb +12 -12
- data/lib/nitro/service/xmlrpc.rb +22 -22
- data/lib/nitro/session.rb +122 -120
- data/lib/nitro/session/drb.rb +9 -9
- data/lib/nitro/session/drbserver.rb +34 -34
- data/lib/nitro/template.rb +171 -155
- data/lib/nitro/testing/assertions.rb +90 -90
- data/lib/nitro/testing/context.rb +16 -16
- data/lib/nitro/testing/testcase.rb +34 -34
- data/proto/conf/lhttpd.conf +9 -9
- data/proto/public/error.xhtml +75 -75
- data/proto/public/index.xhtml +18 -18
- data/proto/public/js/behaviour.js +65 -65
- data/proto/public/js/controls.js +1 -1
- data/proto/public/js/prototype.js +3 -3
- data/proto/public/settings.xhtml +61 -61
- data/proto/run.rb +1 -5
- data/test/nitro/adapter/raw_post1.bin +0 -0
- data/test/nitro/adapter/tc_cgi.rb +57 -57
- data/test/nitro/adapter/tc_webrick.rb +4 -4
- data/test/nitro/mixin/tc_pager.rb +25 -25
- data/test/nitro/mixin/tc_rss.rb +24 -0
- data/test/nitro/mixin/tc_table.rb +31 -0
- data/test/nitro/mixin/tc_xhtml.rb +13 -0
- data/test/nitro/tc_caching.rb +10 -10
- data/test/nitro/tc_context.rb +8 -8
- data/test/nitro/tc_controller.rb +48 -48
- data/test/nitro/tc_cookie.rb +6 -6
- data/test/nitro/tc_dispatcher.rb +64 -64
- data/test/nitro/tc_element.rb +27 -27
- data/test/nitro/tc_flash.rb +31 -31
- data/test/nitro/tc_mail.rb +63 -63
- data/test/nitro/tc_server.rb +26 -26
- data/test/nitro/tc_session.rb +9 -9
- data/test/nitro/tc_template.rb +19 -19
- data/test/public/blog/list.xhtml +1 -1
- metadata +31 -37
- data/lib/nitro/buffering.rb +0 -45
- data/lib/nitro/builder/form.rb +0 -104
- data/lib/nitro/builder/rss.rb +0 -104
- data/lib/nitro/builder/table.rb +0 -80
- data/lib/nitro/builder/xhtml.rb +0 -132
- data/lib/nitro/builder/xml.rb +0 -131
- data/lib/nitro/conf.rb +0 -36
- data/lib/nitro/environment.rb +0 -21
- data/lib/nitro/errors.rb +0 -69
- data/lib/nitro/localization.rb +0 -153
- data/lib/nitro/markup.rb +0 -147
- data/lib/nitro/output.rb +0 -24
- data/lib/nitro/runner.rb +0 -348
- data/lib/nitro/shaders.rb +0 -206
- data/test/nitro/builder/tc_rss.rb +0 -23
- data/test/nitro/builder/tc_table.rb +0 -30
- data/test/nitro/builder/tc_xhtml.rb +0 -39
- data/test/nitro/builder/tc_xml.rb +0 -56
- data/test/nitro/tc_localization.rb +0 -49
data/doc/config.txt
CHANGED
|
@@ -9,13 +9,13 @@ Selects the mechanism employed for storing the sessions.
|
|
|
9
9
|
Available values are:
|
|
10
10
|
|
|
11
11
|
[+:memory+]
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
This is the default mechanism, sessions are stored
|
|
13
|
+
in memory. Only useful in multithreaded environments
|
|
14
|
+
like WEBrick.
|
|
15
15
|
|
|
16
16
|
[+:drb+]
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
Distributed Sessions using DRb. An independed DRb
|
|
18
|
+
server stores the sessions.
|
|
19
19
|
|
|
20
20
|
In the future there will be more options available (:memcache,
|
|
21
21
|
:filesys, :db)
|
data/install.rb
CHANGED
|
@@ -1,28 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
|
|
3
|
-
# * George Moschovitis <gm@navel.gr>
|
|
4
|
-
# (c) 2004-2005 Navel, all rights reserved.
|
|
5
|
-
# $Id: install.rb 1 2005-04-11 11:04:30Z gmosx $
|
|
6
|
-
|
|
7
3
|
require 'rbconfig'
|
|
8
4
|
require 'ftools'
|
|
9
5
|
|
|
10
6
|
dst_dir = Config::CONFIG['sitelibdir']
|
|
11
7
|
|
|
12
8
|
Dir.chdir('lib') do
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
# gmosx: this is potentially dangerous, rethink.
|
|
20
|
-
|
|
21
|
-
Dir.chdir('vendor') do
|
|
22
|
-
Dir['**/*.rb'].each do |file|
|
|
23
|
-
File.mkpath File.join(dst_dir, File.dirname(file)), true
|
|
24
|
-
File.install file, File.join(dst_dir, file), 0644, true
|
|
25
|
-
end
|
|
9
|
+
Dir['**/*.rb'].each do |file|
|
|
10
|
+
File.mkpath File.join(dst_dir, File.dirname(file)), true
|
|
11
|
+
File.install file, File.join(dst_dir, file), 0644, true
|
|
12
|
+
end
|
|
26
13
|
end
|
|
27
14
|
|
|
28
15
|
puts %{
|
|
@@ -45,3 +32,6 @@ at the command line.
|
|
|
45
32
|
|
|
46
33
|
Enjoy the magic of Nitro!
|
|
47
34
|
}
|
|
35
|
+
|
|
36
|
+
# * George Moschovitis <gm@navel.gr>
|
|
37
|
+
|
data/lib/nitro.rb
CHANGED
|
@@ -19,16 +19,21 @@
|
|
|
19
19
|
|
|
20
20
|
require 'glue'
|
|
21
21
|
require 'glue/logger'
|
|
22
|
+
require 'glue/configuration'
|
|
22
23
|
|
|
23
24
|
module Nitro
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
|
|
26
|
+
# The version.
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
Version = '0.21.0'
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
# Library path.
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
LibPath = File.dirname(__FILE__)
|
|
33
|
+
|
|
34
|
+
# The path to the prototype application.
|
|
35
|
+
|
|
36
|
+
setting :proto_path, :default => "#{LibPath}/../proto", :doc => 'The path to the prototype application'
|
|
32
37
|
|
|
33
38
|
end
|
|
34
39
|
|
|
@@ -40,11 +45,35 @@ require 'nitro/context'
|
|
|
40
45
|
require 'nitro/controller'
|
|
41
46
|
require 'nitro/dispatcher'
|
|
42
47
|
require 'nitro/render'
|
|
43
|
-
|
|
44
48
|
require 'nitro/server'
|
|
45
|
-
require 'nitro/conf'
|
|
46
49
|
|
|
47
|
-
|
|
48
|
-
|
|
50
|
+
unless $NITRO_NO_ENVIRONMENT
|
|
51
|
+
# Setup up the proposed environment. You are free
|
|
52
|
+
# to skip this if you dont like it. Just set
|
|
53
|
+
#
|
|
54
|
+
# $NITRO_NO_ENVIRONMENT = true
|
|
55
|
+
#
|
|
56
|
+
# before requiring nitro.
|
|
57
|
+
|
|
58
|
+
Dir.chdir(File.dirname($0))
|
|
59
|
+
|
|
60
|
+
# Application code come here.
|
|
61
|
+
|
|
62
|
+
$LOAD_PATH.unshift 'src'
|
|
63
|
+
|
|
64
|
+
# Library code come here.
|
|
65
|
+
|
|
66
|
+
$LOAD_PATH.unshift 'lib'
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
module Nitro
|
|
70
|
+
|
|
71
|
+
# A helper method to start a Nitro application.
|
|
72
|
+
|
|
73
|
+
def self.run(controller = nil)
|
|
74
|
+
Server.run(controller)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
end
|
|
49
78
|
|
|
50
79
|
# * George Moschovitis <gm@navel.gr>
|
data/lib/nitro/adapter/cgi.rb
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
# * George Moschovitis <gm@navel.gr>
|
|
2
|
-
# * James Britt <james_b@neurogami.com>
|
|
3
|
-
|
|
4
1
|
require 'cgi'
|
|
5
2
|
require 'stringio'
|
|
6
3
|
require 'tempfile'
|
|
@@ -14,328 +11,330 @@ Socket.do_not_reverse_lookup = true
|
|
|
14
11
|
module Nitro
|
|
15
12
|
|
|
16
13
|
class Cgi
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
cattr_accessor :max_content_length, (2 * 1024 * 1024)
|
|
14
|
+
# Maximum content length allowed in requests.
|
|
20
15
|
|
|
21
|
-
|
|
16
|
+
cattr_accessor :max_content_length, (2 * 1024 * 1024)
|
|
22
17
|
|
|
23
|
-
|
|
18
|
+
# Multipart parsing buffer size.
|
|
24
19
|
|
|
25
|
-
|
|
26
|
-
cgi = CGI.new
|
|
27
|
-
conf = Flexob.new(conf) unless conf.is_a?(Flexob)
|
|
28
|
-
context = Context.new(conf)
|
|
29
|
-
context.headers = ENV
|
|
30
|
-
|
|
31
|
-
CgiUtils.parse_params(context)
|
|
32
|
-
CgiUtils.parse_cookies(context)
|
|
20
|
+
cattr_accessor :buffer_size, (10 * 1024)
|
|
33
21
|
|
|
34
|
-
|
|
35
|
-
|
|
22
|
+
#--
|
|
23
|
+
# No need for connection pooling, CGI uses process.
|
|
24
|
+
#++
|
|
25
|
+
|
|
26
|
+
def self.start(server)
|
|
27
|
+
cgi = CGI.new
|
|
28
|
+
|
|
29
|
+
context = Context.new(server)
|
|
30
|
+
context.headers = ENV
|
|
31
|
+
|
|
32
|
+
CgiUtils.parse_params(context)
|
|
33
|
+
CgiUtils.parse_cookies(context)
|
|
36
34
|
|
|
37
|
-
|
|
35
|
+
context.render(context.path)
|
|
38
36
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
cgi.print(context.out)
|
|
43
|
-
end
|
|
37
|
+
cgi.print(CgiUtils.response_headers(context))
|
|
38
|
+
cgi.print(context.out)
|
|
39
|
+
end
|
|
44
40
|
end
|
|
45
41
|
|
|
46
42
|
# CGI utility methods.
|
|
47
43
|
|
|
48
44
|
class CgiUtils
|
|
49
45
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
46
|
+
# HTTP protocol EOL constants
|
|
47
|
+
|
|
48
|
+
CR = "\x0d"
|
|
49
|
+
LF = "\x0a"
|
|
50
|
+
CRLF = "\x0d\x0a"
|
|
51
|
+
EOL = CRLF
|
|
52
|
+
|
|
53
|
+
# Constants for readable code
|
|
54
|
+
|
|
55
|
+
STATUS_OK = 200
|
|
56
|
+
STATUS_PARTIAL_CONTENT = 206
|
|
57
|
+
STATUS_MOVED = 301
|
|
58
|
+
STATUS_REDIRECT = 302
|
|
59
|
+
STATUS_SEE_OTHER = 303 # gmosx: VERIFY THIS
|
|
60
|
+
STATUS_SEE_OTHER_307 = 307 # gmosx: VERIFY THIS
|
|
61
|
+
STATUS_NOT_MODIFIED = 304
|
|
62
|
+
STATUS_BAD_REQUEST = 400
|
|
63
|
+
STATUS_AUTH_REQUIRED = 401
|
|
64
|
+
STATUS_FORBIDDEN = 403
|
|
65
|
+
STATUS_NOT_FOUND = 404
|
|
66
|
+
STATUS_METHOD_NOT_ALLOWED = 405
|
|
67
|
+
STATUS_NOT_ACCEPTABLE = 406
|
|
68
|
+
STATUS_LENGTH_REQUIRED = 411
|
|
69
|
+
STATUS_PRECONDITION_FAILED = 412
|
|
70
|
+
STATUS_SERVER_ERROR = 500
|
|
71
|
+
STATUS_NOT_IMPLEMENTED = 501
|
|
72
|
+
STATUS_BAD_GATEWAY = 502
|
|
73
|
+
STATUS_VARIANT_ALSO_VARIES = 506
|
|
74
|
+
|
|
75
|
+
# Hash to allow id to description maping.
|
|
76
|
+
|
|
77
|
+
STATUS_STRINGS = {
|
|
78
|
+
200 => "OK",
|
|
79
|
+
206 => "Partial Content",
|
|
80
|
+
300 => "Multiple Choices",
|
|
81
|
+
301 => "Moved Permanently",
|
|
82
|
+
302 => "Found",
|
|
83
|
+
303 => "See other", # gmosx: VERIFY THIS
|
|
84
|
+
304 => "Not Modified",
|
|
85
|
+
307 => "See other 07", # gmosx: VERIFY THIS
|
|
86
|
+
400 => "Bad Request",
|
|
87
|
+
401 => "Authorization Required",
|
|
88
|
+
403 => "Forbidden",
|
|
89
|
+
404 => "Not Found",
|
|
90
|
+
405 => "Method Not Allowed",
|
|
91
|
+
406 => "Not Acceptable",
|
|
92
|
+
411 => "Length Required",
|
|
93
|
+
412 => "Precondition Failed",
|
|
94
|
+
500 => "Internal Server Error",
|
|
95
|
+
501 => "Method Not Implemented",
|
|
96
|
+
502 => "Bad Gateway",
|
|
97
|
+
506 => "Variant Also Negotiates"
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
# Returns a hash with the pairs from the query
|
|
101
|
+
# string. The implicit hash construction that is done
|
|
102
|
+
# in parse_request_params is not done here.
|
|
103
|
+
#
|
|
104
|
+
# Parameters in the form xxx[] are converted
|
|
105
|
+
# to arrays.
|
|
106
|
+
|
|
107
|
+
def self.parse_query_string(query_string)
|
|
108
|
+
params = {}
|
|
109
|
+
|
|
110
|
+
# gmosx, THINK: better return nil here?
|
|
111
|
+
return params if (query_string.nil? or query_string.empty?)
|
|
112
|
+
|
|
113
|
+
query_string.split(/[&;]/).each do |p|
|
|
114
|
+
key, val = p.split('=')
|
|
115
|
+
|
|
116
|
+
key = CGI.unescape(key) unless key.nil?
|
|
117
|
+
val = CGI.unescape(val) unless val.nil?
|
|
118
|
+
|
|
119
|
+
if key =~ /(.*)\[\]$/
|
|
120
|
+
if params.has_key?($1)
|
|
121
|
+
params[$1] << val
|
|
122
|
+
else
|
|
123
|
+
params[$1] = [val]
|
|
124
|
+
end
|
|
125
|
+
else
|
|
126
|
+
params[key] = val.nil? ? nil : val
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
return params
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Parse the HTTP_COOKIE header and returns the
|
|
134
|
+
# cookies as a key->value hash. For efficiency no
|
|
135
|
+
# cookie objects are created.
|
|
136
|
+
#
|
|
137
|
+
# [+context+]
|
|
138
|
+
# The context
|
|
139
|
+
|
|
140
|
+
def self.parse_cookies(context)
|
|
141
|
+
env = context.env
|
|
142
|
+
|
|
143
|
+
# FIXME: dont precreate?
|
|
144
|
+
context.cookies = {}
|
|
145
|
+
|
|
146
|
+
if env.has_key?('HTTP_COOKIE') or env.has_key?('COOKIE')
|
|
147
|
+
(env['HTTP_COOKIE'] or env['COOKIE']).split(/; /).each do |c|
|
|
148
|
+
key, val = c.split(/=/, 2)
|
|
149
|
+
|
|
150
|
+
key = CGI.unescape(key)
|
|
151
|
+
val = val.split(/&/).collect{|v| CGI::unescape(v)}.join("\0")
|
|
152
|
+
|
|
153
|
+
if context.cookies.include?(key)
|
|
154
|
+
context.cookies[key] += "\0" + val
|
|
155
|
+
else
|
|
156
|
+
context.cookies[key] = val
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Build the response headers for the context.
|
|
163
|
+
#
|
|
164
|
+
# [+context+]
|
|
165
|
+
# The context of the response.
|
|
166
|
+
#
|
|
167
|
+
# [+proto+]
|
|
168
|
+
# If true emmit the protocol line. Useful for MOD_RUBY.
|
|
169
|
+
#--
|
|
170
|
+
# FIXME: return the correct protocol from env.
|
|
171
|
+
# TODO: Perhaps I can optimize status calc.
|
|
172
|
+
#++
|
|
173
|
+
|
|
174
|
+
def self.response_headers(context, proto = false)
|
|
175
|
+
reason = STATUS_STRINGS[context.status]
|
|
176
|
+
|
|
177
|
+
if proto
|
|
178
|
+
buf = "HTTP/1.1 #{context.status} #{reason}#{EOL}Date: #{CGI::rfc1123_date(Time.now)}#{EOL}"
|
|
179
|
+
else
|
|
180
|
+
buf = "Status: #{context.status} #{reason}#{EOL}"
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
context.response_headers.each do |key, value|
|
|
184
|
+
tmp = key.gsub(/\bwww|^te$|\b\w/) { |s| s.upcase }
|
|
185
|
+
buf << "#{tmp}: #{value}" << EOL
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
context.response_cookies.each do |cookie|
|
|
189
|
+
buf << "Set-Cookie: " << cookie.to_s << EOL
|
|
190
|
+
end if context.response_cookies
|
|
191
|
+
|
|
192
|
+
buf << EOL
|
|
193
|
+
|
|
194
|
+
return buf
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Initialize the request params.
|
|
198
|
+
# Handles multipart forms (in particular, forms that involve
|
|
199
|
+
# file uploads). Reads query parameters in the @params field,
|
|
200
|
+
# and cookies into @cookies.
|
|
201
|
+
|
|
202
|
+
def self.parse_params(context)
|
|
203
|
+
method = context.method
|
|
204
|
+
if (:post == method) and
|
|
205
|
+
%r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n.match(context.headers['CONTENT_TYPE'])
|
|
206
|
+
boundary = $1.dup
|
|
207
|
+
# context.params = read_multipart(boundary, Integer(context.headers['CONTENT_LENGTH']), context.in, context.headers)
|
|
208
|
+
context.params = parse_multipart(context, boundary)
|
|
209
|
+
else
|
|
210
|
+
case method
|
|
211
|
+
when :get, :head
|
|
212
|
+
context.params = CgiUtils.parse_query_string(context.query_string)
|
|
213
|
+
when :post
|
|
214
|
+
context.in.binmode # if defined?(context.in.binmode)
|
|
215
|
+
context.params = CgiUtils.parse_query_string(context.in.read(context.content_length) || '')
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# Parse a multipart request.
|
|
221
|
+
# Adapted from Ruby's cgi.rb
|
|
222
|
+
#--
|
|
223
|
+
# TODO: optimize and rationalize this.
|
|
224
|
+
#++
|
|
225
|
+
|
|
226
|
+
def self.parse_multipart(context, boundary)
|
|
227
|
+
input = context.in
|
|
228
|
+
content_length = context.content_length
|
|
229
|
+
env_table = context.env
|
|
230
|
+
|
|
231
|
+
params = Hash.new([])
|
|
232
|
+
boundary = "--" + boundary
|
|
233
|
+
buf = ""
|
|
234
|
+
|
|
235
|
+
input.binmode if defined? input.binmode
|
|
236
|
+
boundary_size = boundary.size + EOL.size
|
|
237
|
+
content_length -= boundary_size
|
|
238
|
+
status = input.read(boundary_size)
|
|
239
|
+
|
|
240
|
+
if nil == status
|
|
241
|
+
raise EOFError, "no content body"
|
|
242
|
+
elsif boundary + EOL != status
|
|
243
|
+
raise EOFError, "bad content body"
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
loop do
|
|
247
|
+
head = nil
|
|
248
|
+
|
|
249
|
+
if 10240 < content_length
|
|
250
|
+
body = Tempfile.new("CGI")
|
|
251
|
+
else
|
|
252
|
+
begin
|
|
253
|
+
body = StringIO.new
|
|
254
|
+
rescue LoadError
|
|
255
|
+
body = Tempfile.new("CGI")
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
body.binmode if defined? body.binmode
|
|
259
|
+
|
|
260
|
+
until head and /#{boundary}(?:#{EOL}|--)/n.match(buf)
|
|
261
|
+
|
|
262
|
+
if (not head) and /#{EOL}#{EOL}/n.match(buf)
|
|
263
|
+
buf = buf.sub(/\A((?:.|\n)*?#{EOL})#{EOL}/n) do
|
|
264
|
+
head = $1.dup
|
|
265
|
+
""
|
|
266
|
+
end
|
|
267
|
+
next
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
if head and ( (EOL + boundary + EOL).size < buf.size )
|
|
271
|
+
body.print buf[0 ... (buf.size - (EOL + boundary + EOL).size)]
|
|
272
|
+
buf[0 ... (buf.size - (EOL + boundary + EOL).size)] = ""
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
c = if Cgi.buffer_size < content_length
|
|
276
|
+
input.read(Cgi.buffer_size)
|
|
277
|
+
else
|
|
278
|
+
input.read(content_length)
|
|
279
|
+
end
|
|
280
|
+
if c.nil?
|
|
281
|
+
raise EOFError, "bad content body"
|
|
282
|
+
end
|
|
283
|
+
buf.concat(c)
|
|
284
|
+
content_length -= c.size
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
buf = buf.sub(/\A((?:.|\n)*?)(?:[\r\n]{1,2})?#{boundary}([\r\n]{1,2}|--)/n) do
|
|
288
|
+
body.print $1
|
|
289
|
+
if "--" == $2
|
|
290
|
+
content_length = -1
|
|
291
|
+
end
|
|
292
|
+
""
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
body.rewind
|
|
296
|
+
|
|
297
|
+
/Content-Disposition:.* filename="?([^\";]*)"?/ni.match(head)
|
|
298
|
+
|
|
299
|
+
filename = ($1 or "")
|
|
300
|
+
|
|
301
|
+
if /Mac/ni.match(env_table['HTTP_USER_AGENT']) and
|
|
302
|
+
/Mozilla/ni.match(env_table['HTTP_USER_AGENT']) and
|
|
303
|
+
(not /MSIE/ni.match(env_table['HTTP_USER_AGENT']))
|
|
304
|
+
filename = CGI::unescape(filename)
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
/Content-Type: (.*)/ni.match(head)
|
|
308
|
+
content_type = ($1 or "")
|
|
309
|
+
|
|
310
|
+
(class << body; self; end).class_eval do
|
|
311
|
+
alias local_path path
|
|
312
|
+
define_method(:original_filename) { filename.dup.taint }
|
|
313
|
+
define_method(:content_type) { content_type.dup.taint }
|
|
314
|
+
|
|
315
|
+
# gmosx: this hides the performance hit!!
|
|
316
|
+
define_method(:to_s) { read }
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
/Content-Disposition:.* name="?([^\";]*)"?/ni.match(head)
|
|
320
|
+
name = $1.dup
|
|
321
|
+
|
|
322
|
+
if params.has_key?(name)
|
|
323
|
+
params[name] = [params[name]] << body
|
|
324
|
+
else
|
|
325
|
+
params[name] = body
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
break if buf.size == 0
|
|
329
|
+
break if content_length === -1
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
return params
|
|
333
|
+
end
|
|
338
334
|
|
|
339
335
|
end
|
|
340
336
|
|
|
341
337
|
end
|
|
338
|
+
|
|
339
|
+
# * George Moschovitis <gm@navel.gr>
|
|
340
|
+
# * James Britt <james_b@neurogami.com>
|