thin 0.8.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of thin might be problematic. Click here for more details.

Files changed (44) hide show
  1. data/CHANGELOG +15 -0
  2. data/README +1 -1
  3. data/example/adapter.rb +2 -5
  4. data/example/config.ru +2 -5
  5. data/example/vlad.rake +6 -3
  6. data/lib/rack/adapter/loader.rb +27 -23
  7. data/lib/rack/adapter/rails.rb +9 -3
  8. data/lib/thin/backends/base.rb +13 -3
  9. data/lib/thin/command.rb +7 -5
  10. data/lib/thin/connection.rb +68 -28
  11. data/lib/thin/controllers/controller.rb +2 -1
  12. data/lib/thin/daemonizing.rb +25 -20
  13. data/lib/thin/headers.rb +8 -0
  14. data/lib/thin/logging.rb +28 -23
  15. data/lib/thin/request.rb +32 -32
  16. data/lib/thin/response.rb +22 -19
  17. data/lib/thin/runner.rb +14 -7
  18. data/lib/thin/server.rb +6 -2
  19. data/lib/thin/stats.rb +1 -4
  20. data/lib/thin/version.rb +4 -4
  21. data/lib/thin.rb +1 -0
  22. data/spec/backends/tcp_server_spec.rb +11 -0
  23. data/spec/command_spec.rb +7 -1
  24. data/spec/daemonizing_spec.rb +17 -0
  25. data/spec/headers_spec.rb +11 -0
  26. data/spec/logging_spec.rb +6 -2
  27. data/spec/rack/rails_adapter_spec.rb +10 -8
  28. data/spec/request/parser_spec.rb +1 -1
  29. data/spec/response_spec.rb +7 -0
  30. data/spec/runner_spec.rb +22 -3
  31. data/spec/server/pipelining_spec.rb +1 -1
  32. data/spec/server/robustness_spec.rb +1 -1
  33. data/spec/server/stopping_spec.rb +1 -1
  34. data/spec/server/swiftiply_spec.rb +1 -1
  35. data/spec/server/tcp_spec.rb +18 -7
  36. data/spec/server/threaded_spec.rb +1 -1
  37. data/spec/server/unix_socket_spec.rb +1 -1
  38. data/spec/spec_helper.rb +10 -0
  39. data/tasks/announce.rake +1 -1
  40. data/tasks/deploy.rake +2 -2
  41. data/tasks/email.erb +0 -4
  42. data/tasks/gem.rake +2 -2
  43. metadata +6 -4
  44. data/lib/thin_parser.bundle +0 -0
data/CHANGELOG CHANGED
@@ -1,3 +1,18 @@
1
+ == 1.0.0 That's What She Said release
2
+ * Fixed vlad.rake to allow TCP or socket [hellekin]
3
+ * Updated Mack adapter to handle both <0.8.0 and >0.8.0 [Mark Bates]
4
+ * rails rack adapter uses File.readable_real? so it recognizes ACL permissions [Ricardo Chimal]
5
+ * Log a warning if Rack application returns nil body [Michael S. Klishin]
6
+ * Handle nil and Time header values correctly [#76 state:resolved] [tmm1]
7
+ * Add Content-Length header to response automatically when possible [#74 state:resolved] [dkubb]
8
+ * Runner now remembers -r, -D and -V parameters so that clustered servers inherit those and
9
+ `restart` keep your parameters.
10
+ * Make Set-Cookie header, in Rails adapter, compatible with current Rack spec [Pedro Belo]
11
+ [#73, state:resolved]
12
+ * Add --no-epoll option to disable epoll usage on Linux [#61 state:resolved]
13
+ * Add --force (-f) option to force stopping of a daemonized server [#72 state:resolved]
14
+ * Update halycon adapter loader [mtodd]
15
+
1
16
  == 0.8.2 Double Margarita release
2
17
  * Require EventMachine 0.12.0
3
18
  * [bug] Fix timeout handling when running command
data/README CHANGED
@@ -57,7 +57,7 @@ You need to setup a config.ru file and pass it to the thin script:
57
57
 
58
58
  run app
59
59
 
60
- thin start -r config.ru
60
+ thin start -R config.ru
61
61
 
62
62
  See example directory for more samples and run 'thin -h' for usage.
63
63
 
data/example/adapter.rb CHANGED
@@ -8,10 +8,7 @@ class SimpleAdapter
8
8
  body = ["hello!"]
9
9
  [
10
10
  200,
11
- {
12
- 'Content-Type' => 'text/plain',
13
- 'Content-Length' => body.join.size.to_s,
14
- },
11
+ { 'Content-Type' => 'text/plain' },
15
12
  body
16
13
  ]
17
14
  end
@@ -31,5 +28,5 @@ end
31
28
  #
32
29
  # app = Rack::URLMap.new('/test' => SimpleAdapter.new,
33
30
  # '/files' => Rack::File.new('.'))
34
- # Thin::Server.new('0.0.0.0', 3000, app).start
31
+ # Thin::Server.start('0.0.0.0', 3000, app)
35
32
  #
data/example/config.ru CHANGED
@@ -1,6 +1,6 @@
1
1
  # Run with: rackup -s thin
2
2
  # then browse to http://localhost:9292
3
- # Or with: thin start -r config.ru
3
+ # Or with: thin start -R config.ru
4
4
  # then browse to http://localhost:3000
5
5
  #
6
6
  # Check Rack::Builder doc for more details on this file format:
@@ -15,10 +15,7 @@ app = proc do |env|
15
15
 
16
16
  [
17
17
  200, # Status code
18
- {
19
- 'Content-Type' => 'text/html', # Reponse headers
20
- 'Content-Length' => body.join.size.to_s
21
- },
18
+ { 'Content-Type' => 'text/html' }, # Reponse headers
22
19
  body # Body of the response
23
20
  ]
24
21
  end
data/example/vlad.rake CHANGED
@@ -15,7 +15,7 @@ namespace :vlad do
15
15
  set :thin_log_file, nil
16
16
  set :thin_pid_file, nil
17
17
  set :thin_port, nil
18
- set :thin_socket, "/tmp/thin.sock"
18
+ set :thin_socket, nil
19
19
  set :thin_prefix, nil
20
20
  set :thin_servers, 2
21
21
  set :thin_user, nil
@@ -24,10 +24,13 @@ namespace :vlad do
24
24
  configuration is set via the thin_* variables.".cleanup
25
25
 
26
26
  remote_task :setup_app, :roles => :app do
27
+
28
+ raise(ArgumentError, "Please provide either thin_socket or thin_port") if thin_port.nil? && thin_socket.nil?
29
+
27
30
  cmd = [
28
31
  "#{thin_command} config",
29
32
  "-s #{thin_servers}",
30
- "-S #{thin_socket}",
33
+ ("-S #{thin_socket}" if thin_socket),
31
34
  "-e #{thin_environment}",
32
35
  "-a #{thin_address}",
33
36
  "-c #{current_path}",
@@ -58,4 +61,4 @@ configuration is set via the thin_* variables.".cleanup
58
61
  remote_task :stop_app, :roles => :app do
59
62
  run thin("stop -s #{thin_servers}")
60
63
  end
61
- end
64
+ end
@@ -1,25 +1,29 @@
1
1
  module Rack
2
2
  class AdapterNotFound < RuntimeError; end
3
-
4
- # Hash used to guess which adapter to use in <tt>Adapter.for</tt>.
5
- # Framework name => file unique to this framework.
3
+
4
+ # Mapping used to guess which adapter to use in <tt>Adapter.for</tt>.
5
+ # Framework <name> => <file unique to this framework> in order they will
6
+ # be tested.
6
7
  # +nil+ for value to never guess.
7
- ADAPTERS = {
8
- :rails => "config/environment.rb",
9
- :ramaze => "start.rb",
10
- :merb => "config/init.rb",
11
- :halcyon => 'runner.ru',
12
- :mack => 'config/app_config/default.yml',
13
- :file => nil
14
- }
15
-
16
- module Adapter
8
+ # NOTE: If a framework has a file that is not unique, make sure to place
9
+ # it at the end.
10
+ ADAPTERS = [
11
+ [:rails, 'config/environment.rb'],
12
+ [:ramaze, 'start.rb'],
13
+ [:halcyon, 'runner.ru'],
14
+ [:merb, 'config/init.rb'],
15
+ [:mack, 'config/app_config/default.yml'],
16
+ [:mack, 'config/configatron/default.rb'],
17
+ [:file, nil]
18
+ ]
19
+
20
+ module Adapter
17
21
  # Guess which adapter to use based on the directory structure
18
22
  # or file content.
19
23
  # Returns a symbol representing the name of the adapter to use
20
24
  # to load the application under <tt>dir/</tt>.
21
25
  def self.guess(dir)
22
- ADAPTERS.each_pair do |adapter, file|
26
+ ADAPTERS.each do |adapter, file|
23
27
  return adapter if file && ::File.exist?(::File.join(dir, file))
24
28
  end
25
29
  raise AdapterNotFound, "No adapter found for #{dir}"
@@ -33,39 +37,39 @@ module Rack
33
37
 
34
38
  when :ramaze
35
39
  require "#{options[:chdir]}/start"
36
-
40
+
37
41
  Ramaze.trait[:essentials].delete Ramaze::Adapter
38
42
  Ramaze.start :force => true
39
-
43
+
40
44
  return Ramaze::Adapter::Base
41
-
45
+
42
46
  when :merb
43
47
  require 'merb-core'
44
-
48
+
45
49
  Merb::Config.setup(:merb_root => options[:chdir],
46
50
  :environment => options[:environment])
47
51
  Merb.environment = Merb::Config[:environment]
48
52
  Merb.root = Merb::Config[:merb_root]
49
53
  Merb::BootLoader.run
50
-
54
+
51
55
  return Merb::Rack::Application.new
52
-
56
+
53
57
  when :halcyon
54
58
  require 'halcyon'
55
59
 
56
60
  $:.unshift(Halcyon.root/'lib')
57
- Halcyon::Runner.load_config Halcyon.root/'config'/'config.yml'
58
61
 
59
62
  return Halcyon::Runner.new
60
-
63
+
61
64
  when :mack
62
65
  ENV["MACK_ENV"] = options[:environment]
63
66
  load(::File.join(options[:chdir], "Rakefile"))
64
67
  require 'mack'
65
68
  return Mack::Utils::Server.build_app
69
+
66
70
  when :file
67
71
  return Rack::File.new(options[:chdir])
68
-
72
+
69
73
  else
70
74
  raise AdapterNotFound, "Adapter not found: #{name}"
71
75
 
@@ -37,7 +37,7 @@ module Rack
37
37
  # TODO refactor this in File#can_serve?(path) ??
38
38
  def file_exist?(path)
39
39
  full_path = ::File.join(@file_server.root, Utils.unescape(path))
40
- ::File.file?(full_path) && ::File.readable?(full_path)
40
+ ::File.file?(full_path) && ::File.readable_real?(full_path)
41
41
  end
42
42
 
43
43
  def serve_file(env)
@@ -112,10 +112,16 @@ module Rack
112
112
  when Hash then cookie.each { |_, c| cookies << c.to_s }
113
113
  else cookies << cookie.to_s
114
114
  end
115
-
115
+
116
116
  @output_cookies.each { |c| cookies << c.to_s } if @output_cookies
117
117
 
118
- @response['Set-Cookie'] = [@response['Set-Cookie'], cookies].compact.join("\n")
118
+ @response['Set-Cookie'] = [@response['Set-Cookie'], cookies].compact
119
+ # See http://groups.google.com/group/rack-devel/browse_thread/thread/e8759b91a82c5a10/a8dbd4574fe97d69?#a8dbd4574fe97d69
120
+ if Thin.ruby_18?
121
+ @response['Set-Cookie'].flatten!
122
+ else
123
+ @response['Set-Cookie'] = @response['Set-Cookie'].join("\n")
124
+ end
119
125
  end
120
126
 
121
127
  options.each { |k,v| @response[k] = v }
@@ -30,22 +30,32 @@ module Thin
30
30
  # Number of persistent connections currently opened
31
31
  attr_accessor :persistent_connection_count
32
32
 
33
+ # Disable the use of epoll under Linux
34
+ attr_accessor :no_epoll
35
+
33
36
  def initialize
34
37
  @connections = []
35
38
  @timeout = Server::DEFAULT_TIMEOUT
36
39
  @persistent_connection_count = 0
37
40
  @maximum_connections = Server::DEFAULT_MAXIMUM_CONNECTIONS
38
41
  @maximum_persistent_connections = Server::DEFAULT_MAXIMUM_PERSISTENT_CONNECTIONS
42
+ @no_epoll = false
39
43
  end
40
44
 
41
45
  # Start the backend and connect it.
42
46
  def start
43
47
  @stopping = false
44
-
45
- EventMachine.run do
48
+ starter = proc do
46
49
  connect
47
50
  @running = true
48
51
  end
52
+
53
+ # Allow for early run up of eventmachine.
54
+ if EventMachine.reactor_running?
55
+ starter.call
56
+ else
57
+ EventMachine.run(&starter)
58
+ end
49
59
  end
50
60
 
51
61
  # Stop of the backend from accepting new connections.
@@ -72,7 +82,7 @@ module Thin
72
82
  # so you can do crazy stuff that require godlike powers here.
73
83
  def config
74
84
  # See http://rubyeventmachine.com/pub/rdoc/files/EPOLL.html
75
- EventMachine.epoll
85
+ EventMachine.epoll unless @no_epoll
76
86
 
77
87
  # Set the maximum number of socket descriptors that the server may open.
78
88
  # The process needs to have required privilege to set it higher the 1024 on
data/lib/thin/command.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'open3'
2
2
 
3
3
  module Thin
4
- # Run a command though the +thin+ command-line script.
4
+ # Run a command through the +thin+ command-line script.
5
5
  class Command
6
6
  include Logging
7
7
 
@@ -34,12 +34,14 @@ module Thin
34
34
  # Turn into a runnable shell command
35
35
  def shellify
36
36
  shellified_options = @options.inject([]) do |args, (name, value)|
37
- args << case value
37
+ case value
38
38
  when NilClass,
39
- TrueClass then "--#{name}"
39
+ TrueClass then args << "--#{name}"
40
40
  when FalseClass
41
- else "--#{name.to_s.tr('_', '-')}=#{value.inspect}"
41
+ when Array then value.each { |v| args << "--#{name}=#{v.inspect}" }
42
+ else args << "--#{name.to_s.tr('_', '-')}=#{value.inspect}"
42
43
  end
44
+ args
43
45
  end
44
46
 
45
47
  raise ArgumentError, "Path to thin script can't be found, set Command.script" unless self.class.script
@@ -47,4 +49,4 @@ module Thin
47
49
  "#{self.class.script} #{@name} #{shellified_options.compact.join(' ')}"
48
50
  end
49
51
  end
50
- end
52
+ end
@@ -5,30 +5,34 @@ module Thin
5
5
  # This class is instanciated by EventMachine on each new connection
6
6
  # that is opened.
7
7
  class Connection < EventMachine::Connection
8
+ CONTENT_LENGTH = 'Content-Length'.freeze
9
+ TRANSFER_ENCODING = 'Transfer-Encoding'.freeze
10
+ CHUNKED_REGEXP = /\bchunked\b/i.freeze
11
+
8
12
  include Logging
9
-
13
+
10
14
  # Rack application (adapter) served by this connection.
11
15
  attr_accessor :app
12
-
16
+
13
17
  # Backend to the server
14
18
  attr_accessor :backend
15
-
19
+
16
20
  # Current request served by the connection
17
21
  attr_accessor :request
18
-
22
+
19
23
  # Next response sent through the connection
20
24
  attr_accessor :response
21
-
25
+
22
26
  # Calling the application in a threaded allowing
23
27
  # concurrent processing of requests.
24
28
  attr_writer :threaded
25
-
29
+
26
30
  # Get the connection ready to process a request.
27
31
  def post_init
28
32
  @request = Request.new
29
33
  @response = Response.new
30
34
  end
31
-
35
+
32
36
  # Called when data is received from the client.
33
37
  def receive_data(data)
34
38
  trace { data }
@@ -38,7 +42,7 @@ module Thin
38
42
  log_error e
39
43
  close_connection
40
44
  end
41
-
45
+
42
46
  # Called when all data was received and the request
43
47
  # is ready to be processed.
44
48
  def process
@@ -50,63 +54,72 @@ module Thin
50
54
  post_process(pre_process)
51
55
  end
52
56
  end
53
-
57
+
54
58
  def pre_process
55
59
  # Add client info to the request env
56
60
  @request.remote_address = remote_address
57
-
61
+
58
62
  # Process the request calling the Rack adapter
59
63
  @app.call(@request.env)
60
- rescue Object
64
+ rescue Exception
61
65
  handle_error
62
66
  terminate_request
63
67
  nil # Signal to post_process that the request could not be processed
64
68
  end
65
-
69
+
66
70
  def post_process(result)
67
71
  return unless result
68
-
72
+
73
+ # Set the Content-Length header if possible
74
+ set_content_length(result) if need_content_length?(result)
75
+
69
76
  @response.status, @response.headers, @response.body = result
70
-
77
+
78
+ log "!! Rack application returned nil body. Probably you wanted it to be an empty string?" if @response.body.nil?
71
79
  # Make the response persistent if requested by the client
72
80
  @response.persistent! if @request.persistent?
73
-
81
+
74
82
  # Send the response
75
83
  @response.each do |chunk|
76
84
  trace { chunk }
77
85
  send_data chunk
78
86
  end
79
-
87
+
80
88
  # If no more request on that same connection, we close it.
81
89
  close_connection_after_writing unless persistent?
82
-
83
- rescue Object
90
+
91
+ rescue Exception
84
92
  handle_error
85
93
  ensure
86
94
  terminate_request
87
95
  end
88
-
96
+
97
+ # Logs catched exception and closes the connection.
89
98
  def handle_error
90
99
  log "!! Unexpected error while processing request: #{$!.message}"
91
100
  log_error
92
101
  close_connection rescue nil
93
102
  end
94
-
103
+
104
+ # Does request and response cleanup (closes open IO streams and
105
+ # deletes created temporary files).
106
+ # Re-initializes response and request if client supports persistent
107
+ # connection.
95
108
  def terminate_request
96
109
  @request.close rescue nil
97
110
  @response.close rescue nil
98
-
111
+
99
112
  # Prepare the connection for another request if the client
100
113
  # supports HTTP pipelining (persistent connection).
101
114
  post_init if persistent?
102
115
  end
103
-
116
+
104
117
  # Called when the connection is unbinded from the socket
105
118
  # and can no longer be used to process requests.
106
119
  def unbind
107
120
  @backend.connection_finished(self)
108
121
  end
109
-
122
+
110
123
  # Allows this connection to be persistent.
111
124
  def can_persist!
112
125
  @can_persist = true
@@ -122,25 +135,52 @@ module Thin
122
135
  def persistent?
123
136
  @can_persist && @response.persistent?
124
137
  end
125
-
138
+
126
139
  # +true+ if <tt>app.call</tt> will be called inside a thread.
127
140
  # You can set all requests as threaded setting <tt>Connection#threaded=true</tt>
128
141
  # or on a per-request case returning +true+ in <tt>app.deferred?</tt>.
129
142
  def threaded?
130
143
  @threaded || (@app.respond_to?(:deferred?) && @app.deferred?(@request.env))
131
144
  end
132
-
145
+
133
146
  # IP Address of the remote client.
134
147
  def remote_address
135
148
  @request.forwarded_for || socket_address
136
- rescue Object
149
+ rescue Exception
137
150
  log_error
138
151
  nil
139
152
  end
140
-
153
+
141
154
  protected
155
+
156
+ # Returns IP address of peer as a string.
142
157
  def socket_address
143
158
  Socket.unpack_sockaddr_in(get_peername)[1]
144
159
  end
160
+
161
+ private
162
+ def need_content_length?(result)
163
+ status, headers, body = result
164
+ return false if headers.has_key?(CONTENT_LENGTH)
165
+ return false if (100..199).include?(status) || status == 204 || status == 304
166
+ return false if headers.has_key?(TRANSFER_ENCODING) && headers[TRANSFER_ENCODING] =~ CHUNKED_REGEXP
167
+ return false unless body.kind_of?(String) || body.kind_of?(Array)
168
+ true
169
+ end
170
+
171
+ def set_content_length(result)
172
+ headers, body = result[1..2]
173
+ case body
174
+ when String
175
+ # See http://redmine.ruby-lang.org/issues/show/203
176
+ headers[CONTENT_LENGTH] = (body.respond_to?(:bytesize) ? body.bytesize : body.size).to_s
177
+ when Array
178
+ bytes = 0
179
+ body.each do |p|
180
+ bytes += p.respond_to?(:bytesize) ? p.bytesize : p.size
181
+ end
182
+ headers[CONTENT_LENGTH] = bytes.to_s
183
+ end
184
+ end
145
185
  end
146
- end
186
+ end
@@ -49,6 +49,7 @@ module Thin
49
49
  server.maximum_connections = @options[:max_conns]
50
50
  server.maximum_persistent_connections = @options[:max_persistent_conns]
51
51
  server.threaded = @options[:threaded]
52
+ server.no_epoll = @options[:no_epoll] if server.backend.respond_to?(:no_epoll=)
52
53
 
53
54
  # Detach the process, after this line the current process returns
54
55
  server.daemonize if @options[:daemonize]
@@ -83,7 +84,7 @@ module Thin
83
84
  raise OptionRequired, :pid unless @options[:pid]
84
85
 
85
86
  tail_log(@options[:log]) do
86
- if Server.kill(@options[:pid], @options[:timeout] || 60)
87
+ if Server.kill(@options[:pid], @options[:force] ? 0 : (@options[:timeout] || 60))
87
88
  wait_for_file :deletion, @options[:pid]
88
89
  end
89
90
  end
@@ -89,22 +89,16 @@ module Thin
89
89
  end
90
90
 
91
91
  module ClassMethods
92
- # Send a QUIT signal the process which PID is stored in +pid_file+.
92
+ # Send a QUIT or INT (if timeout is +0+) signal the process which
93
+ # PID is stored in +pid_file+.
93
94
  # If the process is still running after +timeout+, KILL signal is
94
95
  # sent.
95
96
  def kill(pid_file, timeout=60)
96
- if pid = send_signal('QUIT', pid_file)
97
- Timeout.timeout(timeout) do
98
- sleep 0.1 while Process.running?(pid)
99
- end
97
+ if timeout == 0
98
+ send_signal('INT', pid_file, timeout)
99
+ else
100
+ send_signal('QUIT', pid_file, timeout)
100
101
  end
101
- rescue Timeout::Error
102
- print "Timeout! "
103
- send_signal('KILL', pid_file)
104
- rescue Interrupt
105
- send_signal('KILL', pid_file)
106
- ensure
107
- File.delete(pid_file) if File.exist?(pid_file)
108
102
  end
109
103
 
110
104
  # Restart the server by sending HUP signal.
@@ -113,20 +107,31 @@ module Thin
113
107
  end
114
108
 
115
109
  # Send a +signal+ to the process which PID is stored in +pid_file+.
116
- def send_signal(signal, pid_file)
117
- if File.exist?(pid_file) && pid = open(pid_file).read
110
+ def send_signal(signal, pid_file, timeout=60)
111
+ if File.file?(pid_file) && pid = File.read(pid_file)
118
112
  pid = pid.to_i
119
- print "Sending #{signal} signal to process #{pid} ... "
113
+ Logging.log "Sending #{signal} signal to process #{pid} ... "
120
114
  Process.kill(signal, pid)
121
- puts
122
- pid
115
+ Timeout.timeout(timeout) do
116
+ sleep 0.1 while Process.running?(pid)
117
+ end
118
+ Logging.log ""
123
119
  else
124
120
  puts "Can't stop process, no PID found in #{pid_file}"
125
- nil
126
121
  end
122
+ rescue Timeout::Error
123
+ Logging.log "Timeout!"
124
+ force_kill pid_file
125
+ rescue Interrupt
126
+ force_kill pid_file
127
127
  rescue Errno::ESRCH # No such process
128
- puts "process not found!"
129
- nil
128
+ Logging.log "process not found!"
129
+ force_kill pid_file
130
+ end
131
+
132
+ def force_kill(pid_file)
133
+ Process.kill("KILL", File.read(pid_file)) rescue nil
134
+ File.delete(pid_file) if File.exist?(pid_file) rescue nil
130
135
  end
131
136
  end
132
137
 
data/lib/thin/headers.rb CHANGED
@@ -16,6 +16,14 @@ module Thin
16
16
  def []=(key, value)
17
17
  if !@sent.has_key?(key) || ALLOWED_DUPLICATES.include?(key)
18
18
  @sent[key] = true
19
+ value = case value
20
+ when Time
21
+ value.httpdate
22
+ when NilClass
23
+ return
24
+ else
25
+ value.to_s
26
+ end
19
27
  @out << HEADER_FORMAT % [key, value]
20
28
  end
21
29
  end
data/lib/thin/logging.rb CHANGED
@@ -15,35 +15,40 @@ module Thin
15
15
  def silent?; @silent end
16
16
  end
17
17
 
18
- # Deprecated silencer methods, those are now module methods
18
+ # Global silencer methods
19
19
  def silent
20
- warn "`#{self.class.name}\#silent` deprecated, use `Thin::Logging.silent?` instead"
21
20
  Logging.silent?
22
21
  end
23
22
  def silent=(value)
24
- warn "`#{self.class.name}\#silent=` deprecated, use `Thin::Logging.silent = #{value}` instead"
25
23
  Logging.silent = value
26
24
  end
27
25
 
28
- protected
29
- # Log a message to the console
30
- def log(msg)
31
- puts msg unless Logging.silent?
32
- end
33
-
34
- # Log a message to the console if tracing is activated
35
- def trace(msg=nil)
36
- log msg || yield if Logging.trace?
37
- end
38
-
39
- # Log a message to the console if debugging is activated
40
- def debug(msg=nil)
41
- log msg || yield if Logging.debug?
42
- end
43
-
44
- # Log an error backtrace if debugging is activated
45
- def log_error(e=$!)
46
- debug "#{e}\n\t" + e.backtrace.join("\n\t")
47
- end
26
+ # Log a message to the console
27
+ def log(msg)
28
+ puts msg unless Logging.silent?
29
+ end
30
+ module_function :log
31
+ public :log
32
+
33
+ # Log a message to the console if tracing is activated
34
+ def trace(msg=nil)
35
+ log msg || yield if Logging.trace?
36
+ end
37
+ module_function :trace
38
+ public :trace
39
+
40
+ # Log a message to the console if debugging is activated
41
+ def debug(msg=nil)
42
+ log msg || yield if Logging.debug?
43
+ end
44
+ module_function :debug
45
+ public :debug
46
+
47
+ # Log an error backtrace if debugging is activated
48
+ def log_error(e=$!)
49
+ debug "#{e}\n\t" + e.backtrace.join("\n\t")
50
+ end
51
+ module_function :log_error
52
+ public :log_error
48
53
  end
49
54
  end