thin 1.5.1 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -20,6 +20,7 @@ module Thin
20
20
  # Freeze some HTTP header names & values
21
21
  SERVER_SOFTWARE = 'SERVER_SOFTWARE'.freeze
22
22
  SERVER_NAME = 'SERVER_NAME'.freeze
23
+ REQUEST_METHOD = 'REQUEST_METHOD'.freeze
23
24
  LOCALHOST = 'localhost'.freeze
24
25
  HTTP_VERSION = 'HTTP_VERSION'.freeze
25
26
  HTTP_1_0 = 'HTTP/1.0'.freeze
@@ -28,6 +29,7 @@ module Thin
28
29
  CONNECTION = 'HTTP_CONNECTION'.freeze
29
30
  KEEP_ALIVE_REGEXP = /\bkeep-alive\b/i.freeze
30
31
  CLOSE_REGEXP = /\bclose\b/i.freeze
32
+ HEAD = 'HEAD'.freeze
31
33
 
32
34
  # Freeze some Rack header names
33
35
  RACK_INPUT = 'rack.input'.freeze
@@ -128,7 +130,7 @@ module Thin
128
130
  def threaded=(value)
129
131
  @env[RACK_MULTITHREAD] = value
130
132
  end
131
-
133
+
132
134
  def async_callback=(callback)
133
135
  @env[ASYNC_CALLBACK] = callback
134
136
  @env[ASYNC_CLOSE] = EventMachine::DefaultDeferrable.new
@@ -138,6 +140,10 @@ module Thin
138
140
  @async_close ||= @env[ASYNC_CLOSE]
139
141
  end
140
142
 
143
+ def head?
144
+ @env[REQUEST_METHOD] == HEAD
145
+ end
146
+
141
147
  # Close any resource used by the request
142
148
  def close
143
149
  @body.delete if @body.class == Tempfile
@@ -1,3 +1,4 @@
1
+ require 'logger'
1
2
  require 'optparse'
2
3
  require 'yaml'
3
4
 
@@ -37,12 +38,13 @@ module Thin
37
38
  :address => '0.0.0.0',
38
39
  :port => Server::DEFAULT_PORT,
39
40
  :timeout => Server::DEFAULT_TIMEOUT,
40
- :log => 'log/thin.log',
41
+ :log => File.join(Dir.pwd, 'log/thin.log'),
41
42
  :pid => 'tmp/pids/thin.pid',
42
43
  :max_conns => Server::DEFAULT_MAXIMUM_CONNECTIONS,
43
44
  :max_persistent_conns => Server::DEFAULT_MAXIMUM_PERSISTENT_CONNECTIONS,
44
45
  :require => [],
45
- :wait => Controllers::Cluster::DEFAULT_WAIT_TIME
46
+ :wait => Controllers::Cluster::DEFAULT_WAIT_TIME,
47
+ :threadpool_size => 20
46
48
  }
47
49
 
48
50
  parse!
@@ -124,6 +126,8 @@ module Thin
124
126
  "(default: #{@options[:max_persistent_conns]})") { |num| @options[:max_persistent_conns] = num.to_i }
125
127
  opts.on( "--threaded", "Call the Rack application in threads " +
126
128
  "[experimental]") { @options[:threaded] = true }
129
+ opts.on( "--threadpool-size NUM", "Sets the size of the EventMachine threadpool.",
130
+ "(default: #{@options[:threadpool_size]})") { |num| @options[:threadpool_size] = num.to_i }
127
131
  opts.on( "--no-epoll", "Disable the use of epoll") { @options[:no_epoll] = true } if Thin.linux?
128
132
 
129
133
  opts.separator ""
@@ -131,7 +135,7 @@ module Thin
131
135
 
132
136
  opts.on_tail("-r", "--require FILE", "require the library") { |file| @options[:require] << file }
133
137
  opts.on_tail("-q", "--quiet", "Silence all logging") { @options[:quiet] = true }
134
- opts.on_tail("-D", "--debug", "Set debugging on") { @options[:debug] = true }
138
+ opts.on_tail("-D", "--debug", "Enable debug logging") { @options[:debug] = true }
135
139
  opts.on_tail("-V", "--trace", "Set tracing on (log raw request/response)") { @options[:trace] = true }
136
140
  opts.on_tail("-h", "--help", "Show this message") { puts opts; exit }
137
141
  opts.on_tail('-v', '--version', "Show version") { puts Thin::SERVER; exit }
@@ -172,9 +176,22 @@ module Thin
172
176
  Dir.chdir(@options[:chdir]) unless CONFIGLESS_COMMANDS.include?(@command)
173
177
 
174
178
  @options[:require].each { |r| ruby_require r }
175
- Logging.debug = @options[:debug]
176
- Logging.trace = @options[:trace]
177
- Logging.silent = @options[:quiet]
179
+
180
+ # Setup the logger
181
+ if @options[:quiet]
182
+ Logging.silent = true
183
+ else
184
+ logger = Logger.new(STDOUT)
185
+ logger.level = Logger::INFO
186
+ logger.level = Logger::DEBUG if @options[:debug]
187
+ logger.formatter = Logging::SimpleFormatter.new
188
+ Logging.logger = logger
189
+ end
190
+
191
+ if @options[:trace]
192
+ # Trace raw requests/responses
193
+ Logging.trace_logger = Logging.logger
194
+ end
178
195
 
179
196
  controller = case
180
197
  when cluster? then Controllers::Cluster.new(@options)
@@ -41,9 +41,12 @@ module Thin
41
41
  # end
42
42
  #
43
43
  # == Controlling with signals
44
- # * QUIT: Gracefull shutdown (see Server#stop)
45
44
  # * INT and TERM: Force shutdown (see Server#stop!)
46
- # Disable signals by passing <tt>:signals => false</tt>
45
+ # * TERM & QUIT calls +stop+ to shutdown gracefully.
46
+ # * HUP calls +restart+ to ... surprise, restart!
47
+ # * USR1 reopen log files.
48
+ # Signals are processed at one second intervals.
49
+ # Disable signals by passing <tt>:signals => false</tt>.
47
50
  #
48
51
  class Server
49
52
  include Logging
@@ -80,7 +83,7 @@ module Thin
80
83
  def_delegators :backend, :maximum_persistent_connections, :maximum_persistent_connections=
81
84
 
82
85
  # Allow using threads in the backend.
83
- def_delegators :backend, :threaded?, :threaded=
86
+ def_delegators :backend, :threaded?, :threaded=, :threadpool_size, :threadpool_size=
84
87
 
85
88
  # Allow using SSL in the backend.
86
89
  def_delegators :backend, :ssl?, :ssl=, :ssl_options=
@@ -130,7 +133,7 @@ module Thin
130
133
  # If in debug mode, wrap in logger adapter
131
134
  @app = Rack::CommonLogger.new(@app) if Logging.debug?
132
135
 
133
- setup_signals unless options[:signals].class == FalseClass
136
+ @setup_signals = options[:signals] != false
134
137
  end
135
138
 
136
139
  # Lil' shortcut to turn this:
@@ -149,14 +152,14 @@ module Thin
149
152
  def start
150
153
  raise ArgumentError, 'app required' unless @app
151
154
 
152
- log ">> Thin web server (v#{VERSION::STRING} codename #{VERSION::CODENAME})"
153
- debug ">> Debugging ON"
154
- trace ">> Tracing ON"
155
+ log_info "Thin web server (v#{VERSION::STRING} codename #{VERSION::CODENAME})"
156
+ log_debug "Debugging ON"
157
+ trace "Tracing ON"
155
158
 
156
- log ">> Maximum connections set to #{@backend.maximum_connections}"
157
- log ">> Listening on #{@backend}, CTRL+C to stop"
159
+ log_info "Maximum connections set to #{@backend.maximum_connections}"
160
+ log_info "Listening on #{@backend}, CTRL+C to stop"
158
161
 
159
- @backend.start
162
+ @backend.start { setup_signals if @setup_signals }
160
163
  end
161
164
  alias :start! :start
162
165
 
@@ -169,8 +172,8 @@ module Thin
169
172
  if running?
170
173
  @backend.stop
171
174
  unless @backend.empty?
172
- log ">> Waiting for #{@backend.size} connection(s) to finish, " +
173
- "can take up to #{timeout} sec, CTRL+C to stop now"
175
+ log_info "Waiting for #{@backend.size} connection(s) to finish, "\
176
+ "can take up to #{timeout} sec, CTRL+C to stop now"
174
177
  end
175
178
  else
176
179
  stop!
@@ -182,7 +185,7 @@ module Thin
182
185
  # This doesn't wait for connection to finish their work and send data.
183
186
  # All current requests will be dropped.
184
187
  def stop!
185
- log ">> Stopping ..."
188
+ log_info "Stopping ..."
186
189
 
187
190
  @backend.stop!
188
191
  end
@@ -192,7 +195,7 @@ module Thin
192
195
  def reopen_log
193
196
  return unless log_file
194
197
  file = File.expand_path(log_file)
195
- log ">> Reopening log file: #{file}"
198
+ log_info "Reopening log file: #{file}"
196
199
  Daemonize.redirect_io(file)
197
200
  end
198
201
 
@@ -217,25 +220,36 @@ module Thin
217
220
  @backend.running?
218
221
  end
219
222
 
220
- # deamonizing kills our HUP signal, so we set them again
221
- def after_daemonize
222
- setup_signals
223
- end
224
-
225
223
  protected
226
- # Register signals:
227
- # * TERM & QUIT calls +stop+ to shutdown gracefully.
228
- # * INT calls <tt>stop!</tt> to force shutdown.
229
- # * HUP calls <tt>restart</tt> to ... surprise, restart!
230
- # * USR1 reopen log files.
231
224
  def setup_signals
232
- trap('INT') { stop! }
233
- trap('TERM') { stop }
234
- unless Thin.win?
235
- trap('QUIT') { stop }
236
- trap('HUP') { restart }
237
- trap('USR1') { reopen_log }
225
+ # Queue up signals so they are processed in non-trap context
226
+ # using a EM timer.
227
+ @signal_queue ||= []
228
+
229
+ %w( INT TERM ).each do |signal|
230
+ trap(signal) { @signal_queue.push signal }
231
+ end
232
+ # *nix only signals
233
+ %w( QUIT HUP USR1 ).each do |signal|
234
+ trap(signal) { @signal_queue.push signal }
235
+ end unless Thin.win?
236
+
237
+ # Signals are processed at one second intervals.
238
+ @signal_timer ||= EM.add_periodic_timer(1) { handle_signals }
239
+ end
240
+
241
+ def handle_signals
242
+ case @signal_queue.shift
243
+ when 'INT'
244
+ stop!
245
+ when 'TERM', 'QUIT'
246
+ stop
247
+ when 'HUP'
248
+ restart
249
+ when 'USR1'
250
+ reopen_log
238
251
  end
252
+ EM.next_tick { handle_signals } unless @signal_queue.empty?
239
253
  end
240
254
 
241
255
  def select_backend(host, port, options)
@@ -261,10 +275,10 @@ module Thin
261
275
  begin
262
276
  require 'cgi_multipart_eof_fix'
263
277
  rescue LoadError
264
- log "!! Ruby 1.8.5 is not secure please install cgi_multipart_eof_fix:"
265
- log " gem install cgi_multipart_eof_fix"
278
+ log_error "Ruby 1.8.5 is not secure please install cgi_multipart_eof_fix:"
279
+ log_error "gem install cgi_multipart_eof_fix"
266
280
  end
267
281
  end
268
282
  end
269
283
  end
270
- end
284
+ end
@@ -49,4 +49,4 @@ module Thin
49
49
  end
50
50
  end
51
51
  end
52
- end
52
+ end
@@ -5,12 +5,12 @@ module Thin
5
5
 
6
6
  module VERSION #:nodoc:
7
7
  MAJOR = 1
8
- MINOR = 5
9
- TINY = 1
8
+ MINOR = 6
9
+ TINY = 0
10
10
 
11
11
  STRING = [MAJOR, MINOR, TINY].join('.')
12
12
 
13
- CODENAME = "Straight Razor".freeze
13
+ CODENAME = "Greek Yogurt".freeze
14
14
 
15
15
  RACK = [1, 0].freeze # Rack protocol version
16
16
  end
metadata CHANGED
@@ -1,62 +1,55 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thin
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.1
5
- prerelease:
4
+ version: 1.6.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Marc-Andre Cournoyer
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-03-18 00:00:00.000000000 Z
11
+ date: 2013-10-02 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rack
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - '>='
20
18
  - !ruby/object:Gem::Version
21
- version: 1.0.0
19
+ version: 1.5.0
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - '>='
28
25
  - !ruby/object:Gem::Version
29
- version: 1.0.0
26
+ version: 1.5.0
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: eventmachine
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - '>='
36
32
  - !ruby/object:Gem::Version
37
- version: 0.12.6
33
+ version: 1.0.0
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - '>='
44
39
  - !ruby/object:Gem::Version
45
- version: 0.12.6
40
+ version: 1.0.0
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: daemons
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - '>='
52
46
  - !ruby/object:Gem::Version
53
47
  version: 1.0.9
54
48
  type: :runtime
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ! '>='
52
+ - - '>='
60
53
  - !ruby/object:Gem::Version
61
54
  version: 1.0.9
62
55
  description: A thin and fast web server
@@ -118,27 +111,25 @@ files:
118
111
  homepage: http://code.macournoyer.com/thin/
119
112
  licenses:
120
113
  - Ruby
114
+ metadata: {}
121
115
  post_install_message:
122
116
  rdoc_options: []
123
117
  require_paths:
124
118
  - lib
125
119
  required_ruby_version: !ruby/object:Gem::Requirement
126
- none: false
127
120
  requirements:
128
- - - ! '>='
121
+ - - '>='
129
122
  - !ruby/object:Gem::Version
130
123
  version: 1.8.5
131
124
  required_rubygems_version: !ruby/object:Gem::Requirement
132
- none: false
133
125
  requirements:
134
- - - ! '>='
126
+ - - '>='
135
127
  - !ruby/object:Gem::Version
136
128
  version: '0'
137
129
  requirements: []
138
130
  rubyforge_project: thin
139
- rubygems_version: 1.8.24
131
+ rubygems_version: 2.0.0
140
132
  signing_key:
141
- specification_version: 3
133
+ specification_version: 4
142
134
  summary: A thin and fast web server
143
135
  test_files: []
144
- has_rdoc: