Protocol::HTTP1SourceProtocolHTTP1Connection

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