knjappserver 0.0.15 → 0.0.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/Gemfile +4 -2
  2. data/Gemfile.lock +24 -10
  3. data/README.rdoc +298 -1
  4. data/VERSION +1 -1
  5. data/bin/check_running.rb +2 -2
  6. data/knjappserver.gemspec +23 -5
  7. data/lib/files/database_schema.rb +124 -111
  8. data/lib/include/class_customio.rb +19 -5
  9. data/lib/include/class_erbhandler.rb +5 -22
  10. data/lib/include/class_httpresp.rb +66 -28
  11. data/lib/include/class_httpserver.rb +27 -14
  12. data/lib/include/class_httpsession.rb +161 -212
  13. data/lib/include/class_httpsession_contentgroup.rb +144 -0
  14. data/lib/include/class_httpsession_knjengine.rb +33 -68
  15. data/lib/include/class_httpsession_mongrel.rb +1 -1
  16. data/lib/include/class_httpsession_webrick.rb +1 -1
  17. data/lib/include/class_knjappserver.rb +105 -130
  18. data/lib/include/class_knjappserver_cleaner.rb +20 -13
  19. data/lib/include/class_knjappserver_cmdline.rb +44 -0
  20. data/lib/include/class_knjappserver_errors.rb +4 -1
  21. data/lib/include/class_knjappserver_logging.rb +48 -8
  22. data/lib/include/class_knjappserver_mailing.rb +36 -14
  23. data/lib/include/class_knjappserver_sessions.rb +78 -0
  24. data/lib/include/class_knjappserver_threadding.rb +18 -45
  25. data/lib/include/class_knjappserver_threadding_timeout.rb +78 -0
  26. data/lib/include/class_knjappserver_translations.rb +30 -0
  27. data/lib/include/class_knjappserver_web.rb +55 -3
  28. data/lib/include/class_log.rb +31 -3
  29. data/lib/include/class_log_access.rb +0 -15
  30. data/lib/include/class_log_data.rb +0 -15
  31. data/lib/include/class_log_data_link.rb +1 -14
  32. data/lib/include/class_log_data_value.rb +5 -17
  33. data/lib/include/class_session.rb +6 -18
  34. data/lib/include/magic_methods.rb +12 -14
  35. data/lib/pages/benchmark.rhtml +0 -0
  36. data/lib/pages/benchmark_print.rhtml +14 -0
  37. data/lib/pages/benchmark_simple.rhtml +3 -0
  38. data/lib/pages/benchmark_threadded_content.rhtml +21 -0
  39. data/lib/pages/spec.rhtml +26 -0
  40. data/lib/pages/spec_test_multiple_clients.rhtml +3 -0
  41. data/lib/pages/spec_threadded_content.rhtml +38 -0
  42. data/lib/scripts/benchmark.rb +65 -0
  43. data/spec/knjappserver_spec.rb +87 -43
  44. metadata +54 -20
@@ -4,11 +4,15 @@ class Knjappserver::Httpserver
4
4
 
5
5
  def initialize(kas)
6
6
  @kas = kas
7
- @http_sessions = []
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 @kas.config[:debug]
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 0.5 sec and then trying again.\n"
29
- sleep 0.5
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 @kas.config[:debug]
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 accept-thread.\n" if @kas.config[:debug]
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 @kas.config[:debug]
60
- @http_sessions.each do |httpsession|
61
- httpsession.destruct
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 @kas.config[:debug]
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 @kas.config[:debug]
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.config[:debug]
15
- self.reset
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
- if @kas.config[:engine_webrick]
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
- Dir.chdir(@kas.config[:doc_root])
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
- sleep 0.1 while @kas.paused? #Check if we should be waiting with executing the pending request.
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 @kas.config[:max_requests_working]
48
- while @httpserver.working_count >= @kas.config[:max_requests_working]
49
- STDOUT.print "Maximum amounts of requests are working (#{@httpserver.working_count}, #{@kas.config[:max_requests_working]}) - sleeping.\n" if @debug
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 WEBrick::HTTPStatus::RequestTimeout, WEBrick::HTTPStatus::EOFError, Errno::ECONNRESET, Errno::EPIPE, Timeout::Error => e
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
- first = e.backtrace.first
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
- @out = StringIO.new
94
+ cgroup_data = Thread.current[:knjappserver][:contentgroup].new_thread
92
95
 
93
- thread_out = StringIO.new
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
- @kas.ob.db.free_thread if @kas.ob.db.opts[:threadsafe]
106
- @kas.db_handler.free_thread if @kas.db_handler.opts[:threadsafe]
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 reset
118
- @out.close if @out
119
- @out = StringIO.new
120
- @parts = [@out]
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
- resp = Knjappserver::Httpresp.new
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
- meta = @handler.meta
166
- cookie = @handler.cookie
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
- pinfo = Knj::Php.pathinfo(page_path)
170
- ext = pinfo["extension"].downcase
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
- ctype = @kas.types[ext.to_sym] if @kas.types[ext.to_sym]
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
- @browser = Knj::Web.browser(meta)
177
- @ip = nil
178
- @ip = meta["HTTP_X_FORWARDED_FOR"].split(",")[0].strip if !@ip and meta["HTTP_X_FORWARDED_FOR"]
179
- @ip = meta["REMOTE_ADDR"] if !@ip and meta["REMOTE_ADDR"]
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
- @ips = [meta["REMOTE_ADDR"]]
182
- @ips << meta["HTTP_X_FORWARDED_FOR"].split(",")[0].strip if meta["HTTP_X_FORWARDED_FOR"]
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
- @session_id = nil
185
- @session_id = "bot" if @browser["browser"] == "bot"
186
- @session_id = cookie["KnjappserverSession"] if cookie["KnjappserverSession"].to_s.length > 0
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 !@session_id
189
- @session_id = Digest::MD5.hexdigest("#{Time.new.to_f}_#{meta["HTTP_HOST"]}_#{meta["REMOTE_HOST"]}_#{meta["HTTP_X_FORWARDED_SERVER"]}_#{meta["HTTP_X_FORWARDED_FOR"]}_#{meta["HTTP_X_FORWARDED_HOST"]}_#{meta["REMOTE_ADDR"]}_#{meta["HTTP_USER_AGENT"]}")
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" => (Knj::Datet.new.months + 12).time
196
- ).to_s)
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 @kas.config[:logging] and @kas.config[:logging][:access_db]
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 => Knj::Datet.new.dbstr,
236
+ :date_request => Time.now,
208
237
  :ips => @ips,
209
- :get => @handler.get,
210
- :post => @handler.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
- time_start = Time.now if @debug
217
- serv_data = self.serve_real(
218
- :filepath => page_path,
219
- :get => @handler.get,
220
- :post => @handler.post,
221
- :cookie => cookie,
222
- :meta => meta,
223
- :headers => {},
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(details)
285
- request = details[:request]
286
- headers = {}
287
- cont = ""
288
- statuscode = nil
289
- lastmod = false
290
- max_age = 365 * 24
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 @handler.headers["cache-control"] and @handler.headers["cache-control"][0]
297
- @handler.headers["cache-control"][0].scan(/(.+)=(.+)/) do |match|
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
- #check if we should use a handler for this request.
305
- handler_use = false
306
- @kas.config[:handlers].each do |handler_info|
307
- if handler_info[:file_ext] and handler_info[:file_ext] == details[:ext]
308
- handler_use = true
309
- ret = handler_info[:callback].call(details)
310
- cont = ret[:content] if ret[:content]
311
- headers = ret[:headers] if ret[:headers]
312
- break
313
- elsif handler_info[:path] and handler_info[:mount] and details[:meta]["SCRIPT_NAME"].slice(0, handler_info[:path].length) == handler_info[:path]
314
- details[:filepath] = "#{handler_info[:mount]}#{details[:meta]["SCRIPT_NAME"].slice(handler_info[:path].length, details[:meta]["SCRIPT_NAME"].length)}"
315
- break
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 !cache
335
- @parts << File.new(details[:filepath]) #get plain content from file.
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