Skip to content

Commit 77a3f0c

Browse files
committed
Add support for multiplexing protocol configurations.
1 parent 5624288 commit 77a3f0c

File tree

6 files changed

+52
-8
lines changed

6 files changed

+52
-8
lines changed

lib/async/http/protocol/http.rb

+17-3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ module HTTP
1616
HTTP2_PREFACE = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
1717
HTTP2_PREFACE_SIZE = HTTP2_PREFACE.bytesize
1818

19+
# Determine if the inbound connection is HTTP/1 or HTTP/2.
20+
#
21+
# @parameter stream [IO::Stream] The stream to detect the protocol for.
22+
# @returns [Class] The protocol class to use.
1923
def self.protocol_for(stream)
2024
# Detect HTTP/2 connection preface
2125
# https://www.rfc-editor.org/rfc/rfc9113.html#section-3.4
@@ -35,18 +39,28 @@ def self.protocol_for(stream)
3539
end
3640
end
3741

38-
# Only inbound connections can detect HTTP1 vs HTTP2 for http://.
39-
# Outbound connections default to HTTP1.
42+
# Create a client for an outbound connection. Defaults to HTTP/1 for plaintext connections.
43+
#
44+
# @parameter peer [IO] The peer to communicate with.
45+
# @parameter options [Hash] Options to pass to the protocol, keyed by protocol class.
4046
def self.client(peer, **options)
47+
options = options[protocol]
48+
4149
HTTP1.client(peer, **options)
4250
end
4351

52+
# Create a server for an inbound connection. Able to detect HTTP1 vs HTTP2.
53+
#
54+
# @parameter peer [IO] The peer to communicate with.
55+
# @parameter options [Hash] Options to pass to the protocol, keyed by protocol class.
4456
def self.server(peer, **options)
4557
stream = ::IO::Stream(peer)
58+
protocol = protocol_for(stream)
4659

47-
return protocol_for(stream).server(stream, **options)
60+
return protocol.server(stream, options[protocol])
4861
end
4962

63+
# @returns [Array] The names of the supported protocols.
5064
def self.names
5165
["h2", "http/1.1", "http/1.0"]
5266
end

lib/async/http/protocol/http1.rb

+11
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,37 @@ module Protocol
1515
module HTTP1
1616
VERSION = "HTTP/1.1"
1717

18+
# @returns [Boolean] Whether the protocol supports bidirectional communication.
1819
def self.bidirectional?
1920
true
2021
end
2122

23+
# @returns [Boolean] Whether the protocol supports trailers.
2224
def self.trailer?
2325
true
2426
end
2527

28+
# Create a client for an outbound connection.
29+
#
30+
# @parameter peer [IO] The peer to communicate with.
31+
# @parameter options [Hash] Options to pass to the client instance.
2632
def self.client(peer, **options)
2733
stream = ::IO::Stream(peer)
2834

2935
return HTTP1::Client.new(stream, VERSION, **options)
3036
end
3137

38+
# Create a server for an inbound connection.
39+
#
40+
# @parameter peer [IO] The peer to communicate with.
41+
# @parameter options [Hash] Options to pass to the server instance.
3242
def self.server(peer, **options)
3343
stream = ::IO::Stream(peer)
3444

3545
return HTTP1::Server.new(stream, VERSION, **options)
3646
end
3747

48+
# @returns [Array] The names of the supported protocol.
3849
def self.names
3950
["http/1.1", "http/1.0"]
4051
end

lib/async/http/protocol/http10.rb

+2
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@ module Protocol
1212
module HTTP10
1313
VERSION = "HTTP/1.0"
1414

15+
# @returns [Boolean] Whether the protocol supports bidirectional communication.
1516
def self.bidirectional?
1617
false
1718
end
1819

20+
# @returns [Boolean] Whether the protocol supports trailers.
1921
def self.trailer?
2022
false
2123
end

lib/async/http/protocol/http11.rb

+2
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ module Protocol
1313
module HTTP11
1414
VERSION = "HTTP/1.1"
1515

16+
# @returns [Boolean] Whether the protocol supports bidirectional communication.
1617
def self.bidirectional?
1718
true
1819
end
1920

21+
# @returns [Boolean] Whether the protocol supports trailers.
2022
def self.trailer?
2123
true
2224
end

lib/async/http/protocol/http2.rb

+2
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@ module Protocol
1515
module HTTP2
1616
VERSION = "HTTP/2"
1717

18+
# @returns [Boolean] Whether the protocol supports bidirectional communication.
1819
def self.bidirectional?
1920
true
2021
end
2122

23+
# @returns [Boolean] Whether the protocol supports trailers.
2224
def self.trailer?
2325
true
2426
end

lib/async/http/protocol/https.rb

+18-5
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,20 @@ module HTTP
1414
module Protocol
1515
# A server that supports both HTTP1.0 and HTTP1.1 semantics by detecting the version of the request.
1616
module HTTPS
17+
# The protocol classes for each supported protocol.
1718
HANDLERS = {
1819
"h2" => HTTP2,
1920
"http/1.1" => HTTP11,
2021
"http/1.0" => HTTP10,
2122
nil => HTTP11,
2223
}
2324

25+
# Determine the protocol of the peer and return the appropriate protocol class.
26+
#
27+
# Use TLS Application Layer Protocol Negotiation (ALPN) to determine the protocol.
28+
#
29+
# @parameter peer [IO] The peer to communicate with.
30+
# @returns [Class] The protocol class to use.
2431
def self.protocol_for(peer)
2532
# alpn_protocol is only available if openssl v1.0.2+
2633
name = peer.alpn_protocol
@@ -34,15 +41,21 @@ def self.protocol_for(peer)
3441
end
3542
end
3643

37-
def self.client(peer)
38-
protocol_for(peer).client(peer)
44+
def self.client(peer, **options)
45+
protocol = protocol_for(peer)
46+
options = options[protocol]
47+
48+
protocol.client(peer, **options)
3949
end
4050

41-
def self.server(peer)
42-
protocol_for(peer).server(peer)
51+
def self.server(peer, **options)
52+
protocol = protocol_for(peer)
53+
options = options[protocol]
54+
55+
protocol.server(peer, **options)
4356
end
4457

45-
# Supported Application Layer Protocol Negotiation names:
58+
# @returns [Array] Supported Application Layer Protocol Negotiation (ALPN) names.
4659
def self.names
4760
HANDLERS.keys.compact
4861
end

0 commit comments

Comments
 (0)