4. 在 HTTP 中使用结构化字段
本节定义如何在文本 HTTP 字段值以及与其兼容的其他编码中序列化和解析 Structured Fields (例如 HTTP/2 [RFC7540] 中 HPACK [RFC7541] 压缩之前的表示).
4.1. 序列化 Structured Fields
给定本规范中定义的结构, 返回适合用作 HTTP 字段值的 ASCII 字符串.
-
如果该结构是 Dictionary 或 List 且其值为空 (即没有成员), 则完全不序列化该字段 (即省略 field-name 和 field-value).
-
如果该结构是 List, 令
output_string为使用该结构运行 Serializing a List (Section 4.1.1) 的结果. -
否则, 如果该结构是 Dictionary, 令
output_string为使用该结构运行 Serializing a Dictionary (Section 4.1.2) 的结果. -
否则, 如果该结构是 Item, 令
output_string为使用该结构运行 Serializing an Item (Section 4.1.3) 的结果. -
否则, 序列化失败.
-
返回使用 ASCII 编码 [RFC0020] 将
output_string转换成的字节数组.
4.1.1. 序列化 List
给定一个由 (member_value, parameters) tuples 组成的数组 input_list, 返回适合用作 HTTP 字段值的 ASCII 字符串.
-
令
output为空字符串. -
对
input_list中的每个(member_value, parameters):-
如果
member_value是数组, 将使用(member_value, parameters)运行 Serializing an Inner List (Section 4.1.1.1) 的结果追加到output. -
否则, 将使用
(member_value, parameters)运行 Serializing an Item (Section 4.1.3) 的结果追加到output. -
如果
input_list中还有更多member_values:-
将 "," 追加到
output. -
将单个 SP 追加到
output.
-
-
-
返回
output.
4.1.1.1. 序列化 Inner List
给定一个由 (member_value, parameters) tuples 组成的数组 inner_list, 以及作为 list_parameters 的 parameters, 返回适合用作 HTTP 字段值的 ASCII 字符串.
-
令
output为字符串 "(". -
对
inner_list中的每个(member_value, parameters):-
将使用
(member_value, parameters)运行 Serializing an Item (Section 4.1.3) 的结果追加到output. -
如果
inner_list中还有更多 values, 将单个 SP 追加到output.
-
-
将 ")" 追加到
output. -
将使用
list_parameters运行 Serializing Parameters (Section 4.1.1.2) 的结果追加到output. -
返回
output.
4.1.1.2. 序列化 Parameters
给定一个有序 Dictionary input_parameters (每个成员具有 param_key 和 param_value), 返回适合用作 HTTP 字段值的 ASCII 字符串.
-
令
output为空字符串. -
对
input_parameters中每个值为param_value的param_key:-
将 ";" 追加到
output. -
将使用
param_key运行 Serializing a Key (Section 4.1.1.3) 的结果追加到output. -
如果
param_value不是 Boolean true:-
将 "=" 追加到
output. -
将使用
param_value运行 Serializing a bare Item (Section 4.1.3.1) 的结果追加到output.
-
-
-
返回
output.
4.1.1.3. 序列化 Key
给定一个 key 作为 input_key, 返回适合用作 HTTP 字段值的 ASCII 字符串.
-
将
input_key转换为 ASCII 字符序列. 如果转换失败, 序列化失败. -
如果
input_key包含不属于 lcalpha, DIGIT, "_", "-", "." 或 "*" 的字符, 序列化失败. -
如果
input_key的第一个字符不是 lcalpha 或 "*", 序列化失败. -
令
output为空字符串. -
将
input_key追加到output. -
返回
output.
4.1.2. 序列化 Dictionary
给定一个有序 Dictionary input_dictionary (每个成员具有 member_key 和 tuple 值 (member_value, parameters)), 返回适合用作 HTTP 字段值的 ASCII 字符串.
-
令
output为空字符串. -
对
input_dictionary中每个值为(member_value, parameters)的member_key:-
将使用该成员的
member_key运行 Serializing a Key (Section 4.1.1.3) 的结果追加到output. -
如果
member_value是 Boolean true:- 将使用
parameters运行 Serializing Parameters (Section 4.1.1.2) 的结果追加到output.
- 将使用
-
否则:
-
将 "=" 追加到
output. -
如果
member_value是数组, 将使用(member_value, parameters)运行 Serializing an Inner List (Section 4.1.1.1) 的结果追加到output. -
否则, 将使用
(member_value, parameters)运行 Serializing an Item (Section 4.1.3) 的结果追加到output.
-
-
如果
input_dictionary中还有更多成员:-
将 "," 追加到
output. -
将单个 SP 追加到
output.
-
-
-
返回
output.
4.1.3. 序列化 Item
给定一个作为 bare_item 的 Item 和作为 item_parameters 的 Parameters, 返回适合用作 HTTP 字段值的 ASCII 字符串.
-
令
output为空字符串. -
将使用
bare_item运行 Serializing a Bare Item (Section 4.1.3.1) 的结果追加到output. -
将使用
item_parameters运行 Serializing Parameters (Section 4.1.1.2) 的结果追加到output. -
返回
output.
4.1.3.1. 序列化 Bare Item
给定一个 Item 作为 input_item, 返回适合用作 HTTP 字段值的 ASCII 字符串.
-
如果
input_item是 Integer, 返回使用input_item运行 Serializing an Integer (Section 4.1.4) 的结果. -
如果
input_item是 Decimal, 返回使用input_item运行 Serializing a Decimal (Section 4.1.5) 的结果. -
如果
input_item是 String, 返回使用input_item运行 Serializing a String (Section 4.1.6) 的结果. -
如果
input_item是 Token, 返回使用input_item运行 Serializing a Token (Section 4.1.7) 的结果. -
如果
input_item是 Byte Sequence, 返回使用input_item运行 Serializing a Byte Sequence (Section 4.1.8) 的结果. -
如果
input_item是 Boolean, 返回使用input_item运行 Serializing a Boolean (Section 4.1.9) 的结果. -
否则, 序列化失败.
4.1.4. 序列化 Integer
给定一个 Integer 作为 input_integer, 返回适合用作 HTTP 字段值的 ASCII 字符串.
-
如果
input_integer不是范围 -999,999,999,999,999 到 999,999,999,999,999 (含端点) 内的整数, 序列化失败. -
令
output为空字符串. -
如果
input_integer小于 (但不等于) 0, 将 "-" 追加到output. -
将
input_integer的数值以十进制表示 (仅使用十进制数字) 追加到output. -
返回
output.
4.1.5. 序列化 Decimal
给定一个 decimal number 作为 input_decimal, 返回适合用作 HTTP 字段值的 ASCII 字符串.
-
如果
input_decimal不是 decimal number, 序列化失败. -
如果
input_decimal在小数点右侧有超过三位有效数字, 将其舍入到三位小数, 最后一位舍入到最接近的值, 若距离相等则舍入到偶数值. -
如果舍入后
input_decimal在小数点左侧有超过 12 位有效数字, 序列化失败. -
令
output为空字符串. -
如果
input_decimal小于 (但不等于) 0, 将 "-" 追加到output. -
将
input_decimal的整数部分以十进制表示 (仅使用十进制数字) 追加到output. 如果该整数部分为零, 追加 "0". -
将 "." 追加到
output. -
如果
input_decimal的小数部分为零, 将 "0" 追加到output. -
否则, 将
input_decimal的小数部分的有效数字以十进制表示 (仅使用十进制数字) 追加到output. -
返回
output.
4.1.6. 序列化 String
给定一个 String 作为 input_string, 返回适合用作 HTTP 字段值的 ASCII 字符串.
-
将
input_string转换为 ASCII 字符序列. 如果转换失败, 序列化失败. -
如果
input_string包含范围 %x00-1f 或 %x7f-ff 中的字符 (即不属于 VCHAR 或 SP), 序列化失败. -
令
output为字符串 DQUOTE. -
对
input_string中的每个字符char:-
如果
char是 "" 或 DQUOTE:- 将 "" 追加到
output.
- 将 "" 追加到
-
将
char追加到output.
-
-
将 DQUOTE 追加到
output. -
返回
output.
4.1.7. 序列化 Token
给定一个 Token 作为 input_token, 返回适合用作 HTTP 字段值的 ASCII 字符串.
-
将
input_token转换为 ASCII 字符序列. 如果转换失败, 序列化失败. -
如果
input_token的第一个字符不是 ALPHA 或 "*", 或者其余部分包含不属于 tchar, ":" 或 "/" 的字符, 序列化失败. -
令
output为空字符串. -
将
input_token追加到output. -
返回
output.
4.1.8. 序列化 Byte Sequence
给定一个 Byte Sequence 作为 input_bytes, 返回适合用作 HTTP 字段值的 ASCII 字符串.
-
如果
input_bytes不是字节序列, 序列化失败. -
令
output为空字符串. -
将 ":" 追加到
output. -
将按 [RFC4648] Section 4 对
input_bytes进行 base64 编码的结果追加到output, 同时考虑下面的要求. -
将 ":" 追加到
output. -
返回
output.
编码数据要求按照 [RFC4648] Section 3.2 使用 "=" 填充.
同样, 除非由于实现约束无法做到, 编码数据 SHOULD 按 [RFC4648] Section 3.5 将 pad bits 置为零.
4.1.9. 序列化 Boolean
给定一个 Boolean 作为 input_boolean, 返回适合用作 HTTP 字段值的 ASCII 字符串.
-
如果
input_boolean不是 boolean, 序列化失败. -
令
output为空字符串. -
将 "?" 追加到
output. -
如果
input_boolean为 true, 将 "1" 追加到output. -
如果
input_boolean为 false, 将 "0" 追加到output. -
返回
output.
4.2. 解析 Structured Fields
当接收实现解析已知为 Structured Fields 的 HTTP 字段时, 必须小心处理, 因为有许多 edge cases 可能导致互操作性问题甚至安全问题. 本节指定执行该操作的算法.
给定表示所选字段 field-value 的字节数组 input_bytes (如果该字段不存在则为空) 和 field_type ("dictionary", "list" 或 "item" 之一), 返回已解析的 header value.
-
将
input_bytes转换为 ASCII 字符串input_string. 如果转换失败, 解析失败. -
丢弃
input_string中所有前导 SP 字符. -
如果
field_type是 "list", 令output为使用input_string运行 Parsing a List (Section 4.2.1) 的结果. -
如果
field_type是 "dictionary", 令output为使用input_string运行 Parsing a Dictionary (Section 4.2.2) 的结果. -
如果
field_type是 "item", 令output为使用input_string运行 Parsing an Item (Section 4.2.3) 的结果. -
丢弃
input_string中所有前导 SP 字符. -
如果
input_string非空, 解析失败. -
否则, 返回
output.
生成 input_bytes 时, parsers MUST 按 [RFC7230] Section 3.2.2 将同一 section (header 或 trailer) 中字段名大小写不敏感匹配的所有字段行合并为一个逗号分隔的 field-value. 这确保整个字段值得到正确处理.
对于 Lists 和 Dictionaries, 只要顶层数据结构中的单个成员未跨多个 header instances 拆分, 这就会正确串接该字段的所有行. 这两种类型的解析算法允许制表符, 因为一些实现可能使用制表符来合并字段行.
拆分到多个字段行的 Strings 将得到不可预测的结果, 因为一个或多个逗号 (以及可选空白) 将成为 parser 输出字符串的一部分. 由于串接可能由上游 intermediary 完成, 即使 serializer 和 parser 都由同一方控制, 结果也不受它们控制.
Tokens, Integers, Decimals 和 Byte Sequences 不能跨多个字段行拆分, 因为插入的逗号会导致解析失败.
当处理分布在多个字段行上的字段值时, 如果其中某一行不能按该字段解析, parsers MAY 失败. 例如, 对于被定义为 sf-string 的 Example-String 字段, parser 允许在处理以下字段 section 时失败:
Example-String: "foo
Example-String: bar"
如果解析失败, 包括调用其他算法时失败, 整个字段值 MUST 被忽略 (即视为该字段未出现在该 section 中). 这是有意严格的要求, 旨在提升互操作性和安全性, 引用本文档的规范不允许放宽此要求.
注意, 此要求不适用于未解析该字段的实现. 例如, intermediary 在转发消息之前并不要求剥除失败的字段.
4.2.1. 解析 List
给定一个 ASCII 字符串作为 input_string, 返回由 (item_or_inner_list, parameters) tuples 组成的数组. input_string 会被修改以移除已解析的值.
-
令
members为空数组. -
当
input_string非空时:-
将使用
input_string运行 Parsing an Item or Inner List (Section 4.2.1.1) 的结果追加到members. -
丢弃
input_string中所有前导 OWS 字符. -
如果
input_string为空, 返回members. -
消费
input_string的第一个字符. 如果它不是 ",", 解析失败. -
丢弃
input_string中所有前导 OWS 字符. -
如果
input_string为空, 则存在尾随逗号. 解析失败.
-
-
未找到结构化数据. 返回
members(此时为空).
4.2.1.1. 解析 Item 或 Inner List
给定一个 ASCII 字符串作为 input_string, 返回 tuple (item_or_inner_list, parameters), 其中 item_or_inner_list 可以是单个 bare item, 也可以是由 (bare_item, parameters) tuples 组成的数组. input_string 会被修改以移除已解析的值.
-
如果
input_string的第一个字符是 "(", 返回使用input_string运行 Parsing an Inner List (Section 4.2.1.2) 的结果. -
返回使用
input_string运行 Parsing an Item (Section 4.2.3) 的结果.
4.2.1.2. 解析 Inner List
给定一个 ASCII 字符串作为 input_string, 返回 tuple (inner_list, parameters), 其中 inner_list 是由 (bare_item, parameters) tuples 组成的数组. input_string 会被修改以移除已解析的值.
-
消费
input_string的第一个字符. 如果它不是 "(", 解析失败. -
令
inner_list为空数组. -
当
input_string非空时:-
丢弃
input_string中所有前导 SP 字符. -
如果
input_string的第一个字符是 ")":-
消费
input_string的第一个字符. -
令
parameters为使用input_string运行 Parsing Parameters (Section 4.2.3.2) 的结果. -
返回 tuple
(inner_list, parameters).
-
-
令
item为使用input_string运行 Parsing an Item (Section 4.2.3) 的结果. -
将
item追加到inner_list. -
如果
input_string的第一个字符不是 SP 或 ")", 解析失败.
-
-
未找到 Inner List 的结尾. 解析失败.
4.2.2. 解析 Dictionary
给定一个 ASCII 字符串作为 input_string, 返回一个有序映射, 其 values 是 (item_or_inner_list, parameters) tuples. input_string 会被修改以移除已解析的值.
-
令
dictionary为空的有序映射. -
当
input_string非空时:-
令
this_key为使用input_string运行 Parsing a Key (Section 4.2.3.3) 的结果. -
如果
input_string的第一个字符是 "=":-
消费
input_string的第一个字符. -
令
member为使用input_string运行 Parsing an Item or Inner List (Section 4.2.1.1) 的结果.
-
-
否则:
-
令
value为 Boolean true. -
令
parameters为使用input_string运行 Parsing Parameters (Section 4.2.3.2) 的结果. -
令
member为 tuple(value, parameters).
-
-
如果
dictionary已经包含 keythis_key(逐字符比较), 用member覆盖其值. -
否则, 将 key
this_key和 valuemember追加到dictionary. -
丢弃
input_string中所有前导 OWS 字符. -
如果
input_string为空, 返回dictionary. -
消费
input_string的第一个字符. 如果它不是 ",", 解析失败. -
丢弃
input_string中所有前导 OWS 字符. -
如果
input_string为空, 则存在尾随逗号. 解析失败.
-
-
未找到结构化数据. 返回
dictionary(此时为空).
注意, 当遇到重复的 Dictionary keys 时, 除最后一个实例外都被忽略.
4.2.3. 解析 Item
给定一个 ASCII 字符串作为 input_string, 返回 (bare_item, parameters) tuple. input_string 会被修改以移除已解析的值.
-
令
bare_item为使用input_string运行 Parsing a Bare Item (Section 4.2.3.1) 的结果. -
令
parameters为使用input_string运行 Parsing Parameters (Section 4.2.3.2) 的结果. -
返回 tuple
(bare_item, parameters).
4.2.3.1. 解析 Bare Item
给定一个 ASCII 字符串作为 input_string, 返回 bare Item. input_string 会被修改以移除已解析的值.
-
如果
input_string的第一个字符是 "-" 或 DIGIT, 返回使用input_string运行 Parsing an Integer or Decimal (Section 4.2.4) 的结果. -
如果
input_string的第一个字符是 DQUOTE, 返回使用input_string运行 Parsing a String (Section 4.2.5) 的结果. -
如果
input_string的第一个字符是 ALPHA 或 "*", 返回使用input_string运行 Parsing a Token (Section 4.2.6) 的结果. -
如果
input_string的第一个字符是 ":", 返回使用input_string运行 Parsing a Byte Sequence (Section 4.2.7) 的结果. -
如果
input_string的第一个字符是 "?", 返回使用input_string运行 Parsing a Boolean (Section 4.2.8) 的结果. -
否则, item type 无法识别. 解析失败.
4.2.3.2. 解析 Parameters
给定一个 ASCII 字符串作为 input_string, 返回一个有序映射, 其 values 是 bare Items. input_string 会被修改以移除已解析的值.
-
令
parameters为空的有序映射. -
当
input_string非空时:-
如果
input_string的第一个字符不是 ";", 退出循环. -
从
input_string开头消费 ";" 字符. -
丢弃
input_string中所有前导 SP 字符. -
令
param_key为使用input_string运行 Parsing a Key (Section 4.2.3.3) 的结果. -
令
param_value为 Boolean true. -
如果
input_string的第一个字符是 "=":-
消费
input_string开头的 "=" 字符. -
令
param_value为使用input_string运行 Parsing a Bare Item (Section 4.2.3.1) 的结果.
-
-
如果
parameters已经包含 keyparam_key(逐字符比较), 用param_value覆盖其值. -
否则, 将 key
param_key和 valueparam_value追加到parameters.
-
-
返回
parameters.
注意, 当遇到重复的 parameter keys 时, 除最后一个实例外都被忽略.
4.2.3.3. 解析 Key
给定一个 ASCII 字符串作为 input_string, 返回 key. input_string 会被修改以移除已解析的值.
-
如果
input_string的第一个字符不是 lcalpha 或 "*", 解析失败. -
令
output_string为空字符串. -
当
input_string非空时:-
如果
input_string的第一个字符不是 lcalpha, DIGIT, "_", "-", "." 或 "*" 之一, 返回output_string. -
令
char为消费input_string第一个字符的结果. -
将
char追加到output_string.
-
-
返回
output_string.
4.2.4. 解析 Integer 或 Decimal
给定一个 ASCII 字符串作为 input_string, 返回 Integer 或 Decimal. input_string 会被修改以移除已解析的值.
NOTE: 此算法同时解析 Integers (Section 3.3.1) 和 Decimals (Section 3.3.2), 并返回相应结构.
-
令
type为 "integer". -
令
sign为 1. -
令
input_number为空字符串. -
如果
input_string的第一个字符是 "-", 消费它并将sign设为 -1. -
如果
input_string为空, 则存在空 integer. 解析失败. -
如果
input_string的第一个字符不是 DIGIT, 解析失败. -
当
input_string非空时:-
令
char为消费input_string第一个字符的结果. -
如果
char是 DIGIT, 将它追加到input_number. -
否则, 如果
type是 "integer" 且char是 ".":-
如果
input_number包含超过 12 个字符, 解析失败. -
否则, 将
char追加到input_number并将type设为 "decimal".
-
-
否则, 将
char放回input_string开头, 并退出循环. -
如果
type是 "integer" 且input_number包含超过 15 个字符, 解析失败. -
如果
type是 "decimal" 且input_number包含超过 16 个字符, 解析失败.
-
-
如果
type是 "integer":- 将
input_number解析为整数, 并令output_number为该结果与sign的乘积.
- 将
-
否则:
-
如果
input_number的最后一个字符是 ".", 解析失败. -
如果
input_number中 "." 后面的字符数大于三, 解析失败. -
将
input_number解析为 decimal number, 并令output_number为该结果与sign的乘积.
-
-
返回
output_number.
4.2.5. 解析 String
给定一个 ASCII 字符串作为 input_string, 返回未加引号的 String. input_string 会被修改以移除已解析的值.
-
令
output_string为空字符串. -
如果
input_string的第一个字符不是 DQUOTE, 解析失败. -
丢弃
input_string的第一个字符. -
当
input_string非空时:-
令
char为消费input_string第一个字符的结果. -
如果
char是反斜杠 ("\"):-
如果
input_string现在为空, 解析失败. -
令
next_char为消费input_string第一个字符的结果. -
如果
next_char不是 DQUOTE 或 "\", 解析失败. -
将
next_char追加到output_string.
-
-
否则, 如果
char是 DQUOTE, 返回output_string. -
否则, 如果
char在范围 %x00-1f 或 %x7f-ff 内 (即不属于 VCHAR 或 SP), 解析失败. -
否则, 将
char追加到output_string.
-
-
到达
input_string末尾但未找到闭合 DQUOTE. 解析失败.
4.2.6. 解析 Token
给定一个 ASCII 字符串作为 input_string, 返回 Token. input_string 会被修改以移除已解析的值.
-
如果
input_string的第一个字符不是 ALPHA 或 "*", 解析失败. -
令
output_string为空字符串. -
当
input_string非空时:-
如果
input_string的第一个字符不属于 tchar, ":" 或 "/", 返回output_string. -
令
char为消费input_string第一个字符的结果. -
将
char追加到output_string.
-
-
返回
output_string.
4.2.7. 解析 Byte Sequence
给定一个 ASCII 字符串作为 input_string, 返回 Byte Sequence. input_string 会被修改以移除已解析的值.
-
如果
input_string的第一个字符不是 ":", 解析失败. -
丢弃
input_string的第一个字符. -
如果在
input_string末尾之前没有 ":" 字符, 解析失败. -
令
b64_content为消费input_string内容直到但不包括第一个 ":" 字符的结果. -
消费
input_string开头的 ":" 字符. -
如果
b64_content包含不属于 ALPHA, DIGIT, "+", "/" 和 "=" 的字符, 解析失败. -
令
binary_content为对b64_content进行 base64 解码 [RFC4648] 的结果, 必要时合成 padding (注意下面关于接收者行为的要求). 如果 base64 解码失败, 解析失败. -
返回
binary_content.
由于某些 base64 实现不允许拒绝未正确使用 "=" padding 的编码数据 (见 [RFC4648] Section 3.2), 除非 parsers 无法被配置为这样做, 否则 parsers SHOULD NOT 在 "=" padding 不存在时失败.
由于某些 base64 实现不允许拒绝具有非零 pad bits 的编码数据 (见 [RFC4648] Section 3.5), 除非 parsers 无法被配置为这样做, 否则 parsers SHOULD NOT 在存在非零 pad bits 时失败.
本规范不放宽 [RFC4648] Sections 3.1 和 3.3 中的要求. 因此, parsers MUST 在出现 base64 alphabet 之外的字符以及编码数据中出现换行符时失败.
4.2.8. 解析 Boolean
给定一个 ASCII 字符串作为 input_string, 返回 Boolean. input_string 会被修改以移除已解析的值.
-
如果
input_string的第一个字符不是 "?", 解析失败. -
丢弃
input_string的第一个字符. -
如果
input_string的第一个字符匹配 "1", 丢弃该第一个字符并返回 true. -
如果
input_string的第一个字符匹配 "0", 丢弃该第一个字符并返回 false. -
没有匹配的值. 解析失败.