class Response
Typically used on the client side for writing a request and reading the incoming response.
Nested
Definitions
def initialize(stream)
Initialize the response from an HTTP/2 stream.
Signature
-
parameter
streamStream The HTTP/2 stream for this response.
Implementation
def initialize(stream)
super(stream.connection.version, nil, nil)
@stream = stream
@request = nil
end
def pool=(pool)
Assign the connection pool, releasing the connection when the stream is closed.
Signature
-
parameter
poolAsync::Pool::Controller The connection pool.
Implementation
def pool=(pool)
# If we are already closed, the stream can be released now:
if @stream.closed?
pool.release(@stream.connection)
else
# Otherwise, we will release the stream when it is closed:
@stream.pool = pool
end
end
def connection
Signature
-
returns
Connection The underlying HTTP/2 connection.
Implementation
def connection
@stream.connection
end
def wait
Wait for the response headers to be received.
Implementation
def wait
@stream.wait
end
def head?
Signature
-
returns
Boolean Whether the original request was a HEAD request.
Implementation
def head?
@request&.head?
end
def valid?
Signature
-
returns
Boolean Whether the response has a valid status.
Implementation
def valid?
!!@status
end
def build_request(headers)
Build a request object from push promise headers.
Signature
-
parameter
headersArray The push promise pseudo-headers and headers.
-
returns
Protocol::HTTP::Request The constructed request.
Implementation
def build_request(headers)
request = ::Protocol::HTTP::Request.new
request.headers = ::Protocol::HTTP::Headers.new
headers.each do |key, value|
if key == SCHEME
raise ::Protocol::HTTP2::HeaderError, "Request scheme already specified!" if request.scheme
request.scheme = value
elsif key == AUTHORITY
raise ::Protocol::HTTP2::HeaderError, "Request authority already specified!" if request.authority
request.authority = value
elsif key == METHOD
raise ::Protocol::HTTP2::HeaderError, "Request method already specified!" if request.method
request.method = value
elsif key == PATH
raise ::Protocol::HTTP2::HeaderError, "Request path is empty!" if value.empty?
raise ::Protocol::HTTP2::HeaderError, "Request path already specified!" if request.path
request.path = value
elsif key.start_with? ":"
raise ::Protocol::HTTP2::HeaderError, "Invalid pseudo-header #{key}!"
else
request.headers[key] = value
end
end
@request = request
end
def send_request(request)
Send a request and read it into this response.
Implementation
def send_request(request)
@request = request
# https://http2.github.io/http2-spec/#rfc.section.8.1.2.3
# All HTTP/2 requests MUST include exactly one valid value for the :method, :scheme, and :path pseudo-header fields, unless it is a CONNECT request (Section 8.3). An HTTP request that omits mandatory pseudo-header fields is malformed (Section 8.1.2.6).
pseudo_headers = [
[SCHEME, request.scheme],
[METHOD, request.method],
]
if path = request.path
pseudo_headers << [PATH, path]
end
# To ensure that the HTTP/1.1 request line can be reproduced accurately, this pseudo-header field MUST be omitted when translating from an HTTP/1.1 request that has a request target in origin or asterisk form (see [RFC7230], Section 5.3). Clients that generate HTTP/2 requests directly SHOULD use the :authority pseudo-header field instead of the Host header field.
if authority = request.authority
pseudo_headers << [AUTHORITY, authority]
end
if protocol = request.protocol
pseudo_headers << [PROTOCOL, protocol]
end
headers = ::Protocol::HTTP::Headers::Merged.new(
pseudo_headers,
request.headers.header
)
if request.body.nil?
@stream.send_headers(headers, ::Protocol::HTTP2::END_STREAM)
else
if length = request.body.length
# This puts it at the end of the pseudo-headers:
pseudo_headers << [CONTENT_LENGTH, length]
end
# This function informs the headers object that any subsequent headers are going to be trailer. Therefore, it must be called *before* sending the headers, to avoid any race conditions.
trailer = request.headers.trailer!
begin
@stream.send_headers(headers)
rescue
raise ::Protocol::HTTP::RefusedError
end
@stream.send_body(request.body, trailer)
end
end