public
Description: A very fast & simple Ruby web server
Homepage: http://code.macournoyer.com/thin/
Clone URL: git://github.com/macournoyer/thin.git
Search Repo:
Merge branch 'master' into keepalive

Conflicts:

  CHANGELOG
  lib/thin/connection.rb
macournoyer (author)
Fri Feb 08 22:59:54 -0800 2008
commit  ab63c2010438d2764e1d566b6b1aa6a34dc42bb5
tree    93e7ec38c12e2ee0175cc61704d9b3882ff95f97
parent  c2475e64f14fdfad1248c69edda3ae50a11eb870 parent  704af3973c881cfa99c6265591d7face9e8a7701
...
3
4
5
 
 
 
 
6
 
7
8
9
...
3
4
5
6
7
8
9
10
11
12
13
14
0
@@ -3,7 +3,12 @@
0
 ext/thin_parser/*.log
0
 ext/thin_parser/*.o
0
 ext/thin_parser/*.bundle
0
+ext/thin_parser/*.obj
0
+ext/thin_parser/*mswin32*
0
+ext/thin_parser/vc60.pdb
0
+ext/thin_parser/*.so
0
 lib/*.bundle
0
+lib/*.so
0
 log/*.log
0
 spec/rails_app/log
0
 doc/rdoc/*
...
1
2
 
 
3
4
5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
7
8
...
1
2
3
4
5
6
 
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
0
@@ -1,8 +1,32 @@
0
 == 0.7.0 Bionic Pickle release
0
  * Persistent connection (keep-alive) & HTTP pipelining support
0
+ * Add Swiftiply support. Use w/ the --swiftiply (-y) option in the thin script,
0
+ closes #28 [Alex MacCaw]
0
 
0
 == 0.6.3 Ninja Cookie release
0
- * Add a script to run thin as a system service that can start at startup, closes #31 [Gump]
0
+ * Add tasks for Vlad the Deployer in example/vlad.rake [cnantais]
0
+ * Add Ramaze Rackup config file in example dir [tmm1]
0
+ Use like this from you Ramaze app dir:
0
+
0
+ thin start -r /path/to/thin/example/ramaze.ru
0
+
0
+ * Add the --rackup option to load a Rack config file instead of the Rails adapter.
0
+ So you can use any framework with the thin script and start cluster and stuff like that.
0
+ A Rack config file is one that is usable through the rackup command and looks like this:
0
+
0
+ use Rack::CommonLogger
0
+ run MyCrazyRackAdapter.new(:uterly, 'cool')
0
+
0
+ Then use it with thin like this:
0
+
0
+ thin start --rackup config.ru
0
+
0
+ * thin config --chrdir ... -C thin/yml do not change current directory anymore, fixes #33.
0
+ * Add a better sample god config file in example/thin.god that loads all info from config
0
+ files in /etc/thin. Drop-in replacement for the thin runlevel service [Gump].
0
+ * Add support for specifying a custom Connector to the server and add more doc about Server
0
+ configuration.
0
+ * Add a script to run thin as a runlevel service that can start at startup, closes #31 [Gump]
0
    Setup the service like this:
0
    
0
      sudo thin install /etc/thin
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
0
@@ -1 +1,50 @@
0
+# Automate benchmarking with ab with various concurrency levels.
0
+require 'optparse'
0
+
0
+options = {
0
+ :address => '0.0.0.0',
0
+ :port => 3000,
0
+ :requests => 1000,
0
+ :start => 1,
0
+ :end => 100,
0
+ :step => 10
0
+}
0
+
0
+OptionParser.new do |opts|
0
+ opts.banner = "Usage: #{$PROGRAM_NAME} [options]"
0
+
0
+ opts.on("-n", "--requests NUM", "Number of requests") { |num| options[:requests] = num }
0
+ opts.on("-a", "--address HOST", "Address (default: 0.0.0.0)") { |host| options[:address] = host }
0
+ opts.on("-p", "--port PORT", "use PORT (default: 3000)") { |port| options[:port] = port.to_i }
0
+ opts.on("-s", "--start N", "First concurrency level") { |n| options[:start] = n.to_i }
0
+ opts.on("-e", "--end N", "Last concurrency level") { |n| options[:end] = n.to_i }
0
+ opts.on("-S", "--step N", "Concurrency level step") { |n| options[:step] = n.to_i }
0
+ opts.on("-u", "--uri PATH", "Path to send to") { |u| options[:uri] = u }
0
+
0
+ opts.on_tail("-h", "--help", "Show this message") { puts opts; exit }
0
+end.parse!(ARGV)
0
+
0
+puts 'request concurrency req/s failures'
0
+puts '=' * 42
0
+
0
+c = options[:start]
0
+until c >= options[:end]
0
+ sleep 0.5
0
+ out = `nice -n20 ab -c #{c} -n #{options[:requests]} #{options[:address]}:#{options[:port]}/#{options[:uri]} 2> /dev/null`
0
+
0
+ r = if requests = out.match(/^Requests.+?(\d+\.\d+)/)
0
+ requests[1].to_i
0
+ else
0
+ 0
0
+ end
0
+ f = if requests = out.match(/^Failed requests.+?(\d+)/)
0
+ requests[1].to_i
0
+ else
0
+ 0
0
+ end
0
+
0
+ puts "#{options[:requests].to_s.ljust(9)} #{c.to_s.ljust(13)} #{r.to_s.ljust(8)} #{f}"
0
+
0
+ c += options[:step]
0
+end
...
1
2
 
 
 
 
3
4
5
...
1
 
2
3
4
5
6
7
8
0
@@ -1,5 +1,8 @@
0
 # Run with: rackup -s thin
0
-# Then browse to http://localhost:9292
0
+# then browse to http://localhost:9292
0
+# Or with: thin start -r config.ru
0
+# then browse to http://localhost:3000
0
+#
0
 # Check Rack::Builder doc for more details on this file format:
0
 # http://rack.rubyforge.org/doc/classes/Rack/Builder.html
0
 
...
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
0
@@ -1 +1,13 @@
0
+# Ramaze Rackup config file.
0
+# by tmm1
0
+# Use with --rackup option:
0
+#
0
+# thin start -r ramaze.ru
0
+#
0
+require 'start'
0
+
0
+Ramaze.trait[:essentials].delete Ramaze::Adapter
0
+Ramaze.start :force => true
0
+
0
+run Ramaze::Adapter::Base
...
1
2
3
4
 
 
 
 
 
 
 
 
 
 
 
5
6
 
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
 
 
 
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
71
72
...
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
 
13
14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
16
17
18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
0
@@ -1,72 +1,76 @@
0
-# WARNING: this config file has not been tested yet.
0
-# If you know God better then I, feel free to tweak it and send it to me.
0
-# Thanks!
0
-# -- Marc
0
+# == God config file
0
+# http://god.rubyforge.org/
0
+# Author: Gump
0
+#
0
+# Config file for god that configures watches for each instance of a thin server for
0
+# each thin configuration file found in /etc/thin.
0
+# In order to get it working on Ubuntu, I had to make a change to god as noted at
0
+# the following blog:
0
+# http://blog.alexgirard.com/2007/10/25/ruby-one-line-to-save-god/
0
+#
0
+require 'yaml'
0
 
0
-RAILS_ROOT = "/Users/marc/projects/refactormycode"
0
+config_path = "/etc/thin"
0
 
0
-God.watch do |w|
0
- w.name = "thin-3000"
0
- w.group = 'thins'
0
- w.interval = 5.seconds # default
0
- w.start = "thin start -c #{RAILS_ROOT} -P #{RAILS_ROOT}/tmp/pids/thin.3000.pid -p 3000 -d"
0
- w.stop = "thin stop -P #{RAILS_ROOT}/tmp/pids/thin.3000.pid"
0
- w.restart = "thin restart -P #{RAILS_ROOT}/tmp/pids/thin.3000.pid -p 3000"
0
- w.pid_file = File.join(RAILS_ROOT, "tmp/pids/thin.3000.pid")
0
-
0
- # clean pid files before start if necessary
0
- w.behavior(:clean_pid_file)
0
-
0
- # determine the state on startup
0
- w.transition(:init, { true => :up, false => :start }) do |on|
0
- on.condition(:process_running) do |c|
0
- c.running = true
0
- end
0
- end
0
-
0
- # determine when process has finished starting
0
- w.transition([:start, :restart], :up) do |on|
0
- on.condition(:process_running) do |c|
0
- c.running = true
0
- end
0
-
0
- # failsafe
0
- on.condition(:tries) do |c|
0
- c.times = 5
0
- c.transition = :start
0
- end
0
- end
0
+Dir[config_path + "/*.yml"].each do |file|
0
+ config = YAML.load_file(file)
0
+ num_servers = config["servers"] ||= 1
0
 
0
- # start if process is not running
0
- w.transition(:up, :start) do |on|
0
- on.condition(:process_exits)
0
- end
0
-
0
- # restart if memory or cpu is too high
0
- w.transition(:up, :restart) do |on|
0
- on.condition(:memory_usage) do |c|
0
- c.interval = 20
0
- c.above = 50.megabytes
0
- c.times = [3, 5]
0
- end
0
-
0
- on.condition(:cpu_usage) do |c|
0
- c.interval = 10
0
- c.above = 10.percent
0
- c.times = [3, 5]
0
- end
0
- end
0
-
0
- # lifecycle
0
- w.lifecycle do |on|
0
- on.condition(:flapping) do |c|
0
- c.to_state = [:start, :restart]
0
- c.times = 5
0
- c.within = 5.minute
0
- c.transition = :unmonitored
0
- c.retry_in = 10.minutes
0
- c.retry_times = 5
0
- c.retry_within = 2.hours
0
+ for i in 0...num_servers
0
+ God.watch do |w|
0
+ w.group = "thin-" + File.basename(file, ".yml")
0
+ w.name = w.group + "-#{i}"
0
+
0
+ w.interval = 30.seconds
0
+
0
+ w.uid = config["user"]
0
+ w.gid = config["group"]
0
+
0
+ w.start = "thin start -C #{file} -o #{i}"
0
+ w.start_grace = 10.seconds
0
+
0
+ w.stop = "thin stop -C #{file} -o #{i}"
0
+ w.stop_grace = 10.seconds
0
+
0
+ w.restart = "thin restart -C #{file} -o #{i}"
0
+
0
+ pid_path = config["chdir"] + "/" + config["pid"]
0
+ ext = File.extname(pid_path)
0
+
0
+ w.pid_file = pid_path.gsub(/#{ext}$/, ".#{i}#{ext}")
0
+
0
+ w.behavior(:clean_pid_file)
0
+
0
+ w.start_if do |start|
0
+ start.condition(:process_running) do |c|
0
+ c.interval = 5.seconds
0
+ c.running = false
0
+ end
0
+ end
0
+
0
+ w.restart_if do |restart|
0
+ restart.condition(:memory_usage) do |c|
0
+ c.above = 150.megabytes
0
+ c.times = [3,5] # 3 out of 5 intervals
0
+ end
0
+
0
+ restart.condition(:cpu_usage) do |c|
0
+ c.above = 50.percent
0
+ c.times = 5
0
+ end
0
+ end
0
+
0
+ w.lifecycle do |on|
0
+ on.condition(:flapping) do |c|
0
+ c.to_state = [:start, :restart]
0
+ c.times = 5
0
+ c.within = 5.minutes
0
+ c.transition = :unmonitored
0
+ c.retry_in = 10.minutes
0
+ c.retry_times = 5
0
+ c.retry_within = 2.hours
0
+ end
0
+ end
0
     end
0
   end
0
 end
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
0
@@ -1 +1,62 @@
0
+# $GEM_HOME/gems/vlad-1.2.0/lib/vlad/thin.rb
0
+# Thin tasks for Vlad the Deployer
0
+# By cnantais
0
+require 'vlad'
0
+
0
+namespace :vlad do
0
+ ##
0
+ # Thin app server
0
+
0
+ set :thin_address, "127.0.0.1"
0
+ set :thin_command, 'thin'
0
+ set(:thin_conf) { "#{shared_path}/thin_cluster.conf" }
0
+ set :thin_environment, "production"
0
+ set :thin_group, nil
0
+ set :thin_log_file, nil
0
+ set :thin_pid_file, nil
0
+ set :thin_port, nil
0
+ set :thin_socket, "/tmp/thin.sock"
0
+ set :thin_prefix, nil
0
+ set :thin_servers, 2
0
+ set :thin_user, nil
0
+
0
+ desc "Prepares application servers for deployment. thin
0
+configuration is set via the thin_* variables.".cleanup
0
+
0
+ remote_task :setup_app, :roles => :app do
0
+ cmd = [
0
+ "#{thin_command} config",
0
+ "-s #{thin_servers}",
0
+ "-S #{thin_socket}",
0
+ "-e #{thin_environment}",
0
+ "-a #{thin_address}",
0
+ "-c #{current_path}",
0
+ "-C #{thin_conf}",
0
+ ("-P #{thin_pid_file}" if thin_pid_file),
0
+ ("-l #{thin_log_file}" if thin_log_file),
0
+ ("--user #{thin_user}" if thin_user),
0
+ ("--group #{thin_group}" if thin_group),
0
+ ("--prefix #{thin_prefix}" if thin_prefix),
0
+ ("-p #{thin_port}" if thin_port),
0
+ ].compact.join ' '
0
+
0
+ run cmd
0
+ end
0
+
0
+ def thin(cmd) # :nodoc:
0
+ "#{thin_command} #{cmd} -C #{thin_conf}"
0
+ end
0
+
0
+ desc "Restart the app servers"
0
+
0
+ remote_task :start_app, :roles => :app do
0
+ run thin("restart -s #{thin_servers}")
0
+ end
0
+
0
+ desc "Stop the app servers"
0
+
0
+ remote_task :stop_app, :roles => :app do
0
+ run thin("stop -s #{thin_servers}")
0
+ end
0
+end
...
1
2
3
4
5
6
...
 
 
 
1
2
3
0
@@ -1,6 +1,3 @@
0
-# This as been submitted to Rack as a patch, tested and everything.
0
-# Bug Christian Neukirchen at chneukirchen@gmail.com to apply the patch!
0
-
0
 require 'cgi'
0
 
0
 # Adapter to run a Rails app with any supported Rack handler.
...
1
2
 
 
 
 
 
3
4
5
6
7
8
9
 
10
11
12
...
1
2
3
4
5
6
7
8
9
10
11
12
13
 
14
15
16
17
0
@@ -1,12 +1,17 @@
0
 module Rack
0
   module Handler
0
+ # Rack Handler stricly to be able to use Thin through the rackup command.
0
+ # To do so, simply require 'thin' in your Rack config file and run like this
0
+ #
0
+ # rackup --server thin
0
+ #
0
     class Thin
0
       def self.run(app, options={})
0
         server = ::Thin::Server.new(options[:Host] || '0.0.0.0',
0
                                     options[:Port] || 8080,
0
                                     app)
0
         yield server if block_given?
0
- server.start!
0
+ server.start
0
       end
0
     end
0
   end
...
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
28
29
...
11
12
13
 
 
 
 
 
 
 
 
 
 
 
 
 
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
0
@@ -11,19 +11,29 @@
0
 require 'thin/statuses'
0
 
0
 module Thin
0
- autoload :Cluster, 'thin/cluster'
0
- autoload :Command, 'thin/command'
0
- autoload :Connection, 'thin/connection'
0
- autoload :Controller, 'thin/controller'
0
- autoload :Daemonizable, 'thin/daemonizing'
0
- autoload :Logging, 'thin/logging'
0
- autoload :Headers, 'thin/headers'
0
- autoload :Request, 'thin/request'
0
- autoload :Response, 'thin/response'
0
- autoload :Runner, 'thin/runner'
0
- autoload :Server, 'thin/server'
0
- autoload :Service, 'thin/service'
0
- autoload :Stats, 'thin/stats'
0
+ autoload :Command, 'thin/command'
0
+ autoload :Connection, 'thin/connection'
0
+ autoload :Daemonizable, 'thin/daemonizing'
0
+ autoload :Logging, 'thin/logging'
0
+ autoload :Headers, 'thin/headers'
0
+ autoload :Request, 'thin/request'
0
+ autoload :Response, 'thin/response'
0
+ autoload :Runner, 'thin/runner'
0
+ autoload :Server, 'thin/server'
0
+ autoload :Stats, 'thin/stats'
0
+
0
+ module Connectors
0
+ autoload :Connector, 'thin/connectors/connector'
0
+ autoload :SwiftiplyClient, 'thin/connectors/swiftiply_client'
0
+ autoload :TcpServer, 'thin/connectors/tcp_server'
0
+ autoload :UnixServer, 'thin/connectors/unix_server'
0
+ end
0
+
0
+ module Controllers
0
+ autoload :Cluster, 'thin/controllers/cluster'
0
+ autoload :Controller, 'thin/controllers/controller'
0
+ autoload :Service, 'thin/controllers/service'
0
+ end
0
 end
0
 
0
 require 'rack'
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0
@@ -1,114 +1 @@
0
-module Thin
0
- # Control a set of servers.
0
- # * Generate start and stop commands and run them.
0
- # * Inject the port or socket number in the pid and log filenames.
0
- # Servers are started throught the +thin+ command-line script.
0
- class Cluster < Controller
0
- # Number of servers in the cluster.
0
- attr_accessor :size
0
-
0
- # Create a new cluster of servers launched using +options+.
0
- def initialize(options)
0
- @options = options.merge(:daemonize => true)
0
- @size = @options.delete(:servers)
0
- @only = @options.delete(:only)
0
-
0
- if socket
0
- @options.delete(:address)
0
- @options.delete(:port)
0
- end
0
- end
0
-
0
- def first_port; @options[:port] end
0
- def address; @options[:address] end
0
- def socket; @options[:socket] end
0
- def pid_file; @options[:pid] end
0
- def log_file; @options[:log] end
0
-
0
- # Start the servers
0
- def start
0
- with_each_server { |port| start_server port }
0
- end
0
-
0
- # Start a single server
0
- def start_server(number)
0
- log "Starting server on #{server_id(number)} ... "
0
-
0
- run :start, @options, number
0
- end
0
-
0
- # Stop the servers
0
- def stop
0
- with_each_server { |n| stop_server n }
0
- end
0
-
0
- # Stop a single server
0
- def stop_server(number)
0
- log "Stopping server on #{server_id(number)} ... "
0
-
0
- run :stop, @options, number
0
- end
0
-
0
- # Stop and start the servers.
0
- def restart
0
- stop
0
- sleep 0.1 # Let's breath a bit shall we ?
0
- start
0
- end
0
-
0
- def server_id(number)
0
- if socket
0
- socket_for(number)
0
- else
0
- [address, number].join(':')
0
- end
0
- end
0
-
0
- def log_file_for(number)
0
- include_server_number log_file, number
0
- end
0
-
0
- def pid_file_for(number)
0
- include_server_number pid_file, number
0
- end
0
-
0
- def socket_for(number)
0
- include_server_number socket, number
0
- end
0
-
0
- def pid_for(number)
0
- File.read(pid_file_for(number)).chomp.to_i
0
- end
0
-
0
- private
0
- # Send the command to the +thin+ script
0
- def run(cmd, options, number)
0
- cmd_options = options.dup
0
- cmd_options.merge!(:pid => pid_file_for(number), :log => log_file_for(number))
0
- if socket
0
- cmd_options.merge!(:socket => socket_for(number))
0
- else
0
- cmd_options.merge!(:port => number)
0
- end
0
- Command.run(cmd, cmd_options)
0
- end
0
-
0
- def with_each_server
0
- if @only
0
- yield @only
0
- else
0
- @size.times do |n|
0
- yield socket ? n : (first_port + n)
0
- end
0
- end
0
- end
0
-
0
- # Add the server port or number in the filename
0
- # so each instance get its own file
0
- def include_server_number(path, number)
0
- ext = File.extname(path)
0
- path.gsub(/#{ext}$/, ".#{number}#{ext}")
0
- end
0
- end
0
-end
...
30
31
32
33
34
 
 
 
35
36
37
...
30
31
32
 
 
33
34
35
36
37
38
0
@@ -30,8 +30,9 @@
0
     def shellify
0
       shellified_options = @options.inject([]) do |args, (name, value)|
0
         args << case value
0
- when NilClass
0
- when TrueClass then "--#{name}"
0
+ when NilClass,
0
+ TrueClass then "--#{name}"
0
+ when FalseClass
0
         else "--#{name.to_s.tr('_', '-')}=#{value.inspect}"
0
         end
0
       end
...
1
2
3
 
4
5
6
7
8
9
10
11
 
 
12
13
14
15
16
17
18
...
44
45
46
47
 
48
49
50
51
52
53
...
56
57
58
59
60
 
 
61
62
63
 
64
65
 
 
 
 
66
67
68
69
70
71
72
73
74
75
 
76
77
78
...
1
2
3
4
5
6
7
8
9
10
 
 
11
12
13
 
 
 
14
15
16
...
42
43
44
 
45
46
47
48
49
50
51
...
54
55
56
 
 
57
58
59
60
 
61
62
63
64
65
66
67
68
69
 
 
 
 
 
 
 
 
70
71
72
73
0
@@ -1,18 +1,16 @@
0
 require 'socket'
0
 
0
 module Thin
0
+ # Connection between the server and client.
0
   class Connection < EventMachine::Connection
0
     include Logging
0
     
0
     # Rack application served by this connection.
0
     attr_accessor :app
0
     
0
- # +true+ if the connection is on a UNIX domain socket.
0
- attr_accessor :unix_socket
0
+ # Connector to the server
0
+ attr_accessor :connector
0
     
0
- # Server owning the connection
0
- attr_accessor :server
0
-
0
     def post_init
0
       @request = Request.new
0
       @response = Response.new
0
@@ -44,7 +42,7 @@
0
       end
0
       
0
       # If no more request on that same connection, we close it.
0
- close_connection_after_writing unless @response.persistent?
0
+ close_connection_after_writing unless persistent?
0
       
0
     rescue Object => e
0
       log "Unexpected error while processing request: #{e.message}"
0
0
0
0
@@ -56,23 +54,20 @@
0
       
0
       # Prepare the connection for another request if the client
0
       # supports HTTP pipelining (persistent connection).
0
- post_init if @response.persistent?
0
- end
0
+ post_init if persistent?
0
+ end
0
     
0
     def unbind
0
- @server.connection_finished(self)
0
+ @connector.connection_finished(self)
0
     end
0
     
0
+ def persistent?
0
+ @response.persistent?
0
+ end
0
+
0
     protected
0
       def remote_address
0
- if remote_addr = @request.forwarded_for
0
- remote_addr
0
- elsif @unix_socket
0
- # FIXME not sure about this, does it even make sense on a UNIX socket?
0
- Socket.unpack_sockaddr_un(get_peername)
0
- else
0
- Socket.unpack_sockaddr_in(get_peername)[1]
0
- end
0
+ @request.forwarded_for || Socket.unpack_sockaddr_in(get_peername)[1]
0
       end
0
   end
0
 end
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
0
@@ -1 +1,66 @@
0
+module Thin
0
+ module Connectors
0
+ # A Connector connect the server to the client. It handles:
0
+ # * connection/disconnection to the server
0
+ # * initialization of the connections
0
+ # * manitoring of the active connections.
0
+ class Connector
0
+ include Logging
0
+
0
+ # Server serving the connections throught the connector
0
+ attr_reader :server
0
+
0
+ # Maximum time for incoming data to arrive
0
+ attr_accessor :timeout
0
+
0
+ def initialize
0
+ @connections = []
0
+ @timeout = 60 # sec
0
+ end
0
+
0
+ # Free up resources used by the connector.
0
+ def close
0
+ end
0
+
0
+ def running?
0
+ @server.running?
0
+ end
0
+
0
+ def server=(server)
0
+ @server = server
0
+ @silent = @server.silent
0
+ end
0
+
0
+ # Initialize a new connection to a client.
0
+ def initialize_connection(connection)
0
+ connection.connector = self
0
+ connection.app = @server.app
0
+ connection.comm_inactivity_timeout = @timeout
0
+ connection.silent = @silent
0
+
0
+ @connections << connection
0
+ end
0
+
0
+ # Close all active connections.
0
+ def close_connections
0
+ @connections.each { |connection| connection.close_connection }
0
+ end
0
+
0
+ # Called by a connection when it's unbinded.
0
+ def connection_finished(connection)
0
+ @connect