thin 1.2.6-x86-mingw32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +273 -0
 - data/COPYING +18 -0
 - data/README +69 -0
 - data/Rakefile +39 -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 +1185 -0
 - data/ext/thin_parser/parser.h +49 -0
 - data/ext/thin_parser/parser.rl +157 -0
 - data/ext/thin_parser/thin.c +436 -0
 - data/lib/rack/adapter/loader.rb +91 -0
 - data/lib/rack/adapter/rails.rb +180 -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 +178 -0
 - data/lib/thin/controllers/controller.rb +182 -0
 - data/lib/thin/controllers/service.rb +75 -0
 - data/lib/thin/controllers/service.sh.erb +39 -0
 - data/lib/thin/daemonizing.rb +176 -0
 - data/lib/thin/headers.rb +39 -0
 - data/lib/thin/logging.rb +54 -0
 - data/lib/thin/request.rb +157 -0
 - data/lib/thin/response.rb +101 -0
 - data/lib/thin/runner.rb +212 -0
 - data/lib/thin/server.rb +248 -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 +267 -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 +42 -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 +243 -0
 - data/spec/request/persistent_spec.rb +35 -0
 - data/spec/request/processing_spec.rb +50 -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 +100 -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 +66 -0
 - data/tasks/rdoc.rake +25 -0
 - data/tasks/site.rake +15 -0
 - data/tasks/spec.rake +43 -0
 - data/tasks/stats.rake +28 -0
 - metadata +219 -0
 
    
        data/lib/thin/headers.rb
    ADDED
    
    | 
         @@ -0,0 +1,39 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Thin
         
     | 
| 
      
 2 
     | 
    
         
            +
              # Store HTTP header name-value pairs direcly to a string
         
     | 
| 
      
 3 
     | 
    
         
            +
              # and allow duplicated entries on some names.
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Headers
         
     | 
| 
      
 5 
     | 
    
         
            +
                HEADER_FORMAT      = "%s: %s\r\n".freeze
         
     | 
| 
      
 6 
     | 
    
         
            +
                ALLOWED_DUPLICATES = %w(Set-Cookie Set-Cookie2 Warning WWW-Authenticate).freeze
         
     | 
| 
      
 7 
     | 
    
         
            +
                
         
     | 
| 
      
 8 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @sent = {}
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @out = []
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
                
         
     | 
| 
      
 13 
     | 
    
         
            +
                # Add <tt>key: value</tt> pair to the headers.
         
     | 
| 
      
 14 
     | 
    
         
            +
                # Ignore if already sent and no duplicates are allowed
         
     | 
| 
      
 15 
     | 
    
         
            +
                # for this +key+.
         
     | 
| 
      
 16 
     | 
    
         
            +
                def []=(key, value)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  if !@sent.has_key?(key) || ALLOWED_DUPLICATES.include?(key)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    @sent[key] = true
         
     | 
| 
      
 19 
     | 
    
         
            +
                    value = case value
         
     | 
| 
      
 20 
     | 
    
         
            +
                            when Time
         
     | 
| 
      
 21 
     | 
    
         
            +
                              value.httpdate
         
     | 
| 
      
 22 
     | 
    
         
            +
                            when NilClass
         
     | 
| 
      
 23 
     | 
    
         
            +
                              return
         
     | 
| 
      
 24 
     | 
    
         
            +
                            else
         
     | 
| 
      
 25 
     | 
    
         
            +
                              value.to_s
         
     | 
| 
      
 26 
     | 
    
         
            +
                            end
         
     | 
| 
      
 27 
     | 
    
         
            +
                    @out << HEADER_FORMAT % [key, value]
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
                
         
     | 
| 
      
 31 
     | 
    
         
            +
                def has_key?(key)
         
     | 
| 
      
 32 
     | 
    
         
            +
                  @sent[key]
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
                
         
     | 
| 
      
 35 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 36 
     | 
    
         
            +
                  @out.join
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
              end
         
     | 
| 
      
 39 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/thin/logging.rb
    ADDED
    
    | 
         @@ -0,0 +1,54 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Thin
         
     | 
| 
      
 2 
     | 
    
         
            +
              # To be included in classes to allow some basic logging
         
     | 
| 
      
 3 
     | 
    
         
            +
              # that can be silenced (<tt>Logging.silent=</tt>) or made
         
     | 
| 
      
 4 
     | 
    
         
            +
              # more verbose.
         
     | 
| 
      
 5 
     | 
    
         
            +
              # <tt>Logging.debug=</tt>: log all error backtrace and messages
         
     | 
| 
      
 6 
     | 
    
         
            +
              #                          logged with +debug+.
         
     | 
| 
      
 7 
     | 
    
         
            +
              # <tt>Logging.trace=</tt>: log all raw request and response and
         
     | 
| 
      
 8 
     | 
    
         
            +
              #                          messages logged with +trace+.
         
     | 
| 
      
 9 
     | 
    
         
            +
              module Logging
         
     | 
| 
      
 10 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 11 
     | 
    
         
            +
                  attr_writer :trace, :debug, :silent
         
     | 
| 
      
 12 
     | 
    
         
            +
                  
         
     | 
| 
      
 13 
     | 
    
         
            +
                  def trace?;  !@silent && @trace  end
         
     | 
| 
      
 14 
     | 
    
         
            +
                  def debug?;  !@silent && @debug  end
         
     | 
| 
      
 15 
     | 
    
         
            +
                  def silent?;  @silent            end
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
                
         
     | 
| 
      
 18 
     | 
    
         
            +
                # Global silencer methods
         
     | 
| 
      
 19 
     | 
    
         
            +
                def silent
         
     | 
| 
      
 20 
     | 
    
         
            +
                  Logging.silent?
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
                def silent=(value)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  Logging.silent = value
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
                
         
     | 
| 
      
 26 
     | 
    
         
            +
                # Log a message to the console
         
     | 
| 
      
 27 
     | 
    
         
            +
                def log(msg)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  puts msg unless Logging.silent?
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
                module_function :log
         
     | 
| 
      
 31 
     | 
    
         
            +
                public :log
         
     | 
| 
      
 32 
     | 
    
         
            +
                
         
     | 
| 
      
 33 
     | 
    
         
            +
                # Log a message to the console if tracing is activated
         
     | 
| 
      
 34 
     | 
    
         
            +
                def trace(msg=nil)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  log msg || yield if Logging.trace?
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
                module_function :trace
         
     | 
| 
      
 38 
     | 
    
         
            +
                public :trace
         
     | 
| 
      
 39 
     | 
    
         
            +
                
         
     | 
| 
      
 40 
     | 
    
         
            +
                # Log a message to the console if debugging is activated
         
     | 
| 
      
 41 
     | 
    
         
            +
                def debug(msg=nil)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  log msg || yield if Logging.debug?
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
                module_function :debug
         
     | 
| 
      
 45 
     | 
    
         
            +
                public :debug
         
     | 
| 
      
 46 
     | 
    
         
            +
                
         
     | 
| 
      
 47 
     | 
    
         
            +
                # Log an error backtrace if debugging is activated
         
     | 
| 
      
 48 
     | 
    
         
            +
                def log_error(e=$!)
         
     | 
| 
      
 49 
     | 
    
         
            +
                  debug "#{e}\n\t" + e.backtrace.join("\n\t")
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
                module_function :log_error
         
     | 
| 
      
 52 
     | 
    
         
            +
                public :log_error
         
     | 
| 
      
 53 
     | 
    
         
            +
              end
         
     | 
| 
      
 54 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/thin/request.rb
    ADDED
    
    | 
         @@ -0,0 +1,157 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "#{Thin::ROOT}/thin_parser"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'tempfile'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Thin
         
     | 
| 
      
 5 
     | 
    
         
            +
              # Raised when an incoming request is not valid
         
     | 
| 
      
 6 
     | 
    
         
            +
              # and the server can not process it.
         
     | 
| 
      
 7 
     | 
    
         
            +
              class InvalidRequest < IOError; end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              # A request sent by the client to the server.
         
     | 
| 
      
 10 
     | 
    
         
            +
              class Request
         
     | 
| 
      
 11 
     | 
    
         
            +
                # Maximum request body size before it is moved out of memory
         
     | 
| 
      
 12 
     | 
    
         
            +
                # and into a tempfile for reading.
         
     | 
| 
      
 13 
     | 
    
         
            +
                MAX_BODY          = 1024 * (80 + 32)
         
     | 
| 
      
 14 
     | 
    
         
            +
                BODY_TMPFILE      = 'thin-body'.freeze
         
     | 
| 
      
 15 
     | 
    
         
            +
                MAX_HEADER        = 1024 * (80 + 32)
         
     | 
| 
      
 16 
     | 
    
         
            +
                
         
     | 
| 
      
 17 
     | 
    
         
            +
                INITIAL_BODY      = ''
         
     | 
| 
      
 18 
     | 
    
         
            +
                # Force external_encoding of request's body to ASCII_8BIT
         
     | 
| 
      
 19 
     | 
    
         
            +
                INITIAL_BODY.encode!(Encoding::ASCII_8BIT) if INITIAL_BODY.respond_to?(:encode!)
         
     | 
| 
      
 20 
     | 
    
         
            +
                
         
     | 
| 
      
 21 
     | 
    
         
            +
                # Freeze some HTTP header names & values
         
     | 
| 
      
 22 
     | 
    
         
            +
                SERVER_SOFTWARE   = 'SERVER_SOFTWARE'.freeze
         
     | 
| 
      
 23 
     | 
    
         
            +
                SERVER_NAME       = 'SERVER_NAME'.freeze
         
     | 
| 
      
 24 
     | 
    
         
            +
                LOCALHOST         = 'localhost'.freeze
         
     | 
| 
      
 25 
     | 
    
         
            +
                HTTP_VERSION      = 'HTTP_VERSION'.freeze
         
     | 
| 
      
 26 
     | 
    
         
            +
                HTTP_1_0          = 'HTTP/1.0'.freeze
         
     | 
| 
      
 27 
     | 
    
         
            +
                REMOTE_ADDR       = 'REMOTE_ADDR'.freeze
         
     | 
| 
      
 28 
     | 
    
         
            +
                CONTENT_LENGTH    = 'CONTENT_LENGTH'.freeze
         
     | 
| 
      
 29 
     | 
    
         
            +
                CONNECTION        = 'HTTP_CONNECTION'.freeze
         
     | 
| 
      
 30 
     | 
    
         
            +
                KEEP_ALIVE_REGEXP = /\bkeep-alive\b/i.freeze
         
     | 
| 
      
 31 
     | 
    
         
            +
                CLOSE_REGEXP      = /\bclose\b/i.freeze
         
     | 
| 
      
 32 
     | 
    
         
            +
                
         
     | 
| 
      
 33 
     | 
    
         
            +
                # Freeze some Rack header names
         
     | 
| 
      
 34 
     | 
    
         
            +
                RACK_INPUT        = 'rack.input'.freeze
         
     | 
| 
      
 35 
     | 
    
         
            +
                RACK_VERSION      = 'rack.version'.freeze
         
     | 
| 
      
 36 
     | 
    
         
            +
                RACK_ERRORS       = 'rack.errors'.freeze
         
     | 
| 
      
 37 
     | 
    
         
            +
                RACK_MULTITHREAD  = 'rack.multithread'.freeze
         
     | 
| 
      
 38 
     | 
    
         
            +
                RACK_MULTIPROCESS = 'rack.multiprocess'.freeze
         
     | 
| 
      
 39 
     | 
    
         
            +
                RACK_RUN_ONCE     = 'rack.run_once'.freeze
         
     | 
| 
      
 40 
     | 
    
         
            +
                ASYNC_CALLBACK    = 'async.callback'.freeze
         
     | 
| 
      
 41 
     | 
    
         
            +
                ASYNC_CLOSE       = 'async.close'.freeze
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                # CGI-like request environment variables
         
     | 
| 
      
 44 
     | 
    
         
            +
                attr_reader :env
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                # Unparsed data of the request
         
     | 
| 
      
 47 
     | 
    
         
            +
                attr_reader :data
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                # Request body
         
     | 
| 
      
 50 
     | 
    
         
            +
                attr_reader :body
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 53 
     | 
    
         
            +
                  @parser   = Thin::HttpParser.new
         
     | 
| 
      
 54 
     | 
    
         
            +
                  @data     = ''
         
     | 
| 
      
 55 
     | 
    
         
            +
                  @nparsed  = 0
         
     | 
| 
      
 56 
     | 
    
         
            +
                  @body     = StringIO.new(INITIAL_BODY.dup)
         
     | 
| 
      
 57 
     | 
    
         
            +
                  @env      = {
         
     | 
| 
      
 58 
     | 
    
         
            +
                    SERVER_SOFTWARE   => SERVER,
         
     | 
| 
      
 59 
     | 
    
         
            +
                    SERVER_NAME       => LOCALHOST,
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                    # Rack stuff
         
     | 
| 
      
 62 
     | 
    
         
            +
                    RACK_INPUT        => @body,
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                    RACK_VERSION      => VERSION::RACK,
         
     | 
| 
      
 65 
     | 
    
         
            +
                    RACK_ERRORS       => STDERR,
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                    RACK_MULTITHREAD  => false,
         
     | 
| 
      
 68 
     | 
    
         
            +
                    RACK_MULTIPROCESS => false,
         
     | 
| 
      
 69 
     | 
    
         
            +
                    RACK_RUN_ONCE     => false
         
     | 
| 
      
 70 
     | 
    
         
            +
                  }
         
     | 
| 
      
 71 
     | 
    
         
            +
                end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                # Parse a chunk of data into the request environment
         
     | 
| 
      
 74 
     | 
    
         
            +
                # Raises a +InvalidRequest+ if invalid.
         
     | 
| 
      
 75 
     | 
    
         
            +
                # Returns +true+ if the parsing is complete.
         
     | 
| 
      
 76 
     | 
    
         
            +
                def parse(data)
         
     | 
| 
      
 77 
     | 
    
         
            +
                  if @parser.finished?  # Header finished, can only be some more body
         
     | 
| 
      
 78 
     | 
    
         
            +
                    body << data
         
     | 
| 
      
 79 
     | 
    
         
            +
                  else                  # Parse more header using the super parser
         
     | 
| 
      
 80 
     | 
    
         
            +
                    @data << data
         
     | 
| 
      
 81 
     | 
    
         
            +
                    raise InvalidRequest, 'Header longer than allowed' if @data.size > MAX_HEADER
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                    @nparsed = @parser.execute(@env, @data, @nparsed)
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                    # Transfert to a tempfile if body is very big
         
     | 
| 
      
 86 
     | 
    
         
            +
                    move_body_to_tempfile if @parser.finished? && content_length > MAX_BODY
         
     | 
| 
      
 87 
     | 
    
         
            +
                  end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                  if finished?   # Check if header and body are complete
         
     | 
| 
      
 91 
     | 
    
         
            +
                    @data = nil
         
     | 
| 
      
 92 
     | 
    
         
            +
                    @body.rewind
         
     | 
| 
      
 93 
     | 
    
         
            +
                    true         # Request is fully parsed
         
     | 
| 
      
 94 
     | 
    
         
            +
                  else
         
     | 
| 
      
 95 
     | 
    
         
            +
                    false        # Not finished, need more data
         
     | 
| 
      
 96 
     | 
    
         
            +
                  end
         
     | 
| 
      
 97 
     | 
    
         
            +
                end
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                # +true+ if headers and body are finished parsing
         
     | 
| 
      
 100 
     | 
    
         
            +
                def finished?
         
     | 
| 
      
 101 
     | 
    
         
            +
                  @parser.finished? && @body.size >= content_length
         
     | 
| 
      
 102 
     | 
    
         
            +
                end
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
                # Expected size of the body
         
     | 
| 
      
 105 
     | 
    
         
            +
                def content_length
         
     | 
| 
      
 106 
     | 
    
         
            +
                  @env[CONTENT_LENGTH].to_i
         
     | 
| 
      
 107 
     | 
    
         
            +
                end
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
                # Returns +true+ if the client expect the connection to be persistent.
         
     | 
| 
      
 110 
     | 
    
         
            +
                def persistent?
         
     | 
| 
      
 111 
     | 
    
         
            +
                  # Clients and servers SHOULD NOT assume that a persistent connection
         
     | 
| 
      
 112 
     | 
    
         
            +
                  # is maintained for HTTP versions less than 1.1 unless it is explicitly
         
     | 
| 
      
 113 
     | 
    
         
            +
                  # signaled. (http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html)
         
     | 
| 
      
 114 
     | 
    
         
            +
                  if @env[HTTP_VERSION] == HTTP_1_0
         
     | 
| 
      
 115 
     | 
    
         
            +
                    @env[CONNECTION] =~ KEEP_ALIVE_REGEXP
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
                  # HTTP/1.1 client intends to maintain a persistent connection unless
         
     | 
| 
      
 118 
     | 
    
         
            +
                  # a Connection header including the connection-token "close" was sent
         
     | 
| 
      
 119 
     | 
    
         
            +
                  # in the request
         
     | 
| 
      
 120 
     | 
    
         
            +
                  else
         
     | 
| 
      
 121 
     | 
    
         
            +
                    @env[CONNECTION].nil? || @env[CONNECTION] !~ CLOSE_REGEXP
         
     | 
| 
      
 122 
     | 
    
         
            +
                  end
         
     | 
| 
      
 123 
     | 
    
         
            +
                end
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
                def remote_address=(address)
         
     | 
| 
      
 126 
     | 
    
         
            +
                  @env[REMOTE_ADDR] = address
         
     | 
| 
      
 127 
     | 
    
         
            +
                end
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
                def threaded=(value)
         
     | 
| 
      
 130 
     | 
    
         
            +
                  @env[RACK_MULTITHREAD] = value
         
     | 
| 
      
 131 
     | 
    
         
            +
                end
         
     | 
| 
      
 132 
     | 
    
         
            +
                
         
     | 
| 
      
 133 
     | 
    
         
            +
                def async_callback=(callback)
         
     | 
| 
      
 134 
     | 
    
         
            +
                  @env[ASYNC_CALLBACK] = callback
         
     | 
| 
      
 135 
     | 
    
         
            +
                  @env[ASYNC_CLOSE] = EventMachine::DefaultDeferrable.new
         
     | 
| 
      
 136 
     | 
    
         
            +
                end
         
     | 
| 
      
 137 
     | 
    
         
            +
                
         
     | 
| 
      
 138 
     | 
    
         
            +
                def async_close
         
     | 
| 
      
 139 
     | 
    
         
            +
                  @async_close ||= @env[ASYNC_CLOSE]
         
     | 
| 
      
 140 
     | 
    
         
            +
                end
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
                # Close any resource used by the request
         
     | 
| 
      
 143 
     | 
    
         
            +
                def close
         
     | 
| 
      
 144 
     | 
    
         
            +
                  @body.delete if @body.class == Tempfile
         
     | 
| 
      
 145 
     | 
    
         
            +
                end
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                private
         
     | 
| 
      
 148 
     | 
    
         
            +
                  def move_body_to_tempfile
         
     | 
| 
      
 149 
     | 
    
         
            +
                    current_body = @body
         
     | 
| 
      
 150 
     | 
    
         
            +
                    current_body.rewind
         
     | 
| 
      
 151 
     | 
    
         
            +
                    @body = Tempfile.new(BODY_TMPFILE)
         
     | 
| 
      
 152 
     | 
    
         
            +
                    @body.binmode
         
     | 
| 
      
 153 
     | 
    
         
            +
                    @body << current_body.read
         
     | 
| 
      
 154 
     | 
    
         
            +
                    @env[RACK_INPUT] = @body
         
     | 
| 
      
 155 
     | 
    
         
            +
                  end
         
     | 
| 
      
 156 
     | 
    
         
            +
              end
         
     | 
| 
      
 157 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,101 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Thin
         
     | 
| 
      
 2 
     | 
    
         
            +
              # A response sent to the client.
         
     | 
| 
      
 3 
     | 
    
         
            +
              class Response
         
     | 
| 
      
 4 
     | 
    
         
            +
                CONNECTION     = 'Connection'.freeze
         
     | 
| 
      
 5 
     | 
    
         
            +
                CLOSE          = 'close'.freeze
         
     | 
| 
      
 6 
     | 
    
         
            +
                KEEP_ALIVE     = 'keep-alive'.freeze
         
     | 
| 
      
 7 
     | 
    
         
            +
                SERVER         = 'Server'.freeze
         
     | 
| 
      
 8 
     | 
    
         
            +
                CONTENT_LENGTH = 'Content-Length'.freeze
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                # Status code
         
     | 
| 
      
 11 
     | 
    
         
            +
                attr_accessor :status
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                # Response body, must respond to +each+.
         
     | 
| 
      
 14 
     | 
    
         
            +
                attr_accessor :body
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                # Headers key-value hash
         
     | 
| 
      
 17 
     | 
    
         
            +
                attr_reader   :headers
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 20 
     | 
    
         
            +
                  @headers    = Headers.new
         
     | 
| 
      
 21 
     | 
    
         
            +
                  @status     = 200
         
     | 
| 
      
 22 
     | 
    
         
            +
                  @persistent = false
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                # String representation of the headers
         
     | 
| 
      
 26 
     | 
    
         
            +
                # to be sent in the response.
         
     | 
| 
      
 27 
     | 
    
         
            +
                def headers_output
         
     | 
| 
      
 28 
     | 
    
         
            +
                  # Set default headers
         
     | 
| 
      
 29 
     | 
    
         
            +
                  @headers[CONNECTION] = persistent? ? KEEP_ALIVE : CLOSE
         
     | 
| 
      
 30 
     | 
    
         
            +
                  @headers[SERVER]     = Thin::SERVER
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  @headers.to_s
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                # Top header of the response,
         
     | 
| 
      
 36 
     | 
    
         
            +
                # containing the status code and response headers.
         
     | 
| 
      
 37 
     | 
    
         
            +
                def head
         
     | 
| 
      
 38 
     | 
    
         
            +
                  "HTTP/1.1 #{@status} #{HTTP_STATUS_CODES[@status.to_i]}\r\n#{headers_output}\r\n"
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                if Thin.ruby_18?
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  # Ruby 1.8 implementation.
         
     | 
| 
      
 44 
     | 
    
         
            +
                  # Respects Rack specs.
         
     | 
| 
      
 45 
     | 
    
         
            +
                  #
         
     | 
| 
      
 46 
     | 
    
         
            +
                  # See http://rack.rubyforge.org/doc/files/SPEC.html
         
     | 
| 
      
 47 
     | 
    
         
            +
                  def headers=(key_value_pairs)
         
     | 
| 
      
 48 
     | 
    
         
            +
                    key_value_pairs.each do |k, vs|
         
     | 
| 
      
 49 
     | 
    
         
            +
                      vs.each { |v| @headers[k] = v.chomp } if vs
         
     | 
| 
      
 50 
     | 
    
         
            +
                    end if key_value_pairs
         
     | 
| 
      
 51 
     | 
    
         
            +
                  end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                else
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                  # Ruby 1.9 doesn't have a String#each anymore.
         
     | 
| 
      
 56 
     | 
    
         
            +
                  # Rack spec doesn't take care of that yet, for now we just use
         
     | 
| 
      
 57 
     | 
    
         
            +
                  # +each+ but fallback to +each_line+ on strings.
         
     | 
| 
      
 58 
     | 
    
         
            +
                  # I wish we could remove that condition.
         
     | 
| 
      
 59 
     | 
    
         
            +
                  # To be reviewed when a new Rack spec comes out.
         
     | 
| 
      
 60 
     | 
    
         
            +
                  def headers=(key_value_pairs)
         
     | 
| 
      
 61 
     | 
    
         
            +
                    key_value_pairs.each do |k, vs|
         
     | 
| 
      
 62 
     | 
    
         
            +
                      next unless vs
         
     | 
| 
      
 63 
     | 
    
         
            +
                      if vs.is_a?(String)
         
     | 
| 
      
 64 
     | 
    
         
            +
                        vs.each_line { |v| @headers[k] = v.chomp }
         
     | 
| 
      
 65 
     | 
    
         
            +
                      else
         
     | 
| 
      
 66 
     | 
    
         
            +
                        vs.each { |v| @headers[k] = v.chomp }
         
     | 
| 
      
 67 
     | 
    
         
            +
                      end
         
     | 
| 
      
 68 
     | 
    
         
            +
                    end if key_value_pairs
         
     | 
| 
      
 69 
     | 
    
         
            +
                  end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                # Close any resource used by the response
         
     | 
| 
      
 74 
     | 
    
         
            +
                def close
         
     | 
| 
      
 75 
     | 
    
         
            +
                  @body.close if @body.respond_to?(:close)
         
     | 
| 
      
 76 
     | 
    
         
            +
                end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                # Yields each chunk of the response.
         
     | 
| 
      
 79 
     | 
    
         
            +
                # To control the size of each chunk
         
     | 
| 
      
 80 
     | 
    
         
            +
                # define your own +each+ method on +body+.
         
     | 
| 
      
 81 
     | 
    
         
            +
                def each
         
     | 
| 
      
 82 
     | 
    
         
            +
                  yield head
         
     | 
| 
      
 83 
     | 
    
         
            +
                  if @body.is_a?(String)
         
     | 
| 
      
 84 
     | 
    
         
            +
                    yield @body
         
     | 
| 
      
 85 
     | 
    
         
            +
                  else
         
     | 
| 
      
 86 
     | 
    
         
            +
                    @body.each { |chunk| yield chunk }
         
     | 
| 
      
 87 
     | 
    
         
            +
                  end
         
     | 
| 
      
 88 
     | 
    
         
            +
                end
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                # Tell the client the connection should stay open
         
     | 
| 
      
 91 
     | 
    
         
            +
                def persistent!
         
     | 
| 
      
 92 
     | 
    
         
            +
                  @persistent = true
         
     | 
| 
      
 93 
     | 
    
         
            +
                end
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                # Persistent connection must be requested as keep-alive
         
     | 
| 
      
 96 
     | 
    
         
            +
                # from the server and have a Content-Length.
         
     | 
| 
      
 97 
     | 
    
         
            +
                def persistent?
         
     | 
| 
      
 98 
     | 
    
         
            +
                  @persistent && @headers.has_key?(CONTENT_LENGTH)
         
     | 
| 
      
 99 
     | 
    
         
            +
                end
         
     | 
| 
      
 100 
     | 
    
         
            +
              end
         
     | 
| 
      
 101 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/thin/runner.rb
    ADDED
    
    | 
         @@ -0,0 +1,212 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'optparse'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'yaml'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Thin  
         
     | 
| 
      
 5 
     | 
    
         
            +
              # CLI runner.
         
     | 
| 
      
 6 
     | 
    
         
            +
              # Parse options and send command to the correct Controller.
         
     | 
| 
      
 7 
     | 
    
         
            +
              class Runner
         
     | 
| 
      
 8 
     | 
    
         
            +
                COMMANDS            = %w(start stop restart config)
         
     | 
| 
      
 9 
     | 
    
         
            +
                LINUX_ONLY_COMMANDS = %w(install)
         
     | 
| 
      
 10 
     | 
    
         
            +
                
         
     | 
| 
      
 11 
     | 
    
         
            +
                # Commands that wont load options from the config file
         
     | 
| 
      
 12 
     | 
    
         
            +
                CONFIGLESS_COMMANDS = %w(config install)
         
     | 
| 
      
 13 
     | 
    
         
            +
                
         
     | 
| 
      
 14 
     | 
    
         
            +
                # Parsed options
         
     | 
| 
      
 15 
     | 
    
         
            +
                attr_accessor :options
         
     | 
| 
      
 16 
     | 
    
         
            +
                
         
     | 
| 
      
 17 
     | 
    
         
            +
                # Name of the command to be runned.
         
     | 
| 
      
 18 
     | 
    
         
            +
                attr_accessor :command
         
     | 
| 
      
 19 
     | 
    
         
            +
                
         
     | 
| 
      
 20 
     | 
    
         
            +
                # Arguments to be passed to the command.
         
     | 
| 
      
 21 
     | 
    
         
            +
                attr_accessor :arguments
         
     | 
| 
      
 22 
     | 
    
         
            +
                
         
     | 
| 
      
 23 
     | 
    
         
            +
                # Return all available commands
         
     | 
| 
      
 24 
     | 
    
         
            +
                def self.commands
         
     | 
| 
      
 25 
     | 
    
         
            +
                  commands  = COMMANDS
         
     | 
| 
      
 26 
     | 
    
         
            +
                  commands += LINUX_ONLY_COMMANDS if Thin.linux?
         
     | 
| 
      
 27 
     | 
    
         
            +
                  commands
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
                
         
     | 
| 
      
 30 
     | 
    
         
            +
                def initialize(argv)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  @argv = argv
         
     | 
| 
      
 32 
     | 
    
         
            +
                  
         
     | 
| 
      
 33 
     | 
    
         
            +
                  # Default options values
         
     | 
| 
      
 34 
     | 
    
         
            +
                  @options = {
         
     | 
| 
      
 35 
     | 
    
         
            +
                    :chdir                => Dir.pwd,
         
     | 
| 
      
 36 
     | 
    
         
            +
                    :environment          => 'development',
         
     | 
| 
      
 37 
     | 
    
         
            +
                    :address              => '0.0.0.0',
         
     | 
| 
      
 38 
     | 
    
         
            +
                    :port                 => Server::DEFAULT_PORT,
         
     | 
| 
      
 39 
     | 
    
         
            +
                    :timeout              => Server::DEFAULT_TIMEOUT,
         
     | 
| 
      
 40 
     | 
    
         
            +
                    :log                  => 'log/thin.log',
         
     | 
| 
      
 41 
     | 
    
         
            +
                    :pid                  => 'tmp/pids/thin.pid',
         
     | 
| 
      
 42 
     | 
    
         
            +
                    :max_conns            => Server::DEFAULT_MAXIMUM_CONNECTIONS,
         
     | 
| 
      
 43 
     | 
    
         
            +
                    :max_persistent_conns => Server::DEFAULT_MAXIMUM_PERSISTENT_CONNECTIONS,
         
     | 
| 
      
 44 
     | 
    
         
            +
                    :require              => [],
         
     | 
| 
      
 45 
     | 
    
         
            +
                    :wait                 => Controllers::Cluster::DEFAULT_WAIT_TIME
         
     | 
| 
      
 46 
     | 
    
         
            +
                  }
         
     | 
| 
      
 47 
     | 
    
         
            +
                  
         
     | 
| 
      
 48 
     | 
    
         
            +
                  parse!
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
                
         
     | 
| 
      
 51 
     | 
    
         
            +
                def parser
         
     | 
| 
      
 52 
     | 
    
         
            +
                  # NOTE: If you add an option here make sure the key in the +options+ hash is the
         
     | 
| 
      
 53 
     | 
    
         
            +
                  # same as the name of the command line option.
         
     | 
| 
      
 54 
     | 
    
         
            +
                  # +option+ keys are used to build the command line to launch other processes,
         
     | 
| 
      
 55 
     | 
    
         
            +
                  # see <tt>lib/thin/command.rb</tt>.
         
     | 
| 
      
 56 
     | 
    
         
            +
                  @parser ||= OptionParser.new do |opts|
         
     | 
| 
      
 57 
     | 
    
         
            +
                    opts.banner = "Usage: thin [options] #{self.class.commands.join('|')}"
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                    opts.separator ""
         
     | 
| 
      
 60 
     | 
    
         
            +
                    opts.separator "Server options:"
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                    opts.on("-a", "--address HOST", "bind to HOST address " +
         
     | 
| 
      
 63 
     | 
    
         
            +
                                                    "(default: #{@options[:address]})")             { |host| @options[:address] = host }
         
     | 
| 
      
 64 
     | 
    
         
            +
                    opts.on("-p", "--port PORT", "use PORT (default: #{@options[:port]})")          { |port| @options[:port] = port.to_i }
         
     | 
| 
      
 65 
     | 
    
         
            +
                    opts.on("-S", "--socket FILE", "bind to unix domain socket")                    { |file| @options[:socket] = file }
         
     | 
| 
      
 66 
     | 
    
         
            +
                    opts.on("-y", "--swiftiply [KEY]", "Run using swiftiply")                       { |key| @options[:swiftiply] = key }
         
     | 
| 
      
 67 
     | 
    
         
            +
                    opts.on("-A", "--adapter NAME", "Rack adapter to use (default: autodetect)",
         
     | 
| 
      
 68 
     | 
    
         
            +
                                                    "(#{Rack::ADAPTERS.map{|(a,b)|a}.join(', ')})") { |name| @options[:adapter] = name }
         
     | 
| 
      
 69 
     | 
    
         
            +
                    opts.on("-R", "--rackup FILE", "Load a Rack config file instead of " +
         
     | 
| 
      
 70 
     | 
    
         
            +
                                                   "Rack adapter")                                  { |file| @options[:rackup] = file }
         
     | 
| 
      
 71 
     | 
    
         
            +
                    opts.on("-c", "--chdir DIR", "Change to dir before starting")                   { |dir| @options[:chdir] = File.expand_path(dir) }
         
     | 
| 
      
 72 
     | 
    
         
            +
                    opts.on(      "--stats PATH", "Mount the Stats adapter under PATH")             { |path| @options[:stats] = path }
         
     | 
| 
      
 73 
     | 
    
         
            +
                    
         
     | 
| 
      
 74 
     | 
    
         
            +
                    opts.separator ""
         
     | 
| 
      
 75 
     | 
    
         
            +
                    opts.separator "Adapter options:"
         
     | 
| 
      
 76 
     | 
    
         
            +
                    opts.on("-e", "--environment ENV", "Framework environment " +                       
         
     | 
| 
      
 77 
     | 
    
         
            +
                                                       "(default: #{@options[:environment]})")      { |env| @options[:environment] = env }
         
     | 
| 
      
 78 
     | 
    
         
            +
                    opts.on(      "--prefix PATH", "Mount the app under PATH (start with /)")       { |path| @options[:prefix] = path }
         
     | 
| 
      
 79 
     | 
    
         
            +
                    
         
     | 
| 
      
 80 
     | 
    
         
            +
                    unless Thin.win? # Daemonizing not supported on Windows
         
     | 
| 
      
 81 
     | 
    
         
            +
                      opts.separator ""
         
     | 
| 
      
 82 
     | 
    
         
            +
                      opts.separator "Daemon options:"
         
     | 
| 
      
 83 
     | 
    
         
            +
                                                                                                  
         
     | 
| 
      
 84 
     | 
    
         
            +
                      opts.on("-d", "--daemonize", "Run daemonized in the background")              { @options[:daemonize] = true }
         
     | 
| 
      
 85 
     | 
    
         
            +
                      opts.on("-l", "--log FILE", "File to redirect output " +                      
         
     | 
| 
      
 86 
     | 
    
         
            +
                                                  "(default: #{@options[:log]})")                   { |file| @options[:log] = file }
         
     | 
| 
      
 87 
     | 
    
         
            +
                      opts.on("-P", "--pid FILE", "File to store PID " +                            
         
     | 
| 
      
 88 
     | 
    
         
            +
                                                  "(default: #{@options[:pid]})")                   { |file| @options[:pid] = file }
         
     | 
| 
      
 89 
     | 
    
         
            +
                      opts.on("-u", "--user NAME", "User to run daemon as (use with -g)")           { |user| @options[:user] = user }
         
     | 
| 
      
 90 
     | 
    
         
            +
                      opts.on("-g", "--group NAME", "Group to run daemon as (use with -u)")         { |group| @options[:group] = group }
         
     | 
| 
      
 91 
     | 
    
         
            +
                      opts.on(      "--tag NAME", "Additional text to display in process listing")  { |tag| @options[:tag] = tag }
         
     | 
| 
      
 92 
     | 
    
         
            +
                                                                                                  
         
     | 
| 
      
 93 
     | 
    
         
            +
                      opts.separator ""
         
     | 
| 
      
 94 
     | 
    
         
            +
                      opts.separator "Cluster options:"                                             
         
     | 
| 
      
 95 
     | 
    
         
            +
                                                                                                  
         
     | 
| 
      
 96 
     | 
    
         
            +
                      opts.on("-s", "--servers NUM", "Number of servers to start")                  { |num| @options[:servers] = num.to_i }
         
     | 
| 
      
 97 
     | 
    
         
            +
                      opts.on("-o", "--only NUM", "Send command to only one server of the cluster") { |only| @options[:only] = only.to_i }
         
     | 
| 
      
 98 
     | 
    
         
            +
                      opts.on("-C", "--config FILE", "Load options from config file")               { |file| @options[:config] = file }
         
     | 
| 
      
 99 
     | 
    
         
            +
                      opts.on(      "--all [DIR]", "Send command to each config files in DIR")      { |dir| @options[:all] = dir } if Thin.linux?
         
     | 
| 
      
 100 
     | 
    
         
            +
                      opts.on("-O", "--onebyone", "Restart the cluster one by one (only works with restart command)") { @options[:onebyone] = true }
         
     | 
| 
      
 101 
     | 
    
         
            +
                      opts.on("-w", "--wait NUM", "Maximum wait time for server to be started in seconds (use with -O)") { |time| @options[:wait] = time.to_i }
         
     | 
| 
      
 102 
     | 
    
         
            +
                    end
         
     | 
| 
      
 103 
     | 
    
         
            +
                    
         
     | 
| 
      
 104 
     | 
    
         
            +
                    opts.separator ""
         
     | 
| 
      
 105 
     | 
    
         
            +
                    opts.separator "Tuning options:"
         
     | 
| 
      
 106 
     | 
    
         
            +
                    
         
     | 
| 
      
 107 
     | 
    
         
            +
                    opts.on("-b", "--backend CLASS", "Backend to use, full classname")              { |name| @options[:backend] = name }
         
     | 
| 
      
 108 
     | 
    
         
            +
                    opts.on("-t", "--timeout SEC", "Request or command timeout in sec " +            
         
     | 
| 
      
 109 
     | 
    
         
            +
                                                   "(default: #{@options[:timeout]})")              { |sec| @options[:timeout] = sec.to_i }
         
     | 
| 
      
 110 
     | 
    
         
            +
                    opts.on("-f", "--force", "Force the execution of the command")                  { @options[:force] = true }
         
     | 
| 
      
 111 
     | 
    
         
            +
                    opts.on(      "--max-conns NUM", "Maximum number of open file descriptors " +
         
     | 
| 
      
 112 
     | 
    
         
            +
                                                     "(default: #{@options[:max_conns]})",
         
     | 
| 
      
 113 
     | 
    
         
            +
                                                     "Might require sudo to set higher then 1024")  { |num| @options[:max_conns] = num.to_i } unless Thin.win?
         
     | 
| 
      
 114 
     | 
    
         
            +
                    opts.on(      "--max-persistent-conns NUM",
         
     | 
| 
      
 115 
     | 
    
         
            +
                                                   "Maximum number of persistent connections",
         
     | 
| 
      
 116 
     | 
    
         
            +
                                                   "(default: #{@options[:max_persistent_conns]})") { |num| @options[:max_persistent_conns] = num.to_i }
         
     | 
| 
      
 117 
     | 
    
         
            +
                    opts.on(      "--threaded", "Call the Rack application in threads " +
         
     | 
| 
      
 118 
     | 
    
         
            +
                                                "[experimental]")                                   { @options[:threaded] = true }
         
     | 
| 
      
 119 
     | 
    
         
            +
                    opts.on(      "--no-epoll", "Disable the use of epoll")                         { @options[:no_epoll] = true } if Thin.linux?
         
     | 
| 
      
 120 
     | 
    
         
            +
                    
         
     | 
| 
      
 121 
     | 
    
         
            +
                    opts.separator ""
         
     | 
| 
      
 122 
     | 
    
         
            +
                    opts.separator "Common options:"
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
      
 124 
     | 
    
         
            +
                    opts.on_tail("-r", "--require FILE", "require the library")                     { |file| @options[:require] << file }
         
     | 
| 
      
 125 
     | 
    
         
            +
                    opts.on_tail("-D", "--debug", "Set debbuging on")                               { @options[:debug] = true }
         
     | 
| 
      
 126 
     | 
    
         
            +
                    opts.on_tail("-V", "--trace", "Set tracing on (log raw request/response)")      { @options[:trace] = true }
         
     | 
| 
      
 127 
     | 
    
         
            +
                    opts.on_tail("-h", "--help", "Show this message")                               { puts opts; exit }
         
     | 
| 
      
 128 
     | 
    
         
            +
                    opts.on_tail('-v', '--version', "Show version")                                 { puts Thin::SERVER; exit }
         
     | 
| 
      
 129 
     | 
    
         
            +
                  end
         
     | 
| 
      
 130 
     | 
    
         
            +
                end
         
     | 
| 
      
 131 
     | 
    
         
            +
                
         
     | 
| 
      
 132 
     | 
    
         
            +
                # Parse the options.
         
     | 
| 
      
 133 
     | 
    
         
            +
                def parse!
         
     | 
| 
      
 134 
     | 
    
         
            +
                  parser.parse! @argv
         
     | 
| 
      
 135 
     | 
    
         
            +
                  @command   = @argv.shift
         
     | 
| 
      
 136 
     | 
    
         
            +
                  @arguments = @argv
         
     | 
| 
      
 137 
     | 
    
         
            +
                end
         
     | 
| 
      
 138 
     | 
    
         
            +
                    
         
     | 
| 
      
 139 
     | 
    
         
            +
                # Parse the current shell arguments and run the command.
         
     | 
| 
      
 140 
     | 
    
         
            +
                # Exits on error.
         
     | 
| 
      
 141 
     | 
    
         
            +
                def run!
         
     | 
| 
      
 142 
     | 
    
         
            +
                  if self.class.commands.include?(@command)
         
     | 
| 
      
 143 
     | 
    
         
            +
                    run_command
         
     | 
| 
      
 144 
     | 
    
         
            +
                  elsif @command.nil?
         
     | 
| 
      
 145 
     | 
    
         
            +
                    puts "Command required"
         
     | 
| 
      
 146 
     | 
    
         
            +
                    puts @parser
         
     | 
| 
      
 147 
     | 
    
         
            +
                    exit 1  
         
     | 
| 
      
 148 
     | 
    
         
            +
                  else
         
     | 
| 
      
 149 
     | 
    
         
            +
                    abort "Unknown command: #{@command}. Use one of #{self.class.commands.join(', ')}"
         
     | 
| 
      
 150 
     | 
    
         
            +
                  end
         
     | 
| 
      
 151 
     | 
    
         
            +
                end
         
     | 
| 
      
 152 
     | 
    
         
            +
                
         
     | 
| 
      
 153 
     | 
    
         
            +
                # Send the command to the controller: single instance or cluster.
         
     | 
| 
      
 154 
     | 
    
         
            +
                def run_command
         
     | 
| 
      
 155 
     | 
    
         
            +
                  load_options_from_config_file! unless CONFIGLESS_COMMANDS.include?(@command)
         
     | 
| 
      
 156 
     | 
    
         
            +
                  
         
     | 
| 
      
 157 
     | 
    
         
            +
                  # PROGRAM_NAME is relative to the current directory, so make sure
         
     | 
| 
      
 158 
     | 
    
         
            +
                  # we store and expand it before changing directory.
         
     | 
| 
      
 159 
     | 
    
         
            +
                  Command.script = File.expand_path($PROGRAM_NAME)
         
     | 
| 
      
 160 
     | 
    
         
            +
                  
         
     | 
| 
      
 161 
     | 
    
         
            +
                  # Change the current directory ASAP so that all relative paths are
         
     | 
| 
      
 162 
     | 
    
         
            +
                  # relative to this one.
         
     | 
| 
      
 163 
     | 
    
         
            +
                  Dir.chdir(@options[:chdir]) unless CONFIGLESS_COMMANDS.include?(@command)
         
     | 
| 
      
 164 
     | 
    
         
            +
                  
         
     | 
| 
      
 165 
     | 
    
         
            +
                  @options[:require].each { |r| ruby_require r }
         
     | 
| 
      
 166 
     | 
    
         
            +
                  Logging.debug = @options[:debug]
         
     | 
| 
      
 167 
     | 
    
         
            +
                  Logging.trace = @options[:trace]
         
     | 
| 
      
 168 
     | 
    
         
            +
                  
         
     | 
| 
      
 169 
     | 
    
         
            +
                  controller = case
         
     | 
| 
      
 170 
     | 
    
         
            +
                  when cluster? then Controllers::Cluster.new(@options)
         
     | 
| 
      
 171 
     | 
    
         
            +
                  when service? then Controllers::Service.new(@options)
         
     | 
| 
      
 172 
     | 
    
         
            +
                  else               Controllers::Controller.new(@options)
         
     | 
| 
      
 173 
     | 
    
         
            +
                  end
         
     | 
| 
      
 174 
     | 
    
         
            +
                  
         
     | 
| 
      
 175 
     | 
    
         
            +
                  if controller.respond_to?(@command)
         
     | 
| 
      
 176 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 177 
     | 
    
         
            +
                      controller.send(@command, *@arguments)
         
     | 
| 
      
 178 
     | 
    
         
            +
                    rescue RunnerError => e
         
     | 
| 
      
 179 
     | 
    
         
            +
                      abort e.message
         
     | 
| 
      
 180 
     | 
    
         
            +
                    end
         
     | 
| 
      
 181 
     | 
    
         
            +
                  else
         
     | 
| 
      
 182 
     | 
    
         
            +
                    abort "Invalid options for command: #{@command}"
         
     | 
| 
      
 183 
     | 
    
         
            +
                  end
         
     | 
| 
      
 184 
     | 
    
         
            +
                end
         
     | 
| 
      
 185 
     | 
    
         
            +
                
         
     | 
| 
      
 186 
     | 
    
         
            +
                # +true+ if we're controlling a cluster.
         
     | 
| 
      
 187 
     | 
    
         
            +
                def cluster?
         
     | 
| 
      
 188 
     | 
    
         
            +
                  @options[:only] || @options[:servers] || @options[:config]
         
     | 
| 
      
 189 
     | 
    
         
            +
                end
         
     | 
| 
      
 190 
     | 
    
         
            +
                
         
     | 
| 
      
 191 
     | 
    
         
            +
                # +true+ if we're acting a as system service.
         
     | 
| 
      
 192 
     | 
    
         
            +
                def service?
         
     | 
| 
      
 193 
     | 
    
         
            +
                  @options.has_key?(:all) || @command == 'install'
         
     | 
| 
      
 194 
     | 
    
         
            +
                end
         
     | 
| 
      
 195 
     | 
    
         
            +
                
         
     | 
| 
      
 196 
     | 
    
         
            +
                private
         
     | 
| 
      
 197 
     | 
    
         
            +
                  def load_options_from_config_file!
         
     | 
| 
      
 198 
     | 
    
         
            +
                    if file = @options.delete(:config)
         
     | 
| 
      
 199 
     | 
    
         
            +
                      YAML.load_file(file).each { |key, value| @options[key.to_sym] = value }
         
     | 
| 
      
 200 
     | 
    
         
            +
                    end
         
     | 
| 
      
 201 
     | 
    
         
            +
                  end
         
     | 
| 
      
 202 
     | 
    
         
            +
                  
         
     | 
| 
      
 203 
     | 
    
         
            +
                  def ruby_require(file)
         
     | 
| 
      
 204 
     | 
    
         
            +
                    if File.extname(file) == '.ru'
         
     | 
| 
      
 205 
     | 
    
         
            +
                      warn 'WARNING: Use the -R option to load a Rack config file'
         
     | 
| 
      
 206 
     | 
    
         
            +
                      @options[:rackup] = file
         
     | 
| 
      
 207 
     | 
    
         
            +
                    else
         
     | 
| 
      
 208 
     | 
    
         
            +
                      require file
         
     | 
| 
      
 209 
     | 
    
         
            +
                    end
         
     | 
| 
      
 210 
     | 
    
         
            +
                  end
         
     | 
| 
      
 211 
     | 
    
         
            +
              end
         
     | 
| 
      
 212 
     | 
    
         
            +
            end
         
     |