hayabusa 0.0.3 → 0.0.4

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.
@@ -1,6 +1,6 @@
1
1
  class Hayabusa::Cgi_session
2
2
  attr_accessor :data, :alert_sent
3
- attr_reader :cookie, :get, :headers, :session, :session_id, :session_hash, :hb, :active, :out, :eruby, :browser, :debug, :resp, :page_path, :post, :cgroup, :meta, :httpsession_var, :handler, :working
3
+ attr_reader :cookie, :get, :headers, :session, :session_id, :session_hash, :hb, :active, :out, :eruby, :browser, :debug, :resp, :page_path, :post, :cgroup, :meta, :httpsession_var, :working
4
4
 
5
5
  def initialize(args)
6
6
  @args = args
@@ -104,7 +104,7 @@ class Hayabusa::Cgi_session
104
104
 
105
105
  Timeout.timeout(@hb.config[:timeout]) do
106
106
  if @handlers_cache.key?(@ext)
107
- STDOUT.print "Calling handler.\n" if @debug
107
+ @hb.log_puts "Calling handler." if @debug
108
108
  @handlers_cache[@ext].call(self)
109
109
  else
110
110
  raise "CGI-mode shouldnt serve static files: '#{@page_path}'."
@@ -126,6 +126,29 @@ class Hayabusa::Cgi_session
126
126
  end
127
127
  end
128
128
 
129
+ def handler
130
+ return self
131
+ end
132
+
133
+ #Parses the if-modified-since header and returns it as a Time-object. Returns false is no if-modified-since-header is given or raises an RuntimeError if it cant be parsed.
134
+ def modified_since
135
+ return @modified_since if @modified_since
136
+ return false if !@meta["HTTP_IF_MODIFIED_SINCE"]
137
+
138
+ mod_match = @meta["HTTP_IF_MODIFIED_SINCE"].match(/^([A-z]+),\s+(\d+)\s+([A-z]+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+(.+)$/)
139
+ raise "Could not parse 'HTTP_IF_MODIFIED_SINCE'." if !mod_match
140
+
141
+ month_no = Datet.month_str_to_no(mod_match[3])
142
+ @modified_since = Time.utc(mod_match[4].to_i, month_no, mod_match[2].to_i, mod_match[5].to_i, mod_match[6].to_i, mod_match[7].to_i)
143
+
144
+ return @modified_since
145
+ end
146
+
147
+ #Forces the content to be the input - nothing else can be added after calling this.
148
+ def force_content(newcont)
149
+ @cgroup.force_content(newcont)
150
+ end
151
+
129
152
  #Creates a new Hayabusa::Binding-object and returns the binding for that object.
130
153
  def create_binding
131
154
  return Hayabusa::Http_session::Page_environment.new(:httpsession => self, :hb => @hb).get_binding
@@ -38,10 +38,7 @@ class Hayabusa::Cgi_tools
38
38
 
39
39
  #This method is used to proxy a request to another FCGI-process, since a single FCGI-process cant handle more requests simultanious.
40
40
  def proxy_request_to(args)
41
- cgi = args[:cgi]
42
- http = args[:http]
43
-
44
- File.open("/tmp/debug_#{Process.pid}_#{Time.new.to_f}.log", "w") do |fp_log|
41
+ cgi, http, fp_log = args[:cgi], args[:http], args[:fp_log]
45
42
 
46
43
  headers = {"Hayabusa_mode" => "proxy"}
47
44
  cgi.env_table.each do |key, val|
@@ -56,6 +53,7 @@ class Hayabusa::Cgi_tools
56
53
  #Make request.
57
54
  uri = Knj::Web.parse_uri(cgi.env_table["REQUEST_URI"])
58
55
  url = File.basename(uri[:path])
56
+ url = url[1, url.length] if url[0] == "/"
59
57
 
60
58
  if cgi.env_table["QUERY_STRING"].to_s.length > 0
61
59
  url << "?#{cgi.env_table["QUERY_STRING"]}"
@@ -64,39 +62,52 @@ class Hayabusa::Cgi_tools
64
62
  #cgi.print "Content-Type: text/html\r\n"
65
63
  #cgi.print "\r\n"
66
64
 
67
- if cgi.request_method == "POST" and cgi.content_type.to_s.downcase.index("multipart/form-data") != nil
68
- count = 0
69
- http.post_multipart(:url => url, :post => self.convert_fcgi_post(cgi.params),
70
- :default_headers => headers,
71
- :cookies => false,
72
- :on_content => proc{|line|
73
- cgi.print(line) if count > 0
74
- count += 1
75
- }
76
- )
77
- elsif cgi.request_method == "POST"
78
- count = 0
79
- http.post(:url => url, :post => self.convert_fcgi_post(cgi.params),
80
- :default_headers => headers,
81
- :cookies => false,
82
- :on_content => proc{|line|
83
- cgi.print(line) if count > 0
84
- count += 1
85
- }
86
- )
65
+ if args[:timeout]
66
+ ttime = args[:timeout]
87
67
  else
88
- count = 0
89
- http.get(:url => url,
90
- :default_headers => headers,
91
- :cookies => false,
92
- :on_content => proc{|line|
93
- fp_log.puts("Line: '#{line}'.")
94
- cgi.print(line) if count > 0
95
- count += 1
96
- }
97
- )
68
+ ttime = 30
98
69
  end
99
70
 
71
+ fp_log.puts("Proxying URL: '#{url}'.") if fp_log
72
+
73
+ require "timeout"
74
+ Timeout.timeout(ttime) do
75
+ if cgi.request_method == "POST" and cgi.content_type.to_s.downcase.index("multipart/form-data") != nil
76
+ count = 0
77
+ http.post_multipart(
78
+ :url => url,
79
+ :post => self.convert_fcgi_post(cgi.params),
80
+ :default_headers => headers,
81
+ :cookies => false,
82
+ :on_content => proc{|line|
83
+ cgi.print(line) if count > 0
84
+ count += 1
85
+ }
86
+ )
87
+ elsif cgi.request_method == "POST"
88
+ count = 0
89
+ http.post(
90
+ :url => url,
91
+ :post => self.convert_fcgi_post(cgi.params),
92
+ :default_headers => headers,
93
+ :cookies => false,
94
+ :on_content => proc{|line|
95
+ cgi.print(line) if count > 0
96
+ count += 1
97
+ }
98
+ )
99
+ else
100
+ count = 0
101
+ http.get(
102
+ :url => url,
103
+ :default_headers => headers,
104
+ :cookies => false,
105
+ :on_content => proc{|line|
106
+ cgi.print(line) if count > 0
107
+ count += 1
108
+ }
109
+ )
110
+ end
100
111
  end
101
112
  end
102
113
  end
@@ -3,8 +3,8 @@ class Hayabusa
3
3
  @config[:threadding] = {} if !@config.has_key?(:threadding)
4
4
  @config[:threadding][:max_running] = 8 if !@config[:threadding].has_key?(:max_running)
5
5
 
6
- @threadpool = Knj::Threadpool.new(:threads => @config[:threadding][:max_running], :sleep => 0.1)
7
- @threadpool.events.connect(:on_error, &self.method(:threadpool_on_error))
6
+ @threadpool = Tpool.new(:threads => @config[:threadding][:max_running])
7
+ @threadpool.on_error(&self.method(:threadpool_on_error))
8
8
  end
9
9
 
10
10
  #Callback for when an error occurs in the threadpool.
@@ -4,7 +4,7 @@ class Hayabusa
4
4
  # print _hb.trans(obj, :title) #=> "Trala"
5
5
  def trans(obj, key, args = {})
6
6
  args[:locale] = self.trans_locale if !args[:locale]
7
- trans_val = @translations.get(obj, key, args).to_s
7
+ trans_val = self.translations.get(obj, key, args).to_s
8
8
  trans_val = @events.call(:trans_no_str, {:obj => obj, :key => key, :args => args}) if trans_val.length <= 0
9
9
  return trans_val
10
10
  end
@@ -30,14 +30,16 @@ class Hayabusa
30
30
  #===Examples
31
31
  # _hb.trans_set(obj, {:title => "Trala"})
32
32
  def trans_set(obj, values, args = {})
33
+ raise "Translations-object now spawned." if !self.translations
33
34
  args[:locale] = self.trans_locale if !args[:locale]
34
- @translations.set(obj, values, args)
35
+ self.translations.set(obj, values, args)
35
36
  end
36
37
 
37
38
  #Deletes all translations for the given object.
38
39
  #===Examples
39
40
  # _hb.trans_del(obj)
40
41
  def trans_del(obj)
41
- @translations.delete(obj)
42
+ raise "Translations-object now spawned." if !self.translations
43
+ self.translations.delete(obj)
42
44
  end
43
45
  end
@@ -0,0 +1,172 @@
1
+ class Hayabusa::Fcgi
2
+ def initialize
3
+ #Spawn CGI-variable to emulate FCGI part.
4
+ @cgi_tools = Hayabusa::Cgi_tools.new
5
+
6
+ #We cant define the Hayabusa-server untuil we receive the first headers, so wait for the first request.
7
+ @hayabusa = nil
8
+ @hayabusa_fcgi_conf_path = nil
9
+ @fcgi_proxy = nil
10
+ @debug = false
11
+ end
12
+
13
+ def evaluate_mode
14
+ #If this is a FCGI-proxy-instance then the HTTP-connection should be checked if it is working.
15
+ if @fcgi_proxy
16
+ if !@fcgi_proxy[:http].socket_working?
17
+ @fcgi_proxy = nil
18
+ end
19
+ end
20
+
21
+ #Skip the actual check if Hayabusa is spawned or this is a working FCGI-proxy-instance.
22
+ return nil if @hayabusa or @fcgi_proxy
23
+
24
+ #Parse the configuration-header and generate Hayabusa-config-hash.
25
+ raise "No HTTP_HAYABUSA_FCGI_CONFIG-header was given." if !@cgi.env_table["HTTP_HAYABUSA_FCGI_CONFIG"]
26
+ @hayabusa_fcgi_conf_path = @cgi.env_table["HTTP_HAYABUSA_FCGI_CONFIG"]
27
+ require @hayabusa_fcgi_conf_path
28
+ raise "No 'Hayabusa::FCGI_CONF'-constant was spawned by '#{@cgi.env_table["HTTP_HAYABUSA_FCGI_CONFIG"]}'." if !Hayabusa.const_defined?(:FCGI_CONF)
29
+ conf = Hayabusa::FCGI_CONF
30
+
31
+ hayabusa_conf = Hayabusa::FCGI_CONF[:hayabusa]
32
+ hayabusa_conf.merge!(
33
+ :cmdline => false,
34
+ :port => 0 #Ruby picks random port and we get the actual port after starting the appserver.
35
+ )
36
+
37
+ #Figure out if this should be a host-FCGI-process or a proxy-FCGI-process.
38
+ fcgi_config_fp = "#{Knj::Os.tmpdir}/hayabusa_fcgi_#{hayabusa_conf[:title]}_fcgi.conf"
39
+ FileUtils.touch(fcgi_config_fp) if !File.exists?(fcgi_config_fp)
40
+
41
+ File.open(fcgi_config_fp) do |fp|
42
+ fp.flock(File::LOCK_EX)
43
+
44
+ fcgi_config_cont = File.read(fcgi_config_fp)
45
+ if !fcgi_config_cont.empty?
46
+ #Seems like an instance is already running - check PID to be sure.
47
+ fcgi_config = Marshal.load(File.read(fcgi_config_fp))
48
+ pid = fcgi_config[:pid]
49
+
50
+ if Knj::Unix_proc.pid_running?(pid)
51
+ #Set this instance to run in proxy-mode.
52
+ begin
53
+ @fcgi_proxy = fcgi_config
54
+ require "http2"
55
+ @fcgi_proxy[:http] = Http2.new(:host => "localhost", :port => @fcgi_proxy[:port].to_i)
56
+
57
+ if hayabusa_conf[:debug]
58
+ @fcgi_proxy[:fp_log] = File.open("/tmp/hayabusa_#{hayabusa_conf[:hayabusa][:title]}_#{Process.pid}.log", "w")
59
+ @fcgi_proxy[:fp_log].sync = true
60
+ end
61
+ rescue
62
+ @fcgi_proxy = nil
63
+ raise
64
+ end
65
+ end
66
+ end
67
+
68
+ #No instance is already running - start new Hayabusa-instance in both CGI- and socket-mode and write that to the config-file so other instances will register this as the main host-instance.
69
+ if !@fcgi_proxy
70
+ File.open(fcgi_config_fp, "w") do |fp|
71
+ @hayabusa = Hayabusa.new(hayabusa_conf)
72
+
73
+ #Start web-server for proxy-requests.
74
+ @hayabusa.start
75
+
76
+ fp.write(Marshal.dump(
77
+ :pid => Process.pid,
78
+ :port => @hayabusa.port
79
+ ))
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ def fcgi_loop
86
+ $stderr.puts "[hayabusa] Starting FCGI." if @debug
87
+ FCGI.each_cgi do |cgi|
88
+ begin
89
+ #cgi.print "Content-Type: text/html\r\n"
90
+ #cgi.print "\r\n"
91
+
92
+ #Set 'cgi'-variable for CGI-tools.
93
+ @cgi_tools.cgi = cgi
94
+ @cgi = cgi
95
+
96
+ #Evaluate the mode of this instance.
97
+ self.evaluate_mode
98
+
99
+ #Ensure the same FCGI-process isnt active for more than one website.
100
+ raise "Expected 'HTTP_HAYABUSA_FCGI_CONFIG' to be '#{@hayabusa_fcgi_conf_path}' but it wasnt: '#{cgi.env_table["HTTP_HAYABUSA_FCGI_CONFIG"]}'." if @hayabusa_fcgi_conf_path and @hayabusa_fcgi_conf_path != cgi.env_table["HTTP_HAYABUSA_FCGI_CONFIG"]
101
+
102
+ if @fcgi_proxy
103
+ #Proxy request to the host-FCGI-process.
104
+ $stderr.puts "[hayabusa] Proxying request." if @debug
105
+ begin
106
+ @cgi_tools.proxy_request_to(:cgi => cgi, :http => @fcgi_proxy[:http], :fp_log => @fcgi_proxy[:fp_log])
107
+ rescue Errno::ECONNABORTED
108
+ @fcgi_proxy = nil #Force re-evaluate if this process should be host or proxy.
109
+ raise
110
+ end
111
+ else
112
+ self.handle_fcgi_request(:cgi => cgi)
113
+ end
114
+ rescue Exception => e
115
+ cgi.print "Content-Type: text/html\r\n"
116
+ cgi.print "\r\n"
117
+ cgi.print Knj::Errors.error_str(e, :html => true)
118
+
119
+ if @hayabusa
120
+ @hayabusa.log_puts e.inspect
121
+ @hayabusa.log_puts e.backtrace
122
+ else
123
+ STDERR.puts e.inspect
124
+ STDERR.puts e.backtrace
125
+ end
126
+ ensure
127
+ @cgi = nil
128
+ @cgi_tools.cgi = nil
129
+ end
130
+ end
131
+ end
132
+
133
+ def handle_fcgi_request(args)
134
+ #Host the FCGI-process.
135
+ $stderr.puts "[hayabusa] Running request as CGI." if @debug
136
+
137
+ #Enforce $stdout variable.
138
+ $stdout = @hayabusa.cio
139
+
140
+ #The rest is copied from the FCGI-part.
141
+ headers = {}
142
+ @cgi.env_table.each do |key, val|
143
+ if key[0, 5] == "HTTP_" and key != "HTTP_HAYABUSA_FCGI_CONFIG"
144
+ key = key[5, key.length].gsub("_", " ").gsub(" ", "-")
145
+ headers[key] = val
146
+ end
147
+ end
148
+
149
+ meta = @cgi.env_table.to_hash
150
+
151
+ uri = Knj::Web.parse_uri(meta["REQUEST_URI"])
152
+ meta["PATH_TRANSLATED"] = File.basename(uri[:path])
153
+
154
+ cgi_data = {
155
+ :cgi => @cgi,
156
+ :headers => headers,
157
+ :get => Knj::Web.parse_urlquery(@cgi.env_table["QUERY_STRING"], :urldecode => true, :force_utf8 => true),
158
+ :meta => meta
159
+ }
160
+ if @cgi.request_method == "POST"
161
+ cgi_data[:post] = @cgi_tools.convert_fcgi_post(@cgi.params)
162
+ else
163
+ cgi_data[:post] = {}
164
+ end
165
+
166
+ @hayabusa.config[:cgi] = cgi_data
167
+
168
+
169
+ #Handle request.
170
+ @hayabusa.start_cgi_request
171
+ end
172
+ end
@@ -21,12 +21,12 @@ class Hayabusa::Http_server
21
21
 
22
22
  @thread_accept = Thread.new do
23
23
  loop do
24
- if !@server or @server.closed?
25
- STDOUT.puts "Starting TCPServer." if @debug
26
- @server = TCPServer.new(@hb.config[:host], @hb.config[:port])
27
- end
28
-
29
24
  begin
25
+ if !@server or @server.closed?
26
+ STDOUT.puts "Starting TCPServer." if @debug
27
+ @server = TCPServer.new(@hb.config[:host], @hb.config[:port])
28
+ end
29
+
30
30
  STDOUT.puts "Trying to spawn new HTTP-session from socket-accept." if @debug
31
31
  self.spawn_httpsession(@server.accept)
32
32
  STDOUT.puts "Starting new HTTP-request." if @debug
@@ -55,7 +55,7 @@ class Hayabusa::Http_session
55
55
 
56
56
  Dir.chdir(@config[:doc_root])
57
57
  ObjectSpace.define_finalizer(self, self.class.method(:finalize).to_proc) if @debug
58
- STDOUT.print "New httpsession #{self.__id__} (total: #{@httpserver.http_sessions.count}).\n" if @debug
58
+ @hb.log_puts "New httpsession #{self.__id__} (total: #{@httpserver.http_sessions.count})." if @debug
59
59
 
60
60
  @thread_request = Thread.new(&self.method(:thread_request_run))
61
61
  end
@@ -80,15 +80,15 @@ class Hayabusa::Http_session
80
80
  @working = false
81
81
  break if @hb.should_restart
82
82
 
83
- STDOUT.print "#{__id__} - Waiting to parse from socket.\n" if @debug
83
+ @hb.log_puts "#{__id__} - Waiting to parse from socket." if @debug
84
84
  Timeout.timeout(1800) do
85
85
  @handler.socket_parse(@socket)
86
86
  end
87
87
 
88
- STDOUT.print "#{__id__} - Done parsing from socket.\n" if @debug
88
+ @hb.log_puts "#{__id__} - Done parsing from socket." if @debug
89
89
 
90
90
  while @hb.paused? #Check if we should be waiting with executing the pending request.
91
- STDOUT.print "#{__id__} - Paused! (#{@hb.paused}) - sleeping.\n" if @debug
91
+ @hb.log_puts "#{__id__} - Paused! (#{@hb.paused}) - sleeping." if @debug
92
92
  sleep 0.1
93
93
  end
94
94
 
@@ -96,7 +96,7 @@ class Hayabusa::Http_session
96
96
 
97
97
  if max_requests_working and @httpserver
98
98
  while @httpserver.working_count.to_i >= max_requests_working
99
- STDOUT.print "#{__id__} - Maximum amounts of requests are working (#{@httpserver.working_count}, #{max_requests_working}) - sleeping.\n" if @debug
99
+ @hb.log_puts "#{__id__} - Maximum amounts of requests are working (#{@httpserver.working_count}, #{max_requests_working}) - sleeping." if @debug
100
100
  sleep 0.1
101
101
  end
102
102
  end
@@ -106,13 +106,13 @@ class Hayabusa::Http_session
106
106
  @hb.ob.db.get_and_register_thread if @hb.ob.db.opts[:threadsafe]
107
107
 
108
108
  @working = true
109
- STDOUT.print "#{__id__} - Serving.\n" if @debug
109
+ @hb.log_puts "#{__id__} - Serving." if @debug
110
110
 
111
111
  @httpserver.count_block do
112
112
  self.serve
113
113
  end
114
114
  ensure
115
- STDOUT.print "#{__id__} - Closing request.\n" if @debug
115
+ @hb.log_puts "#{__id__} - Closing request." if @debug
116
116
  @working = false
117
117
 
118
118
  #Free reserved database-connections.
@@ -121,13 +121,14 @@ class Hayabusa::Http_session
121
121
  end
122
122
  end
123
123
  rescue Timeout::Error
124
- STDOUT.print "#{__id__} - Closing httpsession because of timeout.\n" if @debug
124
+ @hb.log_puts "#{__id__} - Closing httpsession because of timeout." if @debug
125
125
  rescue Errno::ECONNRESET, Errno::ENOTCONN, Errno::EPIPE => e
126
- STDOUT.print "#{__id__} - Connection error (#{e.inspect})...\n" if @debug
126
+ @hb.log_puts "#{__id__} - Connection error (#{e.inspect})..." if @debug
127
+ @hb.log_puts e.backtrace
127
128
  rescue Interrupt => e
128
129
  raise e
129
130
  rescue Exception => e
130
- STDOUT.puts Knj::Errors.error_str(e)
131
+ @hb.log_puts Knj::Errors.error_str(e)
131
132
  ensure
132
133
  self.destruct
133
134
  end
@@ -181,11 +182,11 @@ class Hayabusa::Http_session
181
182
  end
182
183
 
183
184
  def self.finalize(id)
184
- STDOUT.print "Http_session finalize #{id}.\n" if @debug
185
+ @hb.log_puts "Http_session finalize #{id}." if @debug
185
186
  end
186
187
 
187
188
  def destruct
188
- STDOUT.print "Http_session destruct (#{@httpserver.http_sessions.length})\n" if @debug and @httpserver and @httpserver.http_sessions
189
+ @hb.log_puts "Http_session destruct (#{@httpserver.http_sessions.length})" if @debug and @httpserver and @httpserver.http_sessions
189
190
 
190
191
  begin
191
192
  @socket.close if !@socket.closed?
@@ -207,7 +208,7 @@ class Hayabusa::Http_session
207
208
  end
208
209
 
209
210
  def serve
210
- STDOUT.print "Generating meta, cookie, get, post and headers.\n" if @debug
211
+ @hb.log_puts "Generating meta, cookie, get, post and headers." if @debug
211
212
  @meta = @handler.meta.merge(@socket_meta)
212
213
  @cookie = @handler.cookie
213
214
  @get = @handler.get
@@ -244,7 +245,7 @@ class Hayabusa::Http_session
244
245
  raise "Could not figure out the IP of the session."
245
246
  end
246
247
 
247
- STDOUT.print "Figuring out session-ID, session-object and more.\n" if @debug
248
+ @hb.log_puts "Figuring out session-ID, session-object and more." if @debug
248
249
  if @cookie["HayabusaSession"].to_s.length > 0
249
250
  @session_id = @cookie["HayabusaSession"]
250
251
  elsif @browser["browser"] == "bot"
@@ -273,7 +274,7 @@ class Hayabusa::Http_session
273
274
  end
274
275
 
275
276
  if @config.key?(:logging) and @config[:logging][:access_db]
276
- STDOUT.print "Doing access-logging.\n" if @debug
277
+ @hb.log_puts "Doing access-logging." if @debug
277
278
  @ips = [@meta["REMOTE_ADDR"]]
278
279
  @ips << @meta["HTTP_X_FORWARDED_FOR"].split(",")[0].strip if @meta["HTTP_X_FORWARDED_FOR"]
279
280
  @hb.logs_access_pending << {
@@ -287,7 +288,7 @@ class Hayabusa::Http_session
287
288
  }
288
289
  end
289
290
 
290
- STDOUT.print "Initializing thread and content-group.\n" if @debug
291
+ @hb.log_puts "Initializing thread and content-group." if @debug
291
292
  self.init_thread
292
293
  Thread.current[:hayabusa][:contentgroup] = @cgroup
293
294
  time_start = Time.now.to_f if @debug
@@ -297,7 +298,7 @@ class Hayabusa::Http_session
297
298
 
298
299
  Timeout.timeout(@hb.config[:timeout]) do
299
300
  if @handlers_cache.key?(@ext)
300
- STDOUT.print "Calling handler.\n" if @debug
301
+ @hb.log_puts "Calling handler." if @debug
301
302
  @handlers_cache[@ext].call(self)
302
303
  else
303
304
  #check if we should use a handler for this request.
@@ -350,7 +351,7 @@ class Hayabusa::Http_session
350
351
 
351
352
  @cgroup.mark_done
352
353
  @cgroup.write_output
353
- STDOUT.print "#{__id__} - Served '#{@meta["REQUEST_URI"]}' in #{Time.now.to_f - time_start} secs (#{@resp.status}).\n" if @debug
354
+ @hb.log_puts "#{__id__} - Served '#{@meta["REQUEST_URI"]}' in #{Time.now.to_f - time_start} secs (#{@resp.status})." if @debug
354
355
  @cgroup.join
355
356
 
356
357
  @hb.events.call(:request_done, {