thin 1.2.3-x86-mswin32

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of thin might be problematic. Click here for more details.

Files changed (137) hide show
  1. data/CHANGELOG +263 -0
  2. data/COPYING +18 -0
  3. data/README +69 -0
  4. data/Rakefile +36 -0
  5. data/benchmark/abc +51 -0
  6. data/benchmark/benchmarker.rb +80 -0
  7. data/benchmark/runner +82 -0
  8. data/bin/thin +6 -0
  9. data/example/adapter.rb +32 -0
  10. data/example/async_app.ru +126 -0
  11. data/example/async_chat.ru +247 -0
  12. data/example/async_tailer.ru +100 -0
  13. data/example/config.ru +22 -0
  14. data/example/monit_sockets +20 -0
  15. data/example/monit_unixsock +20 -0
  16. data/example/myapp.rb +1 -0
  17. data/example/ramaze.ru +12 -0
  18. data/example/thin.god +80 -0
  19. data/example/thin_solaris_smf.erb +36 -0
  20. data/example/thin_solaris_smf.readme.txt +150 -0
  21. data/example/vlad.rake +64 -0
  22. data/ext/thin_parser/common.rl +55 -0
  23. data/ext/thin_parser/ext_help.h +14 -0
  24. data/ext/thin_parser/extconf.rb +6 -0
  25. data/ext/thin_parser/parser.c +452 -0
  26. data/ext/thin_parser/parser.h +49 -0
  27. data/ext/thin_parser/parser.rl +157 -0
  28. data/ext/thin_parser/thin.c +433 -0
  29. data/lib/rack/adapter/loader.rb +79 -0
  30. data/lib/rack/adapter/rails.rb +181 -0
  31. data/lib/thin.rb +46 -0
  32. data/lib/thin/backends/base.rb +141 -0
  33. data/lib/thin/backends/swiftiply_client.rb +56 -0
  34. data/lib/thin/backends/tcp_server.rb +29 -0
  35. data/lib/thin/backends/unix_server.rb +51 -0
  36. data/lib/thin/command.rb +53 -0
  37. data/lib/thin/connection.rb +222 -0
  38. data/lib/thin/controllers/cluster.rb +127 -0
  39. data/lib/thin/controllers/controller.rb +183 -0
  40. data/lib/thin/controllers/service.rb +75 -0
  41. data/lib/thin/controllers/service.sh.erb +39 -0
  42. data/lib/thin/daemonizing.rb +174 -0
  43. data/lib/thin/headers.rb +39 -0
  44. data/lib/thin/logging.rb +54 -0
  45. data/lib/thin/request.rb +153 -0
  46. data/lib/thin/response.rb +101 -0
  47. data/lib/thin/runner.rb +209 -0
  48. data/lib/thin/server.rb +247 -0
  49. data/lib/thin/stats.html.erb +216 -0
  50. data/lib/thin/stats.rb +52 -0
  51. data/lib/thin/statuses.rb +43 -0
  52. data/lib/thin/version.rb +32 -0
  53. data/lib/thin_parser.so +0 -0
  54. data/spec/backends/swiftiply_client_spec.rb +66 -0
  55. data/spec/backends/tcp_server_spec.rb +33 -0
  56. data/spec/backends/unix_server_spec.rb +37 -0
  57. data/spec/command_spec.rb +25 -0
  58. data/spec/configs/cluster.yml +9 -0
  59. data/spec/configs/single.yml +9 -0
  60. data/spec/connection_spec.rb +106 -0
  61. data/spec/controllers/cluster_spec.rb +235 -0
  62. data/spec/controllers/controller_spec.rb +129 -0
  63. data/spec/controllers/service_spec.rb +50 -0
  64. data/spec/daemonizing_spec.rb +192 -0
  65. data/spec/headers_spec.rb +40 -0
  66. data/spec/logging_spec.rb +46 -0
  67. data/spec/perf/request_perf_spec.rb +50 -0
  68. data/spec/perf/response_perf_spec.rb +19 -0
  69. data/spec/perf/server_perf_spec.rb +39 -0
  70. data/spec/rack/loader_spec.rb +29 -0
  71. data/spec/rack/rails_adapter_spec.rb +106 -0
  72. data/spec/rails_app/app/controllers/application.rb +10 -0
  73. data/spec/rails_app/app/controllers/simple_controller.rb +19 -0
  74. data/spec/rails_app/app/helpers/application_helper.rb +3 -0
  75. data/spec/rails_app/app/views/simple/index.html.erb +15 -0
  76. data/spec/rails_app/config/boot.rb +109 -0
  77. data/spec/rails_app/config/environment.rb +64 -0
  78. data/spec/rails_app/config/environments/development.rb +18 -0
  79. data/spec/rails_app/config/environments/production.rb +19 -0
  80. data/spec/rails_app/config/environments/test.rb +22 -0
  81. data/spec/rails_app/config/initializers/inflections.rb +10 -0
  82. data/spec/rails_app/config/initializers/mime_types.rb +5 -0
  83. data/spec/rails_app/config/routes.rb +35 -0
  84. data/spec/rails_app/public/404.html +30 -0
  85. data/spec/rails_app/public/422.html +30 -0
  86. data/spec/rails_app/public/500.html +30 -0
  87. data/spec/rails_app/public/dispatch.cgi +10 -0
  88. data/spec/rails_app/public/dispatch.fcgi +24 -0
  89. data/spec/rails_app/public/dispatch.rb +10 -0
  90. data/spec/rails_app/public/favicon.ico +0 -0
  91. data/spec/rails_app/public/images/rails.png +0 -0
  92. data/spec/rails_app/public/index.html +277 -0
  93. data/spec/rails_app/public/javascripts/application.js +2 -0
  94. data/spec/rails_app/public/javascripts/controls.js +963 -0
  95. data/spec/rails_app/public/javascripts/dragdrop.js +972 -0
  96. data/spec/rails_app/public/javascripts/effects.js +1120 -0
  97. data/spec/rails_app/public/javascripts/prototype.js +4225 -0
  98. data/spec/rails_app/public/robots.txt +5 -0
  99. data/spec/rails_app/script/about +3 -0
  100. data/spec/rails_app/script/console +3 -0
  101. data/spec/rails_app/script/destroy +3 -0
  102. data/spec/rails_app/script/generate +3 -0
  103. data/spec/rails_app/script/performance/benchmarker +3 -0
  104. data/spec/rails_app/script/performance/profiler +3 -0
  105. data/spec/rails_app/script/performance/request +3 -0
  106. data/spec/rails_app/script/plugin +3 -0
  107. data/spec/rails_app/script/process/inspector +3 -0
  108. data/spec/rails_app/script/process/reaper +3 -0
  109. data/spec/rails_app/script/process/spawner +3 -0
  110. data/spec/rails_app/script/runner +3 -0
  111. data/spec/rails_app/script/server +3 -0
  112. data/spec/request/mongrel_spec.rb +39 -0
  113. data/spec/request/parser_spec.rb +215 -0
  114. data/spec/request/persistent_spec.rb +35 -0
  115. data/spec/request/processing_spec.rb +45 -0
  116. data/spec/response_spec.rb +91 -0
  117. data/spec/runner_spec.rb +168 -0
  118. data/spec/server/builder_spec.rb +44 -0
  119. data/spec/server/pipelining_spec.rb +110 -0
  120. data/spec/server/robustness_spec.rb +34 -0
  121. data/spec/server/stopping_spec.rb +55 -0
  122. data/spec/server/swiftiply.yml +6 -0
  123. data/spec/server/swiftiply_spec.rb +32 -0
  124. data/spec/server/tcp_spec.rb +57 -0
  125. data/spec/server/threaded_spec.rb +27 -0
  126. data/spec/server/unix_socket_spec.rb +26 -0
  127. data/spec/server_spec.rb +96 -0
  128. data/spec/spec_helper.rb +219 -0
  129. data/tasks/announce.rake +22 -0
  130. data/tasks/deploy.rake +13 -0
  131. data/tasks/email.erb +30 -0
  132. data/tasks/gem.rake +74 -0
  133. data/tasks/rdoc.rake +25 -0
  134. data/tasks/site.rake +15 -0
  135. data/tasks/spec.rake +49 -0
  136. data/tasks/stats.rake +28 -0
  137. metadata +246 -0
@@ -0,0 +1,168 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe Runner do
4
+ it "should parse options" do
5
+ runner = Runner.new(%w(start --pid test.pid --port 5000 -o 3000))
6
+
7
+ runner.options[:pid].should == 'test.pid'
8
+ runner.options[:port].should == 5000
9
+ runner.options[:only].should == 3000
10
+ end
11
+
12
+ it "should parse specified command" do
13
+ Runner.new(%w(start)).command.should == 'start'
14
+ Runner.new(%w(stop)).command.should == 'stop'
15
+ Runner.new(%w(restart)).command.should == 'restart'
16
+ end
17
+
18
+ it "should abort on unknow command" do
19
+ runner = Runner.new(%w(poop))
20
+
21
+ runner.should_receive(:abort)
22
+ runner.run!
23
+ end
24
+
25
+ it "should exit on empty command" do
26
+ runner = Runner.new([])
27
+
28
+ runner.should_receive(:exit).with(1)
29
+
30
+ silence_stream(STDOUT) do
31
+ runner.run!
32
+ end
33
+ end
34
+
35
+ it "should use Controller when controlling a single server" do
36
+ runner = Runner.new(%w(start))
37
+
38
+ controller = mock('controller')
39
+ controller.should_receive(:start)
40
+ Controllers::Controller.should_receive(:new).and_return(controller)
41
+
42
+ runner.run!
43
+ end
44
+
45
+ it "should use Cluster controller when controlling multiple servers" do
46
+ runner = Runner.new(%w(start --servers 3))
47
+
48
+ controller = mock('cluster')
49
+ controller.should_receive(:start)
50
+ Controllers::Cluster.should_receive(:new).and_return(controller)
51
+
52
+ runner.run!
53
+ end
54
+
55
+ it "should default to single server controller" do
56
+ Runner.new(%w(start)).should_not be_a_cluster
57
+ end
58
+
59
+ it "should consider as a cluster with :servers option" do
60
+ Runner.new(%w(start --servers 3)).should be_a_cluster
61
+ end
62
+
63
+ it "should consider as a cluster with :only option" do
64
+ Runner.new(%w(start --only 3000)).should be_a_cluster
65
+ end
66
+
67
+ it "should warn when require a rack config file" do
68
+ STDERR.stub!(:write)
69
+ STDERR.should_receive(:write).with(/WARNING:/)
70
+
71
+ runner = Runner.new(%w(start -r config.ru))
72
+ runner.run! rescue nil
73
+
74
+ runner.options[:rackup].should == 'config.ru'
75
+ end
76
+
77
+ it "should require file" do
78
+ runner = Runner.new(%w(start -r unexisting))
79
+ proc { runner.run! }.should raise_error(LoadError)
80
+ end
81
+
82
+ it "should remember requires" do
83
+ runner = Runner.new(%w(start -r rubygems -r thin))
84
+ runner.options[:require].should == %w(rubygems thin)
85
+ end
86
+
87
+ it "should remember debug options" do
88
+ runner = Runner.new(%w(start -D -V))
89
+ runner.options[:debug].should be_true
90
+ runner.options[:trace].should be_true
91
+ end
92
+
93
+ it "should default debug and trace to false" do
94
+ runner = Runner.new(%w(start))
95
+ runner.options[:debug].should_not be_true
96
+ runner.options[:trace].should_not be_true
97
+ end
98
+ end
99
+
100
+ describe Runner, 'with config file' do
101
+ before do
102
+ @runner = Runner.new(%w(start --config spec/configs/cluster.yml))
103
+ end
104
+
105
+ it "should load options from file with :config option" do
106
+ @runner.send :load_options_from_config_file!
107
+
108
+ @runner.options[:environment].should == 'production'
109
+ @runner.options[:chdir].should == 'spec/rails_app'
110
+ @runner.options[:port].should == 5000
111
+ @runner.options[:servers].should == 3
112
+ end
113
+
114
+ it "should change directory after loading config" do
115
+ @orig_dir = Dir.pwd
116
+
117
+ controller = mock('controller')
118
+ controller.should_receive(:respond_to?).with('start').and_return(true)
119
+ controller.should_receive(:start)
120
+ Controllers::Cluster.should_receive(:new).and_return(controller)
121
+ expected_dir = File.expand_path('spec/rails_app')
122
+
123
+ begin
124
+ silence_stream(STDERR) do
125
+ @runner.run!
126
+ end
127
+
128
+ Dir.pwd.should == expected_dir
129
+
130
+ ensure
131
+ # any other spec using relative paths should work as expected
132
+ Dir.chdir(@orig_dir)
133
+ end
134
+ end
135
+ end
136
+
137
+ describe Runner, "service" do
138
+ before do
139
+ Thin.stub!(:linux?).and_return(true)
140
+
141
+ @controller = mock('service')
142
+ Controllers::Service.stub!(:new).and_return(@controller)
143
+ end
144
+
145
+ it "should use Service controller when controlling all servers" do
146
+ runner = Runner.new(%w(start --all))
147
+
148
+ @controller.should_receive(:start)
149
+
150
+ runner.run!
151
+ end
152
+
153
+ it "should call install with arguments" do
154
+ runner = Runner.new(%w(install /etc/cool))
155
+
156
+ @controller.should_receive(:install).with('/etc/cool')
157
+
158
+ runner.run!
159
+ end
160
+
161
+ it "should call install without arguments" do
162
+ runner = Runner.new(%w(install))
163
+
164
+ @controller.should_receive(:install).with()
165
+
166
+ runner.run!
167
+ end
168
+ end
@@ -0,0 +1,44 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Server, 'app builder' do
4
+ it "should build app from constructor" do
5
+ app = proc {}
6
+ server = Server.new('0.0.0.0', 3000, app)
7
+
8
+ server.app.should == app
9
+ end
10
+
11
+ it "should build app from builder block" do
12
+ server = Server.new '0.0.0.0', 3000 do
13
+ run(proc { |env| :works })
14
+ end
15
+
16
+ server.app.call({}).should == :works
17
+ end
18
+
19
+ it "should use middlewares in builder block" do
20
+ server = Server.new '0.0.0.0', 3000 do
21
+ use Rack::ShowExceptions
22
+ run(proc { |env| :works })
23
+ end
24
+
25
+ server.app.class.should == Rack::ShowExceptions
26
+ server.app.call({}).should == :works
27
+ end
28
+
29
+ it "should work with Rack url mapper" do
30
+ server = Server.new '0.0.0.0', 3000 do
31
+ map '/test' do
32
+ run(proc { |env| [200, {}, 'Found /test'] })
33
+ end
34
+ end
35
+
36
+ default_env = { 'SCRIPT_NAME' => '' }
37
+
38
+ server.app.call(default_env.update('PATH_INFO' => '/'))[0].should == 404
39
+
40
+ status, headers, body = server.app.call(default_env.update('PATH_INFO' => '/test'))
41
+ status.should == 200
42
+ body.should == 'Found /test'
43
+ end
44
+ end
@@ -0,0 +1,110 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Server, "HTTP pipelining" do
4
+ before do
5
+ calls = 0
6
+ start_server do |env|
7
+ calls += 1
8
+ body = env['PATH_INFO'] + '-' + calls.to_s
9
+ [200, { 'Content-Type' => 'text/html' }, body]
10
+ end
11
+ @server.maximum_persistent_connections = 1024
12
+ end
13
+
14
+ it "should pipeline request on same socket" do
15
+ socket = TCPSocket.new('0.0.0.0', 3333)
16
+ socket.write "GET /first HTTP/1.1\r\nConnection: keep-alive\r\n\r\n"
17
+ socket.flush
18
+ socket.write "GET /second HTTP/1.1\r\nConnection: close\r\n\r\n"
19
+ socket.flush
20
+ response = socket.read
21
+ socket.close
22
+
23
+ wait_for_requests_to_complete!
24
+
25
+ response.should include('/first-1', '/second-2')
26
+ end
27
+
28
+ it "should pipeline requests by default on HTTP 1.1" do
29
+ socket = TCPSocket.new('0.0.0.0', 3333)
30
+ socket.write "GET /first HTTP/1.1\r\n\r\n"
31
+ socket.flush
32
+ socket.write "GET /second HTTP/1.1\r\nConnection: close\r\n\r\n"
33
+ socket.flush
34
+ response = socket.read
35
+ socket.close
36
+
37
+ wait_for_requests_to_complete!
38
+
39
+ response.should include('/first-1', '/second-2')
40
+ end
41
+
42
+ it "should not pipeline request by default on HTTP 1.0" do
43
+ socket = TCPSocket.new('0.0.0.0', 3333)
44
+ socket.write "GET /first HTTP/1.0\r\n\r\n"
45
+ socket.flush
46
+ socket.write "GET /second HTTP/1.0\r\nConnection: close\r\n\r\n"
47
+ response = socket.read
48
+ socket.close
49
+
50
+ wait_for_requests_to_complete!
51
+
52
+ response.should include('/first-1')
53
+ response.should_not include('/second-2')
54
+ end
55
+
56
+ it "should not pipeline request on same socket when connection is closed" do
57
+ socket = TCPSocket.new('0.0.0.0', 3333)
58
+ socket.write "GET /first HTTP/1.1\r\nConnection: close\r\n\r\n"
59
+ socket.flush
60
+ socket.write "GET /second HTTP/1.1\r\nConnection: close\r\n\r\n"
61
+ response = socket.read
62
+ socket.close
63
+
64
+ wait_for_requests_to_complete!
65
+
66
+ response.should include('/first-1')
67
+ response.should_not include('/second-2')
68
+ end
69
+
70
+ it "should not allow more persistent connection then maximum" do
71
+ @server.maximum_persistent_connections = 1
72
+
73
+ socket1 = TCPSocket.new('0.0.0.0', 3333)
74
+ socket1.write "GET / HTTP/1.1\r\n\r\n"
75
+ socket1.flush
76
+ socket2 = TCPSocket.new('0.0.0.0', 3333)
77
+ socket2.write "GET / HTTP/1.1\r\n\r\n"
78
+ socket2.flush
79
+
80
+ @server.backend.persistent_connection_count.should == 1
81
+ @server.backend.size.should == 2
82
+
83
+ socket1.close
84
+ socket2.close
85
+ end
86
+
87
+ it "should decrement persistent connection on close" do
88
+ socket = TCPSocket.new('0.0.0.0', 3333)
89
+ socket.write "GET / HTTP/1.1\r\n\r\n"
90
+ socket.flush
91
+
92
+ @server.backend.persistent_connection_count.should == 1
93
+
94
+ socket.write "GET / HTTP/1.1\r\nConnection: close\r\n\r\n"
95
+ socket.close
96
+
97
+ wait_for_requests_to_complete!
98
+
99
+ @server.backend.persistent_connection_count.should == 0
100
+ end
101
+
102
+ after do
103
+ stop_server
104
+ end
105
+
106
+ private
107
+ def wait_for_requests_to_complete!
108
+ sleep 0.1 until @server.backend.size == 0
109
+ end
110
+ end
@@ -0,0 +1,34 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Server, 'robustness' do
4
+ before do
5
+ start_server do |env|
6
+ body = 'hello!'
7
+ [200, { 'Content-Type' => 'text/html' }, body]
8
+ end
9
+ end
10
+
11
+ it "should not crash when header too large" do
12
+ 100.times do
13
+ begin
14
+ socket = TCPSocket.new(DEFAULT_TEST_ADDRESS, DEFAULT_TEST_PORT)
15
+ socket.write("GET / HTTP/1.1\r\n")
16
+ socket.write("Host: localhost\r\n")
17
+ socket.write("Connection: close\r\n")
18
+ 10000.times do
19
+ socket.write("X-Foo: #{'x' * 100}\r\n")
20
+ socket.flush
21
+ end
22
+ socket.write("\r\n")
23
+ socket.read
24
+ socket.close
25
+ rescue Errno::EPIPE, Errno::ECONNRESET
26
+ # Ignore.
27
+ end
28
+ end
29
+ end
30
+
31
+ after do
32
+ stop_server
33
+ end
34
+ end
@@ -0,0 +1,55 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Server, "stopping" do
4
+ before do
5
+ start_server do |env|
6
+ [200, { 'Content-Type' => 'text/html' }, ['ok']]
7
+ end
8
+ @done = false
9
+ end
10
+
11
+ it "should wait for current requests before soft stopping" do
12
+ socket = TCPSocket.new('0.0.0.0', 3333)
13
+ socket.write("GET / HTTP/1.1")
14
+ EventMachine.next_tick do
15
+ @server.stop # Stop the server in the middle of a request
16
+ socket.write("\r\n\r\n")
17
+ @done = true
18
+ end
19
+
20
+ timeout(2) do
21
+ Thread.pass until @done
22
+ end
23
+
24
+ out = socket.read
25
+ socket.close
26
+
27
+ out.should_not be_empty
28
+ end
29
+
30
+ it "should not accept new requests when soft stopping" do
31
+ socket = TCPSocket.new('0.0.0.0', 3333)
32
+ socket.write("GET / HTTP/1.1")
33
+ @server.stop # Stop the server in the middle of a request
34
+
35
+ EventMachine.next_tick do
36
+ proc { get('/') }.should raise_error(Errno::ECONNRESET)
37
+ end
38
+
39
+ socket.close
40
+ end
41
+
42
+ it "should drop current requests when hard stopping" do
43
+ socket = TCPSocket.new('0.0.0.0', 3333)
44
+ socket.write("GET / HTTP/1.1")
45
+ @server.stop! # Force stop the server in the middle of a request
46
+
47
+ EventMachine.next_tick do
48
+ socket.should be_closed
49
+ end
50
+ end
51
+
52
+ after do
53
+ stop_server
54
+ end
55
+ end
@@ -0,0 +1,6 @@
1
+ cluster_address: 0.0.0.0
2
+ cluster_port: 3333
3
+ map:
4
+ - incoming: 127.0.0.1
5
+ outgoing: 127.0.0.1:5555
6
+ default: true
@@ -0,0 +1,32 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ if SWIFTIPLY_PATH.empty?
4
+ warn "Ignoring Server on Swiftiply specs, gem install swiftiply to run"
5
+ else
6
+ describe Server, 'on Swiftiply' do
7
+ before do
8
+ @swiftiply = fork do
9
+ exec "#{SWIFTIPLY_PATH} -c #{File.dirname(__FILE__)}/swiftiply.yml"
10
+ end
11
+ wait_for_socket('0.0.0.0', 3333)
12
+ sleep 2 # HACK ooh boy, I wish I knew how to make those specs more stable...
13
+ start_server('0.0.0.0', 5555, :backend => Backends::SwiftiplyClient, :wait_for_socket => false) do |env|
14
+ body = env.inspect + env['rack.input'].read
15
+ [200, { 'Content-Type' => 'text/html' }, body]
16
+ end
17
+ end
18
+
19
+ it 'should GET from Net::HTTP' do
20
+ Net::HTTP.get(URI.parse("http://0.0.0.0:3333/?cthis")).should include('cthis')
21
+ end
22
+
23
+ it 'should POST from Net::HTTP' do
24
+ Net::HTTP.post_form(URI.parse("http://0.0.0.0:3333/"), :arg => 'pirate').body.should include('arg=pirate')
25
+ end
26
+
27
+ after do
28
+ stop_server
29
+ Process.kill(9, @swiftiply)
30
+ end
31
+ end
32
+ end