### Home Classes Methods

### In Files

- lib/phusion_passenger/utils/unseekable_socket.rb

### Parent

Object

### Methods

- ::wrap
- #addr
- #binmode
- #close
- #close_read
- #close_write
- #closed?
- #each
- #eof?
- #fileno
- #flush
- #gets
- #puts
- #read
- #readline
- #readpartial
- #simulate_eof!
- #source_of_exception?
- #stop_simulating_eof!
- #sync=
- #to_io
- #wrap
- #write
- #writev
- #writev2
- #writev3

### Class/Module Index

Quicksearch

- PhusionPassenger
- PhusionPassenger::AbstractInstaller
- PhusionPassenger::AbstractInstaller::Abort
- PhusionPassenger::AbstractInstaller::CommandError
- PhusionPassenger::AdminTools
- PhusionPassenger::AdminTools::MemoryStats
- PhusionPassenger::AdminTools::MemoryStats::Process
- PhusionPassenger::AdminTools::ServerInstance
- PhusionPassenger::AdminTools::ServerInstance::CorruptedDirectoryError
- PhusionPassenger::AdminTools::ServerInstance::GenerationsAbsentError
- PhusionPassenger::AdminTools::ServerInstance::Group
- PhusionPassenger::AdminTools::ServerInstance::Process
- PhusionPassenger::AdminTools::ServerInstance::RoleDeniedError
- PhusionPassenger::AdminTools::ServerInstance::StaleDirectoryError
- PhusionPassenger::AdminTools::ServerInstance::Stats
- PhusionPassenger::AdminTools::ServerInstance::UnsupportedGenerationStructureVersionError
- PhusionPassenger::AnalyticsLogger
- PhusionPassenger::AnalyticsLogger::Connection
- PhusionPassenger::AnalyticsLogger::Lock
- PhusionPassenger::AnalyticsLogger::Log
- PhusionPassenger::ClassicRails
- PhusionPassenger::ClassicRails::CGIFixed
- PhusionPassenger::ClassicRails::ThreadHandlerExtension
- PhusionPassenger::ConsoleTextTemplate
- PhusionPassenger::DebugLogging
- PhusionPassenger::LoaderSharedHelpers
- PhusionPassenger::MessageChannel
- PhusionPassenger::MessageChannel::InvalidHashError
- PhusionPassenger::MessageClient
- PhusionPassenger::NativeSupportLoader
- PhusionPassenger::Packaging
- PhusionPassenger::PlatformInfo
- PhusionPassenger::PlatformInfo::Depcheck
- PhusionPassenger::PlatformInfo::Depcheck::ConsoleRunner
- PhusionPassenger::PlatformInfo::Depcheck::Dependency
- PhusionPassenger::PlatformInfo::RuntimeError
- PhusionPassenger::Plugin
- PhusionPassenger::PreloaderSharedHelpers
- PhusionPassenger::Rack
- PhusionPassenger::Rack::OutOfBandGc
- PhusionPassenger::Rack::ThreadHandlerExtension
- PhusionPassenger::Rails3Extensions
- PhusionPassenger::Rails3Extensions::AnalyticsLogging
- PhusionPassenger::Rails3Extensions::AnalyticsLogging::ACExtension
- PhusionPassenger::Rails3Extensions::AnalyticsLogging::ASBenchmarkableExtension
- PhusionPassenger::Rails3Extensions::AnalyticsLogging::ExceptionLogger
- PhusionPassenger::RequestHandler
- PhusionPassenger::RequestHandler::ThreadHandler
- PhusionPassenger::RequestHandler::ThreadHandler::Interrupted
- PhusionPassenger::SharedConstants
- PhusionPassenger::Standalone
- PhusionPassenger::Standalone::AppFinder
- PhusionPassenger::Standalone::Command
- PhusionPassenger::Standalone::ConfigFile
- PhusionPassenger::Standalone::ConfigFile::DisallowedContextError
- PhusionPassenger::Standalone::HelpCommand
- PhusionPassenger::Standalone::Main
- PhusionPassenger::Standalone::PackageRuntimeCommand
- PhusionPassenger::Standalone::RuntimeInstaller
- PhusionPassenger::Standalone::StartCommand
- PhusionPassenger::Standalone::StatusCommand
- PhusionPassenger::Standalone::StopCommand
- PhusionPassenger::Standalone::Utils
- PhusionPassenger::Standalone::VersionCommand
- PhusionPassenger::Utils
- PhusionPassenger::Utils::AnsiColors
- PhusionPassenger::Utils::FileSystemWatcher
- PhusionPassenger::Utils::FileSystemWatcher::DirInfo
- PhusionPassenger::Utils::FileSystemWatcher::FileInfo
- PhusionPassenger::Utils::HostsFileParser
- PhusionPassenger::Utils::TeeInput
- PhusionPassenger::Utils::TmpIO
- PhusionPassenger::Utils::UnseekableSocket
- CommonLibraryBuilder
- Exception
- GC
- IO
- Object
- Signal

No matching classes.

# PhusionPassenger::Utils::UnseekableSocket

Some frameworks (e.g. Merb) call `seek` and `rewind` on the input stream if it responds to these methods. In case of Phusion Passenger, the input stream is a socket, and altough socket objects respond to `seek` and `rewind`, calling these methods will raise an exception. We don't want this to happen so in AbstractRequestHandler we wrap the client socket into an UnseekableSocket wrapper, which doesn't respond to these methods.

We used to dynamically undef `seek` and `rewind` on sockets, but this blows the Ruby interpreter's method cache and made things slower. Wrapping a socket is faster despite extra method calls.

Furthermore, all exceptions originating from the wrapped socket will be annotated. One can check whether a certain exception originates from the wrapped socket by calling source_of_exception?

### Public Class Methods

wrap(socket) click to toggle source

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 44
    def self.wrap(socket)
            return new.wrap(socket)
    end

### Public Instance Methods

addr() click to toggle source

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 107
    def addr
            @socket.addr
    rescue => e
            raise annotate(e)
    end

binmode() click to toggle source

Already set to binary mode.

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 87
    def binmode
    end

close() click to toggle source

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 203
    def close
            @socket.close
    rescue => e
            raise annotate(e)
    end

close_read() click to toggle source

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 209
    def close_read
            @socket.close_read
    rescue => e
            raise annotate(e)
    end

close_write() click to toggle source

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 215
    def close_write
            @socket.close_write
    rescue => e
            raise annotate(e)
    end

closed?() click to toggle source

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 197
    def closed?
            @socket.closed?
    rescue => e
            raise annotate(e)
    end

each(&block) click to toggle source

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 183
    def each(&block)
            return if @simulate_eof
            @socket.each(&block)
    rescue => e
            raise annotate(e)
    end

eof?() click to toggle source

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 190
    def eof?
            return true if @simulate_eof
            @socket.eof?
    rescue => e
            raise annotate(e)
    end

fileno() click to toggle source

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 103
    def fileno
            @socket.fileno
    end

flush() click to toggle source

Socket is sync'ed so flushing shouldn't do anything.

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 83
    def flush
    end

gets() click to toggle source

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 143
    def gets
            return nil if @simulate_eof
            @socket.gets
    rescue => e
            raise annotate(e)
    end

puts(*args) click to toggle source

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 137
    def puts(*args)
            @socket.puts(*args)
    rescue => e
            raise annotate(e)
    end

read(*args) click to toggle source

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 150
    def read(*args)
            if @simulate_eof
                    length, buffer = args
                    if buffer
                            buffer.replace(binary_string(""))
                    else
                            buffer = binary_string("")
                    end
                    if length
                            return nil
                    else
                            return buffer
                    end
            end
            @socket.read(*args)
    rescue => e
            raise annotate(e)
    end

readline() click to toggle source

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 176
    def readline
            raise EOFError, "end of file reached" if @simulate_eof
            @socket.readline
    rescue => e
            raise annotate(e)
    end

readpartial(*args) click to toggle source

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 169
    def readpartial(*args)
            raise EOFError, "end of file reached" if @simulate_eof
            @socket.readpartial(*args)
    rescue => e
            raise annotate(e)
    end

simulate_eof!() click to toggle source

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 95
    def simulate_eof!
            @simulate_eof = true
    end

source_of_exception?(exception) click to toggle source

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 221
    def source_of_exception?(exception)
            return exception.instance_variable_get(:"@from_unseekable_socket") == @socket.object_id
    end

stop_simulating_eof!() click to toggle source

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 99
    def stop_simulating_eof!
            @simulate_eof = false
    end

sync=(value) click to toggle source

Don't allow disabling of sync.

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 79
    def sync=(value)
    end

to_io() click to toggle source

This makes select() work.

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 91
    def to_io
            @socket
    end

wrap(socket) click to toggle source

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 48
    def wrap(socket)
            # Some people report that sometimes their Ruby (MRI/REE)
            # processes get stuck with 100% CPU usage. Upon further
            # inspection with strace, it turns out that these Ruby
            # processes are continuously calling lseek() on a socket,
            # which of course returns ESPIPE as error. gdb reveals
            # lseek() is called by fwrite(), which in turn is called
            # by rb_fwrite(). The affected socket is the
            # AbstractRequestHandler client socket.
            #
            # I inspected the MRI source code and didn't find
            # anything that would explain this behavior. This makes
            # me think that it's a glibc bug, but that's very
            # unlikely.
            #
            # The rb_fwrite() implementation takes an entirely
            # different code path if I set 'sync' to true: it will
            # skip fwrite() and use write() instead. So here we set
            # 'sync' to true in the hope that this will work around
            # the problem.
            socket.sync = true

            # There's no need to set the encoding for Ruby 1.9 because
            # abstract_request_handler.rb is tagged with 'encoding: binary'.

            @socket = socket

            return self
    end

write(string) click to toggle source

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 113
    def write(string)
            @socket.write(string)
    rescue => e
            raise annotate(e)
    end

writev(components) click to toggle source

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 119
    def writev(components)
            @socket.writev(components)
    rescue => e
            raise annotate(e)
    end

writev2(components, components2) click to toggle source

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 125
    def writev2(components, components2)
            @socket.writev2(components, components2)
    rescue => e
            raise annotate(e)
    end

writev3(components, components2, components3) click to toggle source

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 131
    def writev3(components, components2, components3)
            @socket.writev3(components, components2, components3)
    rescue => e
            raise annotate(e)
    end

[Validate]

Generated with the Darkfish Rdoc Generator 2.