microengine 0.0.2 → 0.0.9
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/README +0 -11
- data/Rakefile +14 -21
- data/bin/microengine +11 -11
- data/config/search spiders +4 -0
- data/config/settings.yaml +11 -0
- data/config/shadow.yaml +3 -0
- data/lib/{microengine/admin.rb → admin.rb} +0 -0
- data/lib/{microengine/admin_exception.rb → admin_exception.rb} +0 -0
- data/lib/{microengine/admin_page.rb → admin_page.rb} +3 -3
- data/lib/{microengine/assambler.rb → assambler.rb} +0 -0
- data/lib/{microengine/dispatcher.rb → dispatcher.rb} +0 -0
- data/lib/{microengine/file_cache.rb → file_cache.rb} +0 -0
- data/lib/{microengine/html → html}/deleter.rhtml +0 -0
- data/lib/{microengine/html → html}/editor.rhtml +0 -0
- data/lib/{microengine/html → html}/en.yaml +0 -0
- data/lib/{microengine/html → html}/error.rhtml +0 -0
- data/lib/{microengine/html → html}/refresher.rhtml +0 -0
- data/lib/{microengine/html → html}/ru.yaml +0 -0
- data/lib/{microengine/html → html}/untranslater.rhtml +0 -0
- data/lib/{microengine/http.rb → http.rb} +0 -0
- data/lib/{microengine/initializer.rb → initializer.rb} +0 -0
- data/lib/{microengine/memory_cache.rb → memory_cache.rb} +0 -0
- data/public/.htaccess +5 -0
- data/public/microengine.fcgi +7 -1
- metadata +23 -22
- data/lib/fcgi/fcgi.rb +0 -618
- data/lib/fcgi/fcgi.so +0 -0
data/README
CHANGED
@@ -18,21 +18,10 @@ It's ideal for simple homepages.
|
|
18
18
|
MicroEngine used only FastCGI, so your web server must be support it.
|
19
19
|
Apache must has mod_rewrite and mod_fastcgi modules.
|
20
20
|
|
21
|
-
=== Gems
|
22
|
-
|
23
21
|
# gem install microengine
|
24
22
|
$ cd /SITE/DIR/
|
25
23
|
$ microengine ./
|
26
24
|
|
27
|
-
=== All-include package
|
28
|
-
It is good choise for hosting where you hasn't root password or access to gem.
|
29
|
-
Just download archive with all libraries and unpack it to neccesary dir.
|
30
|
-
|
31
|
-
$ tar -xf microengine-*.tar.bz2
|
32
|
-
$ mv microengine-* /SITE/DIR/
|
33
|
-
$ cd /SITE/DIR/
|
34
|
-
$ ./bin/microengine ./
|
35
|
-
|
36
25
|
=== Apache example config
|
37
26
|
After install MicroEngine files you must add this information to Apache config
|
38
27
|
file. Note, if .htaccess isn't support, you must copy content of
|
data/Rakefile
CHANGED
@@ -1,29 +1,17 @@
|
|
1
1
|
require 'rake'
|
2
2
|
require 'rake/rdoctask'
|
3
3
|
require 'rake/gempackagetask'
|
4
|
-
require 'rake/contrib/rubyforgepublisher'
|
5
4
|
|
6
5
|
PKG_NAME = "microengine"
|
7
|
-
PKG_VERSION = "0.0.
|
6
|
+
PKG_VERSION = "0.0.9"
|
8
7
|
|
9
8
|
RUBY_FORGE_PROJECT = "microengine"
|
10
9
|
RUBY_FORGE_USER = "iskin"
|
11
10
|
|
12
|
-
PKG_FILES = FileList[
|
13
|
-
"bin/*",
|
14
|
-
"content/**/*",
|
15
|
-
"layouts/**/*",
|
16
|
-
"lib/microengine/**/*",
|
17
|
-
"public/**/*",
|
18
|
-
"access.log",
|
19
|
-
"LICENSE",
|
20
|
-
"Rakefile",
|
21
|
-
"README"]
|
22
|
-
|
23
11
|
# RDoc
|
24
12
|
Rake::RDocTask.new do |rd|
|
25
13
|
rd.main = "README"
|
26
|
-
rd.rdoc_files.include("README", "lib
|
14
|
+
rd.rdoc_files.include("README", "lib/*.rb")
|
27
15
|
rd.title = "MicroEngine"
|
28
16
|
rd.options << "--all"
|
29
17
|
end
|
@@ -43,7 +31,18 @@ spec = Gem::Specification.new do |s|
|
|
43
31
|
|
44
32
|
s.add_dependency 'fcgi'
|
45
33
|
|
46
|
-
s.files =
|
34
|
+
s.files = FileList[
|
35
|
+
"bin/*",
|
36
|
+
"config/**/*",
|
37
|
+
"content/**/*",
|
38
|
+
"layouts/**/*",
|
39
|
+
"lib/**/*",
|
40
|
+
"public/**/*",
|
41
|
+
"public/.htaccess",
|
42
|
+
"access.log",
|
43
|
+
"LICENSE",
|
44
|
+
"Rakefile",
|
45
|
+
"README"]
|
47
46
|
s.require_path = 'lib'
|
48
47
|
s.bindir = "bin"
|
49
48
|
s.executables = ["microengine"]
|
@@ -57,10 +56,4 @@ end
|
|
57
56
|
|
58
57
|
Rake::GemPackageTask.new(spec) do |pkg|
|
59
58
|
pkg.gem_spec = spec
|
60
|
-
end
|
61
|
-
|
62
|
-
# All-include package
|
63
|
-
Rake::PackageTask.new(PKG_NAME, PKG_VERSION) do |pkg|
|
64
|
-
pkg.need_tar_bz2 = true
|
65
|
-
pkg.package_files = PKG_FILES.include ["lib/fcgi/**/*", "cache"]
|
66
59
|
end
|
data/bin/microengine
CHANGED
@@ -30,14 +30,13 @@ end
|
|
30
30
|
distr = File.dirname(__FILE__) + '/../'
|
31
31
|
|
32
32
|
if not File.exists? path + 'content/layout'
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
end
|
33
|
+
files = [
|
34
|
+
"config/*",
|
35
|
+
"content/**/*",
|
36
|
+
"layouts/**/*",
|
37
|
+
"public/**/*",
|
38
|
+
"access.log",
|
39
|
+
"README"]
|
41
40
|
|
42
41
|
begin
|
43
42
|
files.each do |pattern|
|
@@ -56,9 +55,10 @@ if not File.exists? path + 'content/layout'
|
|
56
55
|
FileUtils.chmod_R 0777, path + 'content/'
|
57
56
|
FileUtils.chmod 0777, path + 'cache/'
|
58
57
|
FileUtils.chmod 0777, path + 'access.log'
|
59
|
-
|
60
|
-
|
61
|
-
#
|
58
|
+
FileUtils.chmod 0755, path + 'public/microengine.fcgi'
|
59
|
+
rescue
|
60
|
+
puts "Can't copy files. Ensure that you has permissions to write in #{path} ."
|
61
|
+
Process.exit
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# MicroEngine configration
|
2
|
+
|
3
|
+
# If you set 'memory' memory will be used to store pages cache.
|
4
|
+
# On 'file' pages will be loaded from file cache.
|
5
|
+
cache: memory
|
6
|
+
|
7
|
+
# Language, wich will be returned if visitor didn't know any content languages
|
8
|
+
default_language: en
|
9
|
+
|
10
|
+
# Layout, which was be used in new page
|
11
|
+
default_layout: default
|
data/config/shadow.yaml
ADDED
File without changes
|
File without changes
|
@@ -166,7 +166,7 @@ module Microengine
|
|
166
166
|
|
167
167
|
def load_translation
|
168
168
|
@admin_langs = []
|
169
|
-
Dir.glob(
|
169
|
+
Dir.glob(File.dirname(__FILE__) + '/html/*.yaml') do |file|
|
170
170
|
@admin_langs.push File.basename(file, '.yaml')
|
171
171
|
end
|
172
172
|
|
@@ -176,13 +176,13 @@ module Microengine
|
|
176
176
|
lang = @admin.dispatcher.language(@http, @admin_langs)
|
177
177
|
end
|
178
178
|
|
179
|
-
@translation = YAML::load_file
|
179
|
+
@translation = YAML::load_file File.dirname(__FILE__) + "/html/#{lang}.yaml"
|
180
180
|
end
|
181
181
|
|
182
182
|
# Display admin HTML in page layout
|
183
183
|
def display(view)
|
184
184
|
header = "<title>#{@translation[view]['title']}</title>"
|
185
|
-
rhtml = IO.read
|
185
|
+
rhtml = IO.read File.dirname(__FILE__) + "/html/#{view}.rhtml"
|
186
186
|
body = ERB.new(rhtml).result(binding)
|
187
187
|
|
188
188
|
if 'editor' == view
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/public/.htaccess
ADDED
data/public/microengine.fcgi
CHANGED
@@ -2,4 +2,10 @@
|
|
2
2
|
#
|
3
3
|
# Load microengine and start FastCGI dispatcher
|
4
4
|
|
5
|
-
|
5
|
+
MICROENGINE_ROOT = File.dirname(__FILE__) + '/..'
|
6
|
+
|
7
|
+
require 'rubygems'
|
8
|
+
gem 'microengine'
|
9
|
+
require 'initializer'
|
10
|
+
|
11
|
+
Microengine::Initializer.new
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: microengine
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.0.
|
7
|
-
date: 2008-01
|
6
|
+
version: 0.0.9
|
7
|
+
date: 2008-02-01 00:00:00 +03:00
|
8
8
|
summary: MicroEngine is a fast, simple and minimalistic site engine.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -30,6 +30,9 @@ authors:
|
|
30
30
|
- Andrey "A.I." Sitnik
|
31
31
|
files:
|
32
32
|
- bin/microengine
|
33
|
+
- config/settings.yaml
|
34
|
+
- config/search spiders
|
35
|
+
- config/shadow.yaml
|
33
36
|
- content/403
|
34
37
|
- content/403/ru.body
|
35
38
|
- content/403/ru.header
|
@@ -53,23 +56,23 @@ files:
|
|
53
56
|
- layouts/default/ru.yaml
|
54
57
|
- layouts/default/layout.rhtml
|
55
58
|
- layouts/default/en.yaml
|
56
|
-
- lib/
|
57
|
-
- lib/
|
58
|
-
- lib/
|
59
|
-
- lib/
|
60
|
-
- lib/
|
61
|
-
- lib/
|
62
|
-
- lib/
|
63
|
-
- lib/
|
64
|
-
- lib/
|
65
|
-
- lib/
|
66
|
-
- lib/
|
67
|
-
- lib/
|
68
|
-
- lib/
|
69
|
-
- lib/
|
70
|
-
- lib/
|
71
|
-
- lib/
|
72
|
-
- lib/
|
59
|
+
- lib/file_cache.rb
|
60
|
+
- lib/http.rb
|
61
|
+
- lib/initializer.rb
|
62
|
+
- lib/memory_cache.rb
|
63
|
+
- lib/dispatcher.rb
|
64
|
+
- lib/assambler.rb
|
65
|
+
- lib/admin_exception.rb
|
66
|
+
- lib/admin_page.rb
|
67
|
+
- lib/html
|
68
|
+
- lib/html/ru.yaml
|
69
|
+
- lib/html/untranslater.rhtml
|
70
|
+
- lib/html/editor.rhtml
|
71
|
+
- lib/html/refresher.rhtml
|
72
|
+
- lib/html/error.rhtml
|
73
|
+
- lib/html/en.yaml
|
74
|
+
- lib/html/deleter.rhtml
|
75
|
+
- lib/admin.rb
|
73
76
|
- public/javascripts
|
74
77
|
- public/images
|
75
78
|
- public/styles
|
@@ -77,13 +80,11 @@ files:
|
|
77
80
|
- public/styles/print.css
|
78
81
|
- public/styles/screen.css
|
79
82
|
- public/microengine.fcgi
|
83
|
+
- public/.htaccess
|
80
84
|
- access.log
|
81
85
|
- LICENSE
|
82
86
|
- Rakefile
|
83
87
|
- README
|
84
|
-
- lib/fcgi/fcgi.so
|
85
|
-
- lib/fcgi/fcgi.rb
|
86
|
-
- cache
|
87
88
|
test_files: []
|
88
89
|
|
89
90
|
rdoc_options: []
|
data/lib/fcgi/fcgi.rb
DELETED
@@ -1,618 +0,0 @@
|
|
1
|
-
=begin
|
2
|
-
|
3
|
-
fcgi.rb 0.8.5 - fcgi.so compatible pure-ruby FastCGI library
|
4
|
-
|
5
|
-
fastcgi.rb Copyright (C) 2001 Eli Green
|
6
|
-
fcgi.rb Copyright (C) 2002-2003 MoonWolf <moonwolf@moonwolf.com>
|
7
|
-
fcgi.rb Copyright (C) 2004 Minero Aoki
|
8
|
-
|
9
|
-
=end
|
10
|
-
trap('SIGTERM') { exit }
|
11
|
-
trap('SIGPIPE','IGNORE')
|
12
|
-
|
13
|
-
begin
|
14
|
-
raise LoadError if defined?(FCGI_PURE_RUBY) && FCGI_PURE_RUBY
|
15
|
-
require "fcgi.so"
|
16
|
-
rescue LoadError
|
17
|
-
require 'socket'
|
18
|
-
require 'stringio'
|
19
|
-
|
20
|
-
class FCGI
|
21
|
-
|
22
|
-
def self::is_cgi?
|
23
|
-
begin
|
24
|
-
s = Socket.for_fd($stdin.fileno)
|
25
|
-
s.getpeername
|
26
|
-
false
|
27
|
-
rescue Errno::ENOTCONN
|
28
|
-
false
|
29
|
-
rescue Errno::ENOTSOCK, Errno::EINVAL
|
30
|
-
true
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def self::each(&block)
|
35
|
-
f = default_connection()
|
36
|
-
Server.new(f).each_request(&block)
|
37
|
-
ensure
|
38
|
-
f.close if f
|
39
|
-
end
|
40
|
-
|
41
|
-
def self::each_request(&block)
|
42
|
-
f = default_connection()
|
43
|
-
Server.new(f).each_request(&block)
|
44
|
-
ensure
|
45
|
-
f.close if f
|
46
|
-
end
|
47
|
-
|
48
|
-
def self::default_connection
|
49
|
-
::Socket.for_fd($stdin.fileno)
|
50
|
-
end
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
ProtocolVersion = 1
|
55
|
-
|
56
|
-
# Record types
|
57
|
-
FCGI_BEGIN_REQUEST = 1
|
58
|
-
FCGI_ABORT_REQUEST = 2
|
59
|
-
FCGI_END_REQUEST = 3
|
60
|
-
FCGI_PARAMS = 4
|
61
|
-
FCGI_STDIN = 5
|
62
|
-
FCGI_STDOUT = 6
|
63
|
-
FCGI_STDERR = 7
|
64
|
-
FCGI_DATA = 8
|
65
|
-
FCGI_GET_VALUES = 9
|
66
|
-
FCGI_GET_VALUES_RESULT = 10
|
67
|
-
FCGI_UNKNOWN_TYPE = 11
|
68
|
-
FCGI_MAXTYPE = FCGI_UNKNOWN_TYPE
|
69
|
-
|
70
|
-
FCGI_NULL_REQUEST_ID = 0
|
71
|
-
|
72
|
-
# FCGI_BEGIN_REQUSET.role
|
73
|
-
FCGI_RESPONDER = 1
|
74
|
-
FCGI_AUTHORIZER = 2
|
75
|
-
FCGI_FILTER = 3
|
76
|
-
|
77
|
-
# FCGI_BEGIN_REQUEST.flags
|
78
|
-
FCGI_KEEP_CONN = 1
|
79
|
-
|
80
|
-
# FCGI_END_REQUEST.protocolStatus
|
81
|
-
FCGI_REQUEST_COMPLETE = 0
|
82
|
-
FCGI_CANT_MPX_CONN = 1
|
83
|
-
FCGI_OVERLOADED = 2
|
84
|
-
FCGI_UNKNOWN_ROLE = 3
|
85
|
-
|
86
|
-
|
87
|
-
class Server
|
88
|
-
|
89
|
-
def initialize(server)
|
90
|
-
@server = server
|
91
|
-
@buffers = {}
|
92
|
-
@default_parameters = {
|
93
|
-
"FCGI_MAX_CONNS" => 1,
|
94
|
-
"FCGI_MAX_REQS" => 1,
|
95
|
-
"FCGI_MPX_CONNS" => true
|
96
|
-
}
|
97
|
-
end
|
98
|
-
|
99
|
-
def each_request(&block)
|
100
|
-
graceful = false
|
101
|
-
trap("SIGUSR1") { graceful = true }
|
102
|
-
while true
|
103
|
-
begin
|
104
|
-
session(&block)
|
105
|
-
rescue Errno::EPIPE, EOFError
|
106
|
-
# HTTP request is canceled by the remote user
|
107
|
-
end
|
108
|
-
exit 0 if graceful
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
def session
|
113
|
-
sock, addr = *@server.accept
|
114
|
-
return unless sock
|
115
|
-
fsock = FastCGISocket.new(sock)
|
116
|
-
req = next_request(fsock)
|
117
|
-
yield req
|
118
|
-
respond_to req, fsock, FCGI_REQUEST_COMPLETE
|
119
|
-
ensure
|
120
|
-
sock.close if sock and not sock.closed?
|
121
|
-
end
|
122
|
-
|
123
|
-
private
|
124
|
-
|
125
|
-
def next_request(sock)
|
126
|
-
while rec = sock.read_record
|
127
|
-
if rec.management_record?
|
128
|
-
case rec.type
|
129
|
-
when FCGI_GET_VALUES
|
130
|
-
sock.send_record handle_GET_VALUES(rec)
|
131
|
-
else
|
132
|
-
sock.send_record UnknownTypeRecord.new(rec.request_id, rec.type)
|
133
|
-
end
|
134
|
-
else
|
135
|
-
case rec.type
|
136
|
-
when FCGI_BEGIN_REQUEST
|
137
|
-
@buffers[rec.request_id] = RecordBuffer.new(rec)
|
138
|
-
when FCGI_ABORT_REQUEST
|
139
|
-
raise "got ABORT_REQUEST" # FIXME
|
140
|
-
else
|
141
|
-
buf = @buffers[rec.request_id] or next # inactive request
|
142
|
-
buf.push rec
|
143
|
-
if buf.ready?
|
144
|
-
@buffers.delete rec.request_id
|
145
|
-
return buf.new_request
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
150
|
-
raise "must not happen: FCGI socket unexpected EOF"
|
151
|
-
end
|
152
|
-
|
153
|
-
def handle_GET_VALUES(rec)
|
154
|
-
h = {}
|
155
|
-
rec.values.each_key do |name|
|
156
|
-
h[name] = @default_parameters[name]
|
157
|
-
end
|
158
|
-
ValuesRecord.new(FCGI_GET_VALUES_RESULT, rec.request_id, h)
|
159
|
-
end
|
160
|
-
|
161
|
-
def respond_to(req, sock, status)
|
162
|
-
split_data(FCGI_STDOUT, req.id, req.out) do |rec|
|
163
|
-
sock.send_record rec
|
164
|
-
end
|
165
|
-
split_data(FCGI_STDERR, req.id, req.err) do |rec|
|
166
|
-
sock.send_record rec
|
167
|
-
end if req.err.length > 0
|
168
|
-
sock.send_record EndRequestRecord.new(req.id, 0, status)
|
169
|
-
end
|
170
|
-
|
171
|
-
DATA_UNIT = 16384
|
172
|
-
|
173
|
-
def split_data(type, id, f)
|
174
|
-
unless f.length == 0
|
175
|
-
f.rewind
|
176
|
-
while s = f.read(DATA_UNIT)
|
177
|
-
yield GenericDataRecord.new(type, id, s)
|
178
|
-
end
|
179
|
-
end
|
180
|
-
yield GenericDataRecord.new(type, id, '')
|
181
|
-
end
|
182
|
-
|
183
|
-
end
|
184
|
-
|
185
|
-
|
186
|
-
class FastCGISocket
|
187
|
-
def initialize(sock)
|
188
|
-
@socket = sock
|
189
|
-
end
|
190
|
-
|
191
|
-
def read_record
|
192
|
-
header = @socket.read(Record::HEADER_LENGTH) or return nil
|
193
|
-
return nil unless header.size == Record::HEADER_LENGTH
|
194
|
-
version, type, reqid, clen, padlen, reserved = *Record.parse_header(header)
|
195
|
-
Record.class_for(type).parse(reqid, read_record_body(clen, padlen))
|
196
|
-
end
|
197
|
-
|
198
|
-
def read_record_body(clen, padlen)
|
199
|
-
buf = ''
|
200
|
-
while buf.length < clen
|
201
|
-
buf << @socket.read([1024, clen - buf.length].min)
|
202
|
-
end
|
203
|
-
@socket.read padlen if padlen
|
204
|
-
buf
|
205
|
-
end
|
206
|
-
private :read_record_body
|
207
|
-
|
208
|
-
def send_record(rec)
|
209
|
-
@socket.write rec.serialize
|
210
|
-
@socket.flush
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
214
|
-
|
215
|
-
class RecordBuffer
|
216
|
-
def initialize(rec)
|
217
|
-
@begin_request = rec
|
218
|
-
@envs = []
|
219
|
-
@stdins = []
|
220
|
-
@datas = []
|
221
|
-
end
|
222
|
-
|
223
|
-
def push(rec)
|
224
|
-
case rec
|
225
|
-
when ParamsRecord
|
226
|
-
@envs.push rec
|
227
|
-
when StdinDataRecord
|
228
|
-
@stdins.push rec
|
229
|
-
when DataRecord
|
230
|
-
@datas.push rec
|
231
|
-
else
|
232
|
-
raise "got unknown record: #{rec.class}"
|
233
|
-
end
|
234
|
-
end
|
235
|
-
|
236
|
-
def ready?
|
237
|
-
case @begin_request.role
|
238
|
-
when FCGI_RESPONDER
|
239
|
-
completed?(@envs) and
|
240
|
-
completed?(@stdins)
|
241
|
-
when FCGI_AUTHORIZER
|
242
|
-
completed?(@envs)
|
243
|
-
when FCGI_FILTER
|
244
|
-
completed?(@envs) and
|
245
|
-
completed?(@stdins) and
|
246
|
-
completed?(@datas)
|
247
|
-
else
|
248
|
-
raise "unknown role: #{@begin_request.role}"
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
|
-
def completed?(records)
|
253
|
-
records.last and records.last.empty?
|
254
|
-
end
|
255
|
-
private :completed?
|
256
|
-
|
257
|
-
def new_request
|
258
|
-
Request.new(@begin_request.request_id, env(), stdin(), nil, nil, data())
|
259
|
-
end
|
260
|
-
|
261
|
-
def env
|
262
|
-
h = {}
|
263
|
-
@envs.each {|rec| h.update rec.values }
|
264
|
-
h
|
265
|
-
end
|
266
|
-
|
267
|
-
def stdin
|
268
|
-
StringIO.new(@stdins.inject('') {|buf, rec| buf << rec.flagment })
|
269
|
-
end
|
270
|
-
|
271
|
-
def data
|
272
|
-
StringIO.new(@datas.inject('') {|buf, rec| buf << rec.flagment })
|
273
|
-
end
|
274
|
-
end
|
275
|
-
|
276
|
-
|
277
|
-
class Request
|
278
|
-
def initialize(id, env, stdin, stdout = nil, stderr = nil, data = nil)
|
279
|
-
@id = id
|
280
|
-
@env = env
|
281
|
-
@in = stdin
|
282
|
-
@out = stdout || StringIO.new
|
283
|
-
@err = stderr || StringIO.new
|
284
|
-
@data = data || StringIO.new
|
285
|
-
end
|
286
|
-
|
287
|
-
attr_reader :id
|
288
|
-
attr_reader :env
|
289
|
-
attr_reader :in
|
290
|
-
attr_reader :out
|
291
|
-
attr_reader :err
|
292
|
-
attr_reader :data
|
293
|
-
|
294
|
-
def finish # for backword compatibility
|
295
|
-
end
|
296
|
-
end
|
297
|
-
|
298
|
-
|
299
|
-
class Record
|
300
|
-
# uint8_t protocol_version;
|
301
|
-
# uint8_t record_type;
|
302
|
-
# uint16_t request_id; (big endian)
|
303
|
-
# uint16_t content_length; (big endian)
|
304
|
-
# uint8_t padding_length;
|
305
|
-
# uint8_t reserved;
|
306
|
-
HEADER_FORMAT = 'CCnnCC'
|
307
|
-
HEADER_LENGTH = 8
|
308
|
-
|
309
|
-
def self::parse_header(buf)
|
310
|
-
return *buf.unpack(HEADER_FORMAT)
|
311
|
-
end
|
312
|
-
|
313
|
-
def self::class_for(type)
|
314
|
-
RECORD_CLASS[type]
|
315
|
-
end
|
316
|
-
|
317
|
-
def initialize(type, reqid)
|
318
|
-
@type = type
|
319
|
-
@request_id = reqid
|
320
|
-
end
|
321
|
-
|
322
|
-
def version
|
323
|
-
::FCGI::ProtocolVersion
|
324
|
-
end
|
325
|
-
|
326
|
-
attr_reader :type
|
327
|
-
attr_reader :request_id
|
328
|
-
|
329
|
-
def management_record?
|
330
|
-
@request_id == FCGI_NULL_REQUEST_ID
|
331
|
-
end
|
332
|
-
|
333
|
-
def serialize
|
334
|
-
body = make_body()
|
335
|
-
padlen = body.length % 8
|
336
|
-
header = make_header(body.length, padlen)
|
337
|
-
header + body + "\000" * padlen
|
338
|
-
end
|
339
|
-
|
340
|
-
private
|
341
|
-
|
342
|
-
def make_header(clen, padlen)
|
343
|
-
[version(), @type, @request_id, clen, padlen, 0].pack(HEADER_FORMAT)
|
344
|
-
end
|
345
|
-
end
|
346
|
-
|
347
|
-
class BeginRequestRecord < Record
|
348
|
-
# uint16_t role; (big endian)
|
349
|
-
# uint8_t flags;
|
350
|
-
# uint8_t reserved[5];
|
351
|
-
BODY_FORMAT = 'nCC5'
|
352
|
-
|
353
|
-
def BeginRequestRecord.parse(id, body)
|
354
|
-
role, flags, *reserved = *body.unpack(BODY_FORMAT)
|
355
|
-
new(id, role, flags)
|
356
|
-
end
|
357
|
-
|
358
|
-
def initialize(id, role, flags)
|
359
|
-
super FCGI_BEGIN_REQUEST, id
|
360
|
-
@role = role
|
361
|
-
@flags = flags
|
362
|
-
end
|
363
|
-
|
364
|
-
attr_reader :role
|
365
|
-
attr_reader :flags
|
366
|
-
|
367
|
-
def make_body
|
368
|
-
[@role, @flags, 0, 0, 0, 0, 0].pack(BODY_FORMAT)
|
369
|
-
end
|
370
|
-
end
|
371
|
-
|
372
|
-
class AbortRequestRecord < Record
|
373
|
-
def AbortRequestRecord.parse(id, body)
|
374
|
-
new(id)
|
375
|
-
end
|
376
|
-
|
377
|
-
def initialize(id)
|
378
|
-
super FCGI_ABORT_REQUEST, id
|
379
|
-
end
|
380
|
-
end
|
381
|
-
|
382
|
-
class EndRequestRecord < Record
|
383
|
-
# uint32_t appStatus; (big endian)
|
384
|
-
# uint8_t protocolStatus;
|
385
|
-
# uint8_t reserved[3];
|
386
|
-
BODY_FORMAT = 'NCC3'
|
387
|
-
|
388
|
-
def self::parse(id, body)
|
389
|
-
appstatus, protostatus, *reserved = *body.unpack(BODY_FORMAT)
|
390
|
-
new(id, appstatus, protostatus)
|
391
|
-
end
|
392
|
-
|
393
|
-
def initialize(id, appstatus, protostatus)
|
394
|
-
super FCGI_END_REQUEST, id
|
395
|
-
@application_status = appstatus
|
396
|
-
@protocol_status = protostatus
|
397
|
-
end
|
398
|
-
|
399
|
-
attr_reader :application_status
|
400
|
-
attr_reader :protocol_status
|
401
|
-
|
402
|
-
private
|
403
|
-
|
404
|
-
def make_body
|
405
|
-
[@application_status, @protocol_status, 0, 0, 0].pack(BODY_FORMAT)
|
406
|
-
end
|
407
|
-
end
|
408
|
-
|
409
|
-
class UnknownTypeRecord < Record
|
410
|
-
# uint8_t type;
|
411
|
-
# uint8_t reserved[7];
|
412
|
-
BODY_FORMAT = 'CC7'
|
413
|
-
|
414
|
-
def self::parse(id, body)
|
415
|
-
type, *reserved = *body.unpack(BODY_FORMAT)
|
416
|
-
new(id, type)
|
417
|
-
end
|
418
|
-
|
419
|
-
def initialize(id, t)
|
420
|
-
super FCGI_UNKNOWN_TYPE, id
|
421
|
-
@unknown_type = t
|
422
|
-
end
|
423
|
-
|
424
|
-
attr_reader :unknown_type
|
425
|
-
|
426
|
-
private
|
427
|
-
|
428
|
-
def make_body
|
429
|
-
[@unknown_type, 0, 0, 0, 0, 0, 0, 0].pack(BODY_FORMAT)
|
430
|
-
end
|
431
|
-
end
|
432
|
-
|
433
|
-
class ValuesRecord < Record
|
434
|
-
def self::parse(id, body)
|
435
|
-
new(id, parse_values(body))
|
436
|
-
end
|
437
|
-
|
438
|
-
def self::parse_values(buf)
|
439
|
-
result = {}
|
440
|
-
until buf.empty?
|
441
|
-
name, value = *read_pair(buf)
|
442
|
-
result[name] = value
|
443
|
-
end
|
444
|
-
result
|
445
|
-
end
|
446
|
-
|
447
|
-
def self::read_pair(buf)
|
448
|
-
nlen = read_length(buf)
|
449
|
-
vlen = read_length(buf)
|
450
|
-
return buf.slice!(0, nlen), buf.slice!(0, vlen)
|
451
|
-
end
|
452
|
-
|
453
|
-
def self::read_length(buf)
|
454
|
-
if buf[0] >> 7 == 0
|
455
|
-
then buf.slice!(0,1)[0]
|
456
|
-
else buf.slice!(0,4).unpack('N')[0] & ((1<<31) - 1)
|
457
|
-
end
|
458
|
-
end
|
459
|
-
|
460
|
-
def initialize(type, id, values)
|
461
|
-
super type, id
|
462
|
-
@values = values
|
463
|
-
end
|
464
|
-
|
465
|
-
attr_reader :values
|
466
|
-
|
467
|
-
private
|
468
|
-
|
469
|
-
def make_body
|
470
|
-
buf = ''
|
471
|
-
@values.each do |name, value|
|
472
|
-
buf << serialize_length(name.length)
|
473
|
-
buf << serialize_length(value.length)
|
474
|
-
buf << name
|
475
|
-
buf << value
|
476
|
-
end
|
477
|
-
buf
|
478
|
-
end
|
479
|
-
|
480
|
-
def serialize_length(len)
|
481
|
-
if len < 0x80
|
482
|
-
then len.chr
|
483
|
-
else [len | (1<<31)].pack('N')
|
484
|
-
end
|
485
|
-
end
|
486
|
-
end
|
487
|
-
|
488
|
-
class GetValuesRecord < ValuesRecord
|
489
|
-
def initialize(id, values)
|
490
|
-
super FCGI_GET_VALUES, id, values
|
491
|
-
end
|
492
|
-
end
|
493
|
-
|
494
|
-
class ParamsRecord < ValuesRecord
|
495
|
-
def initialize(id, values)
|
496
|
-
super FCGI_PARAMS, id, values
|
497
|
-
end
|
498
|
-
|
499
|
-
def empty?
|
500
|
-
@values.empty?
|
501
|
-
end
|
502
|
-
end
|
503
|
-
|
504
|
-
class GenericDataRecord < Record
|
505
|
-
def self::parse(id, body)
|
506
|
-
new(id, body)
|
507
|
-
end
|
508
|
-
|
509
|
-
def initialize(type, id, flagment)
|
510
|
-
super type, id
|
511
|
-
@flagment = flagment
|
512
|
-
end
|
513
|
-
|
514
|
-
attr_reader :flagment
|
515
|
-
|
516
|
-
def empty?
|
517
|
-
@flagment.empty?
|
518
|
-
end
|
519
|
-
|
520
|
-
private
|
521
|
-
|
522
|
-
def make_body
|
523
|
-
@flagment
|
524
|
-
end
|
525
|
-
end
|
526
|
-
|
527
|
-
class StdinDataRecord < GenericDataRecord
|
528
|
-
def initialize(id, flagment)
|
529
|
-
super FCGI_STDIN, id, flagment
|
530
|
-
end
|
531
|
-
end
|
532
|
-
|
533
|
-
class StdoutDataRecord < GenericDataRecord
|
534
|
-
def initialize(id, flagment)
|
535
|
-
super FCGI_STDOUT, id, flagment
|
536
|
-
end
|
537
|
-
end
|
538
|
-
|
539
|
-
class DataRecord < GenericDataRecord
|
540
|
-
def initialize(id, flagment)
|
541
|
-
super FCGI_DATA, id, flagment
|
542
|
-
end
|
543
|
-
end
|
544
|
-
|
545
|
-
class Record # redefine
|
546
|
-
RECORD_CLASS = {
|
547
|
-
FCGI_GET_VALUES => GetValuesRecord,
|
548
|
-
|
549
|
-
FCGI_BEGIN_REQUEST => BeginRequestRecord,
|
550
|
-
FCGI_ABORT_REQUEST => AbortRequestRecord,
|
551
|
-
FCGI_PARAMS => ParamsRecord,
|
552
|
-
FCGI_STDIN => StdinDataRecord,
|
553
|
-
FCGI_DATA => DataRecord,
|
554
|
-
FCGI_STDOUT => StdoutDataRecord,
|
555
|
-
FCGI_END_REQUEST => EndRequestRecord
|
556
|
-
}
|
557
|
-
end
|
558
|
-
|
559
|
-
end # FCGI class
|
560
|
-
end # begin
|
561
|
-
|
562
|
-
# There is no C version of 'each_cgi'
|
563
|
-
# Note: for ruby-1.6.8 at least, the constants CGI_PARAMS/CGI_COOKIES
|
564
|
-
# are defined within module 'CGI', even if you have subclassed it
|
565
|
-
|
566
|
-
class FCGI
|
567
|
-
def self::each_cgi(*args)
|
568
|
-
require 'cgi'
|
569
|
-
|
570
|
-
eval(<<-EOS,TOPLEVEL_BINDING)
|
571
|
-
class CGI
|
572
|
-
public :env_table
|
573
|
-
def self::remove_params
|
574
|
-
if (const_defined?(:CGI_PARAMS))
|
575
|
-
remove_const(:CGI_PARAMS)
|
576
|
-
remove_const(:CGI_COOKIES)
|
577
|
-
end
|
578
|
-
end
|
579
|
-
end # ::CGI class
|
580
|
-
|
581
|
-
class FCGI
|
582
|
-
class CGI < ::CGI
|
583
|
-
def initialize(request, *args)
|
584
|
-
::CGI.remove_params
|
585
|
-
@request = request
|
586
|
-
super(*args)
|
587
|
-
@args = *args
|
588
|
-
end
|
589
|
-
def args
|
590
|
-
@args
|
591
|
-
end
|
592
|
-
def env_table
|
593
|
-
@request.env
|
594
|
-
end
|
595
|
-
def stdinput
|
596
|
-
@request.in
|
597
|
-
end
|
598
|
-
def stdoutput
|
599
|
-
@request.out
|
600
|
-
end
|
601
|
-
end # FCGI::CGI class
|
602
|
-
end # FCGI class
|
603
|
-
EOS
|
604
|
-
|
605
|
-
if FCGI::is_cgi?
|
606
|
-
yield ::CGI.new(*args)
|
607
|
-
else
|
608
|
-
exit_requested = false
|
609
|
-
FCGI::each {|request|
|
610
|
-
$stdout, $stderr = request.out, request.err
|
611
|
-
|
612
|
-
yield CGI.new(request, *args)
|
613
|
-
|
614
|
-
request.finish
|
615
|
-
}
|
616
|
-
end
|
617
|
-
end
|
618
|
-
end
|
data/lib/fcgi/fcgi.so
DELETED
Binary file
|