knjappserver 0.0.15 → 0.0.16
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/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
|