thin 1.5.1 → 1.6.0

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