4. 过时语法
本规范的早期版本允许使用与本版本不同且通常更宽松的语法. 此外, 消息中还使用过一些从未被明确记录的语法元素. 尽管根据第 3 节文法, 其中某些语法形式不得被生成, 但符合规范的接收者必须接受并解析它们. 本节记录其中许多语法元素. 将本节给出的定义加入第 3 节文法后, 得到的就是解释消息时使用的文法.
注: 本节标识任何实现都必须合理解释的语法形式. 不过, 确实存在一些 Internet 消息甚至不符合本节给出的附加语法. 某种特定形式未出现在本文档任何章节中, 并不能成为计算机程序崩溃或任何实现不可恢复地丢失畸形数据的理由. 实现需要以健壮方式处理消息.
过时语法与当前语法的关键差异:
-
空白用法: 在结构化头部字段体内 (即任何结构化头部字段中冒号与 CRLF 之间), 空白字符 (包括 folding white space) 和注释可以自由插入到任意语法令牌之间. 这允许许多复杂形式, 而事实证明某些实现很难解析它们.
-
折叠空白规则: 第 3.2.2 节中关于注释和折叠空白中完全由空白组成的行的规则不适用. 见下文第 4.2 节关于 folding white space 的讨论.
-
特殊字符: 某些当前不再允许的字符过去是允许的. NUL 字符 (ASCII 值 0) 曾被允许, 但出于兼容性原因现在不再允许. 同样, 除 CR, LF, SP 和 HTAB 之外的 US-ASCII 控制字符 (ASCII 值 1 到 8, 11, 12, 14 到 31, 以及 127) 曾允许出现在头部字段体中. CR 和 LF 曾允许以非 CRLF 形式出现在消息中; 这种用法也在此处给出.
关键概念
过时语法的目的
Message Generation Message Parsing
↓ ↓
Section 3 Syntax Section 3 + Section 4
(Strict Rules) (Permissive Rules)
↓ ↓
MUST NOT generate MUST accept obsolete forms
obsolete forms
实现要求
| 角色 | 对过时语法的要求 |
|---|---|
| 消息生成器 | MUST NOT 生成过时语法 |
| 消息解析器 | MUST 接受并解析过时语法 |
| 所有实现 | MUST 健壮处理畸形消息 |
4.1. 其他过时令牌
这些语法元素用于过时语法中的其他位置, 或用于主语法. bare CR, bare LF 和 NUL 被加入 obs-qp, obs-body 和 obs-unstruct. US-ASCII 控制字符被加入 obs-qp, obs-unstruct, obs-ctext 和 obs-qtext. 句点字符被加入 obs-phrase. obs-phrase-list 提供一个以逗号分隔的 phrase 列表, 该列表可能为空并且可能包含 "null" 元素. 也就是说, 这类列表中可能有两个或更多连续逗号且中间没有内容, 或者逗号出现在列表开头或末尾.
obs-NO-WS-CTL = %d1-8 / ; US-ASCII control
%d11 / ; characters that do not
%d12 / ; include the carriage
%d14-31 / ; return, line feed, and
%d127 ; white space characters
obs-ctext = obs-NO-WS-CTL
obs-qtext = obs-NO-WS-CTL
obs-utext = %d0 / obs-NO-WS-CTL / VCHAR
obs-qp = "\" (%d0 / obs-NO-WS-CTL / LF / CR)
obs-body = *((*LF *CR *((%d0 / text) *LF *CR)) / CRLF)
obs-unstruct = *((*LF *CR *(obs-utext *LF *CR)) / FWS)
obs-phrase = word *(word / "." / CFWS)
obs-phrase-list = [phrase / CFWS] *("," [phrase / CFWS])
注: obs-phrase 中的 "period" (或 "full stop") 字符 (".") 并不是本规范或任何其他规范早期版本曾允许的形式. phrase 不允许 period (或 specials 中的任何其他字符), 是因为它会带来解析困难, 难以区分 phrase 与 addr-spec 的某些部分 (见第 4.4 节). 此处出现 period 字符, 是因为当前许多消息在地址的 display-name 部分使用句点字符, 特别是用于姓名首字母缩写, 因而必须正确解释.
Bare CR 和 bare LF 在消息中有两种不同含义:
- 作为行分隔符: 在许多情况下, bare CR 或 bare LF 被错误地用来代替 CRLF 表示行分隔
- 作为控制字符: 在其他情况下, bare CR 和 bare LF 只是作为 US-ASCII 控制字符使用, 具有其传统 ASCII 含义
4.2. 过时折叠空白
在过时语法中, 允许 obs-FWS 规则的位置可以插入任意数量的 folding white space. 这会带来一行中出现两个连续 "folds" 的可能, 因而也可能导致应被展开的行没有任何可见内容.
obs-FWS = 1*WSP *(CRLF 1*WSP)
示例:
过时折叠 (允许但不建议):
Subject: This
is valid
(中间行只包含空白)
当前标准 (第 3 节):
禁止完全由空白组成的行
4.3. 过时日期和时间
过时日期格式的语法允许 date 字段中使用 2 位年份, 并允许使用本规范早期版本中采用的一组字母时区规范. 它还允许在许多令牌之间出现注释和 folding white space.
obs-day-of-week = [CFWS] day-name [CFWS]
obs-day = [CFWS] 1*2DIGIT [CFWS]
obs-year = [CFWS] 2*DIGIT [CFWS]
obs-hour = [CFWS] 2DIGIT [CFWS]
obs-minute = [CFWS] 2DIGIT [CFWS]
obs-second = [CFWS] 2DIGIT [CFWS]
obs-zone = "UT" / "GMT" / ; Universal Time
; North American UT
; offsets
"EST" / "EDT" / ; Eastern: - 5/ - 4
"CST" / "CDT" / ; Central: - 6/ - 5
"MST" / "MDT" / ; Mountain: - 7/ - 6
"PST" / "PDT" / ; Pacific: - 8/ - 7
;
%d65-73 / ; Military zones - "A"
%d75-90 / ; through "I" and "K"
%d97-105 / ; through "Z", both
%d107-122 ; upper and lower case
2 位或 3 位年份的解释:
- 00-49: 加 2000, 得到 2000-2049
- 50-99: 加 1900, 得到 1950-1999
- 3 位: 加 1900
时区缩写解释:
| 缩写 | 含义 | 等价值 |
|---|---|---|
| UT, GMT | Universal Time | +0000 |
| EST | Eastern Standard Time | -0500 |
| EDT | Eastern Daylight Time | -0400 |
| CST | Central Standard Time | -0600 |
| CDT | Central Daylight Time | -0500 |
| MST | Mountain Standard Time | -0700 |
| MDT | Mountain Daylight Time | -0600 |
| PST | Pacific Standard Time | -0800 |
| PDT | Pacific Daylight Time | -0700 |
| Military zones (A-Z) | 不可预测 | 应视为 -0000 |
注: 1 字符 military time zones 在 RFC 822 中以非标准方式定义, 因而其含义不可预测. 除非存在带外信息确认其含义, 它们应该全部视为等同于 "-0000".
4.4. 过时地址
地址处理中有四个主要差异:
-
路由: 当 mailbox 地址括在
<和>中时, 过去允许在 addr-spec 之前包含路由部分. route 只是一个以逗号分隔的域名列表, 每个域名前加 "@", 并以冒号结束该列表. -
CFWS 插入: 过去允许在 local-part 和 domain 中以句点分隔的元素之间插入 CFWS (即不使用 dot-atom). 此外, local-part 除 atom 外还允许包含 quoted-string.
-
Null 成员: mailbox-list 和 address-list 过去允许包含 "null" 成员. 也就是说, 这类列表中可能有两个或更多连续逗号且中间没有内容, 或者逗号出现在列表开头或末尾.
-
Domain literals: domain literal 中过去允许 US-ASCII 控制字符和 quoted-pair, 此处将其加入.
obs-angle-addr = [CFWS] "`<" obs-route addr-spec ">`" [CFWS]
obs-route = obs-domain-list ":"
obs-domain-list = *(CFWS / ",") "@" domain
*("," [CFWS] ["@" domain])
obs-mbox-list = *([CFWS] ",") mailbox *("," [mailbox / CFWS])
obs-addr-list = *([CFWS] ",") address *("," [address / CFWS])
obs-group-list = 1*([CFWS] ",") [CFWS]
obs-local-part = word *("." word)
obs-domain = atom *("." atom)
obs-dtext = obs-NO-WS-CTL / quoted-pair
解释消息时, route 部分应该被忽略.
路由地址示例:
过时路由格式:
`<@node1.example,@node2.example:[email protected]>`
↑ ↑
└── 路由 ─────────────┘
解释时, 忽略路由并只使用:
[email protected]
4.5. 过时头部字段
从语法上看, 过时字段语法的主要差异是它允许任何字段出现多次, 并且这些字段可以按任意顺序出现. 此外, 字段名末尾的 ":" 之前允许出现任意数量的空白.
除以下各节另有说明外, 其他字段的解释与第 3 节中对应的非过时字段解释相同.
过时字段特征:
- 允许多次出现
- 允许任意顺序
- 字段名后冒号前允许空白
示例:
过时格式 (不建议):
From : [email protected]
Date:Mon, 21 Nov 1997 09:55:06 GMT
当前标准:
From: [email protected]
Date: Mon, 21 Nov 1997 09:55:06 -0600
第 4 章摘要
关键要点
-
过时语法的双重角色:
- 不得生成
- 必须解析
-
主要差异:
- 更宽松的空白规则
- 允许特殊字符 (NUL, 控制字符)
- 2 位年份
- 字母时区
- 地址路由
- 字段重复
-
实现责任:
- 健壮处理畸形消息
- 不崩溃
- 不丢失数据
兼容性策略
Strict Generation Permissive Parsing
↓ ↓
Use Section 3 only Accept Section 3+4
New standard format Both new and old formats
测试检查清单
解析器实现应测试以下过时格式:
- 2 位年份 (例如 "21 Nov 97")
- 字母时区 (例如 "EST", "PST")
- Bare CR 或 bare LF
- 带路由的地址
- 字段名后的空白
- 完全由空白组成的折叠行
- 包含句点的 phrase
下一节: 5. 安全考虑
上一节: 3. 语法