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:
Add support for connection through UNIX domain socket.
Use the --socket (-S) option w/ the thin script to configure the socket 
filename.
Nginx support binding to a UNIX socket like this:

  upstream  backend {
    server   unix:/tmp/thin.0.sock;
    server   unix:/tmp/thin.1.sock;
    server   unix:/tmp/thin.2.sock;
  }

Start your servers like this:

  thin start -s3 -S/tmp/thin.sock
macournoyer (author)
Wed Jan 23 21:08:39 -0800 2008
commit  a68f46d6646592ba9043998979aec927d5b0febd
tree    0748dd27fb6cd40a4dfa9738a9b57026259dd95a
parent  57eceafee8354b99f06a6bcb29bceb02e863fc9e
...
1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
3
4
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
0
@@ -1,4 +1,19 @@
0
 == 0.5.5 Pony release
0
+ * Add support for connection through UNIX domain socket.
0
+ Use the --socket (-S) option w/ the thin script to configure the socket filename.
0
+ Nginx support binding to a UNIX socket like this:
0
+
0
+ upstream backend {
0
+ server unix:/tmp/thin.0.sock;
0
+ server unix:/tmp/thin.1.sock;
0
+ server unix:/tmp/thin.2.sock;
0
+ }
0
+
0
+ Start your servers like this:
0
+
0
+ thin start -s3 -S/tmp/thin.sock
0
+
0
+ * Remove Server#listen! method. Use Server#start instead.
0
  * Server can now yield a Rack::Builder to allow building an app in one call:
0
  
0
      Server.start '0.0.0.0', 3000 do
...
31
32
33
 
34
35
36
...
79
80
81
82
 
 
 
 
 
83
84
85
...
127
128
129
130
 
131
132
133
...
31
32
33
34
35
36
37
...
80
81
82
 
83
84
85
86
87
88
89
90
...
132
133
134
 
135
136
137
138
0
@@ -31,6 +31,7 @@
0
 
0
   opts.on("-a", "--address HOST", "bind to 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", "--socket PATH", "bind to unix domain socket") { |file| options[:socket] = file }
0
   opts.on("-e", "--environment ENV", "Rails environment (default: development)") { |env| options[:environment] = env }
0
   opts.on("-c", "--chdir PATH", "Change to dir before starting") { |dir| options[:chdir] = File.expand_path(dir) }
0
   opts.on("-s", "--servers NUM", "Number of servers to start",
0
@@ -79,7 +80,11 @@
0
   if cluster?(options)
0
     Thin::Cluster.new(options).start
0
   else
0
- server = Thin::Server.new(options[:address], options[:port])
0
+ if options[:socket]
0
+ server = Thin::Server.new(options[:socket])
0
+ else
0
+ server = Thin::Server.new(options[:address], options[:port])
0
+ end
0
   
0
     server.pid_file = options[:pid]
0
     server.log_file = options[:log]
0
@@ -127,7 +132,7 @@
0
 end
0
 
0
 def config(options)
0
- config_file = options.delete(:config))
0
+ config_file = options.delete(:config) || abort('config option required')
0
 
0
   # Stringify keys
0
   options.keys.each { |o| options[o.to_s] = options.delete(o) }
...
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
...
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
...
93
94
95
96
 
 
 
97
98
99
 
100
101
102
103
 
 
 
104
105
106
...
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
...
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
...
118
119
120
 
121
122
123
124
125
 
126
127
 
 
 
128
129
130
131
132
133
0
@@ -20,36 +20,42 @@
0
     def initialize(options)
0
       @options = options.merge(:daemonize => true)
0
       @size = @options.delete(:servers)
0
- @script = 'thin'
0
+ @script = File.join(File.dirname(__FILE__), '..', '..', 'bin', 'thin')
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 address; @options[:address] end
0
+ def socket; @options[:socket] end
0
     def pid_file; File.expand_path File.join(@options[:chdir], @options[:pid]) end
0
     def log_file; File.expand_path File.join(@options[:chdir], @options[:log]) end
0
     
0
     # Start the servers
0
     def start
0
- with_each_server { |port| start_on_port port }
0
+ with_each_server { |port| start_server port }
0
     end
0
     
0
- # Start the server on a single port
0
- def start_on_port(port)
0
- log "Starting #{address}:#{port} ... "
0
+ # Start a single server
0
+ def start_server(number)
0
+ log "Starting server on #{server_id(number)} ... "
0
       
0
- run :start, @options, port
0
+ run :start, @options, number
0
     end
0
   
0
     # Stop the servers
0
     def stop
0
- with_each_server { |port| stop_on_port port }
0
+ with_each_server { |n| stop_server n }
0
     end
0
     
0
- # Stop the server running on +port+
0
- def stop_on_port(port)
0
- log "Stopping #{address}:#{port} ... "
0
+ # Stop a single server
0
+ def stop_server(number)
0
+ log "Stopping server on #{server_id(number)} ... "
0
       
0
- run :stop, @options, port
0
+ run :stop, @options, number
0
     end
0
     
0
     # Stop and start the servers.
0
0
0
0
0
0
@@ -59,25 +65,44 @@
0
       start
0
     end
0
     
0
- def log_file_for(port)
0
- include_port_number log_file, port
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 pid_file_for(port)
0
- include_port_number pid_file, port
0
+ def log_file_for(number)
0
+ include_server_number log_file, number
0
     end
0
     
0
- def pid_for(port)
0
- File.read(pid_file_for(port)).chomp.to_i
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, port)
0
- shell_cmd = shellify(cmd, options.merge(:port => port, :pid => pid_file_for(port), :log => log_file_for(port)))
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
+ shell_cmd = shellify(cmd, cmd_options)
0
         trace shell_cmd
0
         ouput = `#{shell_cmd}`.chomp
0
- log ouput unless ouput.empty?
0
+ log " " + ouput.gsub("\n", " \n") unless ouput.empty?
0
       end
0
       
0
       # Turn into a runnable shell command
0
0
0
@@ -93,14 +118,16 @@
0
       end
0
       
0
       def with_each_server
0
- @size.times { |n| yield first_port + n }
0
+ @size.times do |n|
0
+ yield socket ? n : (first_port + n)
0
+ end
0
       end
0
       
0
- # Add the port numbers in the filename
0
+ # Add the server port or number in the filename
0
       # so each instance get its own file
0
- def include_port_number(path, port)
0
- raise ArgumentError, "filename '#{path}' must include an extension" unless path =~ /\./
0
- path.gsub(/\.(.+)$/) { ".#{port}.#{$1}" }
0
+ def include_server_number(path, number)
0
+ ext = File.extname(path)
0
+ path.gsub(/#{ext}$/, ".#{number}#{ext}")
0
       end
0
   end
0
 end
...
4
5
6
 
7
8
 
 
 
9
10
11
...
24
25
26
27
 
28
29
30
...
45
46
47
 
 
 
 
 
 
 
 
 
 
 
 
48
49
...
4
5
6
7
8
9
10
11
12
13
14
15
...
28
29
30
 
31
32
33
34
...
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
0
@@ -4,8 +4,12 @@
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
+
0
     def post_init
0
       @request = Request.new
0
       @response = Response.new
0
@@ -24,7 +28,7 @@
0
       env = @request.env
0
       
0
       # Add client info to the request env
0
- env[Request::REMOTE_ADDR] = env[Request::FORWARDED_FOR] || Socket.unpack_sockaddr_in(get_peername)[1]
0
+ env[Request::REMOTE_ADDR] = remote_address(env)
0
       
0
       # Process the request
0
       @response.status, @response.headers, @response.body = @app.call(env)
0
@@ -45,6 +49,18 @@
0
       @request.close rescue nil
0
       @response.close rescue nil
0
     end
0
+
0
+ protected
0
+ def remote_address(env)
0
+ if remote_addr = env[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
+ end
0
   end
0
 end
...
15
16
17
 
 
 
18
19
20
...
22
23
24
25
 
 
 
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
...
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
...
15
16
17
18
19
20
21
22
23
...
25
26
27
 
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
...
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
114
115
116
117
118
119
120
121
0
@@ -15,6 +15,9 @@
0
     # Addresse and port on which the server is listening for connections.
0
     attr_accessor :port, :host
0
     
0
+ # UNIX domain socket on which the server is listening for connections.
0
+ attr_accessor :socket
0
+
0
     # App called with the request that produce the response.
0
     attr_accessor :app
0
     
0
@@ -22,7 +25,9 @@
0
     attr_accessor :timeout
0
     
0
     # Creates a new server binded to <tt>host:port</tt>
0
- # that will pass request to +app+.
0
+ # or to +socket+ that will pass request to +app+.
0
+ # If +host_or_socket+ contains a <tt>/</tt> it is assumed
0
+ # to be a UNIX domain socket filename.
0
     # If a block is passed, a <tt>Rack::Builder</tt> instance
0
     # will be passed to build the +app+.
0
     #
0
0
0
0
0
0
0
0
0
0
0
0
0
@@ -33,66 +38,85 @@
0
     # use Rack::Lint
0
     # run Rack::Lobster.new
0
     # end
0
- # end.start!
0
+ # end.start
0
     #
0
- def initialize(host, port, app=nil, &block)
0
- @host = host
0
- @port = port.to_i
0
+ def initialize(host_or_socket, port=3000, app=nil, &block)
0
+ if host_or_socket.include?('/')
0
+ @socket = host_or_socket
0
+ else
0
+ @host = host_or_socket
0
+ @port = port.to_i
0
+ end
0
       @app = app
0
       @timeout = 60 # sec
0
       
0
       @app = Rack::Builder.new(&block).to_app if block
0
     end
0
     
0
- def self.start(host, port, &block)
0
- new(host, port, &block).start!
0
+ def self.start(*args, &block)
0
+ new(*args, &block).start!
0
     end
0
     
0
- # Starts the handlers.
0
+ # Start the server and listen for connections
0
     def start
0
       raise ArgumentError, "app required" unless @app
0
       
0
- log ">> Thin web server (v#{VERSION::STRING} codename #{VERSION::CODENAME})"
0
- trace ">> Tracing ON"
0
- end
0
-
0
- # Start the server and listen for connections
0
- def start!
0
- start
0
- listen!
0
- end
0
-
0
- # Start listening for connections
0
- def listen!
0
       trap('INT') { stop }
0
       trap('TERM') { stop! }
0
-
0
+
0
       # See http://rubyeventmachine.com/pub/rdoc/files/EPOLL.html
0
       EventMachine.epoll
0
       
0
+ log ">> Thin web server (v#{VERSION::STRING} codename #{VERSION::CODENAME})"
0
+ trace ">> Tracing ON"
0
+
0
       EventMachine.run do
0
         begin
0
- log ">> Listening on #{@host}:#{@port}, CTRL+C to stop"
0
- EventMachine.start_server(@host, @port, Connection) do |connection|
0
- connection.comm_inactivity_timeout = @timeout
0
- connection.app = @app
0
- connection.silent = @silent
0
- end
0
+ start_server
0
         rescue StopServer
0
- EventMachine.stop_event_loop
0
+ stop
0
         end
0
       end
0
     end
0
+ alias :start! :start
0
     
0
+ # Stops the server by stopping the listening loop.
0
     def stop
0
       EventMachine.stop_event_loop
0
     rescue
0
       warn "Error stopping : #{$!}"
0
     end
0
     
0
+ # Stops the server by raising an error.
0
     def stop!
0
       raise StopServer
0
     end
0
+
0
+ protected
0
+ def start_server
0
+ if @socket
0
+ start_server_on_socket
0
+ else
0
+ start_server_on_host
0
+ end
0
+ end
0
+
0
+ def start_server_on_host
0
+ log ">> Listening on #{@host}:#{@port}, CTRL+C to stop"
0
+ EventMachine.start_server(@host, @port, Connection, &method(:initialize_connection))
0
+ end
0
+
0
+ def start_server_on_socket
0
+ log ">> Listening on #{@socket}, CTRL+C to stop"
0
+ EventMachine.start_unix_domain_server(@socket, Connection, &method(:initialize_connection))
0
+ end
0
+
0
+ def initialize_connection(connection)
0
+ connection.comm_inactivity_timeout = @timeout
0
+ connection.app = @app
0
+ connection.silent = @silent
0
+ connection.unix_socket = !@socket.nil?
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
...
41
42
43
 
44
45
46
47
 
48
49
50
51
52
 
53
54
55
56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
58
...
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
...
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
0
@@ -1,25 +1,24 @@
0
 require File.dirname(__FILE__) + '/spec_helper'
0
 
0
-describe Cluster do
0
+describe Cluster, "with host and port" do
0
   before do
0
- @cluster = Thin::Cluster.new(:chdir => File.dirname(__FILE__) + '/rails_app',
0
- :address => '0.0.0.0',
0
- :port => 3000,
0
- :servers => 3,
0
- :timeout => 10,
0
- :log => 'thin.log',
0
- :pid => 'thin.pid'
0
- )
0
+ @cluster = Cluster.new(:chdir => File.dirname(__FILE__) + '/rails_app',
0
+ :address => '0.0.0.0',
0
+ :port => 3000,
0
+ :servers => 3,
0
+ :timeout => 10,
0
+ :log => 'thin.log',
0
+ :pid => 'thin.pid'
0
+ )
0
     @cluster.script = File.dirname(__FILE__) + '/../bin/thin'
0
     @cluster.silent = true
0
   end
0
     
0
   it 'should include port number in file names' do
0
- @cluster.send(:include_port_number, 'thin.log', 3000).should == 'thin.3000.log'
0
- @cluster.send(:include_port_number, 'thin.pid', 3000).should == 'thin.3000.pid'
0
- proc { @cluster.send(:include_port_number, 'thin', 3000) }.should raise_error(ArgumentError)
0
+ @cluster.send(:include_server_number, 'thin.log', 3000).should == 'thin.3000.log'
0
+ @cluster.send(:include_server_number, 'thin.pid', 3000).should == 'thin.3000.pid'
0
   end
0
-
0
+
0
   it 'should call each server' do
0
     calls = []
0
     @cluster.send(:with_each_server) do |port|
0
0
0
0
@@ -41,19 +40,70 @@
0
   it 'should start on specified port' do
0
     @cluster.should_receive(:`) do |with|
0
       with.should include('thin start', '--daemonize', 'thin.3001.log', 'thin.3001.pid', '--port=3001')
0
+ with.should_not include('--socket')
0
       ''
0
     end
0
 
0
- @cluster.start_on_port 3001
0
+ @cluster.start_server 3001
0
   end
0
 
0
   it 'should stop on specified port' do
0
     @cluster.should_receive(:`) do |with|
0
       with.should include('thin stop', '--daemonize', 'thin.3001.log', 'thin.3001.pid', '--port=3001')
0
+ with.should_not include('--socket')
0
       ''
0
     end
0
 
0
- @cluster.stop_on_port 3001
0
+ @cluster.stop_server 3001
0
+ end
0
+end
0
+
0
+describe Cluster, "with UNIX socket" do
0
+ before do
0
+ @cluster = Cluster.new(:chdir => File.dirname(__FILE__) + '/rails_app',
0
+ :socket => '/tmp/thin.sock',
0
+ :address => '0.0.0.0',
0
+ :port => 3000,
0
+ :servers => 3,
0
+ :timeout => 10,
0
+ :log => 'thin.log',
0
+ :pid => 'thin.pid'
0
+ )
0
+ @cluster.script = File.dirname(__FILE__) + '/../bin/thin'
0
+ @cluster.silent = true
0
+ end
0
+
0
+ it 'should include socket number in file names' do
0
+ @cluster.send(:include_server_number, 'thin.sock', 0).should == 'thin.0.sock'
0
+ @cluster.send(:include_server_number, 'thin', 0).should == 'thin.0'
0
+ end
0
+
0
+ it 'should call each server' do
0
+ calls = []
0
+ @cluster.send(:with_each_server) do |n|
0
+ calls << n
0
+ end
0
+ calls.should == [0, 1, 2]
0
+ end
0
+
0
+ it 'should start specified server' do
0
+ @cluster.should_receive(:`) do |with|
0
+ with.should include('thin start', '--daemonize', 'thin.1.log', 'thin.1.pid', '--socket="/tmp/thin.1.sock"')
0
+ with.should_not include('--port', '--address')
0
+ ''
0
+ end
0
+
0
+ @cluster.start_server 1
0
+ end
0
+
0
+ it 'should stop specified server' do
0
+ @cluster.should_receive(:`) do |with|
0
+ with.should include('thin stop', '--daemonize', 'thin.1.log', 'thin.1.pid', '--socket="/tmp/thin.1.sock"')
0
+ with.should_not include('--port', '--address')
0
+ ''
0
+ end
0
+
0
+ @cluster.stop_server 1
0
   end
0
 end
...
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
...
41
42
43
44
 
45
46
47
48
49
 
50
51
52
...
57
58
59
 
 
 
 
60
61
62
...
114
115
116
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
...
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
...
38
39
40
 
41
42
43
44
45
 
46
47
48
49
...
54
55
56
57
58
59
60
61
62
63
...
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
0
@@ -6,30 +6,27 @@
0
   before do
0
     app = proc do |env|
0
       body = ''
0
- body << env['QUERY_STRING'].to_s
0
- body << env['rack.input'].read.to_s
0
+ body << env.inspect
0
+ body << env['rack.input'].read
0
       [200, { 'Content-Type' => 'text/html', 'Content-Length' => body.size.to_s }, body]
0
     end
0
     server = Thin::Server.new('0.0.0.0', 3333, app)
0
     server.timeout = 3
0
     server.silent = true
0
     
0
- server.start
0
- @thread = Thread.new do
0
- server.listen!
0
- end
0
+ @thread = Thread.new { server.start }
0
     sleep 0.1 until @thread.status == 'sleep'
0
   end
0
     
0
   it 'should GET from Net::HTTP' do
0
- get('/?cthis').should == 'cthis'
0
+ get('/?cthis').should include('cthis')
0
   end
0
   
0
   it 'should GET from TCPSocket' do
0
     raw('0.0.0.0', 3333, "GET /?this HTTP/1.1\r\n\r\n").
0
       should include("HTTP/1.1 200 OK",
0
- "Content-Type: text/html", "Content-Length: 4",
0
- "Connection: close", "\r\n\r\nthis")
0
+ "Content-Type: text/html", "Content-Length: ",
0
+ "Connection: close", "this")
0
   end
0
   
0
   it 'should return empty string on incomplete headers' do
0
0
@@ -41,12 +38,12 @@
0
   end
0
   
0
   it 'should POST from Net::HTTP' do
0
- post('/', :arg => 'pirate').should == 'arg=pirate'
0
+ post('/', :arg => 'pirate').should include('arg=pirate')
0
   end
0
   
0
   it 'should handle big POST' do
0
     big = 'X' * (20 * 1024)
0
- post('/', :big => big).size.should == big.size + 4
0
+ post('/', :big => big).should include(big)
0
   end
0
   
0
   it "should handle GET in less then #{get_request_time = 0.004} RubySecond" do
0
@@ -57,6 +54,10 @@
0
     proc { post('/', :file => 'X' * 1000) }.should be_faster_then(post_request_time)
0
   end
0
   
0
+ it "should retreive remote address" do
0
+ get('/').should include('"REMOTE_ADDR"=>"127.0.0.1"')
0
+ end
0
+
0
   after do
0
     @thread.kill
0
   end
0
@@ -114,5 +115,48 @@
0
     server.app.call({})[0].should == 404
0
     server.app.call({'PATH_INFO' => '/test'}).should == :works
0
   end
0
+end
0
+
0
+describe Server, "on UNIX domain socket" do
0
+ before do
0
+ app = proc do |env|
0
+ [200, { 'Content-Type' => 'text/html' }, [env.inspect]]
0
+ end
0
+ server = Thin::Server.new('/tmp/thin_test.sock', nil, app)
0
+ server.timeout = 3
0
+ server.silent = true
0
+
0
+ @thread = Thread.new { server.start }
0
+ sleep 0.1 until @thread.status == 'sleep'
0
+ end
0
+
0
+ it "should accept GET request" do
0
+ get("/?this").should include('this')
0
+ end
0
+
0
+ it "should retreive remote address" do
0
+ get('/').should include('"REMOTE_ADDR"=>""') # Is that right?
0
+ end
0
+
0
+ it "should handle GET in less then #{get_request_time = 0.002} RubySecond" do
0
+ proc { get('/') }.should be_faster_then(get_request_time)
0
+ end
0
+
0
+ after do
0
+ @thread.kill
0
+ end
0
+
0
+ private
0
+ def get(url)
0
+ send_data("GET #{url} HTTP/1.1\r\n\r\n")
0
+ end
0
+
0
+ def send_data(data)
0
+ socket = UNIXSocket.new('/tmp/thin_test.sock')
0
+ socket.write data
0
+ out = socket.read
0
+ socket.close
0
+ out
0
+ end
0
 end

Comments

    No one has commented yet.