friendlyfashion-thin 1.4.1 → 1.4.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/thin/backends/base.rb +30 -25
- data/lib/thin/controllers/cluster.rb +25 -25
- data/lib/thin/daemonizing.rb +23 -23
- data/lib/thin/server.rb +50 -41
- data/lib/thin/version.rb +2 -1
- metadata +3 -3
data/lib/thin/backends/base.rb
CHANGED
@@ -13,30 +13,30 @@ module Thin
|
|
13
13
|
class Base
|
14
14
|
# Server serving the connections throught the backend
|
15
15
|
attr_accessor :server
|
16
|
-
|
16
|
+
|
17
17
|
# Maximum time for incoming data to arrive
|
18
18
|
attr_accessor :timeout
|
19
|
-
|
19
|
+
|
20
20
|
# Maximum number of file or socket descriptors that the server may open.
|
21
21
|
attr_accessor :maximum_connections
|
22
|
-
|
22
|
+
|
23
23
|
# Maximum number of connections that can be persistent
|
24
24
|
attr_accessor :maximum_persistent_connections
|
25
|
-
|
25
|
+
|
26
26
|
# Allow using threads in the backend.
|
27
27
|
attr_writer :threaded
|
28
28
|
def threaded?; @threaded end
|
29
|
-
|
29
|
+
|
30
30
|
# Allow using SSL in the backend.
|
31
31
|
attr_writer :ssl, :ssl_options
|
32
32
|
def ssl?; @ssl end
|
33
|
-
|
33
|
+
|
34
34
|
# Number of persistent connections currently opened
|
35
35
|
attr_accessor :persistent_connection_count
|
36
|
-
|
36
|
+
|
37
37
|
# Disable the use of epoll under Linux
|
38
38
|
attr_accessor :no_epoll
|
39
|
-
|
39
|
+
|
40
40
|
def initialize
|
41
41
|
@connections = []
|
42
42
|
@timeout = Server::DEFAULT_TIMEOUT
|
@@ -47,7 +47,7 @@ module Thin
|
|
47
47
|
@ssl = nil
|
48
48
|
@threaded = nil
|
49
49
|
end
|
50
|
-
|
50
|
+
|
51
51
|
# Start the backend and connect it.
|
52
52
|
def start
|
53
53
|
@stopping = false
|
@@ -55,7 +55,7 @@ module Thin
|
|
55
55
|
connect
|
56
56
|
@running = true
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
# Allow for early run up of eventmachine.
|
60
60
|
if EventMachine.reactor_running?
|
61
61
|
starter.call
|
@@ -63,67 +63,72 @@ module Thin
|
|
63
63
|
EventMachine.run(&starter)
|
64
64
|
end
|
65
65
|
end
|
66
|
-
|
66
|
+
|
67
67
|
# Stop of the backend from accepting new connections.
|
68
68
|
def stop
|
69
69
|
@running = false
|
70
70
|
@stopping = true
|
71
|
-
|
71
|
+
|
72
72
|
# Do not accept anymore connection
|
73
73
|
disconnect
|
74
74
|
stop! if @connections.empty?
|
75
75
|
end
|
76
|
-
|
76
|
+
|
77
77
|
# Force stop of the backend NOW, too bad for the current connections.
|
78
78
|
def stop!
|
79
79
|
@running = false
|
80
80
|
@stopping = false
|
81
|
-
|
81
|
+
|
82
82
|
EventMachine.stop if EventMachine.reactor_running?
|
83
83
|
@connections.each { |connection| connection.close_connection }
|
84
84
|
close
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
87
|
# Configure the backend. This method will be called before droping superuser privileges,
|
88
88
|
# so you can do crazy stuff that require godlike powers here.
|
89
89
|
def config
|
90
90
|
# See http://rubyeventmachine.com/pub/rdoc/files/EPOLL.html
|
91
91
|
EventMachine.epoll unless @no_epoll
|
92
|
-
|
92
|
+
|
93
93
|
# Set the maximum number of socket descriptors that the server may open.
|
94
94
|
# The process needs to have required privilege to set it higher the 1024 on
|
95
95
|
# some systems.
|
96
96
|
@maximum_connections = EventMachine.set_descriptor_table_size(@maximum_connections) unless Thin.win?
|
97
97
|
end
|
98
|
-
|
98
|
+
|
99
99
|
# Free up resources used by the backend.
|
100
100
|
def close
|
101
101
|
end
|
102
|
-
|
102
|
+
|
103
103
|
# Returns +true+ if the backend is connected and running.
|
104
104
|
def running?
|
105
105
|
@running
|
106
106
|
end
|
107
|
-
|
107
|
+
|
108
108
|
# Called by a connection when it's unbinded.
|
109
109
|
def connection_finished(connection)
|
110
110
|
@persistent_connection_count -= 1 if connection.can_persist?
|
111
111
|
@connections.delete(connection)
|
112
|
-
|
112
|
+
|
113
113
|
# Finalize gracefull stop if there's no more active connection.
|
114
114
|
stop! if @stopping && @connections.empty?
|
115
115
|
end
|
116
|
-
|
116
|
+
|
117
117
|
# Returns +true+ if no active connection.
|
118
118
|
def empty?
|
119
119
|
@connections.empty?
|
120
120
|
end
|
121
|
-
|
121
|
+
|
122
122
|
# Number of active connections.
|
123
123
|
def size
|
124
124
|
@connections.size
|
125
125
|
end
|
126
|
-
|
126
|
+
|
127
|
+
# connection list.
|
128
|
+
def connections_list
|
129
|
+
@connections
|
130
|
+
end
|
131
|
+
|
127
132
|
protected
|
128
133
|
# Initialize a new connection to a client.
|
129
134
|
def initialize_connection(connection)
|
@@ -131,7 +136,7 @@ module Thin
|
|
131
136
|
connection.app = @server.app
|
132
137
|
connection.comm_inactivity_timeout = @timeout
|
133
138
|
connection.threaded = @threaded
|
134
|
-
|
139
|
+
|
135
140
|
if @ssl
|
136
141
|
connection.start_tls(@ssl_options)
|
137
142
|
end
|
@@ -145,7 +150,7 @@ module Thin
|
|
145
150
|
|
146
151
|
@connections << connection
|
147
152
|
end
|
148
|
-
|
153
|
+
|
149
154
|
end
|
150
155
|
end
|
151
156
|
end
|
@@ -3,7 +3,7 @@ require 'socket'
|
|
3
3
|
module Thin
|
4
4
|
# An exception class to handle the event that server didn't start on time
|
5
5
|
class RestartTimeout < RuntimeError; end
|
6
|
-
|
6
|
+
|
7
7
|
module Controllers
|
8
8
|
# Control a set of servers.
|
9
9
|
# * Generate start and stop commands and run them.
|
@@ -13,17 +13,17 @@ module Thin
|
|
13
13
|
# Cluster only options that should not be passed in the command sent
|
14
14
|
# to the indiviual servers.
|
15
15
|
CLUSTER_OPTIONS = [:servers, :only, :onebyone, :wait]
|
16
|
-
|
16
|
+
|
17
17
|
# Maximum wait time for the server to be restarted
|
18
18
|
DEFAULT_WAIT_TIME = 30 # seconds
|
19
|
-
|
19
|
+
|
20
20
|
# Create a new cluster of servers launched using +options+.
|
21
21
|
def initialize(options)
|
22
22
|
super
|
23
23
|
# Cluster can only contain daemonized servers
|
24
24
|
@options.merge!(:daemonize => true)
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
def first_port; @options[:port] end
|
28
28
|
def address; @options[:address] end
|
29
29
|
def socket; @options[:socket] end
|
@@ -33,35 +33,35 @@ module Thin
|
|
33
33
|
def only; @options[:only] end
|
34
34
|
def onebyone; @options[:onebyone] end
|
35
35
|
def wait; @options[:wait] end
|
36
|
-
|
36
|
+
|
37
37
|
def swiftiply?
|
38
38
|
@options.has_key?(:swiftiply)
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
# Start the servers
|
42
42
|
def start
|
43
43
|
with_each_server { |n| start_server n }
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
# Start a single server
|
47
47
|
def start_server(number)
|
48
48
|
log "Starting server on #{server_id(number)} ... "
|
49
|
-
|
49
|
+
|
50
50
|
run :start, number
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
# Stop the servers
|
54
54
|
def stop
|
55
55
|
with_each_server { |n| stop_server n }
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
# Stop a single server
|
59
59
|
def stop_server(number)
|
60
60
|
log "Stopping server on #{server_id(number)} ... "
|
61
|
-
|
61
|
+
|
62
62
|
run :stop, number
|
63
63
|
end
|
64
|
-
|
64
|
+
|
65
65
|
# Stop and start the servers.
|
66
66
|
def restart
|
67
67
|
unless onebyone
|
@@ -70,7 +70,7 @@ module Thin
|
|
70
70
|
sleep 0.1 # Let's breath a bit shall we ?
|
71
71
|
start
|
72
72
|
else
|
73
|
-
with_each_server do |n|
|
73
|
+
with_each_server do |n|
|
74
74
|
stop_server(n)
|
75
75
|
sleep 0.1 # Let's breath a bit shall we ?
|
76
76
|
start_server(n)
|
@@ -78,7 +78,7 @@ module Thin
|
|
78
78
|
end
|
79
79
|
end
|
80
80
|
end
|
81
|
-
|
81
|
+
|
82
82
|
def test_socket(number)
|
83
83
|
if socket
|
84
84
|
UNIXSocket.new(socket_for(number))
|
@@ -88,12 +88,12 @@ module Thin
|
|
88
88
|
rescue
|
89
89
|
nil
|
90
90
|
end
|
91
|
-
|
91
|
+
|
92
92
|
# Make sure the server is running before moving on to the next one.
|
93
93
|
def wait_until_server_started(number)
|
94
94
|
log "Waiting for server to start ..."
|
95
95
|
STDOUT.flush # Need this to make sure user got the message
|
96
|
-
|
96
|
+
|
97
97
|
tries = 0
|
98
98
|
loop do
|
99
99
|
if test_socket = test_socket(number)
|
@@ -109,7 +109,7 @@ module Thin
|
|
109
109
|
end
|
110
110
|
end
|
111
111
|
end
|
112
|
-
|
112
|
+
|
113
113
|
def server_id(number)
|
114
114
|
if socket
|
115
115
|
socket_for(number)
|
@@ -119,23 +119,23 @@ module Thin
|
|
119
119
|
[address, number].join(':')
|
120
120
|
end
|
121
121
|
end
|
122
|
-
|
122
|
+
|
123
123
|
def log_file_for(number)
|
124
124
|
include_server_number log_file, number
|
125
125
|
end
|
126
|
-
|
126
|
+
|
127
127
|
def pid_file_for(number)
|
128
128
|
include_server_number pid_file, number
|
129
129
|
end
|
130
|
-
|
130
|
+
|
131
131
|
def socket_for(number)
|
132
132
|
include_server_number socket, number
|
133
133
|
end
|
134
|
-
|
134
|
+
|
135
135
|
def pid_for(number)
|
136
136
|
File.read(pid_file_for(number)).chomp.to_i
|
137
137
|
end
|
138
|
-
|
138
|
+
|
139
139
|
private
|
140
140
|
# Send the command to the +thin+ script
|
141
141
|
def run(cmd, number)
|
@@ -150,10 +150,10 @@ module Thin
|
|
150
150
|
end
|
151
151
|
Command.run(cmd, cmd_options)
|
152
152
|
end
|
153
|
-
|
153
|
+
|
154
154
|
def with_each_server
|
155
155
|
if only
|
156
|
-
if first_port && only <
|
156
|
+
if first_port && only < 1024
|
157
157
|
# interpret +only+ as a sequence number
|
158
158
|
yield first_port + only
|
159
159
|
else
|
@@ -166,7 +166,7 @@ module Thin
|
|
166
166
|
size.times { |n| yield first_port + n }
|
167
167
|
end
|
168
168
|
end
|
169
|
-
|
169
|
+
|
170
170
|
# Add the server port or number in the filename
|
171
171
|
# so each instance get its own file
|
172
172
|
def include_server_number(path, number)
|
data/lib/thin/daemonizing.rb
CHANGED
@@ -16,7 +16,7 @@ end
|
|
16
16
|
module Thin
|
17
17
|
# Raised when the pid file already exist starting as a daemon.
|
18
18
|
class PidFileExist < RuntimeError; end
|
19
|
-
|
19
|
+
|
20
20
|
# Module included in classes that can be turned into a daemon.
|
21
21
|
# Handle stuff like:
|
22
22
|
# * storing the PID in a file
|
@@ -25,37 +25,37 @@ module Thin
|
|
25
25
|
# * killing the process gracefully
|
26
26
|
module Daemonizable
|
27
27
|
attr_accessor :pid_file, :log_file
|
28
|
-
|
28
|
+
|
29
29
|
def self.included(base)
|
30
30
|
base.extend ClassMethods
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
def pid
|
34
|
-
File.exist?(pid_file) ? open(pid_file).read.to_i : nil
|
34
|
+
File.exist?(pid_file) && !File.zero?(pid_file) ? open(pid_file).read.to_i : nil
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
# Turns the current script into a daemon process that detaches from the console.
|
38
38
|
def daemonize
|
39
39
|
raise PlatformNotSupported, 'Daemonizing is not supported on Windows' if Thin.win?
|
40
40
|
raise ArgumentError, 'You must specify a pid_file to daemonize' unless @pid_file
|
41
|
-
|
41
|
+
|
42
42
|
remove_stale_pid_file
|
43
|
-
|
43
|
+
|
44
44
|
pwd = Dir.pwd # Current directory is changed during daemonization, so store it
|
45
|
-
|
45
|
+
|
46
46
|
# HACK we need to create the directory before daemonization to prevent a bug under 1.9
|
47
47
|
# ignoring all signals when the directory is created after daemonization.
|
48
48
|
FileUtils.mkdir_p File.dirname(@pid_file)
|
49
49
|
FileUtils.mkdir_p File.dirname(@log_file)
|
50
|
-
|
50
|
+
|
51
51
|
Daemonize.daemonize(File.expand_path(@log_file), name)
|
52
|
-
|
52
|
+
|
53
53
|
Dir.chdir(pwd)
|
54
|
-
|
54
|
+
|
55
55
|
write_pid_file
|
56
56
|
|
57
57
|
self.after_daemonize if self.respond_to? :after_daemonize
|
58
|
-
|
58
|
+
|
59
59
|
at_exit do
|
60
60
|
log ">> Exiting!"
|
61
61
|
remove_pid_file
|
@@ -66,7 +66,7 @@ module Thin
|
|
66
66
|
# to the specified user and group.
|
67
67
|
def change_privilege(user, group=user)
|
68
68
|
log ">> Changing process privilege to #{user}:#{group}"
|
69
|
-
|
69
|
+
|
70
70
|
uid, gid = Process.euid, Process.egid
|
71
71
|
target_uid = Etc.getpwnam(user).uid
|
72
72
|
target_gid = Etc.getgrnam(group).gid
|
@@ -83,12 +83,12 @@ module Thin
|
|
83
83
|
rescue Errno::EPERM => e
|
84
84
|
log "Couldn't change user and group to #{user}:#{group}: #{e}"
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
87
|
# Register a proc to be called to restart the server.
|
88
88
|
def on_restart(&block)
|
89
89
|
@on_restart = block
|
90
90
|
end
|
91
|
-
|
91
|
+
|
92
92
|
# Restart the server.
|
93
93
|
def restart
|
94
94
|
if @on_restart
|
@@ -99,7 +99,7 @@ module Thin
|
|
99
99
|
exit!
|
100
100
|
end
|
101
101
|
end
|
102
|
-
|
102
|
+
|
103
103
|
module ClassMethods
|
104
104
|
# Send a QUIT or INT (if timeout is +0+) signal the process which
|
105
105
|
# PID is stored in +pid_file+.
|
@@ -112,12 +112,12 @@ module Thin
|
|
112
112
|
send_signal('QUIT', pid_file, timeout)
|
113
113
|
end
|
114
114
|
end
|
115
|
-
|
115
|
+
|
116
116
|
# Restart the server by sending HUP signal.
|
117
117
|
def restart(pid_file)
|
118
118
|
send_signal('HUP', pid_file)
|
119
119
|
end
|
120
|
-
|
120
|
+
|
121
121
|
# Send a +signal+ to the process which PID is stored in +pid_file+.
|
122
122
|
def send_signal(signal, pid_file, timeout=60)
|
123
123
|
if pid = read_pid_file(pid_file)
|
@@ -138,7 +138,7 @@ module Thin
|
|
138
138
|
Logging.log "process not found!"
|
139
139
|
force_kill pid_file
|
140
140
|
end
|
141
|
-
|
141
|
+
|
142
142
|
def force_kill(pid_file)
|
143
143
|
if pid = read_pid_file(pid_file)
|
144
144
|
Logging.log "Sending KILL signal to process #{pid} ... "
|
@@ -148,7 +148,7 @@ module Thin
|
|
148
148
|
Logging.log "Can't stop process, no PID found in #{pid_file}"
|
149
149
|
end
|
150
150
|
end
|
151
|
-
|
151
|
+
|
152
152
|
def read_pid_file(file)
|
153
153
|
if File.file?(file) && pid = File.read(file)
|
154
154
|
pid.to_i
|
@@ -157,18 +157,18 @@ module Thin
|
|
157
157
|
end
|
158
158
|
end
|
159
159
|
end
|
160
|
-
|
160
|
+
|
161
161
|
protected
|
162
162
|
def remove_pid_file
|
163
163
|
File.delete(@pid_file) if @pid_file && File.exists?(@pid_file)
|
164
164
|
end
|
165
|
-
|
165
|
+
|
166
166
|
def write_pid_file
|
167
167
|
log ">> Writing PID to #{@pid_file}"
|
168
168
|
open(@pid_file,"w") { |f| f.write(Process.pid) }
|
169
169
|
File.chmod(0644, @pid_file)
|
170
170
|
end
|
171
|
-
|
171
|
+
|
172
172
|
# If PID file is stale, remove it.
|
173
173
|
def remove_stale_pid_file
|
174
174
|
if File.exist?(@pid_file)
|
data/lib/thin/server.rb
CHANGED
@@ -12,7 +12,7 @@ module Thin
|
|
12
12
|
# == UNIX domain server
|
13
13
|
# Create a new UNIX domain socket bound to +socket+ file by specifiying a filename
|
14
14
|
# as the first argument. Eg.: /tmp/thin.sock. If the first argument contains a <tt>/</tt>
|
15
|
-
# it will be assumed to be a UNIX socket.
|
15
|
+
# it will be assumed to be a UNIX socket.
|
16
16
|
#
|
17
17
|
# Thin::Server.start('/tmp/thin.sock', app)
|
18
18
|
#
|
@@ -30,7 +30,7 @@ module Thin
|
|
30
30
|
# == Building an app in place
|
31
31
|
# If a block is passed, a <tt>Rack::Builder</tt> instance
|
32
32
|
# will be passed to build the +app+. So you can do cool stuff like this:
|
33
|
-
#
|
33
|
+
#
|
34
34
|
# Thin::Server.start('0.0.0.0', 3000) do
|
35
35
|
# use Rack::CommonLogger
|
36
36
|
# use Rack::ShowExceptions
|
@@ -44,19 +44,19 @@ module Thin
|
|
44
44
|
# * QUIT: Gracefull shutdown (see Server#stop)
|
45
45
|
# * INT and TERM: Force shutdown (see Server#stop!)
|
46
46
|
# Disable signals by passing <tt>:signals => false</tt>
|
47
|
-
#
|
47
|
+
#
|
48
48
|
class Server
|
49
49
|
include Logging
|
50
50
|
include Daemonizable
|
51
51
|
extend Forwardable
|
52
|
-
|
52
|
+
|
53
53
|
# Default values
|
54
54
|
DEFAULT_TIMEOUT = 30 #sec
|
55
55
|
DEFAULT_HOST = '0.0.0.0'
|
56
56
|
DEFAULT_PORT = 3000
|
57
57
|
DEFAULT_MAXIMUM_CONNECTIONS = 1024
|
58
58
|
DEFAULT_MAXIMUM_PERSISTENT_CONNECTIONS = 100
|
59
|
-
|
59
|
+
|
60
60
|
# Application (Rack adapter) called with the request that produces the response.
|
61
61
|
attr_accessor :app
|
62
62
|
|
@@ -65,38 +65,38 @@ module Thin
|
|
65
65
|
|
66
66
|
# Backend handling the connections to the clients.
|
67
67
|
attr_accessor :backend
|
68
|
-
|
68
|
+
|
69
69
|
# Maximum number of seconds for incoming data to arrive before the connection
|
70
70
|
# is dropped.
|
71
71
|
def_delegators :backend, :timeout, :timeout=
|
72
|
-
|
72
|
+
|
73
73
|
# Maximum number of file or socket descriptors that the server may open.
|
74
74
|
def_delegators :backend, :maximum_connections, :maximum_connections=
|
75
|
-
|
75
|
+
|
76
76
|
# Maximum number of connection that can be persistent at the same time.
|
77
77
|
# Most browser never close the connection so most of the time they are closed
|
78
78
|
# when the timeout occur. If we don't control the number of persistent connection,
|
79
79
|
# if would be very easy to overflow the server for a DoS attack.
|
80
80
|
def_delegators :backend, :maximum_persistent_connections, :maximum_persistent_connections=
|
81
|
-
|
81
|
+
|
82
82
|
# Allow using threads in the backend.
|
83
83
|
def_delegators :backend, :threaded?, :threaded=
|
84
|
-
|
84
|
+
|
85
85
|
# Allow using SSL in the backend.
|
86
86
|
def_delegators :backend, :ssl?, :ssl=, :ssl_options=
|
87
|
-
|
87
|
+
|
88
88
|
# Address and port on which the server is listening for connections.
|
89
89
|
def_delegators :backend, :host, :port
|
90
|
-
|
90
|
+
|
91
91
|
# UNIX domain socket on which the server is listening for connections.
|
92
92
|
def_delegator :backend, :socket
|
93
|
-
|
93
|
+
|
94
94
|
# Disable the use of epoll under Linux
|
95
95
|
def_delegators :backend, :no_epoll, :no_epoll=
|
96
|
-
|
96
|
+
|
97
97
|
def initialize(*args, &block)
|
98
98
|
host, port, options = DEFAULT_HOST, DEFAULT_PORT, {}
|
99
|
-
|
99
|
+
|
100
100
|
# Guess each parameter by its type so they can be
|
101
101
|
# received in any order.
|
102
102
|
args.each do |arg|
|
@@ -108,58 +108,58 @@ module Thin
|
|
108
108
|
@app = arg if arg.respond_to?(:call)
|
109
109
|
end
|
110
110
|
end
|
111
|
-
|
111
|
+
|
112
112
|
# Set tag if needed
|
113
113
|
self.tag = options[:tag]
|
114
114
|
|
115
115
|
# Try to intelligently select which backend to use.
|
116
116
|
@backend = select_backend(host, port, options)
|
117
|
-
|
117
|
+
|
118
118
|
load_cgi_multipart_eof_fix
|
119
|
-
|
119
|
+
|
120
120
|
@backend.server = self
|
121
|
-
|
121
|
+
|
122
122
|
# Set defaults
|
123
123
|
@backend.maximum_connections = DEFAULT_MAXIMUM_CONNECTIONS
|
124
124
|
@backend.maximum_persistent_connections = DEFAULT_MAXIMUM_PERSISTENT_CONNECTIONS
|
125
125
|
@backend.timeout = DEFAULT_TIMEOUT
|
126
|
-
|
126
|
+
|
127
127
|
# Allow using Rack builder as a block
|
128
128
|
@app = Rack::Builder.new(&block).to_app if block
|
129
|
-
|
129
|
+
|
130
130
|
# If in debug mode, wrap in logger adapter
|
131
131
|
@app = Rack::CommonLogger.new(@app) if Logging.debug?
|
132
|
-
|
132
|
+
|
133
133
|
setup_signals unless options[:signals].class == FalseClass
|
134
134
|
end
|
135
|
-
|
135
|
+
|
136
136
|
# Lil' shortcut to turn this:
|
137
|
-
#
|
137
|
+
#
|
138
138
|
# Server.new(...).start
|
139
|
-
#
|
139
|
+
#
|
140
140
|
# into this:
|
141
|
-
#
|
141
|
+
#
|
142
142
|
# Server.start(...)
|
143
|
-
#
|
143
|
+
#
|
144
144
|
def self.start(*args, &block)
|
145
145
|
new(*args, &block).start!
|
146
146
|
end
|
147
|
-
|
147
|
+
|
148
148
|
# Start the server and listen for connections.
|
149
149
|
def start
|
150
150
|
raise ArgumentError, 'app required' unless @app
|
151
|
-
|
151
|
+
|
152
152
|
log ">> Thin web server (v#{VERSION::STRING} codename #{VERSION::CODENAME})"
|
153
153
|
debug ">> Debugging ON"
|
154
154
|
trace ">> Tracing ON"
|
155
|
-
|
155
|
+
|
156
156
|
log ">> Maximum connections set to #{@backend.maximum_connections}"
|
157
157
|
log ">> Listening on #{@backend}, CTRL+C to stop"
|
158
|
-
|
158
|
+
|
159
159
|
@backend.start
|
160
160
|
end
|
161
161
|
alias :start! :start
|
162
|
-
|
162
|
+
|
163
163
|
# == Gracefull shutdown
|
164
164
|
# Stops the server after processing all current connections.
|
165
165
|
# As soon as this method is called, the server stops accepting
|
@@ -176,7 +176,7 @@ module Thin
|
|
176
176
|
stop!
|
177
177
|
end
|
178
178
|
end
|
179
|
-
|
179
|
+
|
180
180
|
# == Force shutdown
|
181
181
|
# Stops the server closing all current connections right away.
|
182
182
|
# This doesn't wait for connection to finish their work and send data.
|
@@ -186,7 +186,7 @@ module Thin
|
|
186
186
|
|
187
187
|
@backend.stop!
|
188
188
|
end
|
189
|
-
|
189
|
+
|
190
190
|
# == Reopen log file.
|
191
191
|
# Reopen the log file and redirect STDOUT and STDERR to it.
|
192
192
|
def reopen_log
|
@@ -195,39 +195,47 @@ module Thin
|
|
195
195
|
log ">> Reopening log file: #{file}"
|
196
196
|
Daemonize.redirect_io(file)
|
197
197
|
end
|
198
|
-
|
198
|
+
|
199
199
|
# == Configure the server
|
200
200
|
# The process might need to have superuser privilege to configure
|
201
201
|
# server with optimal options.
|
202
202
|
def config
|
203
203
|
@backend.config
|
204
204
|
end
|
205
|
-
|
205
|
+
|
206
206
|
# Name of the server and type of backend used.
|
207
207
|
# This is also the name of the process in which Thin is running as a daemon.
|
208
208
|
def name
|
209
209
|
"thin server (#{@backend})" + (tag ? " [#{tag}]" : "")
|
210
210
|
end
|
211
211
|
alias :to_s :name
|
212
|
-
|
212
|
+
|
213
213
|
# Return +true+ if the server is running and ready to receive requests.
|
214
214
|
# Note that the server might still be running and return +false+ when
|
215
215
|
# shuting down and waiting for active connections to complete.
|
216
216
|
def running?
|
217
217
|
@backend.running?
|
218
218
|
end
|
219
|
-
|
219
|
+
|
220
220
|
# deamonizing kills our HUP signal, so we set them again
|
221
221
|
def after_daemonize
|
222
222
|
setup_signals
|
223
223
|
end
|
224
224
|
|
225
|
+
def print_status
|
226
|
+
puts "THIN_STATUS - '#{DateTime.now.to_s}' - '#{@backend.size}' - '#{@backend}' "
|
227
|
+
@backend.connections_list.each do |c|
|
228
|
+
puts "THIN_CONNECTION: #{c.request.env['REQUEST_METHOD']} #{c.request.env['REQUEST_URI']}" unless c.request.env['REQUEST_METHOD'].nil? || c.request.env['REQUEST_URI'].nil?
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
225
232
|
protected
|
226
233
|
# Register signals:
|
227
234
|
# * TERM & QUIT calls +stop+ to shutdown gracefully.
|
228
235
|
# * INT calls <tt>stop!</tt> to force shutdown.
|
229
236
|
# * HUP calls <tt>restart</tt> to ... surprise, restart!
|
230
237
|
# * USR1 reopen log files.
|
238
|
+
# * USR2 print status.
|
231
239
|
def setup_signals
|
232
240
|
trap('INT') { stop! }
|
233
241
|
trap('TERM') { stop }
|
@@ -235,9 +243,10 @@ module Thin
|
|
235
243
|
trap('QUIT') { stop }
|
236
244
|
trap('HUP') { restart }
|
237
245
|
trap('USR1') { reopen_log }
|
246
|
+
trap('USR2') { print_status }
|
238
247
|
end
|
239
248
|
end
|
240
|
-
|
249
|
+
|
241
250
|
def select_backend(host, port, options)
|
242
251
|
case
|
243
252
|
when options.has_key?(:backend)
|
@@ -251,12 +260,12 @@ module Thin
|
|
251
260
|
Backends::TcpServer.new(host, port)
|
252
261
|
end
|
253
262
|
end
|
254
|
-
|
263
|
+
|
255
264
|
# Taken from Mongrel cgi_multipart_eof_fix
|
256
265
|
# Ruby 1.8.5 has a security bug in cgi.rb, we need to patch it.
|
257
266
|
def load_cgi_multipart_eof_fix
|
258
267
|
version = RUBY_VERSION.split('.').map { |i| i.to_i }
|
259
|
-
|
268
|
+
|
260
269
|
if version[0] <= 1 && version[1] <= 8 && version[2] <= 5 && RUBY_PLATFORM !~ /java/
|
261
270
|
begin
|
262
271
|
require 'cgi_multipart_eof_fix'
|
data/lib/thin/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: friendlyfashion-thin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.4.1
|
4
|
+
version: 1.4.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date: 2012-
|
15
|
+
date: 2012-10-24 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: rack
|
@@ -122,7 +122,7 @@ files:
|
|
122
122
|
- ext/thin_parser/extconf.rb
|
123
123
|
- ext/thin_parser/parser.rl
|
124
124
|
- ext/thin_parser/common.rl
|
125
|
-
homepage:
|
125
|
+
homepage: https://github.com/friendlyfashion/thin
|
126
126
|
licenses:
|
127
127
|
- Ruby
|
128
128
|
post_install_message:
|