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,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,96 @@
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
+ @server.maximum_connections = 100_000
16
+ @server.config
17
+ @server.maximum_connections.should < 100_000
18
+ end
19
+
20
+ it "should default to non-threaded" do
21
+ @server.should_not be_threaded
22
+ end
23
+
24
+ it "should set backend to threaded" do
25
+ @server.threaded = true
26
+ @server.backend.should be_threaded
27
+ end
28
+ end
29
+
30
+ describe Server, "initialization" do
31
+ it "should set host and port" do
32
+ server = Server.new('192.168.1.1', 8080)
33
+
34
+ server.host.should == '192.168.1.1'
35
+ server.port.should == 8080
36
+ end
37
+
38
+ it "should set socket" do
39
+ server = Server.new('/tmp/thin.sock')
40
+
41
+ server.socket.should == '/tmp/thin.sock'
42
+ end
43
+
44
+ it "should set host, port and app" do
45
+ app = proc {}
46
+ server = Server.new('192.168.1.1', 8080, app)
47
+
48
+ server.host.should_not be_nil
49
+ server.app.should == app
50
+ end
51
+
52
+ it "should set socket and app" do
53
+ app = proc {}
54
+ server = Server.new('/tmp/thin.sock', app)
55
+
56
+ server.socket.should_not be_nil
57
+ server.app.should == app
58
+ end
59
+
60
+ it "should set socket, nil and app" do
61
+ app = proc {}
62
+ server = Server.new('/tmp/thin.sock', nil, app)
63
+
64
+ server.socket.should_not be_nil
65
+ server.app.should == app
66
+ end
67
+
68
+ it "should set host, port and backend" do
69
+ server = Server.new('192.168.1.1', 8080, :backend => Thin::Backends::SwiftiplyClient)
70
+
71
+ server.host.should_not be_nil
72
+ server.backend.should be_kind_of(Thin::Backends::SwiftiplyClient)
73
+ end
74
+
75
+ it "should set host, port, app and backend" do
76
+ app = proc {}
77
+ server = Server.new('192.168.1.1', 8080, app, :backend => Thin::Backends::SwiftiplyClient)
78
+
79
+ server.host.should_not be_nil
80
+ server.app.should == app
81
+ server.backend.should be_kind_of(Thin::Backends::SwiftiplyClient)
82
+ end
83
+
84
+ it "should set port as string" do
85
+ app = proc {}
86
+ server = Server.new('192.168.1.1', '8080')
87
+
88
+ server.host.should == '192.168.1.1'
89
+ server.port.should == 8080
90
+ end
91
+
92
+ it "should not register signals w/ :signals => false" do
93
+ Server.should_not_receive(:setup_signals)
94
+ Server.new(:signals => false)
95
+ end
96
+ 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 'benchmark_unit'
8
+ require 'net/http'
9
+ require 'socket'
10
+
11
+ include Thin
12
+
13
+ FileUtils.mkdir_p File.dirname(__FILE__) + '/../log'
14
+ Command.script = File.dirname(__FILE__) + '/../bin/thin'
15
+ Logging.silent = true
16
+
17
+ unless Object.const_defined?(:SWIFTIPLY_PATH)
18
+ SWIFTIPLY_PATH = `which swiftiply`.chomp
19
+ DEFAULT_TEST_ADDRESS = '0.0.0.0'
20
+ DEFAULT_TEST_PORT = 3333
21
+ end
22
+
23
+ module Matchers
24
+ class BeFasterThen
25
+ def initialize(max_time)
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