class Connection
Definitions
attr_accessor :persistent
Whether the connection is persistent. This determines what connection headers are sent in the response and whether the connection can be reused after the response is sent. This setting is automatically managed according to the nature of the request and response. Changing to false is safe. Changing to true from outside this class should generally be avoided and, depending on the response semantics, may be reset to false anyway.
attr_accessor :state
The current state of the connection.
┌────────┐
│ │
┌───────────────────────►│ idle │
│ │ │
│ └───┬────┘
│ │
│ │ send request /
│ │ receive request
│ │
│ ▼
│ ┌────────┐
│ recv ES │ │ send ES
│ ┌────────────┤ open ├────────────┐
│ │ │ │ │
│ ▼ └───┬────┘ ▼
│ ┌──────────┐ │ ┌──────────┐
│ │ half │ │ │ half │
│ │ closed │ │ send R / │ closed │
│ │ (remote) │ │ recv R │ (local) │
│ └────┬─────┘ │ └─────┬────┘
│ │ │ │
│ │ send ES / │ recv ES / │
│ │ close ▼ close │
│ │ ┌────────┐ │
│ └───────────►│ │◄───────────┘
│ │ closed │
└────────────────────────┤ │
persistent └────────┘
ES
: the body was fully received or sent (end of stream).R
: the connection was closed unexpectedly (reset).
State transition methods use a trailing "!".
attr :count
The number of requests processed.
def write_connection_header(version)
Write the appropriate header for connection persistence.
Implementation
def write_connection_header(version)
if version == HTTP10
@stream.write("connection: keep-alive\r\n") if @persistent
else
@stream.write("connection: close\r\n") unless @persistent
end
end
def hijacked?
Indicates whether the connection has been hijacked meaning its IO has been handed over and is not usable anymore.
Implementation
def hijacked?
@stream.nil?
end
def hijack!
Effectively close the connection and return the underlying IO.
Implementation
def hijack!
@persistent = false
if stream = @stream
@stream = nil
stream.flush
@state = :hijacked
self.closed
return stream
end
end
def close(error = nil)
Close the connection and underlying stream.
Implementation
def close(error = nil)
@persistent = false
if stream = @stream
@stream = nil
stream.close
end
unless closed?
@state = :closed
self.closed(error)
end
end
def write_upgrade_body(protocol, body = nil)
Implementation
def write_upgrade_body(protocol, body = nil)
# Once we upgrade the connection, it can no longer handle other requests:
@persistent = false
write_upgrade_header(protocol)
@stream.write("\r\n")
@stream.flush # Don't remove me!
if body
body.each do |chunk|
@stream.write(chunk)
@stream.flush
end
@stream.close_write
end
return @stream
ensure
self.send_end_stream!
end
def closed(error = nil)
The connection (stream) was closed. It may now be in the idle state.
Implementation
def closed(error = nil)
end
def close!(error = nil)
Transition to the closed state.
If no error occurred, and the connection is persistent, this will immediately transition to the idle state.
Signature
-
parameter
error
Exxception
the error that caused the connection to close.
Implementation
def close!(error = nil)
if @persistent and !error
# If there was no error, and the connection is persistent, we can reuse it:
@state = :idle
else
@state = :closed
end
self.closed(error)
end