RFC 9512 YAML 媒体类型 2024 年 2 月
Polli 等人 信息性 [页]
流:
互联网工程任务组(IETF)
RFC:
9512
类别:
信息性
发布:
ISSN:
2070-1721
作者:
R. Polli
DTD,意大利政府
E. Wilde
Axway
E. Aro
Mozilla

RFC 9512

YAML 媒体类型

摘要

本文档向 IANA 注册了 application/yaml 媒体类型和 +yaml 结构化语法后缀。两者都标识根据 YAML 规范 序列化的文档组件。

本备忘录的状态

本文档不是互联网标准轨道规范;它是 为信息性目的而发布的。

本文档是互联网工程任务组 (IETF)的产物。它代表了 IETF 社群的共识。它已 接受公开审查,并已获互联网工程指导组(IESG) 批准发布。并非所有由 IESG 批准的文档 都是任何级别互联网标准的候选;参见 RFC 7841 第 2 节。

关于本文档当前状态、任何勘误以及 如何提供反馈的信息,可在 https://www.rfc-editor.org/info/rfc9512 获取。

目录

1. 引言

YAML [YAML] 是一种数据序列化 格式,能够在单个表示 流(例如文件或网络资源)中传送一个或多个文档。 它广泛用于 互联网,包括 API 领域(例如,见 [OAS]), 但相应的媒体类型和结构化语法后缀此前尚未 由 IANA 注册。

为提高交换 YAML 流时的互操作性,并 在交换 YAML 资源时利用内容协商机制, 本规范注册了 application/yaml 媒体类型 和 +yaml 结构化语法后缀 [MEDIATYPE]

此外,它还提供了与 [YAML] 相关的安全考虑事项和互操作性 考虑事项,包括它与 [JSON] 的关系。

1.1. 符号约定

本文档中的关键词“必须”、“不得”、“要求”、“”、“不应”、“应该”、“不应该”、“推荐”、“不推荐”、 “可以”和“可选”,当且仅当它们如这里所示 以全大写形式出现时,应按 BCP 14 [RFC2119] [RFC8174] 中的描述进行解释。

本文档中的术语“内容协商”和“资源” 应按 [HTTP] 中的含义解释。

本文档中的术语“片段”和“片段标识符” 应按 [URI] 中的含义解释。

本文档中的术语“表示”、“流”、“YAML 文档”、 “表示图”、“标签”、“序列化细节”、“节点”、“别名 节点”、“锚点”和“锚点名称”应按 [YAML] 中的含义解释。

包含 YAML 代码的图总是以 %YAML 指令开头,以提高可读性。

1.2. 片段 标识

片段标识流中的一个节点。

以“*”开头的片段标识符 应被解释为 YAML 别名节点(见 第 1.2.1 节)。

对于单文档 YAML 流,空片段标识符或 以“/”开头的片段标识符应被解释为 JSON Pointer [JSON-POINTER],并在 YAML 表示图上求值,遍历别名节点;特别是, 空片段标识符引用根节点。此语法只能 引用位于由与 JSON 数据模型互操作的节点 组成的路径上的 YAML 节点(见 第 3.4 节)。

片段标识符并不能保证引用现有节点。 因此,应用程序应该定义如何处理未解析的别名节点。

1.2.1. 通过别名节点进行片段 标识

本节描述如何使用 别名节点(见 [YAML] 的第 3.2.2.2 节和第 7.1 节) 作为片段标识符来指定节点。

YAML 别名节点可以在 URI 片段标识符中表示, 方式是使用 UTF-8 [UTF-8] 将其编码为字节,但这些字符的百分号编码不被 [URI] 第 3.5 节中的 fragment 规则允许。

如果多个节点匹配同一个片段标识符, 则选择第一个出现的匹配项。

关心片段标识符互操作性的用户:

  • 应该将别名节点限制在一组 不需要编码 即可表示为 URI 片段标识符的字符内 (这通常是可能的,因为 锚点名称是序列化细节),并且
  • 不应该使用匹配多个节点的别名节点。

在下面的示例资源中,相对引用(见 [URI] 第 4.2 节file.yaml#*foo 标识第一个别名节点 *foo,该节点指向值为 scalar 的节点, 而不是第二个文档中的那个节点;而相对引用 file.yaml#*document_2 标识第二个文档 {one: [a, sequence]} 的根节点。

 %YAML 1.2
 ---
 one: &foo scalar
 two: &bar
   - some
   - sequence
   - items
 ...
 %YAML 1.2
 ---
 &document_2
 one: &foo [a, sequence]
图 1包含两个 YAML 文档的 YAML 流

2. 媒体类型和结构化语法后缀注册

本节包含 IANA 注册 application/yaml 媒体类型和 +yaml 结构化语法后缀 所需的信息,依据 [MEDIATYPE]

2.1. 媒体类型 application/yaml

YAML 的媒体类型是 application/yaml; 以下信息作为此媒体类型的注册表单。

类型名称:

application

子类型名称:

yaml

必需参数:

不适用

可选参数:

不适用;无法识别的参数应被忽略。

编码考虑事项:

二进制

安全考虑事项:

见本文档的第 4 节

互操作性考虑事项:

见本文档的第 3 节

已发布的规范:

[YAML]、本文档

使用此媒体类型的应用程序:

需要一种人类友好、跨语言且 基于 Unicode 的数据序列化语言的应用程序,该语言围绕 动态编程语言的常见数据类型而设计。

片段标识符考虑事项:

见本文档的第 1.2 节

附加信息:


此类型的已弃用别名 名称:
application/x-yaml、text/yaml 和 text/x-yaml。这些 名称已被使用,但未注册。
魔数:
不适用
文件扩展名:
"yaml"(首选)和 "yml"。 见本文档第 3.3 节
Macintosh 文件类型代码:
不适用
Windows 剪贴板名称:
YAML
联系以获取更多信息的人员和电子邮件地址:

见本文档的作者地址部分。

预期用途:

通用

使用限制:

作者:

见本文档的作者地址部分。

变更控制者:

IETF

2.2. +yaml 结构化语法后缀

后缀 +yaml可以与任何媒体类型一起使用,只要其 表示遵循 为 application/yaml 建立的表示。 结构化语法后缀注册表单如下。 有关注册表单各部分的定义,见 [MEDIATYPE]

名称:

YAML 不是标记语言(YAML)

+suffix:

+yaml

参考文献:

[YAML]、本文档

编码考虑事项:

application/yaml

互操作性考虑事项:

application/yaml

片段标识符考虑事项:

application/yaml 不同, 没有为 +yaml 定义 片段标识语法。

具体的 xxx/yyy+yaml 媒体类型 需要定义片段标识符的语法和语义, 因为为 application/yaml 定义的那些语法和语义不会适用,除非明确说明。

安全考虑事项:

application/yaml

联系人:

httpapi@ietf.org 或 art@ietf.org

作者:

见本文档的作者地址部分。

变更控制者:

IETF

3. 互操作性考虑事项

3.1. YAML 是一种演进中的 语言

YAML 是一种演进中的语言,随着时间推移, 一些特性被添加,另一些特性被移除。

application/yaml 媒体类型注册独立于 YAML 版本。 这允许对版本无关的 YAML 资源进行内容协商。

关心与特定 YAML 版本相关特性的实现者 可以在 YAML 文档中使用 %YAML 指令 指定它(见 [YAML] 第 6.8.1 节)。

3.2. YAML 流

YAML 流可以包含零个或多个 YAML 文档。

当接收多文档流时, 只期望单文档流的应用程序 应发出错误信号,而不是忽略额外文档。

当前实现认为流中的不同文档彼此独立, 类似于 JSON 文本序列(见 [RFC7464]); 锚点等元素不保证能够跨不同文档 被引用。

3.3. 文件名扩展名

"yaml" 文件名扩展名是首选; 它在 Web 上最流行且广泛使用。 "yml" 文件名扩展名仍在使用。 在同一上下文中同时使用两个文件名扩展名 可能导致互操作性问题 (例如,当 "config.yaml" 和 "config.yml" 同时存在时)。

3.4. YAML 和 JSON

使用流式集合样式时(见 [YAML] 第 7.4 节), YAML 文档可能看起来像 JSON [JSON]; 因此,适用类似的互操作性考虑事项。

当使用 YAML 作为更高效的格式 来序列化意图作为 JSON 使用的信息时, 未反映在表示图中 且被归类为表示或序列化细节的信息 (见 [YAML] 第 3.2 节)可以被丢弃。 这包括注释(见 [YAML] 第 3.2.3.3 节)、 指令,以及没有 JSON 对应物的别名节点(见 [YAML] 第 7.1 节)。

 %YAML 1.2
 ---
 # This comment will be lost
 # when serializing in JSON.
 Title:
   type: string
   maxLength: &text_limit 64

 Name:
   type: string
   maxLength: *text_limit  # Replaced by the value 64.
图 2JSON 用静态值 替换别名节点

实现者需要确保相关 信息不会在处理期间丢失。 例如,他们可以认为 将别名节点替换为静态值是可接受的。

在某些情况下,实现者可能希望 定义允许的 YAML 特性列表, 同时考虑以下特性可能与 [JSON] 存在互操作性 问题:

  • 多文档 YAML 流
  • 非 UTF-8 编码。在将 YAML 流编码为 UTF-16 或 UTF-32 之前, 需要注意,[JSON] 第 8.1 节规定, 在不属于封闭生态系统的系统之间交换 JSON 文本时 必须使用 UTF-8, 且 [YAML] 第 5.2 节建议 使用 UTF-8。
  • 不是字符串的映射键
  • 使用锚点表示的循环引用(见 第 4.2 节图 4
  • .inf.nan 浮点值,因为 JSON 不支持它们
  • 非 JSON 类型, 包括与 !!timestamp 等标签关联的类型, 这些类型包含在较旧 YAML 版本的默认模式中
  • 一般意义上的标签,特别是那些不映射到 JSON 类型的标签,例如 !!python/object!mytag 等自定义和本地标签(见 [YAML] 第 2.4 节)
 %YAML 1.2
 ---
 non-json-keys:
   0: a number
   [0, 1]: a sequence
   ? {k: v}
   : a map
 ---
 non-json-keys:
   !date 2020-01-01: a timestamp
 non-json-value: !date 2020-01-01
 ...
图 3多文档 YAML 流中 JSON 不支持的映射键和值示例

3.5. 片段标识符

为了允许片段标识符遍历别名节点,需要在 片段标识符求值之前生成 YAML 表示图。重要的是,此求值不得 导致第 3.4 节和第 4 节提到的问题,例如无限循环和 意外代码执行。

实现者需要考虑 YAML 版本和受支持的特性 (例如 merge keys) 可能影响表示图的生成(见 图 9)。

第 1.2 节中,本文档扩展了基于 JSON 数据模型的规范的使用,使其支持 YAML 片段标识符。 这是为了提高既有成熟实践的互操作性, 例如以 YAML 编写 OpenAPI 文档 [OAS]

附录 A 提供了一个 非穷尽示例列表,以帮助 读者理解与片段标识符相关的互操作性问题。

4. 安全考虑事项

媒体类型和媒体类型后缀的安全要求 在 [MEDIATYPE] 第 4.6 节中讨论。

4.1. 任意代码 执行

使用 YAML 标签时应谨慎,因为它们的解析 可能触发意外代码执行。

反序列化器中的代码执行应默认禁用, 并且只能显式启用。 在后一种情况下,实现应确保(例如通过特定函数) 代码执行在严格限定的时间/内存限制内完成。

许多实现提供了能解决这些问题的安全反序列化器。

4.2. 资源耗尽

YAML 文档是有根、连通、有向图, 并且可以包含引用循环, 因此不能把它们当作简单树处理(见 [YAML] 第 3.2.1 节)。 将其当作简单树处理的实现 在遍历 YAML 表示图时有陷入无限循环的风险。 这可能发生在:

  • 尝试将其序列化为 JSON 时,或
  • 使用基于 JSON 数据模型的规范 搜索/标识节点时(例如 [JSON-POINTER])。
 %YAML 1.2
 ---
 x: &x
   y: *x
图 4循环文档

即使表示图不是循环的,将其当作 简单树处理也可能导致不当行为,例如触发 指数级数据膨胀(例如 Billion Laughs 攻击)。

 %YAML 1.2
 ---
 x1: &a1 ["a", "a"]
 x2: &a2 [*a1, *a1]
 x3: &a3 [*a2, *a2]
图 5Billion Laughs 文档

可以通过限制锚点递归深度 并在处理前验证输入的处理器来解决此问题; 即使在这些情况下,也必须 仔细测试将要使用的实现。 当以不支持引用循环的格式序列化 YAML 表示图时, 同样的考虑事项也适用(见 第 3.4 节)。

4.3. YAML 流

对 YAML 流进行增量解析和处理可能产生部分 结果, 并随后指示无法解析流的剩余部分; 为避免部分处理,实现者可能更倾向于同时验证并处理 流中的所有文档。

重复解析和重新编码 YAML 流可能导致 文档分隔符(例如 ---...) 的添加或移除,以及锚点名称和其他序列化细节的修改, 从而破坏签名验证。

4.4. 表示布尔值

[YAML] 第 10.3.2 节 指定只有匹配 正则表达式 true|True|TRUE|false|False|FALSE 的标量会被解释为布尔值。 较旧的 YAML 版本更加宽松(例如,将 NON 解释为 False,并将 YESY 解释为 True)。 使用较旧语法时,YAML 实现可能会将 {insecure: n} 解释为 {insecure: "n"},而不是 {insecure: false}。 使用 [YAML] 第 10.3.2 节中定义的语法可防止这些问题。

5. IANA 考虑事项

IANA 已使用“媒体 类型” 注册表,根据第 2.1 节中的注册信息更新 媒体类型 application/yaml

IANA 已使用“结构化 语法后缀”注册表,根据 第 2.2 节中的注册信息更新结构化语法后缀 +yaml

6. 参考文献

6.1. 规范性参考文献

[HTTP]
Fielding, R.,编Nottingham, M., 编J. Reschke,编“HTTP 语义”STD 97RFC 9110DOI 10.17487/RFC9110<https://www.rfc-editor.org/info/rfc9110>
[JSON]
Bray, T.,编“JavaScript 对象表示法 (JSON)数据交换格式”STD 90RFC 8259DOI 10.17487/RFC8259<https://www.rfc-editor.org/info/rfc8259>
[JSON-POINTER]
Bryan, P.,编Zyp, K.M. Nottingham,编“JavaScript 对象表示法 (JSON)Pointer”RFC 6901DOI 10.17487/RFC6901<https://www.rfc-editor.org/info/rfc6901>
[MEDIATYPE]
Freed, N.Klensin, J.T. Hansen“媒体类型规范和 注册程序”BCP 13RFC 6838DOI 10.17487/RFC6838<https://www.rfc-editor.org/info/rfc6838>
[OAS]
Miller, D.Whitlock, J.Gardiner, M.Ralphson, M.Ratovsky, R.U. Sarid“OpenAPI 规范”v3.0.0
[RFC2119]
Bradner, S.“RFC 中用于 表示要求级别的关键词”BCP 14RFC 2119DOI 10.17487/RFC2119<https://www.rfc-editor.org/info/rfc2119>
[RFC8174]
Leiba, B.“RFC 2119 关键词中 大写与小写的歧义”BCP 14RFC 8174DOI 10.17487/RFC8174<https://www.rfc-editor.org/info/rfc8174>
[URI]
Berners-Lee, T.Fielding, R.L. Masinter“统一资源标识符 (URI):通用语法”STD 66RFC 3986DOI 10.17487/RFC3986<https://www.rfc-editor.org/info/rfc3986>
[UTF-8]
Yergeau, F.“UTF-8,ISO 10646 的一种转换 格式”STD 63RFC 3629DOI 10.17487/RFC3629<https://www.rfc-editor.org/info/rfc3629>
[YAML]
Ben-Kiki, O.Evans, C.dot Net, I.Müller, T.Antoniou, P.Aro, E.T. Smith“YAML 不是标记语言版本 1.2”<https://yaml.org/spec/1.2.2/>

6.2. 资料性参考文献

[RFC7464]
Williams, N.“JavaScript 对象表示法 (JSON)文本序列”RFC 7464DOI 10.17487/RFC7464<https://www.rfc-editor.org/info/rfc7464>

A.1. 不可引用的节点

此示例展示了一组无法 基于 JSON 数据模型引用的 YAML 节点,因为它们的映射键 不是字符串。

 %YAML 1.2
 ---
 a-map-cannot:
   ? {be: expressed}
   : with a JSON Pointer

 0: no numeric mapping keys in JSON
图 6基于 JSON 数据模型 不可引用的 YAML 节点示例

A.2. 引用缺失 节点

在此示例中,片段 #/0 并不引用现有 节点。

 %YAML 1.2
 ---
 0: "JSON Pointer `#/0` references a string mapping key."
图 7不引用现有节点的 JSON Pointer 示例

A.3. 带锚点和循环引用的 表示图

在此 YAML 文档中,#/foo/bar/baz 片段标识符 遍历表示图并引用字符串 you。 此外,循环引用的存在意味着 存在无限多个片段标识符 #/foo/bat/../bat/bar 引用 &anchor 节点。

 %YAML 1.2
 ---
 anchor: &anchor
   baz: you
 foo: &foo
   bar: *anchor
   bat: *foo
图 8循环 引用和别名节点示例

许多 YAML 实现会在表示图中解析 YAML 1.1 中定义的合并键“<<:”。 这意味着片段 #/book/author/given_name 引用字符串 Federico, 并且片段 #/book/<< 将不引用任何现有节点。

 %YAML 1.1
 ---
 # Many implementations use merge keys.
 the-viceroys: &the-viceroys
   title: The Viceroys
   author:
     given_name: Federico
     family_name: De Roberto
 book:
   <<: *the-viceroys
   title: The Illusion
图 9YAML 合并 键示例

致谢

感谢 Erik WildeDavid Biesack 作为本规范的初始贡献者, 也感谢 Darrel MillerRich Salz 在采纳阶段提供的支持。

此外,本文档很大程度上受益于 HTTPAPI 工作组内外的广泛讨论。 以下贡献者通过提交 拉取请求、报告错误、提出有见地的问题、起草或 审阅文本以及评估开放议题,帮助改进了本规范:Tina (tinita) MüllerBen HuttonCarsten BormannManu SpornyJason Desrosiers.

作者地址

Roberto Polli
意大利政府数字化转型部
意大利
Erik Wilde
Axway
瑞士
Eemeli Aro
Mozilla
芬兰