thin 1.2.6-x86-mingw32

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.
Files changed (137) hide show
  1. data/CHANGELOG +273 -0
  2. data/COPYING +18 -0
  3. data/README +69 -0
  4. data/Rakefile +39 -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 +1185 -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 +436 -0
  29. data/lib/rack/adapter/loader.rb +91 -0
  30. data/lib/rack/adapter/rails.rb +180 -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 +178 -0
  39. data/lib/thin/controllers/controller.rb +182 -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 +176 -0
  43. data/lib/thin/headers.rb +39 -0
  44. data/lib/thin/logging.rb +54 -0
  45. data/lib/thin/request.rb +157 -0
  46. data/lib/thin/response.rb +101 -0
  47. data/lib/thin/runner.rb +212 -0
  48. data/lib/thin/server.rb +248 -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 +267 -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 +42 -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 +243 -0
  114. data/spec/request/persistent_spec.rb +35 -0
  115. data/spec/request/processing_spec.rb +50 -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 +100 -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 +66 -0
  133. data/tasks/rdoc.rake +25 -0
  134. data/tasks/site.rake +15 -0
  135. data/tasks/spec.rake +43 -0
  136. data/tasks/stats.rake +28 -0
  137. metadata +219 -0
@@ -0,0 +1,57 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Server, 'on TCP socket' do
4
+ before do
5
+ start_server do |env|
6
+ body = env.inspect + env['rack.input'].read
7
+ [200, { 'Content-Type' => 'text/html' }, body]
8
+ end
9
+ end
10
+
11
+ it 'should GET from Net::HTTP' do
12
+ get('/?cthis').should include('cthis')
13
+ end
14
+
15
+ it 'should GET from TCPSocket' do
16
+ status, headers, body = parse_response(send_data("GET /?this HTTP/1.0\r\nConnection: close\r\n\r\n"))
17
+ status.should == 200
18
+ headers['Content-Type'].should == 'text/html'
19
+ headers['Connection'].should == 'close'
20
+ body.should include('this')
21
+ end
22
+
23
+ it "should add the Content-Length to the response when not present" do
24
+ status, headers, body = parse_response(send_data("GET / HTTP/1.0\r\nConnection: close\r\n\r\n"))
25
+ headers.should have_key('Content-Length')
26
+ end
27
+
28
+ it 'should set the Content-Length to equal the body size in bytes' do
29
+ status, headers, body = parse_response(send_data("GET / HTTP/1.0\r\nConnection: close\r\n\r\n"))
30
+ headers['Content-Length'].should == (body.respond_to?(:bytesize) ? body.bytesize : body.size).to_s
31
+ end
32
+
33
+ it 'should return empty string on incomplete headers' do
34
+ send_data("GET /?this HTTP/1.1\r\nHost:").should be_empty
35
+ end
36
+
37
+ it 'should return empty string on incorrect Content-Length' do
38
+ send_data("POST / HTTP/1.1\r\nContent-Length: 300\r\nConnection: close\r\n\r\naye").should be_empty
39
+ end
40
+
41
+ it 'should POST from Net::HTTP' do
42
+ post('/', :arg => 'pirate').should include('arg=pirate')
43
+ end
44
+
45
+ it 'should handle big POST' do
46
+ big = 'X' * (20 * 1024)
47
+ post('/', :big => big).should include(big)
48
+ end
49
+
50
+ it "should retreive remote address" do
51
+ get('/').should include('"REMOTE_ADDR"=>"127.0.0.1"')
52
+ end
53
+
54
+ after do
55
+ stop_server
56
+ end
57
+ end
@@ -0,0 +1,27 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Server, 'with threads' do
4
+ before do
5
+ @requests = 0
6
+ start_server DEFAULT_TEST_ADDRESS, DEFAULT_TEST_PORT, :threaded => true do |env|
7
+ sleep env['PATH_INFO'].delete('/').to_i
8
+ @requests += 1
9
+ [200, { 'Content-Type' => 'text/html' }, 'hi']
10
+ end
11
+ end
12
+
13
+ it "should process request" do
14
+ get('/').should_not be_empty
15
+ end
16
+
17
+ it "should process requests when blocked" do
18
+ slow_request = Thread.new { get('/3') }
19
+ get('/').should_not be_empty
20
+ @requests.should == 1
21
+ slow_request.kill
22
+ end
23
+
24
+ after do
25
+ stop_server
26
+ end
27
+ end
@@ -0,0 +1,26 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Server, "on UNIX domain socket" do
4
+ before do
5
+ start_server('/tmp/thin_test.sock') do |env|
6
+ [200, { 'Content-Type' => 'text/html' }, [env.inspect]]
7
+ end
8
+ end
9
+
10
+ it "should accept GET request" do
11
+ get("/?this").should include('this')
12
+ end
13
+
14
+ it "should retreive remote address" do
15
+ get('/').should include('"REMOTE_ADDR"=>"127.0.0.1"')
16
+ end
17
+
18
+ it "should remove socket file after server stops" do
19
+ @server.stop!
20
+ File.exist?('/tmp/thin_test.sock').should be_false
21
+ end
22
+
23
+ after do
24
+ stop_server
25
+ end
26
+ end
@@ -0,0 +1,100 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe Server do
4
+ before do
5
+ @server = Server.new('0.0.0.0', 3000)
6
+ end
7
+
8
+ it "should set maximum_connections size" do
9
+ @server.maximum_connections = 100
10
+ @server.config
11
+ @server.maximum_connections.should == 100
12
+ end
13
+
14
+ it "should set lower maximum_connections size when too large" do
15
+ # root users under Linux will not have a limitation on maximum
16
+ # connections, so we cannot really run this test under that
17
+ # condition.
18
+ pending("only for non-root users") if Process.euid == 0
19
+ @server.maximum_connections = 100_000
20
+ @server.config
21
+ @server.maximum_connections.should < 100_000
22
+ end
23
+
24
+ it "should default to non-threaded" do
25
+ @server.should_not be_threaded
26
+ end
27
+
28
+ it "should set backend to threaded" do
29
+ @server.threaded = true
30
+ @server.backend.should be_threaded
31
+ end
32
+ end
33
+
34
+ describe Server, "initialization" do
35
+ it "should set host and port" do
36
+ server = Server.new('192.168.1.1', 8080)
37
+
38
+ server.host.should == '192.168.1.1'
39
+ server.port.should == 8080
40
+ end
41
+
42
+ it "should set socket" do
43
+ server = Server.new('/tmp/thin.sock')
44
+
45
+ server.socket.should == '/tmp/thin.sock'
46
+ end
47
+
48
+ it "should set host, port and app" do
49
+ app = proc {}
50
+ server = Server.new('192.168.1.1', 8080, app)
51
+
52
+ server.host.should_not be_nil
53
+ server.app.should == app
54
+ end
55
+
56
+ it "should set socket and app" do
57
+ app = proc {}
58
+ server = Server.new('/tmp/thin.sock', app)
59
+
60
+ server.socket.should_not be_nil
61
+ server.app.should == app
62
+ end
63
+
64
+ it "should set socket, nil and app" do
65
+ app = proc {}
66
+ server = Server.new('/tmp/thin.sock', nil, app)
67
+
68
+ server.socket.should_not be_nil
69
+ server.app.should == app
70
+ end
71
+
72
+ it "should set host, port and backend" do
73
+ server = Server.new('192.168.1.1', 8080, :backend => Thin::Backends::SwiftiplyClient)
74
+
75
+ server.host.should_not be_nil
76
+ server.backend.should be_kind_of(Thin::Backends::SwiftiplyClient)
77
+ end
78
+
79
+ it "should set host, port, app and backend" do
80
+ app = proc {}
81
+ server = Server.new('192.168.1.1', 8080, app, :backend => Thin::Backends::SwiftiplyClient)
82
+
83
+ server.host.should_not be_nil
84
+ server.app.should == app
85
+ server.backend.should be_kind_of(Thin::Backends::SwiftiplyClient)
86
+ end
87
+
88
+ it "should set port as string" do
89
+ app = proc {}
90
+ server = Server.new('192.168.1.1', '8080')
91
+
92
+ server.host.should == '192.168.1.1'
93
+ server.port.should == 8080
94
+ end
95
+
96
+ it "should not register signals w/ :signals => false" do
97
+ Server.should_not_receive(:setup_signals)
98
+ Server.new(:signals => false)
99
+ end
100
+ end
@@ -0,0 +1,219 @@
1
+ require 'rubygems'
2
+ require 'thin'
3
+ require 'spec'
4
+ require 'benchmark'
5
+ require 'timeout'
6
+ require 'fileutils'
7
+ require 'net/http'
8
+ require 'socket'
9
+
10
+ include Thin
11
+
12
+ FileUtils.mkdir_p File.dirname(__FILE__) + '/../log'
13
+ Command.script = File.dirname(__FILE__) + '/../bin/thin'
14
+ Logging.silent = true
15
+
16
+ unless Object.const_defined?(:SWIFTIPLY_PATH)
17
+ SWIFTIPLY_PATH = `which swiftiply`.chomp
18
+ DEFAULT_TEST_ADDRESS = '0.0.0.0'
19
+ DEFAULT_TEST_PORT = 3333
20
+ end
21
+
22
+ module Matchers
23
+ class BeFasterThen
24
+ def initialize(max_time)
25
+ require 'benchmark_unit'
26
+ @max_time = max_time
27
+ end
28
+
29
+ # Base on benchmark_unit/assertions#compare_benchmarks
30
+ def matches?(proc)
31
+ @time, multiplier = 0, 1
32
+
33
+ while (@time < 0.01) do
34
+ @time = Benchmark::Unit.measure do
35
+ multiplier.times &proc
36
+ end
37
+ multiplier *= 10
38
+ end
39
+
40
+ multiplier /= 10
41
+
42
+ iterations = (Benchmark::Unit::CLOCK_TARGET / @time).to_i * multiplier
43
+ iterations = 1 if iterations < 1
44
+
45
+ total = Benchmark::Unit.measure do
46
+ iterations.times &proc
47
+ end
48
+
49
+ @time = total / iterations
50
+
51
+ @time < @max_time
52
+ end
53
+
54
+ def failure_message(less_more=:less)
55
+ "took <#{@time.inspect} RubySeconds>, should take #{less_more} than #{@max_time} RubySeconds."
56
+ end
57
+
58
+ def negative_failure_message
59
+ failure_message :more
60
+ end
61
+ end
62
+
63
+ class ValidateWithLint
64
+ def matches?(request)
65
+ @request = request
66
+ Rack::Lint.new(proc{[200, {'Content-Type' => 'text/html', 'Content-Length' => '0'}, []]}).call(@request.env)
67
+ true
68
+ rescue Rack::Lint::LintError => e
69
+ @message = e.message
70
+ false
71
+ end
72
+
73
+ def failure_message(negation=nil)
74
+ "should#{negation} validate with Rack Lint: #{@message}"
75
+ end
76
+
77
+ def negative_failure_message
78
+ failure_message ' not'
79
+ end
80
+ end
81
+
82
+ class TakeLessThen
83
+ def initialize(time)
84
+ @time = time
85
+ end
86
+
87
+ def matches?(proc)
88
+ Timeout.timeout(@time) { proc.call }
89
+ true
90
+ rescue Timeout::Error
91
+ false
92
+ end
93
+
94
+ def failure_message(negation=nil)
95
+ "should#{negation} take less then #{@time} sec to run"
96
+ end
97
+
98
+ def negative_failure_message
99
+ failure_message ' not'
100
+ end
101
+ end
102
+
103
+ # Actual matchers that are exposed.
104
+
105
+ def be_faster_then(time)
106
+ BeFasterThen.new(time)
107
+ end
108
+
109
+ def validate_with_lint
110
+ ValidateWithLint.new
111
+ end
112
+
113
+ def take_less_then(time)
114
+ TakeLessThen.new(time)
115
+ end
116
+ end
117
+
118
+ module Helpers
119
+ # Silences any stream for the duration of the block.
120
+ #
121
+ # silence_stream(STDOUT) do
122
+ # puts 'This will never be seen'
123
+ # end
124
+ #
125
+ # puts 'But this will'
126
+ #
127
+ # (Taken from ActiveSupport)
128
+ def silence_stream(stream)
129
+ old_stream = stream.dup
130
+ stream.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null')
131
+ stream.sync = true
132
+ yield
133
+ ensure
134
+ stream.reopen(old_stream)
135
+ end
136
+
137
+ # Create and parse a request
138
+ def R(raw, convert_line_feed=false)
139
+ raw.gsub!("\n", "\r\n") if convert_line_feed
140
+ request = Thin::Request.new
141
+ request.parse(raw)
142
+ request
143
+ end
144
+
145
+ def start_server(address=DEFAULT_TEST_ADDRESS, port=DEFAULT_TEST_PORT, options={}, &app)
146
+ @server = Thin::Server.new(address, port, options, app)
147
+ @server.threaded = options[:threaded]
148
+ @server.timeout = 3
149
+
150
+ @thread = Thread.new { @server.start }
151
+ if options[:wait_for_socket]
152
+ wait_for_socket(address, port)
153
+ else
154
+ # If we can't ping the address fallback to just wait for the server to run
155
+ sleep 1 until @server.running?
156
+ end
157
+ end
158
+
159
+ def stop_server
160
+ @server.stop!
161
+ @thread.kill
162
+ raise "Reactor still running, wtf?" if EventMachine.reactor_running?
163
+ end
164
+
165
+ def wait_for_socket(address=DEFAULT_TEST_ADDRESS, port=DEFAULT_TEST_PORT, timeout=5)
166
+ Timeout.timeout(timeout) do
167
+ loop do
168
+ begin
169
+ if address.include?('/')
170
+ UNIXSocket.new(address).close
171
+ else
172
+ TCPSocket.new(address, port).close
173
+ end
174
+ return true
175
+ rescue
176
+ end
177
+ end
178
+ end
179
+ end
180
+
181
+ def send_data(data)
182
+ if @server.backend.class == Backends::UnixServer
183
+ socket = UNIXSocket.new(@server.socket)
184
+ else
185
+ socket = TCPSocket.new(@server.host, @server.port)
186
+ end
187
+ socket.write data
188
+ out = socket.read
189
+ socket.close
190
+ out
191
+ end
192
+
193
+ def parse_response(response)
194
+ raw_headers, body = response.split("\r\n\r\n", 2)
195
+ raw_status, raw_headers = raw_headers.split("\r\n", 2)
196
+
197
+ status = raw_status.match(%r{\AHTTP/1.1\s+(\d+)\b}).captures.first.to_i
198
+ headers = Hash[ *raw_headers.split("\r\n").map { |h| h.split(/:\s+/, 2) }.flatten ]
199
+
200
+ [ status, headers, body ]
201
+ end
202
+
203
+ def get(url)
204
+ if @server.backend.class == Backends::UnixServer
205
+ send_data("GET #{url} HTTP/1.1\r\nConnection: close\r\n\r\n")
206
+ else
207
+ Net::HTTP.get(URI.parse("http://#{@server.host}:#{@server.port}" + url))
208
+ end
209
+ end
210
+
211
+ def post(url, params={})
212
+ Net::HTTP.post_form(URI.parse("http://#{@server.host}:#{@server.port}" + url), params).body
213
+ end
214
+ end
215
+
216
+ Spec::Runner.configure do |config|
217
+ config.include Matchers
218
+ config.include Helpers
219
+ end
@@ -0,0 +1,22 @@
1
+ require 'erb'
2
+
3
+ MSG_TEMPLATE = File.dirname(__FILE__) + '/email.erb'
4
+ SEND_TO = %w(thin-ruby@googlegroups.com ruby-talk@ruby-lang.org)
5
+
6
+ desc 'Generate a template for the new version annoucement'
7
+ task :ann do
8
+ msg = ERB.new(File.read(MSG_TEMPLATE)).result(binding)
9
+
10
+ body = <<END_OF_MESSAGE
11
+ To: #{SEND_TO.join(', ')}
12
+ Subject: [ANN] Thin #{Thin::VERSION::STRING} #{Thin::VERSION::CODENAME} release
13
+
14
+ #{msg}
15
+ END_OF_MESSAGE
16
+
17
+ fork { `echo "#{body}" | mate` }
18
+ end
19
+
20
+ def changelog
21
+ File.read('CHANGELOG').split("==")[1].split("\n")[1..-1].join("\n")
22
+ end