thin 1.8.0 → 2.0.0.pre
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.
- data/.gitignore +9 -0
- data/CHANGELOG +29 -107
- data/Gemfile +8 -0
- data/README.md +44 -78
- data/Rakefile +28 -18
- data/bin/thin +4 -4
- data/examples/async.ru +21 -0
- data/examples/thin.conf.rb +39 -0
- data/lib/thin.rb +2 -44
- data/lib/thin/async.rb +108 -0
- data/lib/thin/backends/prefork.rb +44 -0
- data/lib/thin/backends/single_process.rb +28 -0
- data/lib/thin/chunked_body.rb +28 -0
- data/lib/thin/configurator.rb +118 -0
- data/lib/thin/connection.rb +246 -172
- data/lib/thin/listener.rb +114 -0
- data/lib/thin/request.rb +94 -76
- data/lib/thin/response.rb +112 -45
- data/lib/thin/runner.rb +134 -197
- data/lib/thin/server.rb +203 -252
- data/lib/thin/system.rb +49 -0
- data/lib/thin/version.rb +11 -26
- data/man/index.txt +3 -0
- data/man/thin-conf.5.ronn +121 -0
- data/man/thin.1.ronn +105 -0
- data/site/.gitignore +2 -0
- data/site/README.md +21 -0
- data/site/Rakefile +20 -0
- data/site/config.ru +4 -0
- data/site/public/images/grid.png +0 -0
- data/site/public/javascripts/dd_belatedpng.js +13 -0
- data/site/public/javascripts/modernizr-1.6.min.js +30 -0
- data/site/public/man/thin-conf.5.html +220 -0
- data/site/public/man/thin.1.html +177 -0
- data/site/site/assets/javascripts/main.coffee +2 -0
- data/site/site/assets/stylesheets/_config.scss +55 -0
- data/site/site/assets/stylesheets/main.scss +24 -0
- data/site/site/helpers.rb +17 -0
- data/site/site/layouts/base.erb +55 -0
- data/site/site/layouts/default.erb +17 -0
- data/site/site/pages/about.md +5 -0
- data/site/site/pages/index.erb +10 -0
- data/site/site/partials/.gitkeep +0 -0
- data/test/fixtures/big.txt +1 -0
- data/test/fixtures/small.txt +1 -0
- data/test/fixtures/thin.conf.rb +15 -0
- data/test/integration/async_test.rb +35 -0
- data/test/integration/big_request_test.rb +30 -0
- data/test/integration/config.ru +57 -0
- data/test/integration/daemonize_test.rb +26 -0
- data/test/integration/env_test.rb +44 -0
- data/test/integration/error_test.rb +37 -0
- data/test/integration/file_sending_test.rb +24 -0
- data/test/integration/keep_alive_test.rb +35 -0
- data/test/integration/robustness_test.rb +37 -0
- data/test/integration/single_process_test.rb +15 -0
- data/test/integration/socket_family_test.rb +38 -0
- data/test/integration/worker_test.rb +22 -0
- data/test/test_helper.rb +195 -0
- data/test/unit/configurator_test.rb +43 -0
- data/test/unit/connection_test.rb +94 -0
- data/test/unit/listener_test.rb +74 -0
- data/test/unit/request_test.rb +74 -0
- data/test/unit/response_test.rb +90 -0
- data/test/unit/server_test.rb +29 -0
- data/test/unit/system_test.rb +17 -0
- data/thin.gemspec +26 -0
- data/v2.todo +21 -0
- metadata +138 -93
- checksums.yaml +0 -7
- data/example/adapter.rb +0 -32
- data/example/async_app.ru +0 -126
- data/example/async_chat.ru +0 -247
- data/example/async_tailer.ru +0 -100
- data/example/config.ru +0 -22
- data/example/monit_sockets +0 -20
- data/example/monit_unixsock +0 -20
- data/example/myapp.rb +0 -1
- data/example/ramaze.ru +0 -12
- data/example/thin.god +0 -80
- data/example/thin_solaris_smf.erb +0 -36
- data/example/thin_solaris_smf.readme.txt +0 -150
- data/example/vlad.rake +0 -72
- data/ext/thin_parser/common.rl +0 -59
- data/ext/thin_parser/ext_help.h +0 -14
- data/ext/thin_parser/extconf.rb +0 -6
- data/ext/thin_parser/parser.c +0 -1447
- data/ext/thin_parser/parser.h +0 -49
- data/ext/thin_parser/parser.rl +0 -152
- data/ext/thin_parser/thin.c +0 -435
- data/lib/rack/adapter/loader.rb +0 -75
- data/lib/rack/adapter/rails.rb +0 -178
- data/lib/rack/handler/thin.rb +0 -38
- data/lib/thin/backends/base.rb +0 -169
- data/lib/thin/backends/swiftiply_client.rb +0 -56
- data/lib/thin/backends/tcp_server.rb +0 -34
- data/lib/thin/backends/unix_server.rb +0 -56
- data/lib/thin/command.rb +0 -53
- data/lib/thin/controllers/cluster.rb +0 -178
- data/lib/thin/controllers/controller.rb +0 -189
- data/lib/thin/controllers/service.rb +0 -76
- data/lib/thin/controllers/service.sh.erb +0 -39
- data/lib/thin/daemonizing.rb +0 -199
- data/lib/thin/headers.rb +0 -40
- data/lib/thin/logging.rb +0 -174
- data/lib/thin/stats.html.erb +0 -216
- data/lib/thin/stats.rb +0 -52
- data/lib/thin/statuses.rb +0 -48
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require "thin/configurator"
|
3
|
+
|
4
|
+
class ConfiguratorTest < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@config = Thin::Configurator.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_worker_processes
|
10
|
+
@config.worker_processes 5
|
11
|
+
assert_equal 5, @config.options[:worker_processes]
|
12
|
+
assert_raise(ArgumentError) { @config.worker_processes "5" }
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_use_epoll
|
16
|
+
@config.use_epoll true
|
17
|
+
@config.use_epoll false
|
18
|
+
assert_raise(ArgumentError) { @config.use_epoll 1 }
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_listen
|
22
|
+
@config.listen 3000
|
23
|
+
@config.listen "0.0.0.0:3000"
|
24
|
+
assert_raise(ArgumentError) { @config.listen false }
|
25
|
+
assert_equal 2, @config.options[:listeners].size
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_before_fork
|
29
|
+
@config.before_fork { :ok }
|
30
|
+
assert_equal :ok, @config.options[:before_fork].call(:server)
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_load_from_file
|
34
|
+
Thin::Configurator.load(File.expand_path("../../fixtures/thin.conf.rb", __FILE__))
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_apply
|
38
|
+
server = Thin::Server.new {}
|
39
|
+
@config.worker_processes 10000
|
40
|
+
@config.apply(server)
|
41
|
+
assert_equal 10000, server.worker_processes
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'thin/connection'
|
3
|
+
|
4
|
+
class ConnectionTest < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@connection = Thin::Connection.new(nil)
|
7
|
+
@connection.server = self
|
8
|
+
@connection.post_init
|
9
|
+
|
10
|
+
@connection.stubs(:send_data)
|
11
|
+
@connection.stubs(:close_connection_after_writing)
|
12
|
+
@connection.stubs(:socket_address).returns("127.0.0.1")
|
13
|
+
end
|
14
|
+
|
15
|
+
#### Server methods
|
16
|
+
def app
|
17
|
+
proc do |env|
|
18
|
+
[200, {"Content-Type" => "text/plain"}, ["ok"]]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
def threaded?; false end
|
22
|
+
def prefork?; false end
|
23
|
+
####
|
24
|
+
|
25
|
+
def teardown
|
26
|
+
@connection.unbind
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_send_response_body
|
30
|
+
request = <<-EOS
|
31
|
+
GET / HTTP/1.1
|
32
|
+
Host: localhost:3000
|
33
|
+
|
34
|
+
EOS
|
35
|
+
|
36
|
+
@connection.expects(:send_data).with(includes("Content-Type: text/plain"))
|
37
|
+
@connection.expects(:send_data).with("ok")
|
38
|
+
@connection.expects(:close_connection_after_writing).once
|
39
|
+
|
40
|
+
@connection.receive_data(request)
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_parse_get_request
|
44
|
+
request = <<-EOS
|
45
|
+
GET /path?yo=dude HTTP/1.1
|
46
|
+
Host: localhost:3000
|
47
|
+
X-Special: awesome
|
48
|
+
|
49
|
+
EOS
|
50
|
+
|
51
|
+
@connection.expects(:process)
|
52
|
+
@connection.receive_data(request)
|
53
|
+
|
54
|
+
env = @connection.request.env
|
55
|
+
|
56
|
+
assert_equal "GET", env["REQUEST_METHOD"]
|
57
|
+
assert_equal "/path", env["PATH_INFO"]
|
58
|
+
assert_equal "HTTP/1.1", env["SERVER_PROTOCOL"]
|
59
|
+
assert_equal "HTTP/1.1", env["HTTP_VERSION"]
|
60
|
+
assert_equal "yo=dude", env["QUERY_STRING"]
|
61
|
+
assert_equal "localhost:3000", env["HTTP_HOST"]
|
62
|
+
assert_equal "awesome", env["HTTP_X_SPECIAL"]
|
63
|
+
|
64
|
+
# rack. values
|
65
|
+
assert_respond_to env["rack.input"], :read
|
66
|
+
assert_equal "http", env["rack.url_scheme"]
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_parse_post_request
|
70
|
+
request = <<-EOS
|
71
|
+
POST /path HTTP/1.1
|
72
|
+
Host: localhost:3000
|
73
|
+
Content-Type: text/plain
|
74
|
+
Content-Length: 2
|
75
|
+
|
76
|
+
hi
|
77
|
+
EOS
|
78
|
+
|
79
|
+
@connection.expects(:process)
|
80
|
+
@connection.receive_data(request)
|
81
|
+
|
82
|
+
env = @connection.request.env
|
83
|
+
|
84
|
+
assert_equal "POST", env["REQUEST_METHOD"]
|
85
|
+
assert_equal "/path", env["PATH_INFO"]
|
86
|
+
assert_equal "hi", env["rack.input"].read
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_async_response_do_not_send_response
|
90
|
+
@connection.expects(:send_response).never
|
91
|
+
|
92
|
+
@connection.process_response(Thin::Response::ASYNC)
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ListenerTest < Test::Unit::TestCase
|
4
|
+
def test_parse_integer_port_addresses
|
5
|
+
listener = Thin::Listener.new(3000)
|
6
|
+
assert_equal "", listener.host
|
7
|
+
assert_equal 3000, listener.port
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_parse_star_port_addresses
|
11
|
+
listener = Thin::Listener.new("*:3000")
|
12
|
+
assert_equal "", listener.host
|
13
|
+
assert_equal 3000, listener.port
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_parse_ipv4_and_port
|
17
|
+
listener = Thin::Listener.new("127.0.0.1:3000")
|
18
|
+
assert_equal "127.0.0.1", listener.host
|
19
|
+
assert_equal 3000, listener.port
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_parse_ipv6_and_port
|
23
|
+
listener = Thin::Listener.new("[::]:3000")
|
24
|
+
assert_equal "::", listener.host
|
25
|
+
assert_equal 3000, listener.port
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_parse_unix_socket
|
29
|
+
listener = Thin::Listener.new("/file.sock")
|
30
|
+
assert_nil listener.host
|
31
|
+
assert_nil listener.port
|
32
|
+
assert_equal "/file.sock", listener.socket_file
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_parse_relative_unix_socket_with_prefix
|
36
|
+
listener = Thin::Listener.new("unix:file.sock")
|
37
|
+
assert_nil listener.host
|
38
|
+
assert_nil listener.port
|
39
|
+
assert_equal "file.sock", listener.socket_file
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_parse_invalid_address
|
43
|
+
assert_raise(ArgumentError) { Thin::Listener.new("file.sock") }
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_ipv4_socket
|
47
|
+
listener = Thin::Listener.new(3000)
|
48
|
+
assert_kind_of Socket, listener.socket
|
49
|
+
ensure
|
50
|
+
listener.close
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_ipv6_socket
|
54
|
+
listener = Thin::Listener.new("[::]:3000")
|
55
|
+
assert_kind_of Socket, listener.socket
|
56
|
+
ensure
|
57
|
+
listener.close
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_unix_socket
|
61
|
+
listener = Thin::Listener.new("/tmp/thin-test.sock")
|
62
|
+
assert_kind_of Socket, listener.socket
|
63
|
+
ensure
|
64
|
+
listener.close
|
65
|
+
assert ! File.exist?("tmp/thin-test.sock")
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_set_socket_option
|
69
|
+
listener = Thin::Listener.new(3000, :tcp_no_delay => true)
|
70
|
+
assert listener.socket.getsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY)
|
71
|
+
ensure
|
72
|
+
listener.close
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require "thin/request"
|
3
|
+
require "rack"
|
4
|
+
|
5
|
+
class RequestTest < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@request = Thin::Request.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_env_contains_requires_rack_variables
|
11
|
+
assert_respond_to @request.env['rack.input'], :read
|
12
|
+
assert_kind_of IO, @request.env['rack.errors']
|
13
|
+
assert_equal [1, 1], @request.env['rack.version']
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_convert_parser_headers_to_rack_env
|
17
|
+
@request.headers = {
|
18
|
+
"Host" => "localhost:9292",
|
19
|
+
"Connection" => "close"
|
20
|
+
}
|
21
|
+
|
22
|
+
assert_equal "localhost:9292", @request.env["HTTP_HOST"]
|
23
|
+
assert_equal "close", @request.env["HTTP_CONNECTION"]
|
24
|
+
assert ! @request.env.key?("HOST")
|
25
|
+
assert ! @request.env.key?("CONNECTION")
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_do_not_prefix_content_type_and_length
|
29
|
+
@request.headers = {
|
30
|
+
"Content-Type" => "text/html",
|
31
|
+
"Content-Length" => "1"
|
32
|
+
}
|
33
|
+
|
34
|
+
assert ! @request.env.key?("HTTP_CONTENT_TYPE")
|
35
|
+
assert ! @request.env.key?("HTTP_CONTENT_LENGTH")
|
36
|
+
assert_equal "text/html", @request.env["CONTENT_TYPE"]
|
37
|
+
assert_equal "1", @request.env["CONTENT_LENGTH"]
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_extracts_server_name_and_port_from_host
|
41
|
+
@request.headers = {
|
42
|
+
"Host" => "localhost:3000"
|
43
|
+
}
|
44
|
+
assert_equal "localhost", @request.env["SERVER_NAME"]
|
45
|
+
assert_equal "3000", @request.env["SERVER_PORT"]
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_defaults_server_name_and_port
|
49
|
+
@request.headers = {}
|
50
|
+
assert_equal "localhost", @request.env["SERVER_NAME"]
|
51
|
+
assert_equal "80", @request.env["SERVER_PORT"]
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_validate_through_rack_lint
|
55
|
+
@request.multithread = false
|
56
|
+
@request.multiprocess = false
|
57
|
+
@request.method = "GET"
|
58
|
+
@request.path = "/info"
|
59
|
+
@request.fragment = "hello"
|
60
|
+
@request.query_string = "hey=there&yo=dude"
|
61
|
+
@request.headers = {
|
62
|
+
"Host" => "localhost:9292",
|
63
|
+
"Connection" => "close",
|
64
|
+
"Content-Type" => "text/plain"
|
65
|
+
}
|
66
|
+
@request.body << "ok"
|
67
|
+
|
68
|
+
app = proc do |env|
|
69
|
+
[200, {"Content-Type" => "text/plain"}, ["ok"]]
|
70
|
+
end
|
71
|
+
|
72
|
+
assert_nothing_raised { Rack::Lint.new(app).call(@request.env) }
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'thin/response'
|
3
|
+
|
4
|
+
class ResponseTest < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@response = Thin::Response.new
|
7
|
+
@response.headers['Content-Type'] = 'text/html'
|
8
|
+
@response.headers['Content-Length'] = '0'
|
9
|
+
@response.body = ''
|
10
|
+
@response.finish
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_initialize_with_values
|
14
|
+
@response = Thin::Response.new(201, {"Content-Type" => "text/plain"}, ["hi"])
|
15
|
+
assert_equal 201, @response.status
|
16
|
+
assert_match "Content-Type: text/plain", @response.headers.to_s
|
17
|
+
assert_equal ["hi"], @response.body
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_output_headers
|
21
|
+
assert_match "Content-Type: text/html", @response.headers.to_s
|
22
|
+
assert_match "Content-Length: 0", @response.headers.to_s
|
23
|
+
assert_match "Connection: close", @response.headers.to_s
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_include_server_name_header
|
27
|
+
assert_match "Server: thin", @response.headers.to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_output_head
|
31
|
+
assert_match /^HTTP\/1.1 200 OK/, @response.head
|
32
|
+
assert_match /\r\n\r\n$/, @response.head
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_allow_duplicates_on_some_headers
|
36
|
+
@response.headers['Set-Cookie'] = 'mium=7'
|
37
|
+
@response.headers['Set-Cookie'] = 'hi=there'
|
38
|
+
|
39
|
+
assert_match "Set-Cookie: mium=7", @response.head
|
40
|
+
assert_match "Set-Cookie: hi=there", @response.head
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_parse_simple_header_values
|
44
|
+
@response.headers = {
|
45
|
+
'Host' => 'localhost'
|
46
|
+
}
|
47
|
+
|
48
|
+
assert_match "Host: localhost", @response.head
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_parse_multiline_header_values_in_several_headers
|
52
|
+
@response.headers = {
|
53
|
+
'Set-Cookie' => "mium=7\nhi=there"
|
54
|
+
}
|
55
|
+
|
56
|
+
assert_match "Set-Cookie: mium=7", @response.head
|
57
|
+
assert_match "Set-Cookie: hi=there", @response.head
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_ignore__nil_headers
|
61
|
+
@response.headers = nil
|
62
|
+
@response.headers = { 'Host' => 'localhost' }
|
63
|
+
@response.headers = { 'Set-Cookie' => nil }
|
64
|
+
assert_no_match /Set-Cookie/, @response.head
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_body
|
68
|
+
@response.body = ['<html>', '</html>']
|
69
|
+
|
70
|
+
out = ''
|
71
|
+
@response.each { |l| out << l }
|
72
|
+
assert_match /\r\n\r\n<html><\/html>$/, out
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_string_body
|
76
|
+
@response.body = '<html></html>'
|
77
|
+
|
78
|
+
out = ''
|
79
|
+
@response.each { |l| out << l }
|
80
|
+
assert_match /\r\n\r\n<html><\/html>$/, out
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_close
|
84
|
+
@response.close
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_async
|
88
|
+
assert Thin::Response.new(*Thin::Response::ASYNC).async?
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ServerTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
app = proc { |env| [200, {}, ["ok"]] }
|
6
|
+
@server = Thin::Server.new { app }
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_pick_prefork_backend_if_any_workers
|
10
|
+
@server.worker_processes = 1
|
11
|
+
assert_kind_of Thin::Backends::Prefork, @server.backend
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_pick_single_process_backend_if_no_workers
|
15
|
+
@server.worker_processes = 0
|
16
|
+
assert_kind_of Thin::Backends::SingleProcess, @server.backend
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_cant_daemonize_single_process
|
20
|
+
@server.worker_processes = 0
|
21
|
+
assert_raise(NotImplementedError) do
|
22
|
+
silence_streams { @server.start(true) }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_do_not_preload_app
|
27
|
+
Thin::Server.new { fail "Should not load app before starting" }
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class SystemTest < Test::Unit::TestCase
|
4
|
+
def test_processor_count
|
5
|
+
assert_not_equal 0, Thin::System.processor_count
|
6
|
+
end
|
7
|
+
|
8
|
+
if Thin::System.java? || Thin::System.win?
|
9
|
+
def test_should_not_support_fork
|
10
|
+
assert ! Thin::System.supports_fork?
|
11
|
+
end
|
12
|
+
else
|
13
|
+
def test_should_support_fork
|
14
|
+
assert Thin::System.supports_fork?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/thin.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "thin/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "thin"
|
7
|
+
s.version = Thin::VERSION::STRING
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Marc-Andre Cournoyer"]
|
10
|
+
s.email = ["thin@macournoyer.com"]
|
11
|
+
s.homepage = "http://code.macournoyer.com/thin"
|
12
|
+
s.summary = %q{A thin and fast web server}
|
13
|
+
s.description = %q{Thin is a Rack based, high performance web server}
|
14
|
+
|
15
|
+
s.rubyforge_project = "thin"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_dependency "eventmachine-le", "~> 1.1.0"
|
23
|
+
s.add_dependency "http_parser.rb", "~> 0.5.3"
|
24
|
+
s.add_dependency "preforker", "~> 0.1.1"
|
25
|
+
s.add_dependency "rack", "~> 1.4"
|
26
|
+
end
|