Parent

Class/Module Index [+]

Quicksearch

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.