knjappserver 0.0.15 → 0.0.16
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +4 -2
- data/Gemfile.lock +24 -10
- data/README.rdoc +298 -1
- data/VERSION +1 -1
- data/bin/check_running.rb +2 -2
- data/knjappserver.gemspec +23 -5
- data/lib/files/database_schema.rb +124 -111
- data/lib/include/class_customio.rb +19 -5
- data/lib/include/class_erbhandler.rb +5 -22
- data/lib/include/class_httpresp.rb +66 -28
- data/lib/include/class_httpserver.rb +27 -14
- data/lib/include/class_httpsession.rb +161 -212
- data/lib/include/class_httpsession_contentgroup.rb +144 -0
- data/lib/include/class_httpsession_knjengine.rb +33 -68
- data/lib/include/class_httpsession_mongrel.rb +1 -1
- data/lib/include/class_httpsession_webrick.rb +1 -1
- data/lib/include/class_knjappserver.rb +105 -130
- data/lib/include/class_knjappserver_cleaner.rb +20 -13
- data/lib/include/class_knjappserver_cmdline.rb +44 -0
- data/lib/include/class_knjappserver_errors.rb +4 -1
- data/lib/include/class_knjappserver_logging.rb +48 -8
- data/lib/include/class_knjappserver_mailing.rb +36 -14
- data/lib/include/class_knjappserver_sessions.rb +78 -0
- data/lib/include/class_knjappserver_threadding.rb +18 -45
- data/lib/include/class_knjappserver_threadding_timeout.rb +78 -0
- data/lib/include/class_knjappserver_translations.rb +30 -0
- data/lib/include/class_knjappserver_web.rb +55 -3
- data/lib/include/class_log.rb +31 -3
- data/lib/include/class_log_access.rb +0 -15
- data/lib/include/class_log_data.rb +0 -15
- data/lib/include/class_log_data_link.rb +1 -14
- data/lib/include/class_log_data_value.rb +5 -17
- data/lib/include/class_session.rb +6 -18
- data/lib/include/magic_methods.rb +12 -14
- data/lib/pages/benchmark.rhtml +0 -0
- data/lib/pages/benchmark_print.rhtml +14 -0
- data/lib/pages/benchmark_simple.rhtml +3 -0
- data/lib/pages/benchmark_threadded_content.rhtml +21 -0
- data/lib/pages/spec.rhtml +26 -0
- data/lib/pages/spec_test_multiple_clients.rhtml +3 -0
- data/lib/pages/spec_threadded_content.rhtml +38 -0
- data/lib/scripts/benchmark.rb +65 -0
- data/spec/knjappserver_spec.rb +87 -43
- metadata +54 -20
@@ -4,11 +4,15 @@ class Knjappserver::Httpserver
|
|
4
4
|
|
5
5
|
def initialize(kas)
|
6
6
|
@kas = kas
|
7
|
-
@
|
8
|
-
@working_count = 0
|
7
|
+
@debug = @kas.config[:debug]
|
9
8
|
end
|
10
9
|
|
11
10
|
def start
|
11
|
+
@http_sessions = []
|
12
|
+
@working_count = 0
|
13
|
+
|
14
|
+
raise "No host was given." if !@kas.config.has_key?(:host)
|
15
|
+
raise "No port was given." if !@kas.config.has_key?(:port)
|
12
16
|
@server = TCPServer.new(@kas.config[:host], @kas.config[:port])
|
13
17
|
|
14
18
|
@thread_accept = Knj::Thread.new do
|
@@ -20,13 +24,13 @@ class Knjappserver::Httpserver
|
|
20
24
|
|
21
25
|
begin
|
22
26
|
self.spawn_httpsession(@server.accept)
|
23
|
-
STDOUT.print "Starting new HTTP-request.\n" if @
|
27
|
+
STDOUT.print "Starting new HTTP-request.\n" if @debug
|
24
28
|
rescue => e
|
25
29
|
STDOUT.puts e.inspect
|
26
30
|
STDOUT.puts e.backtrace
|
27
31
|
STDOUT.print "\n"
|
28
|
-
STDOUT.print "Could not accept HTTP-request - waiting
|
29
|
-
sleep
|
32
|
+
STDOUT.print "Could not accept HTTP-request - waiting 1 sec and then trying again.\n"
|
33
|
+
sleep 1
|
30
34
|
end
|
31
35
|
end
|
32
36
|
end
|
@@ -47,24 +51,26 @@ class Knjappserver::Httpserver
|
|
47
51
|
|
48
52
|
def stop
|
49
53
|
begin
|
50
|
-
STDOUT.print "Stopping accept-thread.\n" if @
|
54
|
+
STDOUT.print "Stopping accept-thread.\n" if @debug
|
51
55
|
@thread_accept.kill if @thread_accept and @thread_accept.alive?
|
52
56
|
@thread_restart.kill if @thread_restart and @thread_restart.alive?
|
53
57
|
rescue => e
|
54
|
-
STDOUT.print "Could not stop
|
58
|
+
STDOUT.print "Could not stop threads.\n" if @debug
|
55
59
|
STDOUT.puts e.inspect
|
56
60
|
STDOUT.puts e.backtrace
|
57
61
|
end
|
58
62
|
|
59
|
-
STDOUT.print "Stopping all HTTP sessions.\n" if @
|
60
|
-
@http_sessions
|
61
|
-
httpsession
|
63
|
+
STDOUT.print "Stopping all HTTP sessions.\n" if @debug
|
64
|
+
if @http_sessions
|
65
|
+
@http_sessions.each do |httpsession|
|
66
|
+
httpsession.destruct
|
67
|
+
end
|
62
68
|
end
|
63
69
|
|
64
70
|
begin
|
65
|
-
STDOUT.print "Stopping TCPServer.\n" if @
|
71
|
+
STDOUT.print "Stopping TCPServer.\n" if @debug
|
66
72
|
@server.close if @server and !@server.closed?
|
67
|
-
STDOUT.print "TCPServer was closed.\n" if @
|
73
|
+
STDOUT.print "TCPServer was closed.\n" if @debug
|
68
74
|
rescue Timeout::Error
|
69
75
|
raise "Could not close TCPserver.\n"
|
70
76
|
rescue IOError => e
|
@@ -74,6 +80,13 @@ class Knjappserver::Httpserver
|
|
74
80
|
raise e
|
75
81
|
end
|
76
82
|
end
|
83
|
+
|
84
|
+
@http_sessions = nil
|
85
|
+
@thread_accept = nil
|
86
|
+
@thread_restart = nil
|
87
|
+
@server = nil
|
88
|
+
@working_count = nil
|
89
|
+
@kas = nil
|
77
90
|
end
|
78
91
|
|
79
92
|
def spawn_httpsession(socket)
|
@@ -81,11 +94,11 @@ class Knjappserver::Httpserver
|
|
81
94
|
end
|
82
95
|
|
83
96
|
def handle_request(&block)
|
84
|
-
@working_count += 1
|
97
|
+
@working_count += 1 if @working_count
|
85
98
|
begin
|
86
99
|
block.call
|
87
100
|
ensure
|
88
|
-
@working_count -= 1
|
101
|
+
@working_count -= 1 if @working_count
|
89
102
|
end
|
90
103
|
end
|
91
104
|
end
|
@@ -1,52 +1,66 @@
|
|
1
1
|
require "digest"
|
2
2
|
|
3
3
|
class Knjappserver::Httpsession
|
4
|
-
attr_accessor :data
|
5
|
-
attr_reader :session, :session_id, :session_hash, :kas, :active, :out, :eruby, :browser, :debug
|
4
|
+
attr_accessor :data, :size_send, :alert_sent
|
5
|
+
attr_reader :session, :session_id, :session_hash, :kas, :active, :out, :eruby, :browser, :debug, :resp, :page_path, :cgroup, :written_size
|
6
6
|
|
7
7
|
def initialize(httpserver, socket)
|
8
8
|
@data = {}
|
9
9
|
@socket = socket
|
10
10
|
@httpserver = httpserver
|
11
11
|
@kas = httpserver.kas
|
12
|
+
@types = @kas.types
|
13
|
+
@config = @kas.config
|
12
14
|
@active = true
|
13
15
|
@eruby = Knj::Eruby.new(:cache_hash => @kas.eruby_cache)
|
14
|
-
@debug = @kas.
|
15
|
-
|
16
|
+
@debug = @kas.debug
|
17
|
+
|
18
|
+
@cgroup = Knjappserver::Httpsession::Contentgroup.new(
|
19
|
+
:socket => @socket,
|
20
|
+
:restart_proc => proc{
|
21
|
+
begin
|
22
|
+
@resp.write(@socket) if @meta["METHOD"] != "HEAD"
|
23
|
+
rescue Errno::ECONNRESET, Errno::ENOTCONN, Errno::EPIPE, Timeout::Error
|
24
|
+
#Ignore - the user probaly left.
|
25
|
+
end
|
26
|
+
}
|
27
|
+
)
|
16
28
|
|
17
|
-
|
18
|
-
require "#{File.dirname(__FILE__)}/class_httpsession_webrick"
|
19
|
-
@handler = Knjappserver::Httpsession::Webrick.new(:kas => @kas)
|
20
|
-
elsif @kas.config[:engine_mongrel]
|
21
|
-
require "#{File.dirname(__FILE__)}/class_httpsession_mongrel"
|
22
|
-
@handler = Knjappserver::Httpsession::Mongrel.new(:kas => @kas)
|
23
|
-
elsif @kas.config[:engine_knjengine]
|
24
|
-
require "#{File.dirname(__FILE__)}/class_httpsession_knjengine"
|
25
|
-
@handler = Knjappserver::Httpsession::Knjengine.new(:kas => @kas)
|
26
|
-
else
|
27
|
-
raise "Unknown handler."
|
28
|
-
end
|
29
|
+
@resp = Knjappserver::Httpresp.new(:cgroup => @cgroup)
|
29
30
|
|
30
|
-
|
31
|
+
require "#{File.dirname(__FILE__)}/class_httpsession_knjengine"
|
32
|
+
@handler = Knjappserver::Httpsession::Knjengine.new(:kas => @kas)
|
33
|
+
|
34
|
+
Dir.chdir(@config[:doc_root])
|
31
35
|
ObjectSpace.define_finalizer(self, self.class.method(:finalize).to_proc) if @debug
|
32
36
|
STDOUT.print "New httpsession #{self.__id__} (total: #{@httpserver.http_sessions.count}).\n" if @debug
|
33
37
|
|
34
38
|
@thread_request = Knj::Thread.new do
|
39
|
+
Thread.current[:knjappserver] = {} if !Thread.current[:knjappserver]
|
40
|
+
|
35
41
|
@kas.db_handler.get_and_register_thread if @kas.db_handler.opts[:threadsafe]
|
36
42
|
@kas.ob.db.get_and_register_thread if @kas.ob.db.opts[:threadsafe]
|
37
43
|
|
38
44
|
begin
|
39
45
|
while @active
|
40
46
|
begin
|
47
|
+
@cgroup.reset
|
48
|
+
@written_size = 0
|
49
|
+
@size_send = @config[:size_send]
|
50
|
+
@alert_sent = false
|
51
|
+
|
41
52
|
Timeout.timeout(30) do
|
42
53
|
@handler.socket_parse(@socket)
|
43
54
|
end
|
44
55
|
|
45
|
-
|
56
|
+
while @kas.paused? #Check if we should be waiting with executing the pending request.
|
57
|
+
STDOUT.print "Paused! (#{@kas.paused}) - sleeping.\n" if @debug
|
58
|
+
sleep 0.1
|
59
|
+
end
|
46
60
|
|
47
|
-
if @
|
48
|
-
while @httpserver.working_count >= @
|
49
|
-
STDOUT.print "Maximum amounts of requests are working (#{@httpserver.working_count}, #{@
|
61
|
+
if @config.key?(:max_requests_working)
|
62
|
+
while @httpserver.working_count >= @config[:max_requests_working]
|
63
|
+
STDOUT.print "Maximum amounts of requests are working (#{@httpserver.working_count}, #{@config[:max_requests_working]}) - sleeping.\n" if @debug
|
50
64
|
sleep 0.1
|
51
65
|
end
|
52
66
|
end
|
@@ -56,28 +70,17 @@ class Knjappserver::Httpsession
|
|
56
70
|
end
|
57
71
|
ensure
|
58
72
|
@kas.served += 1 if @kas
|
59
|
-
self.reset
|
60
73
|
end
|
61
74
|
end
|
62
|
-
rescue
|
75
|
+
rescue Errno::ECONNRESET, Errno::ENOTCONN, Errno::EPIPE, Timeout::Error => e
|
63
76
|
#Ignore - the user probaly left.
|
64
77
|
#STDOUT.puts e.inspect
|
65
78
|
#STDOUT.puts e.backtrace
|
66
79
|
rescue SystemExit, Interrupt => e
|
67
80
|
raise e
|
68
81
|
rescue RuntimeError, Exception => e
|
69
|
-
|
70
|
-
|
71
|
-
if first.index("webrick/httprequest.rb") != nil or first.index("webrick/httpresponse.rb") != nil
|
72
|
-
if debug
|
73
|
-
STDOUT.print "Notice: Webrick error - properly faulty request - ignoring!\n"
|
74
|
-
STDOUT.puts e.inspect
|
75
|
-
STDOUT.puts e.backtrace
|
76
|
-
end
|
77
|
-
else
|
78
|
-
STDOUT.puts e.inspect
|
79
|
-
STDOUT.puts e.backtrace
|
80
|
-
end
|
82
|
+
STDOUT.puts e.inspect
|
83
|
+
STDOUT.puts e.backtrace
|
81
84
|
ensure
|
82
85
|
@kas.db_handler.free_thread if @kas and @kas.db_handler.opts[:threadsafe]
|
83
86
|
@kas.ob.db.free_thread if @kas and @kas.ob.db.opts[:threadsafe]
|
@@ -88,36 +91,37 @@ class Knjappserver::Httpsession
|
|
88
91
|
|
89
92
|
def threadded_content(block)
|
90
93
|
raise "No block was given." if !block
|
91
|
-
|
94
|
+
cgroup_data = Thread.current[:knjappserver][:contentgroup].new_thread
|
92
95
|
|
93
|
-
|
94
|
-
thread = Thread.new(Thread.current[:knjappserver].clone) do |data|
|
95
|
-
Thread.current[:knjappserver] = data
|
96
|
-
Thread.current[:knjappserver][:stringio] = thread_out
|
97
|
-
Thread.current[:knjappserver][:db] = @kas.db_handler
|
98
|
-
|
99
|
-
@kas.db_handler.get_and_register_thread if @kas.db_handler.opts[:threadsafe]
|
100
|
-
@kas.ob.db.get_and_register_thread if @kas.ob.db.opts[:threadsafe]
|
101
|
-
|
96
|
+
cgroup_data[:thread] = Thread.new(Thread.current[:knjappserver].clone) do |data|
|
102
97
|
begin
|
98
|
+
self.init_thread
|
99
|
+
cgroup_data[:cgroup].register_thread
|
100
|
+
|
101
|
+
@kas.db_handler.get_and_register_thread if @kas and @kas.db_handler.opts[:threadsafe]
|
102
|
+
@kas.ob.db.get_and_register_thread if @kas and @kas.ob.db.opts[:threadsafe]
|
103
|
+
|
103
104
|
block.call
|
105
|
+
rescue Exception => e
|
106
|
+
Thread.current[:knjappserver][:contentgroup].write Knj::Errors.error_str(e, {:html => true})
|
107
|
+
_kas.handle_error(e)
|
104
108
|
ensure
|
105
|
-
|
106
|
-
@kas.
|
109
|
+
Thread.current[:knjappserver][:contentgroup].mark_done
|
110
|
+
@kas.ob.db.free_thread if @kas and @kas.ob.db.opts[:threadsafe]
|
111
|
+
@kas.db_handler.free_thread if @kas and @kas.db_handler.opts[:threadsafe]
|
107
112
|
end
|
108
113
|
end
|
109
|
-
|
110
|
-
@parts << {
|
111
|
-
:thread => thread,
|
112
|
-
:stringio => thread_out
|
113
|
-
}
|
114
|
-
@parts << @out
|
115
114
|
end
|
116
115
|
|
117
|
-
def
|
118
|
-
|
119
|
-
|
120
|
-
|
116
|
+
def init_thread
|
117
|
+
Thread.current[:knjappserver] = {} if !Thread.current[:knjappserver]
|
118
|
+
Thread.current[:knjappserver][:kas] = @kas
|
119
|
+
Thread.current[:knjappserver][:httpsession] = self
|
120
|
+
Thread.current[:knjappserver][:session] = @session
|
121
|
+
Thread.current[:knjappserver][:get] = @get
|
122
|
+
Thread.current[:knjappserver][:post] = @post
|
123
|
+
Thread.current[:knjappserver][:meta] = @meta
|
124
|
+
Thread.current[:knjappserver][:cookie] = @cookie
|
121
125
|
end
|
122
126
|
|
123
127
|
def self.finalize(id)
|
@@ -125,7 +129,7 @@ class Knjappserver::Httpsession
|
|
125
129
|
end
|
126
130
|
|
127
131
|
def destruct
|
128
|
-
STDOUT.print "Httpsession destruct (#{@httpserver.http_sessions.length})\n" if @debug and @httpserver
|
132
|
+
STDOUT.print "Httpsession destruct (#{@httpserver.http_sessions.length})\n" if @debug and @httpserver and @httpserver.http_sessions
|
129
133
|
|
130
134
|
begin
|
131
135
|
@socket.close if @socket and !@socket.closed?
|
@@ -135,7 +139,7 @@ class Knjappserver::Httpsession
|
|
135
139
|
#ignore if it fails...
|
136
140
|
end
|
137
141
|
|
138
|
-
@httpserver.http_sessions.delete(self) if @httpserver
|
142
|
+
@httpserver.http_sessions.delete(self) if @httpserver and @httpserver.http_sessions
|
139
143
|
@httpserver = nil
|
140
144
|
|
141
145
|
@data = nil
|
@@ -147,204 +151,149 @@ class Knjappserver::Httpsession
|
|
147
151
|
@out = nil
|
148
152
|
@socket = nil
|
149
153
|
@browser = nil
|
154
|
+
@resp = nil
|
155
|
+
@cgroup = nil
|
156
|
+
@handler = nil
|
150
157
|
|
151
158
|
@eruby.destroy if @eruby
|
152
159
|
@eruby = nil
|
153
160
|
|
154
|
-
@handler.destroy if @handler
|
155
|
-
@handler = nil
|
156
|
-
|
157
161
|
thread = @thread_request
|
158
162
|
@thread_request = nil
|
159
163
|
thread.kill if thread and thread.alive?
|
160
164
|
end
|
161
165
|
|
162
166
|
def serve
|
163
|
-
|
167
|
+
@meta = @handler.meta
|
168
|
+
@cookie = @handler.cookie
|
169
|
+
@get = @handler.get
|
170
|
+
@post = @handler.post
|
171
|
+
@headers = @handler.headers
|
172
|
+
|
173
|
+
close = true if @meta["HTTP_CONNECTION"] == "close"
|
174
|
+
@resp.reset(
|
175
|
+
:http_version => @handler.http_version,
|
176
|
+
:close => close
|
177
|
+
)
|
178
|
+
if @handler.http_version == "1.1"
|
179
|
+
@cgroup.chunked = true
|
180
|
+
else
|
181
|
+
@cgroup.chunked = false
|
182
|
+
end
|
164
183
|
|
165
|
-
|
166
|
-
|
167
|
-
page_path = @handler.page_path
|
184
|
+
@page_path = @handler.page_path
|
185
|
+
@ext = File.extname(@page_path).downcase[1..-1].to_s
|
168
186
|
|
169
|
-
|
170
|
-
|
187
|
+
@ctype = @types[@ext.to_sym] if @ext.length > 0 and @types.key?(@ext.to_sym)
|
188
|
+
@ctype = @config[:default_filetype] if !@ctype and @config.key?(:default_filetype)
|
189
|
+
@resp.header("Content-Type", @ctype)
|
171
190
|
|
172
|
-
|
173
|
-
ctype = @kas.config[:default_filetype] if !ctype and @kas.config.has_key?(:default_filetype)
|
174
|
-
resp.header("Content-Type", ctype)
|
191
|
+
@browser = Knj::Web.browser(@meta)
|
175
192
|
|
176
|
-
@
|
177
|
-
|
178
|
-
@
|
179
|
-
|
193
|
+
if @meta["HTTP_X_FORWARDED_FOR"]
|
194
|
+
@ip = @meta["HTTP_X_FORWARDED_FOR"].split(",")[0].strip
|
195
|
+
elsif @meta["REMOTE_ADDR"]
|
196
|
+
@ip = @meta["REMOTE_ADDR"]
|
197
|
+
else
|
198
|
+
raise "Could not figure out the IP of the session."
|
199
|
+
end
|
180
200
|
|
181
|
-
@
|
182
|
-
|
201
|
+
if @cookie["KnjappserverSession"].to_s.length > 0
|
202
|
+
@session_id = @cookie["KnjappserverSession"]
|
203
|
+
elsif @browser["browser"] == "bot"
|
204
|
+
@session_id = "bot"
|
205
|
+
else
|
206
|
+
@session_id = @kas.session_generate_id(:meta => @meta)
|
207
|
+
send_cookie = true
|
208
|
+
end
|
183
209
|
|
184
|
-
|
185
|
-
|
186
|
-
|
210
|
+
begin
|
211
|
+
session = @kas.session_fromid(:idhash => @session_id, :ip => @ip, :meta => @meta)
|
212
|
+
rescue Knj::Errors::InvalidData => e
|
213
|
+
#User should not have the session he asked for because of invalid user-agent or invalid IP.
|
214
|
+
@session_id = @kas.session_generate_id(:meta => meta)
|
215
|
+
session = @kas.session_fromid(:idhash => @session_id, :ip => @ip, :meta => meta)
|
216
|
+
send_cookie = true
|
217
|
+
end
|
187
218
|
|
188
|
-
if
|
189
|
-
@
|
190
|
-
|
191
|
-
resp.cookie(CGI::Cookie.new(
|
219
|
+
if send_cookie
|
220
|
+
@resp.cookie(
|
192
221
|
"name" => "KnjappserverSession",
|
193
222
|
"value" => @session_id,
|
194
223
|
"path" => "/",
|
195
|
-
"expires" =>
|
196
|
-
)
|
224
|
+
"expires" => Time.now + 32140800 #add around 12 months
|
225
|
+
)
|
197
226
|
end
|
198
227
|
|
199
|
-
session = @kas.session_fromid(:idhash => @session_id, :ip => @ip)
|
200
|
-
|
201
228
|
@session = session[:dbobj]
|
202
229
|
@session_hash = session[:hash]
|
203
230
|
|
204
|
-
if @
|
231
|
+
if @config.key?(:logging) and @config[:logging][:access_db]
|
232
|
+
@ips = [@meta["REMOTE_ADDR"]]
|
233
|
+
@ips << @meta["HTTP_X_FORWARDED_FOR"].split(",")[0].strip if @meta["HTTP_X_FORWARDED_FOR"]
|
205
234
|
@kas.logs_access_pending << {
|
206
235
|
:session_id => @session.id,
|
207
|
-
:date_request =>
|
236
|
+
:date_request => Time.now,
|
208
237
|
:ips => @ips,
|
209
|
-
:get => @
|
210
|
-
:post => @
|
211
|
-
:meta => meta,
|
212
|
-
:cookie => cookie
|
238
|
+
:get => @get,
|
239
|
+
:post => @post,
|
240
|
+
:meta => @meta,
|
241
|
+
:cookie => @cookie
|
213
242
|
}
|
214
243
|
end
|
215
244
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
:ctype => ctype,
|
225
|
-
:ext => ext,
|
226
|
-
:session => @session,
|
227
|
-
:session_id => @session_id,
|
228
|
-
:session_hash => @session_hash,
|
229
|
-
:httpsession => self,
|
230
|
-
:db => @kas.db_handler,
|
231
|
-
:kas => @kas
|
232
|
-
)
|
233
|
-
|
234
|
-
serv_data[:headers].each do |header|
|
235
|
-
key = header[0]
|
236
|
-
val = header[1]
|
237
|
-
keystr = key.to_s.strip.downcase
|
238
|
-
|
239
|
-
if keystr.match(/^set-cookie/)
|
240
|
-
WEBrick::Cookie.parse_set_cookies(val).each do |cookie|
|
241
|
-
resp.cookie(cookie.to_s)
|
242
|
-
end
|
243
|
-
else
|
244
|
-
resp.header(key, val)
|
245
|
-
end
|
246
|
-
end
|
247
|
-
|
248
|
-
body_parts = []
|
249
|
-
@parts.each do |part|
|
250
|
-
if part.is_a?(Hash) and part[:thread]
|
251
|
-
part[:thread].join
|
252
|
-
part[:stringio].rewind
|
253
|
-
body_parts << part[:stringio]
|
254
|
-
elsif part.is_a?(StringIO) or part.is_a?(File)
|
255
|
-
part.rewind
|
256
|
-
body_parts << part
|
257
|
-
else
|
258
|
-
raise "Unknown object: '#{part.class.name}'."
|
259
|
-
end
|
260
|
-
end
|
261
|
-
resp.body = body_parts
|
262
|
-
|
263
|
-
if serv_data[:lastmod]
|
264
|
-
resp.header("Last-Modified", serv_data[:lastmod].time)
|
265
|
-
resp.header("Expires", Time.now + (3600 * 24))
|
266
|
-
end
|
267
|
-
|
268
|
-
if serv_data[:cache]
|
269
|
-
resp.status = 304
|
270
|
-
resp.header("Last-Modified", serv_data[:lastmod].time)
|
271
|
-
resp.header("Expires", Time.now + (3600 * 24))
|
272
|
-
end
|
273
|
-
|
274
|
-
resp.status = serv_data[:statuscode] if serv_data[:statuscode]
|
275
|
-
STDOUT.print "Served '#{meta["REQUEST_URI"]}' in #{Time.now.to_f - time_start.to_f} secs.\n" if @debug
|
276
|
-
|
277
|
-
resp.write_chunked(@socket) if meta["METHOD"] != "HEAD"
|
278
|
-
resp.destroy
|
279
|
-
|
280
|
-
#Letting them be nil is simply not enough (read that on a forum) - knj.
|
281
|
-
serv_data.clear
|
245
|
+
self.init_thread
|
246
|
+
Thread.current[:knjappserver][:contentgroup] = @cgroup
|
247
|
+
time_start = Time.now.to_f if @debug
|
248
|
+
self.serve_real
|
249
|
+
@cgroup.mark_done
|
250
|
+
@cgroup.write_output
|
251
|
+
STDOUT.print "#{__id__} - Served '#{@meta["REQUEST_URI"]}' in #{Time.now.to_f - time_start} secs (#{@resp.status}).\n" if @debug
|
252
|
+
@cgroup.join
|
282
253
|
end
|
283
254
|
|
284
|
-
def serve_real
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
255
|
+
def serve_real
|
256
|
+
#check if we should use a handler for this request.
|
257
|
+
@config[:handlers].each do |handler_info|
|
258
|
+
if handler_info.key?(:file_ext) and handler_info[:file_ext] == @ext
|
259
|
+
return handler_info[:callback].call(self)
|
260
|
+
elsif handler_info.key?(:path) and handler_info[:mount] and @meta["SCRIPT_NAME"].slice(0, handler_info[:path].length) == handler_info[:path]
|
261
|
+
@page_path = "#{handler_info[:mount]}#{@meta["SCRIPT_NAME"].slice(handler_info[:path].length, @meta["SCRIPT_NAME"].length)}"
|
262
|
+
break
|
263
|
+
end
|
264
|
+
end
|
291
265
|
|
292
|
-
cache = false
|
293
266
|
cache_control = {}
|
294
267
|
cache_use = true
|
295
268
|
|
296
|
-
if @
|
297
|
-
@
|
269
|
+
if @headers["cache-control"] and @headers["cache-control"][0]
|
270
|
+
@headers["cache-control"][0].scan(/(.+)=(.+)/) do |match|
|
298
271
|
cache_control[match[1]] = match[2]
|
299
272
|
end
|
300
273
|
end
|
301
274
|
|
302
|
-
cache_use = false if cache_control["max-age"].to_i <= 0
|
275
|
+
cache_use = false if cache_control.key?("max-age") and cache_control["max-age"].to_i <= 0
|
303
276
|
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
end
|
317
|
-
end
|
318
|
-
|
319
|
-
if !handler_use
|
320
|
-
if !File.exists?(details[:filepath])
|
321
|
-
statuscode = 404
|
322
|
-
headers["Content-Type"] = "text/html"
|
323
|
-
@parts << StringIO.new("File you are looking for was not found: '#{details[:meta]["REQUEST_URI"]}'.")
|
324
|
-
else
|
325
|
-
lastmod = Knj::Datet.new(File.new(details[:filepath]).mtime)
|
326
|
-
|
327
|
-
if cache_use and @handler.headers["if-modified-since"] and @handler.headers["if-modified-since"][0]
|
328
|
-
request_mod = Knj::Datet.parse(@handler.headers["if-modified-since"][0])
|
329
|
-
if request_mod == lastmod
|
330
|
-
cache = true
|
331
|
-
end
|
332
|
-
end
|
277
|
+
if !File.exists?(@page_path)
|
278
|
+
@resp.status = 404
|
279
|
+
@resp.header("Content-Type", "text/html")
|
280
|
+
@cgroup.write("File you are looking for was not found: '#{@meta["REQUEST_URI"]}'.")
|
281
|
+
else
|
282
|
+
lastmod = File.mtime(@page_path)
|
283
|
+
|
284
|
+
@resp.header("Last-Modified", lastmod.httpdate)
|
285
|
+
@resp.header("Expires", (Time.now + 86400).httpdate) #next day.
|
286
|
+
|
287
|
+
if cache_use and @headers["if-modified-since"] and @headers["if-modified-since"][0]
|
288
|
+
request_mod = Knj::Datet.parse(@headers["if-modified-since"][0]).time
|
333
289
|
|
334
|
-
if
|
335
|
-
@
|
290
|
+
if request_mod == lastmod
|
291
|
+
@resp.status = 304
|
292
|
+
return nil
|
336
293
|
end
|
337
294
|
end
|
295
|
+
|
296
|
+
@cgroup.new_io(File.new(@page_path))
|
338
297
|
end
|
339
|
-
|
340
|
-
details.clear
|
341
|
-
|
342
|
-
return {
|
343
|
-
:statuscode => statuscode,
|
344
|
-
:content => cont,
|
345
|
-
:headers => headers,
|
346
|
-
:lastmod => lastmod,
|
347
|
-
:cache => cache
|
348
|
-
}
|
349
298
|
end
|
350
299
|
end
|