thin 1.2.6-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (137) hide show
  1. data/CHANGELOG +273 -0
  2. data/COPYING +18 -0
  3. data/README +69 -0
  4. data/Rakefile +39 -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 +1185 -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 +436 -0
  29. data/lib/rack/adapter/loader.rb +91 -0
  30. data/lib/rack/adapter/rails.rb +180 -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 +178 -0
  39. data/lib/thin/controllers/controller.rb +182 -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 +176 -0
  43. data/lib/thin/headers.rb +39 -0
  44. data/lib/thin/logging.rb +54 -0
  45. data/lib/thin/request.rb +157 -0
  46. data/lib/thin/response.rb +101 -0
  47. data/lib/thin/runner.rb +212 -0
  48. data/lib/thin/server.rb +248 -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 +267 -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 +42 -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 +243 -0
  114. data/spec/request/persistent_spec.rb +35 -0
  115. data/spec/request/processing_spec.rb +50 -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 +100 -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 +66 -0
  133. data/tasks/rdoc.rake +25 -0
  134. data/tasks/site.rake +15 -0
  135. data/tasks/spec.rake +43 -0
  136. data/tasks/stats.rake +28 -0
  137. metadata +219 -0
@@ -0,0 +1,91 @@
1
+ module Rack
2
+ class AdapterNotFound < RuntimeError; end
3
+
4
+ # Mapping used to guess which adapter to use in <tt>Adapter.for</tt>.
5
+ # Framework <name> => <file unique to this framework> in order they will
6
+ # be tested.
7
+ # +nil+ for value to never guess.
8
+ # NOTE: If a framework has a file that is not unique, make sure to place
9
+ # it at the end.
10
+ ADAPTERS = [
11
+ [:rack, 'config.ru'],
12
+ [:rails, 'config/environment.rb'],
13
+ [:ramaze, 'start.rb'],
14
+ [:halcyon, 'runner.ru'],
15
+ [:merb, 'config/init.rb'],
16
+ [:mack, 'config/app_config/default.yml'],
17
+ [:mack, 'config/configatron/default.rb'],
18
+ [:file, nil]
19
+ ]
20
+
21
+ module Adapter
22
+ # Guess which adapter to use based on the directory structure
23
+ # or file content.
24
+ # Returns a symbol representing the name of the adapter to use
25
+ # to load the application under <tt>dir/</tt>.
26
+ def self.guess(dir)
27
+ ADAPTERS.each do |adapter, file|
28
+ return adapter if file && ::File.exist?(::File.join(dir, file))
29
+ end
30
+ raise AdapterNotFound, "No adapter found for #{dir}"
31
+ end
32
+
33
+ # Load a Rack application from a Rack config file (.ru).
34
+ def self.load(config)
35
+ rackup_code = ::File.read(config)
36
+ eval("Rack::Builder.new {( #{rackup_code}\n )}.to_app", TOPLEVEL_BINDING, config)
37
+ end
38
+
39
+ # Loads an adapter identified by +name+ using +options+ hash.
40
+ def self.for(name, options={})
41
+ ENV['RACK_ENV'] = options[:environment]
42
+
43
+ case name.to_sym
44
+ when :rack
45
+ return load(::File.join(options[:chdir], "config.ru"))
46
+
47
+ when :rails
48
+ return Rails.new(options.merge(:root => options[:chdir]))
49
+
50
+ when :ramaze
51
+ require "#{options[:chdir]}/start"
52
+
53
+ Ramaze.trait[:essentials].delete Ramaze::Adapter
54
+ Ramaze.start :force => true
55
+
56
+ return Ramaze::Adapter::Base
57
+
58
+ when :merb
59
+ require 'merb-core'
60
+
61
+ Merb::Config.setup(:merb_root => options[:chdir],
62
+ :environment => options[:environment])
63
+ Merb.environment = Merb::Config[:environment]
64
+ Merb.root = Merb::Config[:merb_root]
65
+ Merb::BootLoader.run
66
+
67
+ return Merb::Rack::Application.new
68
+
69
+ when :halcyon
70
+ require 'halcyon'
71
+
72
+ $:.unshift(Halcyon.root/'lib')
73
+
74
+ return Halcyon::Runner.new
75
+
76
+ when :mack
77
+ ENV["MACK_ENV"] = options[:environment]
78
+ load(::File.join(options[:chdir], "Rakefile"))
79
+ require 'mack'
80
+ return Mack::Utils::Server.build_app
81
+
82
+ when :file
83
+ return Rack::File.new(options[:chdir])
84
+
85
+ else
86
+ raise AdapterNotFound, "Adapter not found: #{name}"
87
+
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,180 @@
1
+ require 'cgi'
2
+
3
+ # Adapter to run a Rails app with any supported Rack handler.
4
+ # By default it will try to load the Rails application in the
5
+ # current directory in the development environment.
6
+ #
7
+ # Options:
8
+ # root: Root directory of the Rails app
9
+ # environment: Rails environment to run in (development [default], production or test)
10
+ # prefix: Set the relative URL root.
11
+ #
12
+ # Based on http://fuzed.rubyforge.org/ Rails adapter
13
+ module Rack
14
+ module Adapter
15
+ class Rails
16
+ FILE_METHODS = %w(GET HEAD).freeze
17
+
18
+ def initialize(options={})
19
+ @root = options[:root] || Dir.pwd
20
+ @env = options[:environment] || 'development'
21
+ @prefix = options[:prefix]
22
+
23
+ load_application
24
+
25
+ @rails_app = if rack_based?
26
+ ActionController::Dispatcher.new
27
+ else
28
+ CgiApp.new
29
+ end
30
+
31
+ @file_app = Rack::File.new(::File.join(RAILS_ROOT, "public"))
32
+ end
33
+
34
+ def rack_based?
35
+ rails_version = ::Rails::VERSION
36
+ rails_version::MAJOR >= 2 && rails_version::MINOR >= 2 && rails_version::TINY >= 3
37
+ end
38
+
39
+ def load_application
40
+ ENV['RAILS_ENV'] = @env
41
+
42
+ require "#{@root}/config/environment"
43
+ require 'dispatcher'
44
+
45
+ if @prefix
46
+ if ActionController::Base.respond_to?(:relative_url_root=)
47
+ ActionController::Base.relative_url_root = @prefix # Rails 2.1.1
48
+ else
49
+ ActionController::AbstractRequest.relative_url_root = @prefix
50
+ end
51
+ end
52
+ end
53
+
54
+ def file_exist?(path)
55
+ full_path = ::File.join(@file_app.root, Utils.unescape(path))
56
+ ::File.file?(full_path) && ::File.readable_real?(full_path)
57
+ end
58
+
59
+ def call(env)
60
+ path = env['PATH_INFO'].chomp('/')
61
+ method = env['REQUEST_METHOD']
62
+ cached_path = (path.empty? ? 'index' : path) + ActionController::Base.page_cache_extension
63
+
64
+ if FILE_METHODS.include?(method)
65
+ if file_exist?(path) # Serve the file if it's there
66
+ return @file_app.call(env)
67
+ elsif file_exist?(cached_path) # Serve the page cache if it's there
68
+ env['PATH_INFO'] = cached_path
69
+ return @file_app.call(env)
70
+ end
71
+ end
72
+
73
+ # No static file, let Rails handle it
74
+ @rails_app.call(env)
75
+ end
76
+
77
+ protected
78
+ # For Rails pre Rack (2.3)
79
+ class CgiApp
80
+ def call(env)
81
+ request = Request.new(env)
82
+ response = Response.new
83
+ session_options = ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS
84
+ cgi = CGIWrapper.new(request, response)
85
+
86
+ Dispatcher.dispatch(cgi, session_options, response)
87
+
88
+ response.finish
89
+ end
90
+ end
91
+
92
+ class CGIWrapper < ::CGI
93
+ def initialize(request, response, *args)
94
+ @request = request
95
+ @response = response
96
+ @args = *args
97
+ @input = request.body
98
+
99
+ super *args
100
+ end
101
+
102
+ def header(options = "text/html")
103
+ if options.is_a?(String)
104
+ @response['Content-Type'] = options unless @response['Content-Type']
105
+ else
106
+ @response['Content-Length'] = options.delete('Content-Length').to_s if options['Content-Length']
107
+
108
+ @response['Content-Type'] = options.delete('type') || "text/html"
109
+ @response['Content-Type'] += "; charset=" + options.delete('charset') if options['charset']
110
+
111
+ @response['Content-Language'] = options.delete('language') if options['language']
112
+ @response['Expires'] = options.delete('expires') if options['expires']
113
+
114
+ @response.status = options.delete('Status') if options['Status']
115
+
116
+ # Convert 'cookie' header to 'Set-Cookie' headers.
117
+ # Because Set-Cookie header can appear more the once in the response body,
118
+ # we store it in a line break seperated string that will be translated to
119
+ # multiple Set-Cookie header by the handler.
120
+ if cookie = options.delete('cookie')
121
+ cookies = []
122
+
123
+ case cookie
124
+ when Array then cookie.each { |c| cookies << c.to_s }
125
+ when Hash then cookie.each { |_, c| cookies << c.to_s }
126
+ else cookies << cookie.to_s
127
+ end
128
+
129
+ @output_cookies.each { |c| cookies << c.to_s } if @output_cookies
130
+
131
+ @response['Set-Cookie'] = [@response['Set-Cookie'], cookies].compact
132
+ # See http://groups.google.com/group/rack-devel/browse_thread/thread/e8759b91a82c5a10/a8dbd4574fe97d69?#a8dbd4574fe97d69
133
+ if Thin.ruby_18?
134
+ @response['Set-Cookie'].flatten!
135
+ else
136
+ @response['Set-Cookie'] = @response['Set-Cookie'].join("\n")
137
+ end
138
+ end
139
+
140
+ options.each { |k,v| @response[k] = v }
141
+ end
142
+
143
+ ""
144
+ end
145
+
146
+ def params
147
+ @params ||= @request.params
148
+ end
149
+
150
+ def cookies
151
+ @request.cookies
152
+ end
153
+
154
+ def query_string
155
+ @request.query_string
156
+ end
157
+
158
+ # Used to wrap the normal args variable used inside CGI.
159
+ def args
160
+ @args
161
+ end
162
+
163
+ # Used to wrap the normal env_table variable used inside CGI.
164
+ def env_table
165
+ @request.env
166
+ end
167
+
168
+ # Used to wrap the normal stdinput variable used inside CGI.
169
+ def stdinput
170
+ @input
171
+ end
172
+
173
+ def stdoutput
174
+ STDERR.puts "stdoutput should not be used."
175
+ @response.body
176
+ end
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,46 @@
1
+ require 'fileutils'
2
+ require 'timeout'
3
+ require 'stringio'
4
+ require 'time'
5
+ require 'forwardable'
6
+ require 'openssl'
7
+ require 'eventmachine'
8
+ require 'rack'
9
+
10
+ module Thin
11
+ ROOT = File.expand_path(File.dirname(__FILE__))
12
+
13
+ autoload :Command, "#{ROOT}/thin/command"
14
+ autoload :Connection, "#{ROOT}/thin/connection"
15
+ autoload :Daemonizable, "#{ROOT}/thin/daemonizing"
16
+ autoload :Logging, "#{ROOT}/thin/logging"
17
+ autoload :Headers, "#{ROOT}/thin/headers"
18
+ autoload :Request, "#{ROOT}/thin/request"
19
+ autoload :Response, "#{ROOT}/thin/response"
20
+ autoload :Runner, "#{ROOT}/thin/runner"
21
+ autoload :Server, "#{ROOT}/thin/server"
22
+ autoload :Stats, "#{ROOT}/thin/stats"
23
+
24
+ module Backends
25
+ autoload :Base, "#{ROOT}/thin/backends/base"
26
+ autoload :SwiftiplyClient, "#{ROOT}/thin/backends/swiftiply_client"
27
+ autoload :TcpServer, "#{ROOT}/thin/backends/tcp_server"
28
+ autoload :UnixServer, "#{ROOT}/thin/backends/unix_server"
29
+ end
30
+
31
+ module Controllers
32
+ autoload :Cluster, "#{ROOT}/thin/controllers/cluster"
33
+ autoload :Controller, "#{ROOT}/thin/controllers/controller"
34
+ autoload :Service, "#{ROOT}/thin/controllers/service"
35
+ end
36
+ end
37
+
38
+ require "#{Thin::ROOT}/thin/version"
39
+ require "#{Thin::ROOT}/thin/statuses"
40
+ require "#{Thin::ROOT}/rack/adapter/loader"
41
+
42
+ module Rack
43
+ module Adapter
44
+ autoload :Rails, "#{Thin::ROOT}/rack/adapter/rails"
45
+ end
46
+ end
@@ -0,0 +1,141 @@
1
+ module Thin
2
+ module Backends
3
+ # A Backend connects the server to the client. It handles:
4
+ # * connection/disconnection to the server
5
+ # * initialization of the connections
6
+ # * manitoring of the active connections.
7
+ #
8
+ # == Implementing your own backend
9
+ # You can create your own minimal backend by inheriting this class and
10
+ # defining the +connect+ and +disconnect+ method.
11
+ # If your backend is not based on EventMachine you also need to redefine
12
+ # the +start+, +stop+, <tt>stop!</tt> and +config+ methods.
13
+ class Base
14
+ # Server serving the connections throught the backend
15
+ attr_accessor :server
16
+
17
+ # Maximum time for incoming data to arrive
18
+ attr_accessor :timeout
19
+
20
+ # Maximum number of file or socket descriptors that the server may open.
21
+ attr_accessor :maximum_connections
22
+
23
+ # Maximum number of connections that can be persistent
24
+ attr_accessor :maximum_persistent_connections
25
+
26
+ # Allow using threads in the backend.
27
+ attr_writer :threaded
28
+ def threaded?; @threaded end
29
+
30
+ # Number of persistent connections currently opened
31
+ attr_accessor :persistent_connection_count
32
+
33
+ # Disable the use of epoll under Linux
34
+ attr_accessor :no_epoll
35
+
36
+ def initialize
37
+ @connections = []
38
+ @timeout = Server::DEFAULT_TIMEOUT
39
+ @persistent_connection_count = 0
40
+ @maximum_connections = Server::DEFAULT_MAXIMUM_CONNECTIONS
41
+ @maximum_persistent_connections = Server::DEFAULT_MAXIMUM_PERSISTENT_CONNECTIONS
42
+ @no_epoll = false
43
+ end
44
+
45
+ # Start the backend and connect it.
46
+ def start
47
+ @stopping = false
48
+ starter = proc do
49
+ connect
50
+ @running = true
51
+ end
52
+
53
+ # Allow for early run up of eventmachine.
54
+ if EventMachine.reactor_running?
55
+ starter.call
56
+ else
57
+ EventMachine.run(&starter)
58
+ end
59
+ end
60
+
61
+ # Stop of the backend from accepting new connections.
62
+ def stop
63
+ @running = false
64
+ @stopping = true
65
+
66
+ # Do not accept anymore connection
67
+ disconnect
68
+ stop! if @connections.empty?
69
+ end
70
+
71
+ # Force stop of the backend NOW, too bad for the current connections.
72
+ def stop!
73
+ @running = false
74
+ @stopping = false
75
+
76
+ EventMachine.stop if EventMachine.reactor_running?
77
+ @connections.each { |connection| connection.close_connection }
78
+ close
79
+ end
80
+
81
+ # Configure the backend. This method will be called before droping superuser privileges,
82
+ # so you can do crazy stuff that require godlike powers here.
83
+ def config
84
+ # See http://rubyeventmachine.com/pub/rdoc/files/EPOLL.html
85
+ EventMachine.epoll unless @no_epoll
86
+
87
+ # Set the maximum number of socket descriptors that the server may open.
88
+ # The process needs to have required privilege to set it higher the 1024 on
89
+ # some systems.
90
+ @maximum_connections = EventMachine.set_descriptor_table_size(@maximum_connections) unless Thin.win?
91
+ end
92
+
93
+ # Free up resources used by the backend.
94
+ def close
95
+ end
96
+
97
+ # Returns +true+ if the backend is connected and running.
98
+ def running?
99
+ @running
100
+ end
101
+
102
+ # Called by a connection when it's unbinded.
103
+ def connection_finished(connection)
104
+ @persistent_connection_count -= 1 if connection.can_persist?
105
+ @connections.delete(connection)
106
+
107
+ # Finalize gracefull stop if there's no more active connection.
108
+ stop! if @stopping && @connections.empty?
109
+ end
110
+
111
+ # Returns +true+ if no active connection.
112
+ def empty?
113
+ @connections.empty?
114
+ end
115
+
116
+ # Number of active connections.
117
+ def size
118
+ @connections.size
119
+ end
120
+
121
+ protected
122
+ # Initialize a new connection to a client.
123
+ def initialize_connection(connection)
124
+ connection.backend = self
125
+ connection.app = @server.app
126
+ connection.comm_inactivity_timeout = @timeout
127
+ connection.threaded = @threaded
128
+
129
+ # We control the number of persistent connections by keeping
130
+ # a count of the total one allowed yet.
131
+ if @persistent_connection_count < @maximum_persistent_connections
132
+ connection.can_persist!
133
+ @persistent_connection_count += 1
134
+ end
135
+
136
+ @connections << connection
137
+ end
138
+
139
+ end
140
+ end
141
+ end