friendlyfashion-thin 1.4.1 → 1.4.1.1
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.
- 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:
|