type ALPNProtocolName is String val
"""
The name of an application protocol, as it travels over the wire in the ALPN
extension. Between 1 and 255 bytes.
"""
primitive ALPNFatal
"""
Select no protocol and fail the handshake. OpenSSL sends the peer a fatal
alert.
"""
primitive ALPNNoAck
"""
Select no protocol and let the handshake finish. The connection carries no
negotiated protocol.
"""
primitive ALPNWarning
"""
Select no protocol and let the handshake finish. OpenSSL sends the peer a
warning alert first.
"""
type ALPNMatchResult is (ALPNProtocolName | ALPNNoAck | ALPNWarning | ALPNFatal)
"""
What an `ALPNProtocolResolver` gives back: the protocol it chose, or one of
the three ways to choose none.
"""
type _ALPNSelectCallback is @{(
Pointer[_SSL] tag,
Pointer[Pointer[U8] tag] tag,
Pointer[U8] tag,
Pointer[U8] box,
U32,
ALPNProtocolResolver val)
: I32}
primitive _ALPNMatchResultCode
"""
The `SSL_TLSEXT_ERR_*` values an ALPN select callback returns to OpenSSL.
"""
fun ok(): I32 => 0
fun warning(): I32 => 1
fun fatal(): I32 => 2
fun no_ack(): I32 => 3
primitive _ALPNProtocolList
fun from_array(protocols: Array[String] box): String ? =>
"""
Try to pack the protocol names in `protocols` into a *protocol name list*
"""
if protocols.size() == 0 then
error
end
let list = recover trn String end
for proto in protocols.values() do
let len = proto.size()
if (len == 0) or (len > 255) then error end
list.push(U8.from[USize](len))
list.append(proto)
end
list
fun offset_of(protocol_list: String box, name: String box): USize ? =>
"""
The offset within `protocol_list` of the bytes of `name`.
`protocol_list` is a *protocol name list*. Raises an error when the list is
malformed, or when none of the names in it is `name`.
The length prefix is what makes this an exact match rather than a search:
`"h2"` is not found in a list whose only name is `"h2c"`.
"""
let size = name.size()
var index = USize(0)
while index < protocol_list.size() do
let len = USize.from[U8](protocol_list(index)?)
if len == 0 then error end
let start = index + 1
if (start + len) > protocol_list.size() then error end
if (len == size) and protocol_list.at(name, start.isize()) then
return start
end
index = start + len
end
error
fun to_array(protocol_list: String box): Array[ALPNProtocolName] val ? =>
"""
Try to unpack a *protocol name list* into an `Array[String]`
"""
let arr = recover trn Array[ALPNProtocolName] end
var index = USize(1)
var remain = try protocol_list(0)? else error end
var buf = recover trn String end
if remain == 0 then error end
while index < protocol_list.size() do
let ch = try protocol_list(index)? else error end
if remain > 0 then
buf.push(ch)
remain = remain - 1
end
if remain == 0 then
let final_protocol: String = buf = recover String end
arr.push(final_protocol)
let has_next_char = index < (protocol_list.size() - 1)
if has_next_char then
remain = try protocol_list(index + 1)? else error end
if remain == 0 then error end
index = index + 1
end
end
index = index + 1
end
if remain > 0 then error end
arr