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?

Methods
Public Class methods
wrap(socket)
    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 44
44:         def self.wrap(socket)
45:                 return new.wrap(socket)
46:         end
Public Instance methods
addr()
    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 94
94:         def addr
95:                 @socket.addr
96:         rescue => e
97:                 raise annotate(e)
98:         end
binmode()

Already set to binary mode.

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 87
87:         def binmode
88:         end
close()
     # File lib/phusion_passenger/utils/unseekable_socket.rb, line 166
166:         def close
167:                 @socket.close
168:         rescue => e
169:                 raise annotate(e)
170:         end
close_read()
     # File lib/phusion_passenger/utils/unseekable_socket.rb, line 172
172:         def close_read
173:                 @socket.close_read
174:         rescue => e
175:                 raise annotate(e)
176:         end
close_write()
     # File lib/phusion_passenger/utils/unseekable_socket.rb, line 178
178:         def close_write
179:                 @socket.close_write
180:         rescue => e
181:                 raise annotate(e)
182:         end
closed?()
     # File lib/phusion_passenger/utils/unseekable_socket.rb, line 160
160:         def closed?
161:                 @socket.closed?
162:         rescue => e
163:                 raise annotate(e)
164:         end
each(&block)
     # File lib/phusion_passenger/utils/unseekable_socket.rb, line 154
154:         def each(&block)
155:                 @socket.each(&block)
156:         rescue => e
157:                 raise annotate(e)
158:         end
flush()

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

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 83
83:         def flush
84:         end
gets()
     # File lib/phusion_passenger/utils/unseekable_socket.rb, line 130
130:         def gets
131:                 @socket.gets
132:         rescue => e
133:                 raise annotate(e)
134:         end
puts(*args)
     # File lib/phusion_passenger/utils/unseekable_socket.rb, line 124
124:         def puts(*args)
125:                 @socket.puts(*args)
126:         rescue => e
127:                 raise annotate(e)
128:         end
read(*args)
     # File lib/phusion_passenger/utils/unseekable_socket.rb, line 136
136:         def read(*args)
137:                 @socket.read(*args)
138:         rescue => e
139:                 raise annotate(e)
140:         end
readline()
     # File lib/phusion_passenger/utils/unseekable_socket.rb, line 148
148:         def readline
149:                 @socket.readline
150:         rescue => e
151:                 raise annotate(e)
152:         end
readpartial(*args)
     # File lib/phusion_passenger/utils/unseekable_socket.rb, line 142
142:         def readpartial(*args)
143:                 @socket.readpartial(*args)
144:         rescue => e
145:                 raise annotate(e)
146:         end
source_of_exception?(exception)
     # File lib/phusion_passenger/utils/unseekable_socket.rb, line 184
184:         def source_of_exception?(exception)
185:                 return exception.instance_variable_get("@from_unseekable_socket""@from_unseekable_socket") == @socket.object_id
186:         end
sync=(value)

Don‘t allow disabling of sync.

    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 79
79:         def sync=(value)
80:         end
to_io()
    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 90
90:         def to_io
91:                 self
92:         end
wrap(socket)
    # File lib/phusion_passenger/utils/unseekable_socket.rb, line 48
48:         def wrap(socket)
49:                 # Some people report that sometimes their Ruby (MRI/REE)
50:                 # processes get stuck with 100% CPU usage. Upon further
51:                 # inspection with strace, it turns out that these Ruby
52:                 # processes are continuously calling lseek() on a socket,
53:                 # which of course returns ESPIPE as error. gdb reveals
54:                 # lseek() is called by fwrite(), which in turn is called
55:                 # by rb_fwrite(). The affected socket is the
56:                 # AbstractRequestHandler client socket.
57:                 #
58:                 # I inspected the MRI source code and didn't find
59:                 # anything that would explain this behavior. This makes
60:                 # me think that it's a glibc bug, but that's very
61:                 # unlikely.
62:                 #
63:                 # The rb_fwrite() implementation takes an entirely
64:                 # different code path if I set 'sync' to true: it will
65:                 # skip fwrite() and use write() instead. So here we set
66:                 # 'sync' to true in the hope that this will work around
67:                 # the problem.
68:                 socket.sync = true
69:                 
70:                 # There's no need to set the encoding for Ruby 1.9 because
71:                 # abstract_request_handler.rb is tagged with 'encoding: binary'.
72:                 
73:                 @socket = socket
74:                 
75:                 return self
76:         end
write(string)
     # File lib/phusion_passenger/utils/unseekable_socket.rb, line 100
100:         def write(string)
101:                 @socket.write(string)
102:         rescue => e
103:                 raise annotate(e)
104:         end
writev(components)
     # File lib/phusion_passenger/utils/unseekable_socket.rb, line 106
106:         def writev(components)
107:                 @socket.writev(components)
108:         rescue => e
109:                 raise annotate(e)
110:         end
writev2(components, components2)
     # File lib/phusion_passenger/utils/unseekable_socket.rb, line 112
112:         def writev2(components, components2)
113:                 @socket.writev2(components, components2)
114:         rescue => e
115:                 raise annotate(e)
116:         end
writev3(components, components2, components3)
     # File lib/phusion_passenger/utils/unseekable_socket.rb, line 118
118:         def writev3(components, components2, components3)
119:                 @socket.writev3(components, components2, components3)
120:         rescue => e
121:                 raise annotate(e)
122:         end