lib/pitchfork/http_parser.rb in pitchfork-0.13.0 vs lib/pitchfork/http_parser.rb in pitchfork-0.14.0
- old
+ new
@@ -25,11 +25,10 @@
# :stopdoc:
HTTP_RESPONSE_START = [ 'HTTP', '/1.1 ' ]
EMPTY_ARRAY = [].freeze
@@input_class = Pitchfork::TeeInput
@@check_client_connection = false
- @@tcpi_inspect_ok = Socket.const_defined?(:TCP_INFO)
def self.input_class
@@input_class
end
@@ -106,83 +105,29 @@
def hijacked?
env.include?('rack.hijack_io')
end
- if Raindrops.const_defined?(:TCP_Info)
- TCPI = Raindrops::TCP_Info.allocate
-
+ if Socket.const_defined?(:TCP_INFO) # Linux
def check_client_connection(socket) # :nodoc:
if TCPSocket === socket
- # Raindrops::TCP_Info#get!, #state (reads struct tcp_info#tcpi_state)
- raise Errno::EPIPE, "client closed connection".freeze,
- EMPTY_ARRAY if closed_state?(TCPI.get!(socket).state)
- else
- write_http_header(socket)
- end
- end
-
- if Raindrops.const_defined?(:TCP)
- # raindrops 0.18.0+ supports FreeBSD + Linux using the same names
- # Evaluate these hash lookups at load time so we can
- # generate an opt_case_dispatch instruction
- eval <<-EOS
- def closed_state?(state) # :nodoc:
- case state
- when #{Raindrops::TCP[:ESTABLISHED]}
- false
- when #{Raindrops::TCP.values_at(
- :CLOSE_WAIT, :TIME_WAIT, :CLOSE, :LAST_ACK, :CLOSING).join(',')}
- true
- else
- false
+ begin
+ tcp_info = socket.getsockopt(Socket::IPPROTO_TCP, Socket::TCP_INFO)
+ rescue IOError, SystemCallError
+ return write_http_header(socket)
end
- end
- EOS
- else
- # raindrops before 0.18 only supported TCP_INFO under Linux
- def closed_state?(state) # :nodoc:
- case state
- when 1 # ESTABLISHED
- false
- when 8, 6, 7, 9, 11 # CLOSE_WAIT, TIME_WAIT, CLOSE, LAST_ACK, CLOSING
- true
- else
- false
- end
- end
- end
- else
- # Ruby 2.2+ can show struct tcp_info as a string Socket::Option#inspect.
- # Not that efficient, but probably still better than doing unnecessary
- # work after a client gives up.
- def check_client_connection(socket) # :nodoc:
- if TCPSocket === socket && @@tcpi_inspect_ok
- opt = socket.getsockopt(Socket::IPPROTO_TCP, Socket::TCP_INFO).inspect
- if opt =~ /\bstate=(\S+)/
- raise Errno::EPIPE, "client closed connection".freeze,
- EMPTY_ARRAY if closed_state_str?($1)
- else
- @@tcpi_inspect_ok = false
- write_http_header(socket)
+ case tcp_info.data.unpack1("C")
+ when 6, 7, 8, 9, 11 # TIME_WAIT, CLOSE, CLOSE_WAIT, LAST_ACK, CLOSING
+ raise Errno::EPIPE, "client closed connection", EMPTY_ARRAY
end
- opt.clear
else
write_http_header(socket)
end
end
-
- def closed_state_str?(state)
- case state
- when 'ESTABLISHED'
- false
- # not a typo, ruby maps TCP_CLOSE (no 'D') to state=CLOSED (w/ 'D')
- when 'CLOSE_WAIT', 'TIME_WAIT', 'CLOSED', 'LAST_ACK', 'CLOSING'
- true
- else
- false
- end
+ else
+ def check_client_connection(socket) # :nodoc:
+ write_http_header(socket)
end
end
def write_http_header(socket) # :nodoc:
if headers?