class Async::HTTP::Protocol::HTTP2

A server that supports both HTTP1.0 and HTTP1.1 semantics by detecting the version of the request.

def self.client(stream)

def self.client(stream)
	self.new(::HTTP2::Client.new, stream)
end

def self.server(stream)

def self.server(stream)
	self.new(::HTTP2::Server.new, stream)
end

def close

def close
	Async.logger.debug(self) {"Closing connection"}
	@reader.stop
	@stream.close
end

def initialize(controller, stream)

def initialize(controller, stream)
	@controller = controller
	@stream = stream
	
	@controller.on(:frame) do |data|
		@stream.write(data)
		@stream.flush
	end
	
	@controller.on(:frame_sent) do |frame|
		Async.logger.debug(self) {"Sent frame: #{frame.inspect}"}
	end
	
	@controller.on(:frame_received) do |frame|
		Async.logger.debug(self) {"Received frame: #{frame.inspect}"}
	end
	
	if @controller.is_a? ::HTTP2::Client
		@controller.send_connection_preface
	end
	
	@reader = read_in_background
end

def multiplex

Multiple requests can be processed at the same time.
def multiplex
	@controller.remote_settings[:settings_max_concurrent_streams]
end

def read_in_background(task: Task.current)

def read_in_background(task: Task.current)
	task.async do |nested_task|
		buffer = Async::IO::BinaryString.new
		
		while data = @stream.io.read(1024*8, buffer)
			@controller << data
		end
		
		Async.logger.debug(self) {"Connection reset by peer!"}
	end
end

def receive_requests(task: Task.current, &block)

def receive_requests(task: Task.current, &block)
	# emits new streams opened by the client
	@controller.on(:stream) do |stream|
		request = Request.new
		request.version = VERSION
		request.headers = {}
		request.body = Body.new
		
		stream.on(:headers) do |headers|
			headers.each do |key, value|
				if key == METHOD
					request.method = value
				elsif key == PATH
					request.path = value
				elsif key == AUTHORITY
					request.authority = value
				else
					request.headers[key] = value
				end
			end
		end
		
		stream.on(:data) do |chunk|
			request.body.write(chunk.to_s) unless chunk.empty?
		end
		
		stream.on(:half_close) do
			response = yield request
			
			request.body.finish
			
			# send response
			headers = {STATUS => response[0].to_s}
			headers.update(response[1])
			
			stream.headers(headers, end_stream: false)
			
			response[2].each do |chunk|
				stream.data(chunk, end_stream: false)
			end
			
			stream.data("", end_stream: true)
		end
	end
	
	@reader.wait
end

def reusable?

def reusable?
	@reader.alive?
end

def send_request(authority, method, path, headers = {}, body = nil)

def send_request(authority, method, path, headers = {}, body = nil)
	stream = @controller.new_stream
	
	internal_headers = {
		SCHEME => HTTPS,
		METHOD => method,
		PATH => path,
		AUTHORITY => authority,
	}.merge(headers)
	
	stream.headers(internal_headers, end_stream: body.nil?)
	
	if body
		body.each do |chunk|
			stream.data(chunk, end_stream: false)
		end
		
		stream.data("", end_stream: true)
	end
	
	finished = Async::Notification.new
	
	response = Response.new
	response.version = RESPONSE_VERSION
	response.headers = {}
	response.body = Body.new
	
	stream.on(:headers) do |headers|
		# Async.logger.debug(self) {"Stream headers: #{headers.inspect}"}
		
		headers.each do |key, value|
			if key == STATUS
				response.status = value.to_i
			elsif key == REASON
				response.reason = value
			else
				response.headers[key] = value
			end
		end
		
		finished.signal
	end
	
	stream.on(:data) do |chunk|
		Async.logger.debug(self) {"Stream data: #{chunk.inspect}"}
		response.body.write(chunk.to_s) unless chunk.empty?
	end
	
	stream.on(:half_close) do
		Async.logger.debug(self) {"Stream half-closed."}
	end
	
	stream.on(:close) do
		Async.logger.debug(self) {"Stream closed, sending signal."}
		# TODO should we prefer `response.finish`?
		response.body.finish
	end
	
	@stream.flush
	
	# Async.logger.debug(self) {"Stream flushed, waiting for signal."}
	finished.wait
	
	# Async.logger.debug(self) {"Stream finished: #{response.inspect}"}
	return response
end