swift-http-structured-headers

HTTP 结构化头部字段值规范的 Swift 实现。

提供结构化头部字段值的解析和序列化功能,以及 EncoderDecoder 的实现,允许使用 Codable 数据类型作为 HTTP 结构化头部字段的有效载荷。

关于结构化头部字段值

HTTP 结构化头部字段值是 RFC 9651 中记录的 HTTP 扩展。它们提供了一组数据类型和算法,用于以一致的方式处理 HTTP 头部字段值,允许单个解析器和序列化器处理各种头部字段值。

Swift HTTP 结构化头部字段值

此包提供了一个实现 RFC 9651 的解析器和序列化器。它们是完全完整的,能够处理所有有效的 HTTP 结构化头部字段值。此包还提供了 EncoderDecoder 对象,用于在 Swift 中使用 Codable。这允许快速原型设计和实验 HTTP 结构化头部字段值,以及与更广泛的 Swift Codable 社区进行交互。

此包提供两个顶级模块:StructuredFieldValuesRawStructuredFieldValues

基础模块 RawStructuredFieldValues 提供了序列化器和解析器的底层实现。这两者都编写为避免使用 Foundation,使其适用于 Foundation 不可用的各种用例。它们完全依赖于 Swift 标准库,并尽可能以通用方式实现。由于缺少 Foundation,其中一个限制是此接口无法执行 Base64 编码或解码:用户可以自由选择他们使用的任何编码器和解码器。

这个 API 是底层的,将原始解析树暴露为序列化器和解析器的格式。这允许高性能和高灵活性的解析和序列化,但代价是冗长而复杂。用户需要理解结构化头部格式并操作稍微笨拙的类型,但保留了最大的保真度,并且性能开销很低。

高级模块 StructuredFieldValues 引入了 EncoderDecoder,并且还添加了对 Foundation 的依赖。这个 Foundation 依赖项对于正确处理 base64 格式以及为二进制数据(Data)和日期(Date)提供良好的自然容器是必要的。此接口更加友好且易于使用,使用 Swift 的 Codable 支持来提供出色的用户体验。

在大多数情况下,用户应首选使用 StructuredFieldValues,除非他们知道他们需要 RawStructuredFieldValues 的性能优势。体验会好得多。

使用结构化头部字段值

swift-http-structured-headers 具有一个简单易用的高级 API,用于处理结构化头部字段值。首先,让我们考虑 HTTP 客户端提示规范。 这定义了以下新的头部字段

Accept-CH 响应头字段指示服务器支持其值中指示的提示。希望通过客户端提示接收用户代理信息的服务器应尽快将 Accept-CH 响应头添加到其响应中。

Accept-CH 是一个结构化头部。它的值必须是一个 sf-list,其成员是 token。其 ABNF 是

Accept-CH = sf-list

例如

Accept-CH: Sec-CH-Example, Sec-CH-Example-2

swift-http-structured-headers 可以非常简单地解析和序列化此字段

let field = Array("Sec-CH-Example, Sec-CH-Example-2".utf8)

struct AcceptCH: StructuredFieldValue {
    static let structuredFieldType: StructuredFieldType = .list

    var items: [String]
}

// Decoding
let decoder = StructuredFieldValueDecoder()
let parsed = try decoder.decode(AcceptCH.self, from: field)

// Encoding
let encoder = StructuredFieldValueEncoder()
let serialized = try encoder.encode(AcceptCH(items: ["Sec-CH-Example", "Sec-CH-Example-2"]))

但是,结构化头部字段值可能相当复杂。 结构化头部字段可以使用 4 个容器和 8 种基本项目类型。 容器是

  1. 字典。 这些是顶级元素,并将 token 键与值关联。 这些值可以是项目,也可以是内部列表,并且每个值也可以具有与其关联的参数。 StructuredFieldValues 可以将字典建模为 Swift 对象(其中属性名称是字典键)。
  2. 列表。 这些是顶级元素,提供项目或内部列表的序列。 每个项目或内部列表都可以具有与其关联的参数。 StructuredFieldValues 将这些建模为具有一个键 items 的 Swift 对象,该键必须是条目的集合。
  3. 内部列表。 这些是可以是字典或列表的子条目的列表。 列表条目是项目,这些项目可以具有与其关联的参数:此外,内部列表也可以具有与其自身关联的参数。 StructuredFieldValues 将这些建模为 Swift Array ,如果提取参数很重要,则建模为双字段 Swift struct,其中一个字段名为 items 并包含一个 Array,另一个字段名为 parameters 并包含一个字典。
  4. 参数。 参数将 token 键与没有参数的项目关联。 这些用于存储有关字段内对象的元数据。 StructuredFieldValues 将这些建模为 Swift 对象(其中属性名称是参数键)或 Swift 字典。

基本类型是

  1. 布尔值。 StructuredFieldValues 将这些建模为 Swift 的 Bool 类型。
  2. 整数。 StructuredFieldValues 将这些建模为任何固定宽度的整数类型。
  3. 小数。 StructuredFieldValues 将这些建模为任何浮点类型,或 Foundation 的 Decimal
  4. Token。 StructuredFieldValues 将这些建模为 Swift 的 String 类型,其中字符范围受到限制。
  5. 字符串。 StructuredFieldValues 将这些建模为 Swift 的 String 类型。
  6. 二进制数据。 StructuredFieldValues 将此建模为 Foundation 的 Data 类型。
  7. 日期。 StructuredFieldValues 将这些建模为 Foundation 的 Date 类型。
  8. 显示字符串。 StructuredFieldValues 将这些建模为它提供的 DisplayString 类型。

对于任何结构化头部字段值项,该项目可以直接由适当的类型表示,也可以由具有两个属性的 Swift 结构表示:itemparameters。 后一种模式是如何捕获给定项目上的参数。

顶级结构化头部字段值必须标识它对应的头部字段的类型:.item.list.dictionary。 这是字段类型固有的,将在相关的字段规范中指定。

更低层级

在某些情况下,Codable 接口对于预期的用例来说不够高效或强大。 在这种情况下,用户可以使用 RawStructuredFieldValues 模块中的类型。

有两个核心类型:StructuredFieldValueParserStructuredFieldValueSerializer。 这两个对象不使用高级 Swift 对象,而是生成或接受给定结构化头部字段的数据树的 Swift 表示。

这暴露了有关头部字段的最大量信息。 它允许用户处理 Codable 不一定能提供相关信息的情况,例如在字典排序具有语义的情况下,或者需要更紧密地控制字段是 token 还是字符串的情况下。

这些 API 的开销也比 StructuredFieldValues API 低。

代价是这些 API 更加冗长。 考虑上面的头部字段 Accept-CH。 在 RawStructuredFieldValues 中解析或序列化它会是这样

let field = Array("Sec-CH-Example, Sec-CH-Example-2".utf8)
var parser = StructuredFieldValueParser(field)
let parsed = parser.parseListFieldValue()

print(parsed)
// [
//     .item(Item(bareItem: .token("Sec-CH-Example"), parameters: [])),
//     .item(Item(bareItem: .token("Sec-CH-Example-2"), parameters: [])),
// ]

var serializer = StructuredFieldValueSerializer()
let serialized = serializer.writeListFieldValue(parsed)

请注意此操作中涉及的类型明显更加冗长。 这些类型具有高度通用性,从而为解析和序列化提供了大大减少运行时开销的机会。 它们还可以更容易地区分 token 和字符串,并观察字典或参数中对象的顺序,这可能会在 Codable 级别丢失。

一般来说,用户只有在确信他们需要灵活性或性能时才应考虑使用此 API。 对于不经常演变或高度动态的头部字段,这可能很有价值。

安全

swift-http-structured-headers 在 SECURITY.md 中概述了安全策略。