nitro 0.8.0 → 0.9.3
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 +3 -4
- data/ChangeLog +418 -0
- data/LICENSE +1 -1
- data/README +157 -89
- data/RELEASES +50 -0
- data/Rakefile +5 -7
- data/benchmark/nitro/bench.rb +5 -0
- data/benchmark/nitro/simple-webrick-n-200.txt +44 -0
- data/benchmark/nitro/static-webrick-n-200.txt +43 -0
- data/benchmark/nitro/tiny-lhttpd-n-200-c-5.txt +43 -0
- data/benchmark/nitro/tiny-webrick-n-200-c-5.txt +44 -0
- data/benchmark/nitro/tiny-webrick-n-200.txt +44 -0
- data/benchmark/nitro/tiny2-webrick-n-200.txt +44 -0
- data/{lib/nitro/server/cluster.rb → bin/cluster} +26 -30
- data/bin/proto/README +2 -2
- data/bin/proto/{apache.conf → conf/apache.conf} +0 -0
- data/bin/proto/conf/app.conf.rb +22 -0
- data/bin/proto/conf/lhttpd.conf +236 -0
- data/bin/proto/ctl +4 -0
- data/bin/proto/lib/README +5 -0
- data/bin/proto/log/README +3 -0
- data/bin/proto/root/fcgi.rb +6 -0
- data/bin/proto/root/index.xhtml +65 -7
- data/bin/proto/root/m/nitro.png +0 -0
- data/examples/blog/README +7 -5
- data/examples/blog/{apache.conf → conf/apache.conf} +0 -0
- data/examples/blog/conf/app.conf.rb +56 -0
- data/examples/blog/conf/lhttpd.conf +236 -0
- data/examples/blog/ctl +4 -0
- data/examples/blog/lib/blog.rb +11 -136
- data/examples/blog/lib/blog/controller.rb +99 -0
- data/examples/blog/lib/blog/model.rb +39 -0
- data/examples/blog/log/README +3 -0
- data/examples/blog/root/comments.xhtml +2 -2
- data/examples/blog/root/fcgi.rb +6 -0
- data/examples/blog/root/index.xhtml +4 -5
- data/examples/blog/root/login.xhtml +2 -2
- data/examples/blog/root/style.xsl +9 -9
- data/examples/blog/root/view_entry.xhtml +2 -2
- data/examples/flash/conf/app.conf.rb +23 -0
- data/examples/flash/ctl +4 -0
- data/examples/flash/log/README +3 -0
- data/examples/flash/root/index.xhtml +0 -9
- data/examples/flash/root/show_inline_text.xhtml +10 -5
- data/examples/no_xsl_blog/README +12 -0
- data/examples/no_xsl_blog/conf/apache.conf +0 -0
- data/examples/no_xsl_blog/conf/app.conf.rb +57 -0
- data/examples/no_xsl_blog/conf/lhttpd.conf +236 -0
- data/examples/no_xsl_blog/ctl +4 -0
- data/examples/no_xsl_blog/lib/blog.rb +20 -0
- data/examples/no_xsl_blog/lib/blog/controller.rb +102 -0
- data/examples/no_xsl_blog/lib/blog/model.rb +39 -0
- data/examples/no_xsl_blog/lib/blog/template.rb +134 -0
- data/examples/no_xsl_blog/log/README +3 -0
- data/examples/no_xsl_blog/root/comments.xhtml +41 -0
- data/examples/no_xsl_blog/root/entry_form.xhtml +22 -0
- data/examples/no_xsl_blog/root/fcgi.rb +6 -0
- data/examples/no_xsl_blog/root/index.xhtml +39 -0
- data/examples/no_xsl_blog/root/login.xhtml +21 -0
- data/examples/no_xsl_blog/root/m/bubbles.gif +0 -0
- data/examples/no_xsl_blog/root/m/comments_curve.gif +0 -0
- data/examples/no_xsl_blog/root/m/down.gif +0 -0
- data/examples/no_xsl_blog/root/m/footer_bg.gif +0 -0
- data/examples/no_xsl_blog/root/m/garrow.gif +0 -0
- data/examples/no_xsl_blog/root/m/gbull.gif +0 -0
- data/examples/no_xsl_blog/root/m/grbull.gif +0 -0
- data/examples/no_xsl_blog/root/m/h1_bg.gif +0 -0
- data/examples/no_xsl_blog/root/m/header_bg.gif +0 -0
- data/examples/no_xsl_blog/root/m/nitro.gif +0 -0
- data/examples/no_xsl_blog/root/m/obull.gif +0 -0
- data/examples/no_xsl_blog/root/m/page_bg.gif +0 -0
- data/examples/no_xsl_blog/root/m/rss.gif +0 -0
- data/examples/no_xsl_blog/root/m/side_title_bg.gif +0 -0
- data/examples/no_xsl_blog/root/m/sidebar_bg.gif +0 -0
- data/examples/no_xsl_blog/root/recent_posts.xhtml +14 -0
- data/examples/no_xsl_blog/root/style.css +301 -0
- data/examples/no_xsl_blog/root/view_entry.xhtml +25 -0
- data/examples/no_xsl_blog/root/view_entry.xml +12 -0
- data/examples/og/run.rb +2 -2
- data/examples/tiny/README +2 -2
- data/examples/tiny/conf/apache.conf +5 -0
- data/examples/tiny/conf/app.conf.rb +21 -0
- data/examples/tiny/conf/lhttpd.conf +236 -0
- data/examples/tiny/ctl +4 -0
- data/examples/tiny/log/README +3 -0
- data/examples/tiny/root/fcgi.rb +6 -0
- data/examples/tiny/root/index.xhtml +7 -4
- data/examples/tiny/root/nitro.png +0 -0
- data/lib/glue.rb +13 -9
- data/lib/glue/array.rb +1 -1
- data/lib/glue/cache.rb +1 -1
- data/lib/glue/flexob.rb +12 -0
- data/lib/glue/hash.rb +1 -1
- data/lib/glue/inflector.rb +2 -2
- data/lib/glue/logger.rb +4 -8
- data/lib/glue/misc.rb +14 -0
- data/lib/glue/number.rb +1 -1
- data/lib/glue/object.rb +26 -0
- data/lib/glue/pool.rb +1 -1
- data/lib/glue/property.rb +84 -91
- data/lib/glue/string.rb +1 -1
- data/lib/glue/time.rb +1 -1
- data/lib/glue/validation.rb +1 -1
- data/lib/nitro.rb +18 -6
- data/lib/nitro/adaptors/cgi.rb +291 -0
- data/lib/nitro/adaptors/fastcgi.rb +42 -0
- data/lib/nitro/adaptors/runner.rb +123 -0
- data/lib/nitro/adaptors/webrick.rb +110 -0
- data/lib/nitro/buffering.rb +43 -0
- data/lib/nitro/builders/form.rb +1 -1
- data/lib/nitro/builders/rss.rb +1 -1
- data/{bin → lib/nitro}/cluster.rb +26 -30
- data/lib/nitro/context.rb +82 -0
- data/lib/nitro/controller.rb +50 -0
- data/lib/nitro/cookie.rb +46 -0
- data/lib/nitro/dispatcher.rb +105 -0
- data/lib/nitro/filters.rb +9 -10
- data/lib/nitro/localization.rb +42 -0
- data/lib/nitro/mail.rb +11 -14
- data/lib/nitro/render.rb +275 -0
- data/lib/nitro/request.rb +128 -0
- data/lib/nitro/response.rb +38 -0
- data/lib/nitro/scaffold.rb +11 -11
- data/lib/nitro/session.rb +84 -0
- data/lib/nitro/{server/shaders.rb → shaders.rb} +56 -36
- data/lib/nitro/ui/pager.rb +23 -26
- data/lib/nitro/{sitemap.rb → ui/sitemap.rb} +4 -12
- data/lib/nitro/uri.rb +1 -1
- data/lib/nitro/version.rb +10 -8
- data/lib/og.rb +66 -65
- data/lib/og/backend.rb +1 -1
- data/lib/og/backends/mysql.rb +48 -52
- data/lib/og/backends/psql.rb +34 -37
- data/lib/og/connection.rb +15 -15
- data/lib/og/enchant.rb +16 -9
- data/lib/og/meta.rb +127 -54
- data/lib/og/mock.rb +18 -18
- data/lib/og/version.rb +6 -4
- data/lib/parts/content.rb +4 -8
- data/test/glue/tc_logger.rb +3 -0
- data/test/glue/tc_property.rb +19 -3
- data/test/nitro/adaptors/tc_cgi.rb +63 -0
- data/test/nitro/adaptors/tc_webrick.rb +15 -0
- data/test/nitro/builders/tc_xml.rb +2 -2
- data/test/nitro/tc_context.rb +13 -0
- data/test/nitro/tc_controller.rb +47 -0
- data/test/nitro/tc_dispatcher.rb +64 -0
- data/test/nitro/tc_session.rb +20 -0
- data/test/nitro/{tc_sitemap.rb → ui/tc_sitemap.rb} +1 -1
- data/test/root/blog/list.xhtml +6 -0
- data/test/tc_og.rb +41 -4
- metadata +115 -59
- data/bin/proto/app.rb +0 -20
- data/bin/proto/config.rb +0 -77
- data/examples/blog/app.rb +0 -21
- data/examples/blog/config.rb +0 -95
- data/examples/blog/env.rb +0 -22
- data/examples/flash/README +0 -34
- data/examples/flash/app.rb +0 -20
- data/examples/flash/config.rb +0 -38
- data/examples/flash/lib/flash.rb +0 -40
- data/examples/flash/tmp.swf +0 -0
- data/examples/tiny/app.rb +0 -19
- data/examples/tiny/config.rb +0 -29
- data/examples/tiny/root/nitro-small.png +0 -0
- data/lib/nitro/application.rb +0 -217
- data/lib/nitro/config.rb +0 -128
- data/lib/nitro/events.rb +0 -122
- data/lib/nitro/html.rb +0 -151
- data/lib/nitro/http.rb +0 -102
- data/lib/nitro/l10n.rb +0 -30
- data/lib/nitro/server.rb +0 -59
- data/lib/nitro/server/appserver.rb +0 -67
- data/lib/nitro/server/cookie.rb +0 -87
- data/lib/nitro/server/dispatcher.rb +0 -62
- data/lib/nitro/server/filters.rb +0 -75
- data/lib/nitro/server/filters/autologin.rb +0 -51
- data/lib/nitro/server/fragment.rb +0 -70
- data/lib/nitro/server/handlers.rb +0 -127
- data/lib/nitro/server/render.rb +0 -426
- data/lib/nitro/server/request.rb +0 -658
- data/lib/nitro/server/requestpart.rb +0 -54
- data/lib/nitro/server/script.rb +0 -387
- data/lib/nitro/server/server.rb +0 -57
- data/lib/nitro/server/session.rb +0 -220
- data/lib/nitro/server/user.rb +0 -46
- data/lib/nitro/server/webrick.rb +0 -180
- data/lib/nitro/service.rb +0 -26
- data/lib/xsl/ui.xsl +0 -51
- data/lib/xsl/xforms.xsl +0 -28
- data/test/nitro/server/tc_cookie.rb +0 -34
- data/test/nitro/server/tc_filters.rb +0 -38
- data/test/nitro/server/tc_request.rb +0 -70
- data/test/nitro/server/tc_requestpart.rb +0 -28
- data/test/nitro/server/tc_session.rb +0 -34
- data/test/nitro/tc_events.rb +0 -44
- data/test/nitro/tc_html.rb +0 -79
- data/test/nitro/tc_http.rb +0 -18
data/lib/glue/string.rb
CHANGED
data/lib/glue/time.rb
CHANGED
data/lib/glue/validation.rb
CHANGED
|
@@ -216,7 +216,7 @@ module Validation
|
|
|
216
216
|
|
|
217
217
|
for name in params
|
|
218
218
|
confirm_name = "#{name}#{c[:postfix]}"
|
|
219
|
-
attr_accessor
|
|
219
|
+
eval "attr_accessor :#{confirm_name}"
|
|
220
220
|
|
|
221
221
|
code = %{
|
|
222
222
|
if obj.#{confirm_name}.nil? or (obj.#{confirm_name} != obj.#{name})
|
data/lib/nitro.rb
CHANGED
|
@@ -5,13 +5,25 @@
|
|
|
5
5
|
# robust infrastructure for scalable web applications that can be
|
|
6
6
|
# distributed over a server cluster. However, Nitro can also power
|
|
7
7
|
# simple web applications for deployment on intranets or even personal
|
|
8
|
-
# computers.
|
|
9
|
-
# library.
|
|
8
|
+
# computers.
|
|
10
9
|
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
10
|
+
# Nitro integrates the powerful Og Object-Relational mapping
|
|
11
|
+
# library.
|
|
13
12
|
#
|
|
14
|
-
|
|
15
|
-
#
|
|
13
|
+
#--
|
|
14
|
+
# George Moschovitis <gm@navel.gr>
|
|
15
|
+
# (c) 2004-2005 Navel, all rights reserved.
|
|
16
|
+
# $Id: nitro.rb 215 2005-01-24 10:44:05Z gmosx $
|
|
17
|
+
#++
|
|
16
18
|
|
|
17
19
|
require 'glue'
|
|
20
|
+
require 'glue/logger'
|
|
21
|
+
|
|
22
|
+
require 'nitro/context'
|
|
23
|
+
require 'nitro/dispatcher'
|
|
24
|
+
require 'nitro/render'
|
|
25
|
+
|
|
26
|
+
# Define Nitro namespace.
|
|
27
|
+
|
|
28
|
+
module Nitro
|
|
29
|
+
end
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
# * George Moschovitis <gm@navel.gr>
|
|
2
|
+
# (c) 2005 Navel, all rights reserved.
|
|
3
|
+
# $Id$
|
|
4
|
+
|
|
5
|
+
require 'cgi'
|
|
6
|
+
|
|
7
|
+
module N
|
|
8
|
+
|
|
9
|
+
=begin
|
|
10
|
+
# Extend the Request module.
|
|
11
|
+
|
|
12
|
+
module Request
|
|
13
|
+
include CGI::QueryExtension
|
|
14
|
+
|
|
15
|
+
def stdinput
|
|
16
|
+
@in
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
=end
|
|
20
|
+
|
|
21
|
+
# CGI utility methods.
|
|
22
|
+
|
|
23
|
+
class CgiUtils
|
|
24
|
+
|
|
25
|
+
# HTTP protocol EOL constants
|
|
26
|
+
|
|
27
|
+
CR = "\x0d"
|
|
28
|
+
LF = "\x0a"
|
|
29
|
+
CRLF = "\x0d\x0a"
|
|
30
|
+
EOL = CRLF
|
|
31
|
+
|
|
32
|
+
# Constants for readable code
|
|
33
|
+
|
|
34
|
+
STATUS_OK = 200
|
|
35
|
+
STATUS_PARTIAL_CONTENT = 206
|
|
36
|
+
STATUS_MOVED = 301
|
|
37
|
+
STATUS_REDIRECT = 302
|
|
38
|
+
STATUS_SEE_OTHER = 303 # gmosx: VERIFY THIS
|
|
39
|
+
STATUS_SEE_OTHER_307 = 307 # gmosx: VERIFY THIS
|
|
40
|
+
STATUS_NOT_MODIFIED = 304
|
|
41
|
+
STATUS_BAD_REQUEST = 400
|
|
42
|
+
STATUS_AUTH_REQUIRED = 401
|
|
43
|
+
STATUS_FORBIDDEN = 403
|
|
44
|
+
STATUS_NOT_FOUND = 404
|
|
45
|
+
STATUS_METHOD_NOT_ALLOWED = 405
|
|
46
|
+
STATUS_NOT_ACCEPTABLE = 406
|
|
47
|
+
STATUS_LENGTH_REQUIRED = 411
|
|
48
|
+
STATUS_PRECONDITION_FAILED = 412
|
|
49
|
+
STATUS_SERVER_ERROR = 500
|
|
50
|
+
STATUS_NOT_IMPLEMENTED = 501
|
|
51
|
+
STATUS_BAD_GATEWAY = 502
|
|
52
|
+
STATUS_VARIANT_ALSO_VARIES = 506
|
|
53
|
+
|
|
54
|
+
# Hash to allow id to description maping.
|
|
55
|
+
|
|
56
|
+
STATUS_STRINGS = {
|
|
57
|
+
200 => "OK",
|
|
58
|
+
206 => "Partial Content",
|
|
59
|
+
300 => "Multiple Choices",
|
|
60
|
+
301 => "Moved Permanently",
|
|
61
|
+
302 => "Found",
|
|
62
|
+
303 => "See other", # gmosx: VERIFY THIS
|
|
63
|
+
304 => "Not Modified",
|
|
64
|
+
307 => "See other 07", # gmosx: VERIFY THIS
|
|
65
|
+
400 => "Bad Request",
|
|
66
|
+
401 => "Authorization Required",
|
|
67
|
+
403 => "Forbidden",
|
|
68
|
+
404 => "Not Found",
|
|
69
|
+
405 => "Method Not Allowed",
|
|
70
|
+
406 => "Not Acceptable",
|
|
71
|
+
411 => "Length Required",
|
|
72
|
+
412 => "Precondition Failed",
|
|
73
|
+
500 => "Internal Server Error",
|
|
74
|
+
501 => "Method Not Implemented",
|
|
75
|
+
502 => "Bad Gateway",
|
|
76
|
+
506 => "Variant Also Negotiates"
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# Returns a hash with the pairs from the query
|
|
80
|
+
# string. The implicit hash construction that is done
|
|
81
|
+
# in parse_request_params is not done here.
|
|
82
|
+
#
|
|
83
|
+
# Parameters in the form xxx[] are converted
|
|
84
|
+
# to arrays.
|
|
85
|
+
|
|
86
|
+
def self.parse_query_string(query_string)
|
|
87
|
+
# gmosx, THINK: better return nil here?
|
|
88
|
+
|
|
89
|
+
return {} if (query_string.nil? or query_string.empty?)
|
|
90
|
+
|
|
91
|
+
params = {}
|
|
92
|
+
|
|
93
|
+
query_string.split(/[&;]/).each do |p|
|
|
94
|
+
key, val = p.split('=')
|
|
95
|
+
|
|
96
|
+
key = CGI.unescape(key) unless key.nil?
|
|
97
|
+
val = CGI.unescape(val) unless val.nil?
|
|
98
|
+
|
|
99
|
+
if key =~ /(.*)\[\]$/
|
|
100
|
+
if params.has_key?($1)
|
|
101
|
+
params[$1] << val
|
|
102
|
+
else
|
|
103
|
+
params[$1] = [val]
|
|
104
|
+
end
|
|
105
|
+
else
|
|
106
|
+
params[key] = val.nil? ? nil : val
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
return params
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Parse the HTTP_COOKIE header and returns the
|
|
114
|
+
# cookies as a key->value hash. For efficiency no
|
|
115
|
+
# cookie objects are created.
|
|
116
|
+
#
|
|
117
|
+
# [+context+]
|
|
118
|
+
# The context
|
|
119
|
+
|
|
120
|
+
def self.parse_cookies(context)
|
|
121
|
+
env = context.env
|
|
122
|
+
|
|
123
|
+
# FIXME: dont precreate?
|
|
124
|
+
context.cookies = {}
|
|
125
|
+
|
|
126
|
+
if env.has_key?('HTTP_COOKIE') or env.has_key?('COOKIE')
|
|
127
|
+
(env['HTTP_COOKIE'] or env['COOKIE']).split(/; /).each do |c|
|
|
128
|
+
key, val = c.split(/=/, 2)
|
|
129
|
+
|
|
130
|
+
key = CGI.unescape(key)
|
|
131
|
+
val = val.split(/&/).collect{|v| CGI::unescape(v)}.join("\0")
|
|
132
|
+
|
|
133
|
+
if context.cookies.include?(key)
|
|
134
|
+
context.cookies[key] += "\0" + val
|
|
135
|
+
else
|
|
136
|
+
context.cookies[key] = val
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Build the response headers for the context.
|
|
143
|
+
|
|
144
|
+
def self.response_headers(context)
|
|
145
|
+
reason = STATUS_STRINGS[context.status]
|
|
146
|
+
buf = "HTTP/1.1 #{context.status} #{reason} #{EOL}"
|
|
147
|
+
|
|
148
|
+
context.response_headers.each do |key, value|
|
|
149
|
+
tmp = key.gsub(/\bwww|^te$|\b\w/) { |s| s.upcase }
|
|
150
|
+
buf << "#{tmp}: #{value}" << EOL
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
context.response_cookies.each do |cookie|
|
|
154
|
+
buf << "Set-Cookie: " << cookie.to_s << EOL
|
|
155
|
+
end if context.response_cookies
|
|
156
|
+
|
|
157
|
+
buf << EOL
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Initialize the request params.
|
|
161
|
+
# Handles multipart forms (in particular, forms that involve
|
|
162
|
+
# file uploads). Reads query parameters in the @params field,
|
|
163
|
+
# and cookies into @cookies.
|
|
164
|
+
|
|
165
|
+
def self.parse_params(context)
|
|
166
|
+
method = context.method
|
|
167
|
+
if (:post == method) and
|
|
168
|
+
%r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n.match(context.headers['CONTENT_TYPE'])
|
|
169
|
+
boundary = $1.dup
|
|
170
|
+
context.params = read_multipart(boundary, Integer(context.headers['CONTENT_LENGTH']))
|
|
171
|
+
else
|
|
172
|
+
case method
|
|
173
|
+
when :get, :head
|
|
174
|
+
context.params = CgiUtils.parse_query_string(context.query_string)
|
|
175
|
+
when :post
|
|
176
|
+
context.in.binmode if defined?(context.in.binmode)
|
|
177
|
+
|
|
178
|
+
context.params = CgiUtils.parse_query_string(
|
|
179
|
+
context.in.read(
|
|
180
|
+
Integer(context.headers['CONTENT_LENGTH'])) || '')
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Parse a multipart request.
|
|
186
|
+
|
|
187
|
+
def self.read_multipart(boundary, content_length)
|
|
188
|
+
params = Hash.new([])
|
|
189
|
+
boundary = "--" + boundary
|
|
190
|
+
buf = ""
|
|
191
|
+
bufsize = 10 * 1024
|
|
192
|
+
|
|
193
|
+
# start multipart/form-data
|
|
194
|
+
stdinput.binmode if defined? stdinput.binmode
|
|
195
|
+
boundary_size = boundary.size + EOL.size
|
|
196
|
+
content_length -= boundary_size
|
|
197
|
+
status = stdinput.read(boundary_size)
|
|
198
|
+
if nil == status
|
|
199
|
+
raise EOFError, "no content body"
|
|
200
|
+
elsif boundary + EOL != status
|
|
201
|
+
raise EOFError, "bad content body"
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
loop do
|
|
205
|
+
head = nil
|
|
206
|
+
if 10240 < content_length
|
|
207
|
+
require "tempfile"
|
|
208
|
+
body = Tempfile.new("CGI")
|
|
209
|
+
else
|
|
210
|
+
begin
|
|
211
|
+
require "stringio"
|
|
212
|
+
body = StringIO.new
|
|
213
|
+
rescue LoadError
|
|
214
|
+
require "tempfile"
|
|
215
|
+
body = Tempfile.new("CGI")
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
body.binmode if defined? body.binmode
|
|
219
|
+
|
|
220
|
+
until head and /#{boundary}(?:#{EOL}|--)/n.match(buf)
|
|
221
|
+
|
|
222
|
+
if (not head) and /#{EOL}#{EOL}/n.match(buf)
|
|
223
|
+
buf = buf.sub(/\A((?:.|\n)*?#{EOL})#{EOL}/n) do
|
|
224
|
+
head = $1.dup
|
|
225
|
+
""
|
|
226
|
+
end
|
|
227
|
+
next
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
if head and ( (EOL + boundary + EOL).size < buf.size )
|
|
231
|
+
body.print buf[0 ... (buf.size - (EOL + boundary + EOL).size)]
|
|
232
|
+
buf[0 ... (buf.size - (EOL + boundary + EOL).size)] = ""
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
c = if bufsize < content_length
|
|
236
|
+
stdinput.read(bufsize)
|
|
237
|
+
else
|
|
238
|
+
stdinput.read(content_length)
|
|
239
|
+
end
|
|
240
|
+
if c.nil?
|
|
241
|
+
raise EOFError, "bad content body"
|
|
242
|
+
end
|
|
243
|
+
buf.concat(c)
|
|
244
|
+
content_length -= c.size
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
buf = buf.sub(/\A((?:.|\n)*?)(?:[\r\n]{1,2})?#{boundary}([\r\n]{1,2}|--)/n) do
|
|
248
|
+
body.print $1
|
|
249
|
+
if "--" == $2
|
|
250
|
+
content_length = -1
|
|
251
|
+
end
|
|
252
|
+
""
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
body.rewind
|
|
256
|
+
|
|
257
|
+
/Content-Disposition:.* filename="?([^\";]*)"?/ni.match(head)
|
|
258
|
+
filename = ($1 or "")
|
|
259
|
+
if /Mac/ni.match(env_table['HTTP_USER_AGENT']) and
|
|
260
|
+
/Mozilla/ni.match(env_table['HTTP_USER_AGENT']) and
|
|
261
|
+
(not /MSIE/ni.match(env_table['HTTP_USER_AGENT']))
|
|
262
|
+
filename = CGI::unescape(filename)
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
/Content-Type: (.*)/ni.match(head)
|
|
266
|
+
content_type = ($1 or "")
|
|
267
|
+
|
|
268
|
+
(class << body; self; end).class_eval do
|
|
269
|
+
alias local_path path
|
|
270
|
+
define_method(:original_filename) {filename.dup.taint}
|
|
271
|
+
define_method(:content_type) {content_type.dup.taint}
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
/Content-Disposition:.* name="?([^\";]*)"?/ni.match(head)
|
|
275
|
+
name = $1.dup
|
|
276
|
+
|
|
277
|
+
if params.has_key?(name)
|
|
278
|
+
params[name].push(body)
|
|
279
|
+
else
|
|
280
|
+
params[name] = [body]
|
|
281
|
+
end
|
|
282
|
+
break if buf.size == 0
|
|
283
|
+
break if content_length === -1
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
params
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# * George Moschovitis <gm@navel.gr>
|
|
2
|
+
# (c) 2005 Navel, all rights reserved.
|
|
3
|
+
# $Id$
|
|
4
|
+
|
|
5
|
+
require 'cgi'
|
|
6
|
+
require 'fcgi'
|
|
7
|
+
|
|
8
|
+
require 'nitro/context'
|
|
9
|
+
require 'nitro/dispatcher'
|
|
10
|
+
require 'nitro/adaptors/cgi'
|
|
11
|
+
|
|
12
|
+
module N
|
|
13
|
+
|
|
14
|
+
# FastCGI Adaptor. FastCGI is a language independent,
|
|
15
|
+
# scalable, open extension to CGI that provides high
|
|
16
|
+
# performance without the limitations of server
|
|
17
|
+
# specific APIs.
|
|
18
|
+
|
|
19
|
+
class FastCGI
|
|
20
|
+
|
|
21
|
+
def self.start(conf)
|
|
22
|
+
FCGI.each do |cgi|
|
|
23
|
+
context = Context.new(conf)
|
|
24
|
+
|
|
25
|
+
context.in = cgi.in
|
|
26
|
+
context.headers = cgi.env
|
|
27
|
+
|
|
28
|
+
CgiUtils.parse_params(context)
|
|
29
|
+
CgiUtils.parse_cookies(context)
|
|
30
|
+
|
|
31
|
+
context.render(context.path)
|
|
32
|
+
|
|
33
|
+
cgi.out.print(CgiUtils.response_headers(context))
|
|
34
|
+
cgi.out.print(context.out)
|
|
35
|
+
|
|
36
|
+
cgi.finish
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
# * George Moschovitis <gm@navel.gr>
|
|
4
|
+
# (c) 2004-2005 Navel, all rights reserved.
|
|
5
|
+
# $Id$
|
|
6
|
+
|
|
7
|
+
require 'optparse'
|
|
8
|
+
|
|
9
|
+
module N
|
|
10
|
+
|
|
11
|
+
# The Runner is a helper class that encapsulates a web
|
|
12
|
+
# application and is responsible for launching the
|
|
13
|
+
# application using different adaptors. Default arguments
|
|
14
|
+
# parsing is also provided.
|
|
15
|
+
#
|
|
16
|
+
# You can implement your own, custom version of the Runner
|
|
17
|
+
# to run your custom web applications.
|
|
18
|
+
#
|
|
19
|
+
#--
|
|
20
|
+
# TODO: find a better name
|
|
21
|
+
#++
|
|
22
|
+
|
|
23
|
+
class Runner
|
|
24
|
+
|
|
25
|
+
# Parse the arguments and run the web application
|
|
26
|
+
# using the declared environment and adaptor
|
|
27
|
+
|
|
28
|
+
def self.run(argv)
|
|
29
|
+
|
|
30
|
+
# :start, :stop, :restart.
|
|
31
|
+
|
|
32
|
+
action = :start
|
|
33
|
+
|
|
34
|
+
# :webrick, :lhttp, :apache
|
|
35
|
+
|
|
36
|
+
server = :webrick
|
|
37
|
+
|
|
38
|
+
# daemonize? (in webrick only)
|
|
39
|
+
|
|
40
|
+
daemon = false
|
|
41
|
+
|
|
42
|
+
# log to file ?
|
|
43
|
+
|
|
44
|
+
log_to_file = false
|
|
45
|
+
|
|
46
|
+
# Parse the arguments.
|
|
47
|
+
|
|
48
|
+
parser = OptionParser.new do |opts|
|
|
49
|
+
|
|
50
|
+
opts.banner = 'Usage: ctl [options]'
|
|
51
|
+
opts.separator ''
|
|
52
|
+
opts.separator 'Specific options:'
|
|
53
|
+
|
|
54
|
+
opts.on("-s", "--start", "Start application.") do
|
|
55
|
+
action = :start
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
opts.on("-S", "--stop", "Stop application.") do
|
|
59
|
+
action = :stop
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
opts.on("-r", "--restart", "Restart application.") do
|
|
63
|
+
action = :restart
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
opts.on("-d", "--daemon", "Run application as a daemon.") do
|
|
67
|
+
daemon = true
|
|
68
|
+
log_to_file = true
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
opts.on("-D", "--debug", "Run application in debug mode.") do
|
|
72
|
+
$DBG = true
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
opts.on("-w", "--webrick", "Use a webrick server [default].") do
|
|
76
|
+
server = :webrick
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
opts.on("-l", "--lhttpd", "Use a webrick server [default].") do
|
|
80
|
+
server = :lhttpd
|
|
81
|
+
log_to_file = true
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
opts.on_tail("-v", "--version", "Show version.") do
|
|
85
|
+
require 'nitro/version'
|
|
86
|
+
puts "Nitro #{Nitro::Version}"
|
|
87
|
+
exit
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
opts.on_tail("-?", "--help", "Show this message.") do
|
|
91
|
+
puts opts
|
|
92
|
+
exit
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
parser.parse!(ARGV)
|
|
98
|
+
|
|
99
|
+
require 'conf/app.conf.rb'
|
|
100
|
+
|
|
101
|
+
if log_to_file
|
|
102
|
+
Logger.set(Logger.new('log/app.log'))
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
case server
|
|
106
|
+
|
|
107
|
+
when :webrick
|
|
108
|
+
require 'nitro/adaptors/webrick'
|
|
109
|
+
N::Webrick.start($conf)
|
|
110
|
+
|
|
111
|
+
when :lhttpd
|
|
112
|
+
require 'nitro/adaptors/fastcgi'
|
|
113
|
+
`lighttpd -f conf/lhttpd.conf`
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Run the app!
|
|
120
|
+
|
|
121
|
+
Runner.run(ARGV)
|
|
122
|
+
|
|
123
|
+
end
|