thin 0.5.3 → 0.5.4
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 +10 -0
- data/bin/thin +1 -1
- data/example/config.ru +16 -2
- data/lib/thin.rb +1 -1
- data/lib/thin/connection.rb +4 -2
- data/lib/thin/response.rb +24 -14
- data/lib/thin/version.rb +2 -2
- data/spec/response_spec.rb +22 -9
- data/spec/server_spec.rb +8 -3
- metadata +2 -2
data/CHANGELOG
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
== 0.5.4 Flying Mustard release
|
2
|
+
* Don't read the full body, use direct streaming when sending response.
|
3
|
+
See: Response#each
|
4
|
+
As a result, the Content-Length can not be calculated anymore.
|
5
|
+
You have to do set this in your adapter. All frameworks do it anyway.
|
6
|
+
It improve memory usage and boost speed for low concurrency.
|
7
|
+
Thanks to Kent Sibilev and Ezra for their help on that one.
|
8
|
+
* Add 'Server' response header
|
9
|
+
* Fix --user and --group option not changing daemon process privileges
|
10
|
+
|
1
11
|
== 0.5.3 Purple Yogurt release
|
2
12
|
* win32 pre-compiled gem now available
|
3
13
|
* change rake task configuration to allow win32 gem build
|
data/bin/thin
CHANGED
@@ -73,8 +73,8 @@ def start(options)
|
|
73
73
|
server.timeout = options[:timeout]
|
74
74
|
|
75
75
|
if options[:daemonize]
|
76
|
-
server.change_privilege options[:user], options[:group] if options[:user] && options[:group]
|
77
76
|
server.daemonize
|
77
|
+
server.change_privilege options[:user], options[:group] if options[:user] && options[:group]
|
78
78
|
end
|
79
79
|
|
80
80
|
server.app = Rack::Adapter::Rails.new(options.merge(:root => options[:chdir]))
|
data/example/config.ru
CHANGED
@@ -4,6 +4,20 @@
|
|
4
4
|
# http://rack.rubyforge.org/doc/classes/Rack/Builder.html
|
5
5
|
|
6
6
|
require File.dirname(__FILE__) + '/../lib/thin'
|
7
|
-
require 'rack/lobster'
|
8
7
|
|
9
|
-
|
8
|
+
app = proc do |env|
|
9
|
+
# Response body has to respond to each and yield strings
|
10
|
+
# See Rack specs for more info: http://rack.rubyforge.org/doc/files/SPEC.html
|
11
|
+
body = ['hi!']
|
12
|
+
|
13
|
+
[
|
14
|
+
200, # Status code
|
15
|
+
{
|
16
|
+
'Content-Type' => 'text/html', # Reponse headers
|
17
|
+
'Content-Length' => body.join.size.to_s
|
18
|
+
},
|
19
|
+
body # Body of the response
|
20
|
+
]
|
21
|
+
end
|
22
|
+
|
23
|
+
run app
|
data/lib/thin.rb
CHANGED
data/lib/thin/connection.rb
CHANGED
@@ -30,8 +30,10 @@ module Thin
|
|
30
30
|
@response.status, @response.headers, @response.body = @app.call(env)
|
31
31
|
|
32
32
|
# Send the response
|
33
|
-
|
34
|
-
|
33
|
+
@response.each do |chunk|
|
34
|
+
trace { chunk }
|
35
|
+
send_data chunk
|
36
|
+
end
|
35
37
|
|
36
38
|
close_connection_after_writing
|
37
39
|
|
data/lib/thin/response.rb
CHANGED
@@ -1,25 +1,35 @@
|
|
1
1
|
module Thin
|
2
2
|
# A response sent to the client.
|
3
3
|
class Response
|
4
|
-
CONTENT_LENGTH = 'Content-Length'.freeze
|
5
4
|
CONNECTION = 'Connection'.freeze
|
5
|
+
SERVER = 'Server'.freeze
|
6
6
|
CLOSE = 'close'.freeze
|
7
7
|
|
8
|
+
# Status code
|
8
9
|
attr_accessor :status
|
9
|
-
|
10
|
+
|
11
|
+
# Response body, must respond to +each+.
|
12
|
+
attr_accessor :body
|
13
|
+
|
14
|
+
# Headers key-value hash
|
15
|
+
attr_reader :headers
|
10
16
|
|
11
17
|
def initialize
|
12
18
|
@headers = Headers.new
|
13
|
-
@body = StringIO.new
|
14
19
|
@status = 200
|
15
20
|
end
|
16
21
|
|
22
|
+
# String representation of the headers
|
23
|
+
# to be sent in the response.
|
17
24
|
def headers_output
|
18
|
-
@headers[CONTENT_LENGTH] = @body.size
|
19
25
|
@headers[CONNECTION] = CLOSE
|
26
|
+
@headers[SERVER] = Thin::SERVER
|
27
|
+
|
20
28
|
@headers.to_s
|
21
29
|
end
|
22
30
|
|
31
|
+
# Top header of the response,
|
32
|
+
# containing the status code and response headers.
|
23
33
|
def head
|
24
34
|
"HTTP/1.1 #{@status} #{HTTP_STATUS_CODES[@status.to_i]}\r\n#{headers_output}\r\n"
|
25
35
|
end
|
@@ -30,19 +40,19 @@ module Thin
|
|
30
40
|
end
|
31
41
|
end
|
32
42
|
|
33
|
-
|
34
|
-
stream.each do |part|
|
35
|
-
@body << part
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
43
|
+
# Close any resource used by the response
|
39
44
|
def close
|
40
|
-
@body.close
|
45
|
+
@body.close if @body.respond_to?(:close)
|
41
46
|
end
|
42
47
|
|
43
|
-
|
44
|
-
|
45
|
-
|
48
|
+
# Yields each chunk of the response.
|
49
|
+
# To controler the size of the chunks sent to the client
|
50
|
+
# define your own +each+ method on +body+.
|
51
|
+
def each
|
52
|
+
yield head
|
53
|
+
@body.each do |chunk|
|
54
|
+
yield chunk
|
55
|
+
end
|
46
56
|
end
|
47
57
|
end
|
48
58
|
end
|
data/lib/thin/version.rb
CHANGED
data/spec/response_spec.rb
CHANGED
@@ -4,21 +4,28 @@ describe Response do
|
|
4
4
|
before do
|
5
5
|
@response = Response.new
|
6
6
|
@response.headers['Content-Type'] = 'text/html'
|
7
|
+
@response.headers['Content-Length'] = '0'
|
8
|
+
@response.body = ''
|
7
9
|
end
|
8
10
|
|
9
11
|
it 'should output headers' do
|
10
|
-
@response.headers_output.should
|
12
|
+
@response.headers_output.should include("Content-Type: text/html", "Content-Length: 0", "Connection: close")
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should include server name header' do
|
16
|
+
@response.headers_output.should include("Server: thin")
|
11
17
|
end
|
12
18
|
|
13
19
|
it 'should output head' do
|
14
|
-
@response.head.should
|
20
|
+
@response.head.should include("HTTP/1.1 200 OK", "Content-Type: text/html", "Content-Length: 0",
|
21
|
+
"Connection: close", "\r\n\r\n")
|
15
22
|
end
|
16
23
|
|
17
24
|
it 'should allow duplicates in headers' do
|
18
25
|
@response.headers['Set-Cookie'] = 'mium=7'
|
19
26
|
@response.headers['Set-Cookie'] = 'hi=there'
|
20
27
|
|
21
|
-
@response.head.should
|
28
|
+
@response.head.should include("Set-Cookie: mium=7", "Set-Cookie: hi=there")
|
22
29
|
end
|
23
30
|
|
24
31
|
it 'should parse simple header values' do
|
@@ -26,7 +33,7 @@ describe Response do
|
|
26
33
|
'Host' => 'localhost'
|
27
34
|
}
|
28
35
|
|
29
|
-
@response.head.should
|
36
|
+
@response.head.should include("Host: localhost")
|
30
37
|
end
|
31
38
|
|
32
39
|
it 'should parse multiline header values in several headers' do
|
@@ -34,16 +41,18 @@ describe Response do
|
|
34
41
|
'Set-Cookie' => "mium=7\nhi=there"
|
35
42
|
}
|
36
43
|
|
37
|
-
@response.head.should
|
44
|
+
@response.head.should include("Set-Cookie: mium=7", "Set-Cookie: hi=there")
|
38
45
|
end
|
39
46
|
|
40
47
|
it 'should output body' do
|
41
|
-
@response.body
|
48
|
+
@response.body = '<html></html>'
|
42
49
|
|
43
|
-
|
50
|
+
out = ''
|
51
|
+
@response.each { |l| out << l }
|
52
|
+
out.should include("\r\n\r\n<html></html>")
|
44
53
|
end
|
45
54
|
|
46
|
-
it "should be faster then #{max_parsing_time = 0.
|
55
|
+
it "should be faster then #{max_parsing_time = 0.07} ms" do
|
47
56
|
@response.body << <<-EOS
|
48
57
|
<html><head><title>Dir listing</title></head>
|
49
58
|
<body><h1>Listing stuff</h1><ul>
|
@@ -51,6 +60,10 @@ describe Response do
|
|
51
60
|
</ul></body></html>
|
52
61
|
EOS
|
53
62
|
|
54
|
-
proc { @response.
|
63
|
+
proc { @response.each { |l| l } }.should be_faster_then(max_parsing_time)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should be closeable" do
|
67
|
+
@response.close
|
55
68
|
end
|
56
69
|
end
|
data/spec/server_spec.rb
CHANGED
@@ -5,8 +5,10 @@ require 'socket'
|
|
5
5
|
describe Server do
|
6
6
|
before do
|
7
7
|
app = proc do |env|
|
8
|
-
body =
|
9
|
-
|
8
|
+
body = ''
|
9
|
+
body << env['QUERY_STRING'].to_s
|
10
|
+
body << env['rack.input'].read.to_s
|
11
|
+
[200, { 'Content-Type' => 'text/html', 'Content-Length' => body.size.to_s }, body]
|
10
12
|
end
|
11
13
|
server = Thin::Server.new('0.0.0.0', 3333, app)
|
12
14
|
server.timeout = 3
|
@@ -24,7 +26,10 @@ describe Server do
|
|
24
26
|
end
|
25
27
|
|
26
28
|
it 'should GET from TCPSocket' do
|
27
|
-
raw('0.0.0.0', 3333, "GET /?this HTTP/1.1\r\n\r\n").
|
29
|
+
raw('0.0.0.0', 3333, "GET /?this HTTP/1.1\r\n\r\n").
|
30
|
+
should include("HTTP/1.1 200 OK",
|
31
|
+
"Content-Type: text/html", "Content-Length: 4",
|
32
|
+
"Connection: close", "\r\n\r\nthis")
|
28
33
|
end
|
29
34
|
|
30
35
|
it 'should return empty string on incomplete headers' do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marc-Andre Cournoyer
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-01-
|
12
|
+
date: 2008-01-19 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|