From 73023929f01db91510d834ba3dcc1d8d75b46f77 Mon Sep 17 00:00:00 2001 From: Daniel <44275041+Irvin-Solis@users.noreply.github.com> Date: Wed, 30 Jul 2025 15:36:57 -0500 Subject: [PATCH 1/3] added requires for missing logger --- lib/thin/server.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/thin/server.rb b/lib/thin/server.rb index 1251ec7d..2f1c4c93 100644 --- a/lib/thin/server.rb +++ b/lib/thin/server.rb @@ -1,3 +1,6 @@ +require 'thin' +require 'rack/handler/thin' + module Thin # The utterly famous Thin HTTP server. # It listens for incoming requests through a given +backend+ From de65007fbca89148e4cb73a23264e3cd3920ce1f Mon Sep 17 00:00:00 2001 From: "Jimenez-Solis, Irvin" Date: Wed, 30 Jul 2025 18:57:27 -0500 Subject: [PATCH 2/3] logic for handling rack versions --- lib/rack/handler/thin.rb | 11 +++++- lib/thin/server.rb | 83 +++++++++++++++++++--------------------- 2 files changed, 50 insertions(+), 44 deletions(-) diff --git a/lib/rack/handler/thin.rb b/lib/rack/handler/thin.rb index 0f374907..5c762d4e 100644 --- a/lib/rack/handler/thin.rb +++ b/lib/rack/handler/thin.rb @@ -1,6 +1,15 @@ # frozen_string_literal: true -require 'rack/handler' +# Try the old rack/handler (Rack 1 & 2), fall back to rackup/handler (Rack 3) +begin + require 'rack/handler' +rescue LoadError + require 'rackup/handler' +end + +# Load Thin and its Logging module before we subclass +require 'thin' +require 'thin/logging' require_relative '../../thin/rackup/handler' module Rack diff --git a/lib/thin/server.rb b/lib/thin/server.rb index 2f1c4c93..a061acf2 100644 --- a/lib/thin/server.rb +++ b/lib/thin/server.rb @@ -1,6 +1,3 @@ -require 'thin' -require 'rack/handler/thin' - module Thin # The utterly famous Thin HTTP server. # It listens for incoming requests through a given +backend+ @@ -15,7 +12,7 @@ module Thin # == UNIX domain server # Create a new UNIX domain socket bound to +socket+ file by specifiying a filename # as the first argument. Eg.: /tmp/thin.sock. If the first argument contains a / - # it will be assumed to be a UNIX socket. + # it will be assumed to be a UNIX socket. # # Thin::Server.start('/tmp/thin.sock', app) # @@ -33,7 +30,7 @@ module Thin # == Building an app in place # If a block is passed, a Rack::Builder instance # will be passed to build the +app+. So you can do cool stuff like this: - # + # # Thin::Server.start('0.0.0.0', 3000) do # use Rack::CommonLogger # use Rack::ShowExceptions @@ -50,19 +47,19 @@ module Thin # * USR1 reopen log files. # Signals are processed at one second intervals. # Disable signals by passing :signals => false. - # + # class Server include Logging include Daemonizable extend Forwardable - + # Default values DEFAULT_TIMEOUT = 30 #sec DEFAULT_HOST = '0.0.0.0' DEFAULT_PORT = 3000 DEFAULT_MAXIMUM_CONNECTIONS = 1024 DEFAULT_MAXIMUM_PERSISTENT_CONNECTIONS = 100 - + # Application (Rack adapter) called with the request that produces the response. attr_accessor :app @@ -71,38 +68,38 @@ class Server # Backend handling the connections to the clients. attr_accessor :backend - + # Maximum number of seconds for incoming data to arrive before the connection # is dropped. def_delegators :backend, :timeout, :timeout= - + # Maximum number of file or socket descriptors that the server may open. def_delegators :backend, :maximum_connections, :maximum_connections= - + # Maximum number of connections that can be persistent at the same time. # Most browsers never close the connection so most of the time they are closed # when the timeout occurs. If we don't control the number of persistent connections, # it would be very easy to overflow the server for a DoS attack. def_delegators :backend, :maximum_persistent_connections, :maximum_persistent_connections= - + # Allow using threads in the backend. def_delegators :backend, :threaded?, :threaded=, :threadpool_size, :threadpool_size= - + # Allow using SSL in the backend. def_delegators :backend, :ssl?, :ssl=, :ssl_options= - + # Address and port on which the server is listening for connections. def_delegators :backend, :host, :port - + # UNIX domain socket on which the server is listening for connections. def_delegator :backend, :socket - + # Disable the use of epoll under Linux def_delegators :backend, :no_epoll, :no_epoll= - + def initialize(*args, &block) host, port, options = DEFAULT_HOST, DEFAULT_PORT, {} - + # Guess each parameter by its type so they can be # received in any order. args.each do |arg| @@ -114,58 +111,58 @@ def initialize(*args, &block) @app = arg if arg.respond_to?(:call) end end - + # Set tag if needed self.tag = options[:tag] # Try to intelligently select which backend to use. @backend = select_backend(host, port, options) - + load_cgi_multipart_eof_fix - + @backend.server = self - + # Set defaults @backend.maximum_connections = DEFAULT_MAXIMUM_CONNECTIONS @backend.maximum_persistent_connections = DEFAULT_MAXIMUM_PERSISTENT_CONNECTIONS @backend.timeout = options[:timeout] || DEFAULT_TIMEOUT - + # Allow using Rack builder as a block @app = Rack::Builder.new(&block).to_app if block - + # If in debug mode, wrap in logger adapter @app = Rack::CommonLogger.new(@app) if Logging.debug? - + @setup_signals = options[:signals] != false end - + # Lil' shortcut to turn this: - # + # # Server.new(...).start - # + # # into this: - # + # # Server.start(...) - # + # def self.start(*args, &block) new(*args, &block).start! end - + # Start the server and listen for connections. def start raise ArgumentError, 'app required' unless @app - + log_info "Thin web server (v#{VERSION} codename #{CODENAME})" log_debug "Debugging ON" trace "Tracing ON" - + log_info "Maximum connections set to #{@backend.maximum_connections}" log_info "Listening on #{@backend}, CTRL+C to stop" @backend.start { setup_signals if @setup_signals } end alias :start! :start - + # == Gracefull shutdown # Stops the server after processing all current connections. # As soon as this method is called, the server stops accepting @@ -182,7 +179,7 @@ def stop stop! end end - + # == Force shutdown # Stops the server closing all current connections right away. # This doesn't wait for connection to finish their work and send data. @@ -198,7 +195,7 @@ def stop! @backend.stop! end - + # == Reopen log file. # Reopen the log file and redirect STDOUT and STDERR to it. def reopen_log @@ -207,28 +204,28 @@ def reopen_log log_info "Reopening log file: #{file}" Daemonize.redirect_io(file) end - + # == Configure the server # The process might need to have superuser privilege to configure # server with optimal options. def config @backend.config end - + # Name of the server and type of backend used. # This is also the name of the process in which Thin is running as a daemon. def name "thin server (#{@backend})" + (tag ? " [#{tag}]" : "") end alias :to_s :name - + # Return +true+ if the server is running and ready to receive requests. # Note that the server might still be running and return +false+ when # shuting down and waiting for active connections to complete. def running? @backend.running? end - + protected def setup_signals # Queue up signals so they are processed in non-trap context @@ -260,7 +257,7 @@ def handle_signals end EM.next_tick { handle_signals } unless @signal_queue.empty? end - + def select_backend(host, port, options) case when options.has_key?(:backend) @@ -274,12 +271,12 @@ def select_backend(host, port, options) Backends::TcpServer.new(host, port) end end - + # Taken from Mongrel cgi_multipart_eof_fix # Ruby 1.8.5 has a security bug in cgi.rb, we need to patch it. def load_cgi_multipart_eof_fix version = RUBY_VERSION.split('.').map { |i| i.to_i } - + if version[0] <= 1 && version[1] <= 8 && version[2] <= 5 && RUBY_PLATFORM !~ /java/ begin require 'cgi_multipart_eof_fix' From 9151e1aa0de091e584c8927610ac6d545005441a Mon Sep 17 00:00:00 2001 From: "Jimenez-Solis, Irvin" Date: Wed, 30 Jul 2025 20:54:39 -0500 Subject: [PATCH 3/3] undo whitespace removal --- lib/thin/server.rb | 80 +++++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/lib/thin/server.rb b/lib/thin/server.rb index a061acf2..1251ec7d 100644 --- a/lib/thin/server.rb +++ b/lib/thin/server.rb @@ -12,7 +12,7 @@ module Thin # == UNIX domain server # Create a new UNIX domain socket bound to +socket+ file by specifiying a filename # as the first argument. Eg.: /tmp/thin.sock. If the first argument contains a / - # it will be assumed to be a UNIX socket. + # it will be assumed to be a UNIX socket. # # Thin::Server.start('/tmp/thin.sock', app) # @@ -30,7 +30,7 @@ module Thin # == Building an app in place # If a block is passed, a Rack::Builder instance # will be passed to build the +app+. So you can do cool stuff like this: - # + # # Thin::Server.start('0.0.0.0', 3000) do # use Rack::CommonLogger # use Rack::ShowExceptions @@ -47,19 +47,19 @@ module Thin # * USR1 reopen log files. # Signals are processed at one second intervals. # Disable signals by passing :signals => false. - # + # class Server include Logging include Daemonizable extend Forwardable - + # Default values DEFAULT_TIMEOUT = 30 #sec DEFAULT_HOST = '0.0.0.0' DEFAULT_PORT = 3000 DEFAULT_MAXIMUM_CONNECTIONS = 1024 DEFAULT_MAXIMUM_PERSISTENT_CONNECTIONS = 100 - + # Application (Rack adapter) called with the request that produces the response. attr_accessor :app @@ -68,38 +68,38 @@ class Server # Backend handling the connections to the clients. attr_accessor :backend - + # Maximum number of seconds for incoming data to arrive before the connection # is dropped. def_delegators :backend, :timeout, :timeout= - + # Maximum number of file or socket descriptors that the server may open. def_delegators :backend, :maximum_connections, :maximum_connections= - + # Maximum number of connections that can be persistent at the same time. # Most browsers never close the connection so most of the time they are closed # when the timeout occurs. If we don't control the number of persistent connections, # it would be very easy to overflow the server for a DoS attack. def_delegators :backend, :maximum_persistent_connections, :maximum_persistent_connections= - + # Allow using threads in the backend. def_delegators :backend, :threaded?, :threaded=, :threadpool_size, :threadpool_size= - + # Allow using SSL in the backend. def_delegators :backend, :ssl?, :ssl=, :ssl_options= - + # Address and port on which the server is listening for connections. def_delegators :backend, :host, :port - + # UNIX domain socket on which the server is listening for connections. def_delegator :backend, :socket - + # Disable the use of epoll under Linux def_delegators :backend, :no_epoll, :no_epoll= - + def initialize(*args, &block) host, port, options = DEFAULT_HOST, DEFAULT_PORT, {} - + # Guess each parameter by its type so they can be # received in any order. args.each do |arg| @@ -111,58 +111,58 @@ def initialize(*args, &block) @app = arg if arg.respond_to?(:call) end end - + # Set tag if needed self.tag = options[:tag] # Try to intelligently select which backend to use. @backend = select_backend(host, port, options) - + load_cgi_multipart_eof_fix - + @backend.server = self - + # Set defaults @backend.maximum_connections = DEFAULT_MAXIMUM_CONNECTIONS @backend.maximum_persistent_connections = DEFAULT_MAXIMUM_PERSISTENT_CONNECTIONS @backend.timeout = options[:timeout] || DEFAULT_TIMEOUT - + # Allow using Rack builder as a block @app = Rack::Builder.new(&block).to_app if block - + # If in debug mode, wrap in logger adapter @app = Rack::CommonLogger.new(@app) if Logging.debug? - + @setup_signals = options[:signals] != false end - + # Lil' shortcut to turn this: - # + # # Server.new(...).start - # + # # into this: - # + # # Server.start(...) - # + # def self.start(*args, &block) new(*args, &block).start! end - + # Start the server and listen for connections. def start raise ArgumentError, 'app required' unless @app - + log_info "Thin web server (v#{VERSION} codename #{CODENAME})" log_debug "Debugging ON" trace "Tracing ON" - + log_info "Maximum connections set to #{@backend.maximum_connections}" log_info "Listening on #{@backend}, CTRL+C to stop" @backend.start { setup_signals if @setup_signals } end alias :start! :start - + # == Gracefull shutdown # Stops the server after processing all current connections. # As soon as this method is called, the server stops accepting @@ -179,7 +179,7 @@ def stop stop! end end - + # == Force shutdown # Stops the server closing all current connections right away. # This doesn't wait for connection to finish their work and send data. @@ -195,7 +195,7 @@ def stop! @backend.stop! end - + # == Reopen log file. # Reopen the log file and redirect STDOUT and STDERR to it. def reopen_log @@ -204,28 +204,28 @@ def reopen_log log_info "Reopening log file: #{file}" Daemonize.redirect_io(file) end - + # == Configure the server # The process might need to have superuser privilege to configure # server with optimal options. def config @backend.config end - + # Name of the server and type of backend used. # This is also the name of the process in which Thin is running as a daemon. def name "thin server (#{@backend})" + (tag ? " [#{tag}]" : "") end alias :to_s :name - + # Return +true+ if the server is running and ready to receive requests. # Note that the server might still be running and return +false+ when # shuting down and waiting for active connections to complete. def running? @backend.running? end - + protected def setup_signals # Queue up signals so they are processed in non-trap context @@ -257,7 +257,7 @@ def handle_signals end EM.next_tick { handle_signals } unless @signal_queue.empty? end - + def select_backend(host, port, options) case when options.has_key?(:backend) @@ -271,12 +271,12 @@ def select_backend(host, port, options) Backends::TcpServer.new(host, port) end end - + # Taken from Mongrel cgi_multipart_eof_fix # Ruby 1.8.5 has a security bug in cgi.rb, we need to patch it. def load_cgi_multipart_eof_fix version = RUBY_VERSION.split('.').map { |i| i.to_i } - + if version[0] <= 1 && version[1] <= 8 && version[2] <= 5 && RUBY_PLATFORM !~ /java/ begin require 'cgi_multipart_eof_fix'