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.
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