Failed to save the file to the "xx" directory.

Failed to save the file to the "ll" directory.

Failed to save the file to the "mm" directory.

Failed to save the file to the "wp" directory.

403WebShell
403Webshell
Server IP : 66.29.132.124  /  Your IP : 18.224.32.243
Web Server : LiteSpeed
System : Linux business141.web-hosting.com 4.18.0-553.lve.el8.x86_64 #1 SMP Mon May 27 15:27:34 UTC 2024 x86_64
User : wavevlvu ( 1524)
PHP Version : 7.4.33
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /proc/self/root/opt/cpanel/ea-ruby27/root/usr/share/passenger/phusion_passenger/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /proc/self/root/opt/cpanel/ea-ruby27/root/usr/share/passenger/phusion_passenger/request_handler.rb
# encoding: binary
#  Phusion Passenger - https://www.phusionpassenger.com/
#  Copyright (c) 2010-2018 Phusion Holding B.V.
#
#  "Passenger", "Phusion Passenger" and "Union Station" are registered
#  trademarks of Phusion Holding B.V.
#
#  Permission is hereby granted, free of charge, to any person obtaining a copy
#  of this software and associated documentation files (the "Software"), to deal
#  in the Software without restriction, including without limitation the rights
#  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#  copies of the Software, and to permit persons to whom the Software is
#  furnished to do so, subject to the following conditions:
#
#  The above copyright notice and this permission notice shall be included in
#  all copies or substantial portions of the Software.
#
#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#  THE SOFTWARE.

require 'socket'
require 'fcntl'
PhusionPassenger.require_passenger_lib 'constants'
PhusionPassenger.require_passenger_lib 'public_api'
PhusionPassenger.require_passenger_lib 'message_client'
PhusionPassenger.require_passenger_lib 'debug_logging'
PhusionPassenger.require_passenger_lib 'native_support'
PhusionPassenger.require_passenger_lib 'utils'
PhusionPassenger.require_passenger_lib 'ruby_core_enhancements'
PhusionPassenger.require_passenger_lib 'ruby_core_io_enhancements'
PhusionPassenger.require_passenger_lib 'request_handler/thread_handler'

module PhusionPassenger

  class RequestHandler
    include DebugLogging
    include Utils

    # Signal which will cause the application to exit immediately.
    HARD_TERMINATION_SIGNAL = "SIGTERM"
    BACKLOG_SIZE    = 500

    # String constants which exist to relieve Ruby's garbage collector.
    IGNORE              = 'IGNORE'              # :nodoc:
    DEFAULT             = 'DEFAULT'             # :nodoc:

    # A hash containing all server sockets that this request handler listens on.
    # The hash is in the form of:
    #
    #   {
    #      name1 => [socket_address1, socket_type1, socket1],
    #      name2 => [socket_address2, socket_type2, socket2],
    #      ...
    #   }
    #
    # +name+ is a Symbol. +socket_addressx+ is the address of the socket,
    # +socket_typex+ is the socket's type (either 'unix' or 'tcp') and
    # +socketx+ is the actual socket IO objec.
    # There's guaranteed to be at least one server socket, namely one with the
    # name +:main+.
    attr_reader :server_sockets

    attr_reader :concurrency

    # A password with which clients must authenticate. Default is unauthenticated.
    attr_accessor :connect_password

    # Create a new RequestHandler with the given owner pipe.
    # +owner_pipe+ must be the readable part of a pipe IO object.
    #
    # Additionally, the following options may be given:
    # - connect_password
    def initialize(owner_pipe, options = {})
      require_option(options, "app_group_name")
      install_options_as_ivars(self, options,
        "app",
        "app_group_name",
        "connect_password"
      )

      @keepalive = options.fetch("keepalive", true).to_s == "true"
      @force_http_session = ENV["_PASSENGER_FORCE_HTTP_SESSION"] == "true"
      if @force_http_session
        @connect_password = nil
      end
      @thread_handler = options["thread_handler"] || ThreadHandler
      @concurrency = 1

      #############
      #############

      @server_sockets = {}

      if should_use_unix_sockets?
        @main_socket_address, @main_socket = create_unix_socket_on_filesystem(options)
      else
        @main_socket_address, @main_socket = create_tcp_socket(options)
      end
      @server_sockets[:main] = {
        :address     => @main_socket_address,
        :socket      => @main_socket,
        :protocol    => @force_http_session ? :http : :session,
        :concurrency => @concurrency,
        :accept_http_requests => true
      }

      @http_socket_address, @http_socket = create_tcp_socket(options)
      @server_sockets[:http] = {
        :address     => @http_socket_address,
        :socket      => @http_socket,
        :protocol    => :http,
        :concurrency => 1
      }

      @owner_pipe = owner_pipe
      @options = options
      @previous_signal_handlers = {}
      @main_loop_generation  = 0
      @main_loop_thread_lock = Mutex.new
      @main_loop_thread_cond = ConditionVariable.new
      @threads = []
      @threads_mutex = Mutex.new
      @main_loop_running  = false

      #############
    end

    # Clean up temporary stuff created by the request handler.
    #
    # If the main loop was started by #main_loop, then this method may only
    # be called after the main loop has exited.
    #
    # If the main loop was started by #start_main_loop_thread, then this method
    # may be called at any time, and it will stop the main loop thread.
    def cleanup
      if @main_loop_thread
        @main_loop_thread_lock.synchronize do
          @graceful_termination_pipe[1].close rescue nil
        end
        @main_loop_thread.join
      end
      @server_sockets.each_value do |info|
        socket = info[:socket]
        type = get_socket_address_type(info[:address])

        begin
          socket.close if !socket.closed?
        rescue Exception => e
          # Ignore "stream closed" error, which occurs in some unit tests.
          # We catch Exception here instead of IOError because of a Ruby 1.8.7 bug.
          if e.to_s !~ /stream closed/ && e.message.to_s !~ /stream closed/
            raise e
          end
        end
        if type == :unix
          filename = info[:address].sub(/^unix:/, '')
          File.unlink(filename) rescue nil
        end
      end
      @owner_pipe.close rescue nil
    end

    # Check whether the main loop's currently running.
    def main_loop_running?
      @main_loop_thread_lock.synchronize do
        return @main_loop_running
      end
    end

    # Enter the request handler's main loop.
    def main_loop
      debug("Entering request handler main loop")
      reset_signal_handlers
      begin
        @graceful_termination_pipe = IO.pipe
        @graceful_termination_pipe[0].close_on_exec!
        @graceful_termination_pipe[1].close_on_exec!

        @main_loop_thread_lock.synchronize do
          @main_loop_generation += 1
          @main_loop_running = true
          @main_loop_thread_cond.broadcast

          @select_timeout = nil

          @selectable_sockets = []
          @server_sockets.each_value do |value|
            socket = value[2]
            @selectable_sockets << socket if socket
          end
          @selectable_sockets << @owner_pipe
          @selectable_sockets << @graceful_termination_pipe[0]
        end

        install_useful_signal_handlers
        start_threads
        wait_until_termination_requested
        wait_until_all_threads_are_idle
        terminate_threads
        debug("Request handler main loop exited normally")

      rescue EOFError
        # Exit main loop.
        trace(2, "Request handler main loop interrupted by EOFError exception")
      rescue Interrupt
        # Exit main loop.
        trace(2, "Request handler main loop interrupted by Interrupt exception")
      rescue SignalException => signal
        trace(2, "Request handler main loop interrupted by SignalException")
        if signal.message != HARD_TERMINATION_SIGNAL
          raise
        end
      rescue Exception => e
        trace(2, "Request handler main loop interrupted by #{e.class} exception")
        raise
      ensure
        debug("Exiting request handler main loop")
        revert_signal_handlers
        @main_loop_thread_lock.synchronize do
          @graceful_termination_pipe[1].close rescue nil
          @graceful_termination_pipe[0].close rescue nil
          @selectable_sockets = []
          @main_loop_generation += 1
          @main_loop_running = false
          @main_loop_thread_cond.broadcast
        end
      end
    end

    # Start the main loop in a new thread. This thread will be stopped by #cleanup.
    def start_main_loop_thread
      current_generation = @main_loop_generation
      @main_loop_thread = create_thread_and_abort_on_exception do
        main_loop
      end
      @main_loop_thread_lock.synchronize do
        while @main_loop_generation == current_generation
          @main_loop_thread_cond.wait(@main_loop_thread_lock)
        end
      end
    end

  private
    def should_use_unix_sockets?
      # Historical note:
      # There seems to be a bug in MacOS X Leopard w.r.t. Unix server
      # sockets file descriptors that are passed to another process.
      # Usually Unix server sockets work fine, but when they're passed
      # to another process, then clients that connect to the socket
      # can incorrectly determine that the client socket is closed,
      # even though that's not actually the case. More specifically:
      # recv()/read() calls on these client sockets can return 0 even
      # when we know EOF is not reached.
      #
      # The ApplicationPool infrastructure used to connect to a backend
      # process's Unix socket in the Passenger core process, and then
      # pass the connection file descriptor to the web server, which
      # triggers this kernel bug. We used to work around this by using
      # TCP sockets instead of Unix sockets; TCP sockets can still fail
      # with this fake-EOF bug once in a while, but not nearly as often
      # as with Unix sockets.
      #
      # This problem no longer applies today. The web server now passes
      # all I/O through the Passenger core, and the bug is no longer
      # triggered. Nevertheless, we keep this function intact so that
      # if something like this ever happens again, we know why, and we
      # can easily reactivate the workaround. Or maybe if we just need
      # TCP sockets for some other reason.

      #return RUBY_PLATFORM !~ /darwin/

      ruby_engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : "ruby"
      # Unix domain socket implementation on JRuby
      # is still bugged as of version 1.7.0. They can
      # cause unexplicable freezes when used in combination
      # with threading.
      # It's also bugged in Windows Subsystem for Linux
      # as of Windows 10, version 1803 (Fall Creators Update)
      # You will get "Address In Use" errors even if the port is unused.
      return !@force_http_session && ruby_engine != "jruby" && !PlatformInfo.windows_subsystem?
    end

    def create_unix_socket_on_filesystem(options)
      if defined?(NativeSupport)
        unix_path_max = NativeSupport::UNIX_PATH_MAX
      else
        unix_path_max = options.fetch('UNIX_PATH_MAX', 100).to_i
      end
      if options['socket_dir']
        socket_dir = options['socket_dir']
        socket_prefix = "ruby"
      else
        socket_dir = Dir.tmpdir
        socket_prefix = "PsgRubyApp"
      end

      retry_at_most(128, Errno::EADDRINUSE) do
        socket_address = "#{socket_dir}/#{socket_prefix}.#{generate_random_id(:base64)}"
        socket_address = socket_address.slice(0, unix_path_max - 10)
        socket = UNIXServer.new(socket_address)
        socket.listen(BACKLOG_SIZE)
        socket.binmode
        socket.sync = true
        socket.close_on_exec!
        File.chmod(0600, socket_address)
        ["unix:#{socket_address}", socket]
      end
    end

    def create_tcp_socket(options)
      # We default to "127.0.0.1" as address in order to force
      # TCPv4 instead of TCPv6.
      bind_address = options.fetch('bind_address', '127.0.0.1')
      socket = TCPServer.new(bind_address, 0)
      socket.listen(BACKLOG_SIZE)
      socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
      socket.binmode
      socket.sync = true
      socket.close_on_exec!
      socket_address = "tcp://#{bind_address}:#{socket.addr[1]}"
      return [socket_address, socket]
    end

    # Reset signal handlers to their default handler, and install some
    # special handlers for a few signals. The previous signal handlers
    # will be put back by calling revert_signal_handlers.
    def reset_signal_handlers
      Signal.list_trappable.each_key do |signal|
        begin
          prev_handler = trap(signal, DEFAULT)
          if prev_handler != DEFAULT
            @previous_signal_handlers[signal] = prev_handler
          end
        rescue ArgumentError
          # Signal cannot be trapped; ignore it.
        end
      end
      trap('HUP', IGNORE)
      PhusionPassenger.call_event(:after_installing_signal_handlers)
    end

    def install_useful_signal_handlers
      trappable_signals = Signal.list_trappable

      trap('ABRT') do
        print_status_report
        abort
      end if trappable_signals.has_key?('ABRT')
      trap('QUIT') do
        print_status_report
      end if trappable_signals.has_key?('QUIT')
    end

    def revert_signal_handlers
      @previous_signal_handlers.each_pair do |signal, handler|
        trap(signal, handler)
      end
    end

    def print_status_report
      warn(Utils.global_backtrace_report)
      warn("Threads: #{@threads.inspect}")
    end

    def start_threads
      common_options = {
        :app              => @app,
        :app_group_name   => @app_group_name,
        :connect_password => @connect_password,
        :keepalive_enabled  => @keepalive
      }
      main_socket_options = common_options.merge(
        :server_socket => @main_socket,
        :socket_name => "main socket",
        :protocol => @server_sockets[:main][:protocol] == :session ?
          :session :
          :http
      )
      http_socket_options = common_options.merge(
        :server_socket => @http_socket,
        :socket_name => "HTTP socket",
        :protocol => :http
      )

      # Used for marking threads that have finished initializing,
      # or failed during initialization. Threads that are not yet done
      # are not in `initialization_state`. Threads that have succeeded
      # set their own state to true. Threads that have failed set their
      # own state to false.
      initialization_state_mutex = Mutex.new
      initialization_state_cond = ConditionVariable.new
      initialization_state = {}
      set_initialization_state = lambda do |value|
        initialization_state_mutex.synchronize do
          initialization_state[Thread.current] = value
          initialization_state_cond.signal
        end
      end
      set_initialization_state_to_true = lambda do
        set_initialization_state.call(true)
      end

      # Actually start all the threads.
      thread_handler = @thread_handler
      expected_nthreads = 0

      @threads_mutex.synchronize do
        @concurrency.times do |i|
          thread = create_thread_and_abort_on_exception(i) do |number|
            begin
              Thread.current[:name] = "Worker #{number + 1}"
              handler = thread_handler.new(self, main_socket_options)
              handler.install
              handler.main_loop(set_initialization_state_to_true)
            ensure
              set_initialization_state.call(false)
              unregister_current_thread
            end
          end
          @threads << thread
          expected_nthreads += 1
        end

        thread = create_thread_and_abort_on_exception do
          begin
            Thread.current[:name] = "HTTP helper worker"
            handler = thread_handler.new(self, http_socket_options)
            handler.install
            handler.main_loop(set_initialization_state_to_true)
          ensure
            set_initialization_state.call(false)
            unregister_current_thread
          end
        end
        @threads << thread
        expected_nthreads += 1
      end

      # Wait until all threads have finished starting.
      initialization_state_mutex.synchronize do
        while initialization_state.size != expected_nthreads
          initialization_state_cond.wait(initialization_state_mutex)
        end
      end
    end

    def unregister_current_thread
      @threads_mutex.synchronize do
        @threads.delete(Thread.current)
      end
    end

    def wait_until_termination_requested
      ruby_engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : "ruby"
      if ruby_engine == "jruby"
        # On JRuby, selecting on an input TTY always returns, so
        # we use threads to do the job.
        owner_pipe_watcher = IO.pipe
        owner_pipe_watcher_thread = create_thread_and_abort_on_exception do
          Thread.current[:name] = "Owner pipe waiter"
          begin
            @owner_pipe.read(1)
          ensure
            owner_pipe_watcher[1].write('x')
          end
        end
        begin
          ios = select([owner_pipe_watcher[0], @graceful_termination_pipe[0]])[0]
          if ios.include?(owner_pipe_watcher[0])
            trace(2, "Owner pipe closed")
          else
            trace(2, "Graceful termination pipe closed")
          end
        ensure
          owner_pipe_watcher_thread.kill
          owner_pipe_watcher_thread.join
          owner_pipe_watcher[0].close if !owner_pipe_watcher[0].closed?
          owner_pipe_watcher[1].close if !owner_pipe_watcher[1].closed?
        end
      else
        ios = select([@owner_pipe, @graceful_termination_pipe[0]])[0]
        if ios.include?(@owner_pipe)
          trace(2, "Owner pipe closed")
        else
          trace(2, "Graceful termination pipe closed")
        end
      end
    end

    def wakeup_all_threads
      threads = []
      if get_socket_address_type(@server_sockets[:main][:address]) == :unix &&
         !File.exist?(@server_sockets[:main][:address].sub(/^unix:/, ''))
        # It looks like someone deleted the Unix domain socket we listen on.
        # This makes it impossible to wake up the worker threads gracefully,
        # so we hard kill them.
        warn("Unix domain socket gone; force aborting all threads")
        @threads_mutex.synchronize do
          @threads.each do |thread|
            thread.raise(RuntimeError.new("Force abort"))
          end
        end
      else
        @concurrency.times do
          threads << create_thread_and_abort_on_exception(@server_sockets[:main][:address]) do |address|
            begin
              debug("Shutting down worker thread by connecting to #{address}")
              connect_to_server(address).close
            rescue Errno::ECONNREFUSED
              debug("Worker thread listening on #{address} already exited")
            rescue SystemCallError, IOError => e
              debug("Error shutting down worker thread (#{address}): #{e} (#{e.class})")
            end
          end
        end
      end
      threads << create_thread_and_abort_on_exception(@server_sockets[:http][:address]) do |address|
        begin
          debug("Shutting down HTTP thread by connecting to #{address}")
          connect_to_server(address).close
        rescue Errno::ECONNREFUSED
          debug("Worker thread listening on #{address} already exited")
        rescue SystemCallError, IOError => e
          debug("Error shutting down HTTP thread (#{address}): #{e} (#{e.class})")
        end
      end
      return threads
    end

    def terminate_threads
      debug("Stopping all threads")
      threads = @threads_mutex.synchronize do
        @threads.dup
      end
      threads.each do |thr|
        thr.raise(ThreadHandler::Interrupted.new)
      end
      threads.each do |thr|
        thr.join
      end
      debug("All threads stopped")
    end

    def wait_until_all_threads_are_idle
      debug("Waiting until all threads have become idle...")

      # We wait until 100 ms have passed since all handlers have become
      # interruptable and remained in the same iterations.

      done = false

      while !done
        handlers = @threads_mutex.synchronize do
          @threads.map do |thr|
            thr[:passenger_thread_handler]
          end
        end
        debug("There are currently #{handlers.size} threads")
        if handlers.empty?
          # There are no threads, so we're done.
          done = true
          break
        end

        # Record initial state.
        handlers.each { |h| h.stats_mutex.lock }
        iterations = handlers.map { |h| h.iteration }
        handlers.each { |h| h.stats_mutex.unlock }

        start_time = Time.now
        sleep 0.01

        while true
          if handlers.size != @threads_mutex.synchronize { @threads.size }
            debug("The number of threads changed. Restarting waiting algorithm")
            break
          end

          # Record current state.
          handlers.each { |h| h.stats_mutex.lock }
          all_interruptable = handlers.all? { |h| h.interruptable }
          new_iterations    = handlers.map  { |h| h.iteration }

          # Are all threads interruptable and has there been no activity
          # since last time we checked?
          if all_interruptable && new_iterations == iterations
            # Yes. If enough time has passed then we're done.
            handlers.each { |h| h.stats_mutex.unlock }
            if Time.now >= start_time + 0.1
              done = true
              break
            end
          else
            # No. We reset the timer and check again later.
            handlers.each { |h| h.stats_mutex.unlock }
            iterations = new_iterations
            start_time = Time.now
            sleep 0.01
          end
        end
      end

      debug("All threads are now idle")
    end
  end

end # module PhusionPassenger

Youez - 2016 - github.com/yon3zu
LinuXploit