steamcannon-thin 1.2.8

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 +288 -0
  2. data/COPYING +18 -0
  3. data/README +69 -0
  4. data/Rakefile +44 -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 +1249 -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 +183 -0
  31. data/lib/thin.rb +56 -0
  32. data/lib/thin/backends/base.rb +149 -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 +224 -0
  38. data/lib/thin/controllers/cluster.rb +178 -0
  39. data/lib/thin/controllers/controller.rb +188 -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 +180 -0
  43. data/lib/thin/headers.rb +39 -0
  44. data/lib/thin/logging.rb +54 -0
  45. data/lib/thin/request.rb +156 -0
  46. data/lib/thin/response.rb +101 -0
  47. data/lib/thin/runner.rb +220 -0
  48. data/lib/thin/server.rb +253 -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 +196 -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 +173 -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 +254 -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 +220 -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 +251 -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,183 @@
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 self.class.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 load_application
35
+ ENV['RAILS_ENV'] = @env
36
+
37
+ require "#{@root}/config/environment"
38
+ require 'dispatcher'
39
+
40
+ if @prefix
41
+ if ActionController::Base.respond_to?(:relative_url_root=)
42
+ ActionController::Base.relative_url_root = @prefix # Rails 2.1.1
43
+ else
44
+ ActionController::AbstractRequest.relative_url_root = @prefix
45
+ end
46
+ end
47
+ end
48
+
49
+ def file_exist?(path)
50
+ full_path = ::File.join(@file_app.root, Utils.unescape(path))
51
+ ::File.file?(full_path) && ::File.readable_real?(full_path)
52
+ end
53
+
54
+ def call(env)
55
+ path = env['PATH_INFO'].chomp('/')
56
+ method = env['REQUEST_METHOD']
57
+ cached_path = (path.empty? ? 'index' : path) + ActionController::Base.page_cache_extension
58
+
59
+ if FILE_METHODS.include?(method)
60
+ if file_exist?(path) # Serve the file if it's there
61
+ return @file_app.call(env)
62
+ elsif file_exist?(cached_path) # Serve the page cache if it's there
63
+ env['PATH_INFO'] = cached_path
64
+ return @file_app.call(env)
65
+ end
66
+ end
67
+
68
+ # No static file, let Rails handle it
69
+ @rails_app.call(env)
70
+ end
71
+
72
+ def self.rack_based?
73
+ rails_version = ::Rails::VERSION
74
+ return false if rails_version::MAJOR < 2
75
+ return false if rails_version::MAJOR == 2 && rails_version::MINOR < 2
76
+ return false if rails_version::MAJOR == 2 && rails_version::MINOR == 2 && rails_version::TINY < 3
77
+ true # >= 2.2.3
78
+ end
79
+
80
+ protected
81
+ # For Rails pre Rack (2.3)
82
+ class CgiApp
83
+ def call(env)
84
+ request = Request.new(env)
85
+ response = Response.new
86
+ session_options = ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS
87
+ cgi = CGIWrapper.new(request, response)
88
+
89
+ Dispatcher.dispatch(cgi, session_options, response)
90
+
91
+ response.finish
92
+ end
93
+ end
94
+
95
+ class CGIWrapper < ::CGI
96
+ def initialize(request, response, *args)
97
+ @request = request
98
+ @response = response
99
+ @args = *args
100
+ @input = request.body
101
+
102
+ super *args
103
+ end
104
+
105
+ def header(options = "text/html")
106
+ if options.is_a?(String)
107
+ @response['Content-Type'] = options unless @response['Content-Type']
108
+ else
109
+ @response['Content-Length'] = options.delete('Content-Length').to_s if options['Content-Length']
110
+
111
+ @response['Content-Type'] = options.delete('type') || "text/html"
112
+ @response['Content-Type'] += "; charset=" + options.delete('charset') if options['charset']
113
+
114
+ @response['Content-Language'] = options.delete('language') if options['language']
115
+ @response['Expires'] = options.delete('expires') if options['expires']
116
+
117
+ @response.status = options.delete('Status') if options['Status']
118
+
119
+ # Convert 'cookie' header to 'Set-Cookie' headers.
120
+ # Because Set-Cookie header can appear more the once in the response body,
121
+ # we store it in a line break seperated string that will be translated to
122
+ # multiple Set-Cookie header by the handler.
123
+ if cookie = options.delete('cookie')
124
+ cookies = []
125
+
126
+ case cookie
127
+ when Array then cookie.each { |c| cookies << c.to_s }
128
+ when Hash then cookie.each { |_, c| cookies << c.to_s }
129
+ else cookies << cookie.to_s
130
+ end
131
+
132
+ @output_cookies.each { |c| cookies << c.to_s } if @output_cookies
133
+
134
+ @response['Set-Cookie'] = [@response['Set-Cookie'], cookies].compact
135
+ # See http://groups.google.com/group/rack-devel/browse_thread/thread/e8759b91a82c5a10/a8dbd4574fe97d69?#a8dbd4574fe97d69
136
+ if Thin.ruby_18?
137
+ @response['Set-Cookie'].flatten!
138
+ else
139
+ @response['Set-Cookie'] = @response['Set-Cookie'].join("\n")
140
+ end
141
+ end
142
+
143
+ options.each { |k,v| @response[k] = v }
144
+ end
145
+
146
+ ""
147
+ end
148
+
149
+ def params
150
+ @params ||= @request.params
151
+ end
152
+
153
+ def cookies
154
+ @request.cookies
155
+ end
156
+
157
+ def query_string
158
+ @request.query_string
159
+ end
160
+
161
+ # Used to wrap the normal args variable used inside CGI.
162
+ def args
163
+ @args
164
+ end
165
+
166
+ # Used to wrap the normal env_table variable used inside CGI.
167
+ def env_table
168
+ @request.env
169
+ end
170
+
171
+ # Used to wrap the normal stdinput variable used inside CGI.
172
+ def stdinput
173
+ @input
174
+ end
175
+
176
+ def stdoutput
177
+ STDERR.puts "stdoutput should not be used."
178
+ @response.body
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end
data/lib/thin.rb ADDED
@@ -0,0 +1,56 @@
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
+ # support multiple Ruby version (fat binaries under windows)
43
+ begin
44
+ require "#{Thin::ROOT}/thin_parser"
45
+ rescue LoadError
46
+ if RUBY_PLATFORM =~ /mingw|mswin/ then
47
+ RUBY_VERSION =~ /(\d+.\d+)/
48
+ require "#{Thin::ROOT}/#{$1}/thin_parser"
49
+ end
50
+ end
51
+
52
+ module Rack
53
+ module Adapter
54
+ autoload :Rails, "#{Thin::ROOT}/rack/adapter/rails"
55
+ end
56
+ end
@@ -0,0 +1,149 @@
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
+ # Allow using SSL in the backend.
31
+ attr_writer :ssl, :ssl_options
32
+ def ssl?; @ssl end
33
+
34
+ # Number of persistent connections currently opened
35
+ attr_accessor :persistent_connection_count
36
+
37
+ # Disable the use of epoll under Linux
38
+ attr_accessor :no_epoll
39
+
40
+ def initialize
41
+ @connections = []
42
+ @timeout = Server::DEFAULT_TIMEOUT
43
+ @persistent_connection_count = 0
44
+ @maximum_connections = Server::DEFAULT_MAXIMUM_CONNECTIONS
45
+ @maximum_persistent_connections = Server::DEFAULT_MAXIMUM_PERSISTENT_CONNECTIONS
46
+ @no_epoll = false
47
+ end
48
+
49
+ # Start the backend and connect it.
50
+ def start
51
+ @stopping = false
52
+ starter = proc do
53
+ connect
54
+ @running = true
55
+ end
56
+
57
+ # Allow for early run up of eventmachine.
58
+ if EventMachine.reactor_running?
59
+ starter.call
60
+ else
61
+ EventMachine.run(&starter)
62
+ end
63
+ end
64
+
65
+ # Stop of the backend from accepting new connections.
66
+ def stop
67
+ @running = false
68
+ @stopping = true
69
+
70
+ # Do not accept anymore connection
71
+ disconnect
72
+ stop! if @connections.empty?
73
+ end
74
+
75
+ # Force stop of the backend NOW, too bad for the current connections.
76
+ def stop!
77
+ @running = false
78
+ @stopping = false
79
+
80
+ EventMachine.stop if EventMachine.reactor_running?
81
+ @connections.each { |connection| connection.close_connection }
82
+ close
83
+ end
84
+
85
+ # Configure the backend. This method will be called before droping superuser privileges,
86
+ # so you can do crazy stuff that require godlike powers here.
87
+ def config
88
+ # See http://rubyeventmachine.com/pub/rdoc/files/EPOLL.html
89
+ EventMachine.epoll unless @no_epoll
90
+
91
+ # Set the maximum number of socket descriptors that the server may open.
92
+ # The process needs to have required privilege to set it higher the 1024 on
93
+ # some systems.
94
+ @maximum_connections = EventMachine.set_descriptor_table_size(@maximum_connections) unless Thin.win?
95
+ end
96
+
97
+ # Free up resources used by the backend.
98
+ def close
99
+ end
100
+
101
+ # Returns +true+ if the backend is connected and running.
102
+ def running?
103
+ @running
104
+ end
105
+
106
+ # Called by a connection when it's unbinded.
107
+ def connection_finished(connection)
108
+ @persistent_connection_count -= 1 if connection.can_persist?
109
+ @connections.delete(connection)
110
+
111
+ # Finalize gracefull stop if there's no more active connection.
112
+ stop! if @stopping && @connections.empty?
113
+ end
114
+
115
+ # Returns +true+ if no active connection.
116
+ def empty?
117
+ @connections.empty?
118
+ end
119
+
120
+ # Number of active connections.
121
+ def size
122
+ @connections.size
123
+ end
124
+
125
+ protected
126
+ # Initialize a new connection to a client.
127
+ def initialize_connection(connection)
128
+ connection.backend = self
129
+ connection.app = @server.app
130
+ connection.comm_inactivity_timeout = @timeout
131
+ connection.threaded = @threaded
132
+
133
+ if @ssl
134
+ connection.start_tls(@ssl_options)
135
+ end
136
+
137
+ # We control the number of persistent connections by keeping
138
+ # a count of the total one allowed yet.
139
+ if @persistent_connection_count < @maximum_persistent_connections
140
+ connection.can_persist!
141
+ @persistent_connection_count += 1
142
+ end
143
+
144
+ @connections << connection
145
+ end
146
+
147
+ end
148
+ end
149
+ end