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.
- data/CHANGELOG +263 -0
- data/COPYING +18 -0
- data/README +69 -0
- data/Rakefile +36 -0
- data/benchmark/abc +51 -0
- data/benchmark/benchmarker.rb +80 -0
- data/benchmark/runner +82 -0
- data/bin/thin +6 -0
- data/example/adapter.rb +32 -0
- data/example/async_app.ru +126 -0
- data/example/async_chat.ru +247 -0
- data/example/async_tailer.ru +100 -0
- data/example/config.ru +22 -0
- data/example/monit_sockets +20 -0
- data/example/monit_unixsock +20 -0
- data/example/myapp.rb +1 -0
- data/example/ramaze.ru +12 -0
- data/example/thin.god +80 -0
- data/example/thin_solaris_smf.erb +36 -0
- data/example/thin_solaris_smf.readme.txt +150 -0
- data/example/vlad.rake +64 -0
- data/ext/thin_parser/common.rl +55 -0
- data/ext/thin_parser/ext_help.h +14 -0
- data/ext/thin_parser/extconf.rb +6 -0
- data/ext/thin_parser/parser.c +452 -0
- data/ext/thin_parser/parser.h +49 -0
- data/ext/thin_parser/parser.rl +157 -0
- data/ext/thin_parser/thin.c +433 -0
- data/lib/rack/adapter/loader.rb +79 -0
- data/lib/rack/adapter/rails.rb +181 -0
- data/lib/thin.rb +46 -0
- data/lib/thin/backends/base.rb +141 -0
- data/lib/thin/backends/swiftiply_client.rb +56 -0
- data/lib/thin/backends/tcp_server.rb +29 -0
- data/lib/thin/backends/unix_server.rb +51 -0
- data/lib/thin/command.rb +53 -0
- data/lib/thin/connection.rb +222 -0
- data/lib/thin/controllers/cluster.rb +127 -0
- data/lib/thin/controllers/controller.rb +183 -0
- data/lib/thin/controllers/service.rb +75 -0
- data/lib/thin/controllers/service.sh.erb +39 -0
- data/lib/thin/daemonizing.rb +174 -0
- data/lib/thin/headers.rb +39 -0
- data/lib/thin/logging.rb +54 -0
- data/lib/thin/request.rb +153 -0
- data/lib/thin/response.rb +101 -0
- data/lib/thin/runner.rb +209 -0
- data/lib/thin/server.rb +247 -0
- data/lib/thin/stats.html.erb +216 -0
- data/lib/thin/stats.rb +52 -0
- data/lib/thin/statuses.rb +43 -0
- data/lib/thin/version.rb +32 -0
- data/lib/thin_parser.so +0 -0
- data/spec/backends/swiftiply_client_spec.rb +66 -0
- data/spec/backends/tcp_server_spec.rb +33 -0
- data/spec/backends/unix_server_spec.rb +37 -0
- data/spec/command_spec.rb +25 -0
- data/spec/configs/cluster.yml +9 -0
- data/spec/configs/single.yml +9 -0
- data/spec/connection_spec.rb +106 -0
- data/spec/controllers/cluster_spec.rb +235 -0
- data/spec/controllers/controller_spec.rb +129 -0
- data/spec/controllers/service_spec.rb +50 -0
- data/spec/daemonizing_spec.rb +192 -0
- data/spec/headers_spec.rb +40 -0
- data/spec/logging_spec.rb +46 -0
- data/spec/perf/request_perf_spec.rb +50 -0
- data/spec/perf/response_perf_spec.rb +19 -0
- data/spec/perf/server_perf_spec.rb +39 -0
- data/spec/rack/loader_spec.rb +29 -0
- data/spec/rack/rails_adapter_spec.rb +106 -0
- data/spec/rails_app/app/controllers/application.rb +10 -0
- data/spec/rails_app/app/controllers/simple_controller.rb +19 -0
- data/spec/rails_app/app/helpers/application_helper.rb +3 -0
- data/spec/rails_app/app/views/simple/index.html.erb +15 -0
- data/spec/rails_app/config/boot.rb +109 -0
- data/spec/rails_app/config/environment.rb +64 -0
- data/spec/rails_app/config/environments/development.rb +18 -0
- data/spec/rails_app/config/environments/production.rb +19 -0
- data/spec/rails_app/config/environments/test.rb +22 -0
- data/spec/rails_app/config/initializers/inflections.rb +10 -0
- data/spec/rails_app/config/initializers/mime_types.rb +5 -0
- data/spec/rails_app/config/routes.rb +35 -0
- data/spec/rails_app/public/404.html +30 -0
- data/spec/rails_app/public/422.html +30 -0
- data/spec/rails_app/public/500.html +30 -0
- data/spec/rails_app/public/dispatch.cgi +10 -0
- data/spec/rails_app/public/dispatch.fcgi +24 -0
- data/spec/rails_app/public/dispatch.rb +10 -0
- data/spec/rails_app/public/favicon.ico +0 -0
- data/spec/rails_app/public/images/rails.png +0 -0
- data/spec/rails_app/public/index.html +277 -0
- data/spec/rails_app/public/javascripts/application.js +2 -0
- data/spec/rails_app/public/javascripts/controls.js +963 -0
- data/spec/rails_app/public/javascripts/dragdrop.js +972 -0
- data/spec/rails_app/public/javascripts/effects.js +1120 -0
- data/spec/rails_app/public/javascripts/prototype.js +4225 -0
- data/spec/rails_app/public/robots.txt +5 -0
- data/spec/rails_app/script/about +3 -0
- data/spec/rails_app/script/console +3 -0
- data/spec/rails_app/script/destroy +3 -0
- data/spec/rails_app/script/generate +3 -0
- data/spec/rails_app/script/performance/benchmarker +3 -0
- data/spec/rails_app/script/performance/profiler +3 -0
- data/spec/rails_app/script/performance/request +3 -0
- data/spec/rails_app/script/plugin +3 -0
- data/spec/rails_app/script/process/inspector +3 -0
- data/spec/rails_app/script/process/reaper +3 -0
- data/spec/rails_app/script/process/spawner +3 -0
- data/spec/rails_app/script/runner +3 -0
- data/spec/rails_app/script/server +3 -0
- data/spec/request/mongrel_spec.rb +39 -0
- data/spec/request/parser_spec.rb +215 -0
- data/spec/request/persistent_spec.rb +35 -0
- data/spec/request/processing_spec.rb +45 -0
- data/spec/response_spec.rb +91 -0
- data/spec/runner_spec.rb +168 -0
- data/spec/server/builder_spec.rb +44 -0
- data/spec/server/pipelining_spec.rb +110 -0
- data/spec/server/robustness_spec.rb +34 -0
- data/spec/server/stopping_spec.rb +55 -0
- data/spec/server/swiftiply.yml +6 -0
- data/spec/server/swiftiply_spec.rb +32 -0
- data/spec/server/tcp_spec.rb +57 -0
- data/spec/server/threaded_spec.rb +27 -0
- data/spec/server/unix_socket_spec.rb +26 -0
- data/spec/server_spec.rb +96 -0
- data/spec/spec_helper.rb +219 -0
- data/tasks/announce.rake +22 -0
- data/tasks/deploy.rake +13 -0
- data/tasks/email.erb +30 -0
- data/tasks/gem.rake +74 -0
- data/tasks/rdoc.rake +25 -0
- data/tasks/site.rake +15 -0
- data/tasks/spec.rake +49 -0
- data/tasks/stats.rake +28 -0
- 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
|
data/spec/server_spec.rb
ADDED
@@ -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
|
data/spec/spec_helper.rb
ADDED
@@ -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
|
data/tasks/announce.rake
ADDED
@@ -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
|