thin 0.5.3-x86-mswin32-60 → 0.5.4-x86-mswin32-60

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 (52) hide show
  1. data/CHANGELOG +8 -0
  2. data/benchmark/previous.rb +14 -0
  3. data/benchmark/simple.rb +3 -38
  4. data/benchmark/utils.rb +51 -0
  5. data/bin/thin +1 -1
  6. data/example/config.ru +9 -2
  7. data/lib/thin.rb +1 -1
  8. data/lib/thin/connection.rb +4 -2
  9. data/lib/thin/response.rb +22 -14
  10. data/lib/thin/version.rb +2 -2
  11. data/lib/thin_parser.so +0 -0
  12. data/spec/response_spec.rb +22 -9
  13. data/spec/server_spec.rb +8 -3
  14. metadata +5 -56
  15. data/doc/rdoc/classes/Process.html +0 -181
  16. data/doc/rdoc/classes/Rack.html +0 -156
  17. data/doc/rdoc/classes/Rack/Adapter.html +0 -155
  18. data/doc/rdoc/classes/Rack/Adapter/Rails.html +0 -289
  19. data/doc/rdoc/classes/Rack/Adapter/Rails/CGIWrapper.html +0 -359
  20. data/doc/rdoc/classes/Rack/Handler.html +0 -155
  21. data/doc/rdoc/classes/Rack/Handler/Thin.html +0 -175
  22. data/doc/rdoc/classes/Thin.html +0 -164
  23. data/doc/rdoc/classes/Thin/Cluster.html +0 -399
  24. data/doc/rdoc/classes/Thin/Connection.html +0 -223
  25. data/doc/rdoc/classes/Thin/Daemonizable.html +0 -260
  26. data/doc/rdoc/classes/Thin/Daemonizable/ClassMethods.html +0 -197
  27. data/doc/rdoc/classes/Thin/Headers.html +0 -238
  28. data/doc/rdoc/classes/Thin/InvalidRequest.html +0 -144
  29. data/doc/rdoc/classes/Thin/Logging.html +0 -201
  30. data/doc/rdoc/classes/Thin/Request.html +0 -231
  31. data/doc/rdoc/classes/Thin/Response.html +0 -271
  32. data/doc/rdoc/classes/Thin/Server.html +0 -295
  33. data/doc/rdoc/classes/Thin/StopServer.html +0 -143
  34. data/doc/rdoc/created.rid +0 -1
  35. data/doc/rdoc/files/README.html +0 -226
  36. data/doc/rdoc/files/bin/thin.html +0 -245
  37. data/doc/rdoc/files/lib/rack/adapter/rails_rb.html +0 -146
  38. data/doc/rdoc/files/lib/rack/handler/thin_rb.html +0 -146
  39. data/doc/rdoc/files/lib/thin/cluster_rb.html +0 -146
  40. data/doc/rdoc/files/lib/thin/connection_rb.html +0 -145
  41. data/doc/rdoc/files/lib/thin/daemonizing_rb.html +0 -146
  42. data/doc/rdoc/files/lib/thin/headers_rb.html +0 -146
  43. data/doc/rdoc/files/lib/thin/logging_rb.html +0 -146
  44. data/doc/rdoc/files/lib/thin/request_rb.html +0 -145
  45. data/doc/rdoc/files/lib/thin/response_rb.html +0 -145
  46. data/doc/rdoc/files/lib/thin/server_rb.html +0 -145
  47. data/doc/rdoc/files/lib/thin/statuses_rb.html +0 -145
  48. data/doc/rdoc/files/lib/thin/version_rb.html +0 -145
  49. data/doc/rdoc/files/lib/thin_rb.html +0 -152
  50. data/doc/rdoc/index.html +0 -10
  51. data/doc/rdoc/logo.gif +0 -0
  52. data/doc/rdoc/rdoc-style.css +0 -55
data/CHANGELOG CHANGED
@@ -1,3 +1,11 @@
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 any more.
5
+ You have to do set it in your adapter. All frameworks do it anyway.
6
+ * Add Server response header
7
+ * Fix --user and --group option not changing daemon process privileges
8
+
1
9
  == 0.5.3 Purple Yogurt release
2
10
  * win32 pre-compiled gem now available
3
11
  * change rake task configuration to allow win32 gem build
@@ -0,0 +1,14 @@
1
+ # Benchmark to compare Thin performance against
2
+ # previous Thin version (the one installed as a gem).
3
+ #
4
+ # Run with:
5
+ #
6
+ # ruby previous.rb [num of request]
7
+ #
8
+ require 'rubygems'
9
+ require 'rack'
10
+ require File.dirname(__FILE__) + '/utils'
11
+
12
+ request = (ARGV[0] || 1000).to_i # Number of request to send (ab -n option)
13
+
14
+ benchmark %w(current gem), request
@@ -6,43 +6,8 @@
6
6
  # ruby simple.rb [num of request]
7
7
  #
8
8
  require File.dirname(__FILE__) + '/../lib/thin'
9
- require 'rack/lobster'
9
+ require File.dirname(__FILE__) + '/utils'
10
10
 
11
- REQUEST = (ARGV[0] || 1000).to_i # Number of request to send (ab -n option)
11
+ request = (ARGV[0] || 1000).to_i # Number of request to send (ab -n option)
12
12
 
13
- def run(handler_name, c=1, n=REQUEST)
14
- server = fork do
15
- [STDOUT, STDERR].each { |o| o.reopen "/dev/null" }
16
-
17
- app = Rack::Lobster.new
18
-
19
- if handler_name == 'EMongrel'
20
- require 'swiftcore/evented_mongrel'
21
- handler_name = 'Mongrel'
22
- end
23
- handler = Rack::Handler.const_get(handler_name)
24
- handler.run app, :Host => '0.0.0.0', :Port => 7000
25
- end
26
-
27
- sleep 2
28
-
29
- out = `nice -n20 ab -c #{c} -n #{n} http://127.0.0.1:7000/ 2> /dev/null`
30
-
31
- Process.kill('SIGKILL', server)
32
- Process.wait
33
-
34
- if requests = out.match(/^Requests.+?(\d+\.\d+)/)
35
- failed = out.match(/^Failed requests.+?(\d+)$/)[1]
36
- "#{requests[1].to_s.ljust(9)} #{failed}"
37
- else
38
- 'ERROR'
39
- end
40
- end
41
-
42
- puts 'server request concurrency req/s failures'
43
- puts '=' * 53
44
- [1, 10, 100].each do |c|
45
- %w(WEBrick Mongrel EMongrel Thin).each do |server|
46
- puts "#{server.ljust(8)} #{REQUEST} #{c.to_s.ljust(4)} #{run(server, c)}"
47
- end
48
- end
13
+ benchmark %w(WEBrick Mongrel EMongrel Thin), request
@@ -0,0 +1,51 @@
1
+ require 'rack/lobster'
2
+
3
+ def run(handler_name, n=1000, c=1)
4
+ server = fork do
5
+ [STDOUT, STDERR].each { |o| o.reopen "/dev/null" }
6
+
7
+ case handler_name
8
+ when 'EMongrel'
9
+ require 'swiftcore/evented_mongrel'
10
+ handler_name = 'Mongrel'
11
+
12
+ when 'gem' # Load the current Thin gem
13
+ require 'thin'
14
+ handler_name = 'Thin'
15
+
16
+ when 'current' # Load the current Thin version under /lib
17
+ require File.dirname(__FILE__) + '/../lib/thin'
18
+ handler_name = 'Thin'
19
+
20
+ end
21
+
22
+ app = Rack::Lobster.new
23
+
24
+ handler = Rack::Handler.const_get(handler_name)
25
+ handler.run app, :Host => '0.0.0.0', :Port => 7000
26
+ end
27
+
28
+ sleep 2
29
+
30
+ out = `nice -n20 ab -c #{c} -n #{n} http://127.0.0.1:7000/ 2> /dev/null`
31
+
32
+ Process.kill('SIGKILL', server)
33
+ Process.wait
34
+
35
+ if requests = out.match(/^Requests.+?(\d+\.\d+)/)
36
+ failed = out.match(/^Failed requests.+?(\d+)$/)[1]
37
+ "#{requests[1].to_s.ljust(9)} #{failed}"
38
+ else
39
+ 'ERROR'
40
+ end
41
+ end
42
+
43
+ def benchmark(servers, request, concurrency_levels=[1, 10, 100])
44
+ puts 'server request concurrency req/s failures'
45
+ puts '=' * 53
46
+ concurrency_levels.each do |c|
47
+ servers.each do |server|
48
+ puts "#{server.ljust(8)} #{request} #{c.to_s.ljust(4)} #{run(server, request, c)}"
49
+ end
50
+ end
51
+ end
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]))
@@ -4,6 +4,13 @@
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
- run Rack::Lobster.new
8
+ app = proc do |env|
9
+ [
10
+ 200,
11
+ {'Content-Type' => 'text/html'},
12
+ ['hi!']
13
+ ]
14
+ end
15
+
16
+ run app
@@ -1,4 +1,4 @@
1
- $: << File.expand_path(File.dirname(__FILE__))
1
+ $:.unshift File.expand_path(File.dirname(__FILE__))
2
2
 
3
3
  require 'fileutils'
4
4
  require 'timeout'
@@ -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
- trace { @response.to_s }
34
- send_data @response.to_s
33
+ @response.each do |chunk|
34
+ trace { chunk }
35
+ send_data chunk
36
+ end
35
37
 
36
38
  close_connection_after_writing
37
39
 
@@ -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
- attr_reader :headers, :body
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,17 @@ module Thin
30
40
  end
31
41
  end
32
42
 
33
- def body=(stream)
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
- def to_s
44
- @body.rewind
45
- head + @body.read
48
+ # Yields each chunk of the response
49
+ def each
50
+ yield head
51
+ @body.each do |chunk|
52
+ yield chunk
53
+ end
46
54
  end
47
55
  end
48
56
  end
@@ -2,10 +2,10 @@ module Thin
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 5
5
- TINY = 3
5
+ TINY = 4
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
 
9
- CODENAME = 'Purple Yogurt'
9
+ CODENAME = 'Flying Mustard'
10
10
  end
11
11
  end
Binary file
@@ -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 == "Content-Type: text/html\r\nContent-Length: 0\r\nConnection: close\r\n"
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 == "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: 0\r\nConnection: close\r\n\r\n"
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 == "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nSet-Cookie: mium=7\r\nSet-Cookie: hi=there\r\nContent-Length: 0\r\nConnection: close\r\n\r\n"
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 == "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nHost: localhost\r\nContent-Length: 0\r\nConnection: close\r\n\r\n"
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 == "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nSet-Cookie: mium=7\r\nSet-Cookie: hi=there\r\nContent-Length: 0\r\nConnection: close\r\n\r\n"
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 << '<html></html>'
48
+ @response.body = '<html></html>'
42
49
 
43
- @response.to_s.should == "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: 13\r\nConnection: close\r\n\r\n<html></html>"
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.06} ms" do
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.to_s }.should be_faster_then(max_parsing_time)
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
@@ -5,8 +5,10 @@ require 'socket'
5
5
  describe Server do
6
6
  before do
7
7
  app = proc do |env|
8
- body = [env['QUERY_STRING'], env['rack.input'].read].compact
9
- [200, { 'Content-Type' => 'text/html' }, body]
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").should == "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: 4\r\nConnection: close\r\n\r\nthis"
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.3
4
+ version: 0.5.4
5
5
  platform: x86-mswin32-60
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-18 00:00:00 -07:00
12
+ date: 2008-01-19 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -43,62 +43,11 @@ files:
43
43
  - CHANGELOG
44
44
  - README
45
45
  - Rakefile
46
+ - benchmark/previous.rb
46
47
  - benchmark/simple.rb
48
+ - benchmark/utils.rb
47
49
  - bin/thin
48
50
  - doc/benchmarks.txt
49
- - doc/rdoc
50
- - doc/rdoc/classes
51
- - doc/rdoc/classes/Process.html
52
- - doc/rdoc/classes/Rack
53
- - doc/rdoc/classes/Rack/Adapter
54
- - doc/rdoc/classes/Rack/Adapter/Rails
55
- - doc/rdoc/classes/Rack/Adapter/Rails/CGIWrapper.html
56
- - doc/rdoc/classes/Rack/Adapter/Rails.html
57
- - doc/rdoc/classes/Rack/Adapter.html
58
- - doc/rdoc/classes/Rack/Handler
59
- - doc/rdoc/classes/Rack/Handler/Thin.html
60
- - doc/rdoc/classes/Rack/Handler.html
61
- - doc/rdoc/classes/Rack.html
62
- - doc/rdoc/classes/Thin
63
- - doc/rdoc/classes/Thin/Cluster.html
64
- - doc/rdoc/classes/Thin/Connection.html
65
- - doc/rdoc/classes/Thin/Daemonizable
66
- - doc/rdoc/classes/Thin/Daemonizable/ClassMethods.html
67
- - doc/rdoc/classes/Thin/Daemonizable.html
68
- - doc/rdoc/classes/Thin/Headers.html
69
- - doc/rdoc/classes/Thin/InvalidRequest.html
70
- - doc/rdoc/classes/Thin/Logging.html
71
- - doc/rdoc/classes/Thin/Request.html
72
- - doc/rdoc/classes/Thin/Response.html
73
- - doc/rdoc/classes/Thin/Server.html
74
- - doc/rdoc/classes/Thin/StopServer.html
75
- - doc/rdoc/classes/Thin.html
76
- - doc/rdoc/created.rid
77
- - doc/rdoc/files
78
- - doc/rdoc/files/bin
79
- - doc/rdoc/files/bin/thin.html
80
- - doc/rdoc/files/lib
81
- - doc/rdoc/files/lib/rack
82
- - doc/rdoc/files/lib/rack/adapter
83
- - doc/rdoc/files/lib/rack/adapter/rails_rb.html
84
- - doc/rdoc/files/lib/rack/handler
85
- - doc/rdoc/files/lib/rack/handler/thin_rb.html
86
- - doc/rdoc/files/lib/thin
87
- - doc/rdoc/files/lib/thin/cluster_rb.html
88
- - doc/rdoc/files/lib/thin/connection_rb.html
89
- - doc/rdoc/files/lib/thin/daemonizing_rb.html
90
- - doc/rdoc/files/lib/thin/headers_rb.html
91
- - doc/rdoc/files/lib/thin/logging_rb.html
92
- - doc/rdoc/files/lib/thin/request_rb.html
93
- - doc/rdoc/files/lib/thin/response_rb.html
94
- - doc/rdoc/files/lib/thin/server_rb.html
95
- - doc/rdoc/files/lib/thin/statuses_rb.html
96
- - doc/rdoc/files/lib/thin/version_rb.html
97
- - doc/rdoc/files/lib/thin_rb.html
98
- - doc/rdoc/files/README.html
99
- - doc/rdoc/index.html
100
- - doc/rdoc/logo.gif
101
- - doc/rdoc/rdoc-style.css
102
51
  - example/config.ru
103
52
  - example/thin.god
104
53
  - lib/rack
@@ -118,6 +67,7 @@ files:
118
67
  - lib/thin/statuses.rb
119
68
  - lib/thin/version.rb
120
69
  - lib/thin.rb
70
+ - lib/thin_parser.so
121
71
  - spec/cluster_spec.rb
122
72
  - spec/daemonizing_spec.rb
123
73
  - spec/headers_spec.rb
@@ -188,7 +138,6 @@ files:
188
138
  - ext/thin_parser/extconf.rb
189
139
  - ext/thin_parser/common.rl
190
140
  - ext/thin_parser/parser.rl
191
- - lib/thin_parser.so
192
141
  has_rdoc: false
193
142
  homepage: http://code.macournoyer.com/thin/
194
143
  post_install_message: