摘要

  • 普通 Date 记录创作者何时认为消息已经完成、可以提交,并不记录它实际何时开始传输。
  • Netnews 中继必须限制重复历史的保存规模,并拒绝过旧文章;若拿写作时间执行这项任务,刚刚入网的延迟稿也可能被误判。
  • Injection-Date 增加了入网时钟,却不重写原来的 Date。它改善了接纳依据,但没有证明作者身份、时钟准确性或每台服务器的到达时间。

一份周五才发出的周一稿

设想作者在没有网络时写完文章。周一,软件写入 Date;周五,设备重新连接,posting agent 才把文章交给新闻服务器。

从作者一侧看,周一完全正确,那是文字定稿的时刻。可是维护有限历史记录的中继看到旧日期,会想到另一种风险:这也许是已经清除 Message-ID 记录之后又绕回来的旧文章。服务器若无法拒绝这种回流,重复内容会不断消耗存储与传播能力。

同一个字段被迫承担相反要求。保留周一,旧实现可能把新入网文章当成陈旧流量;改成周五,系统就抹掉真实写作历史。看似只能在传播成功和时间诚实之间二选一。

Injection-Date 的解法不是选一个,而是保留第一个时间,再给入网边界增加自己的观察。

Date 原本是一条不随传播改写的线

1987 年的 RFC 1036 把 Date——早先名为 Posted——描述为消息最初发布到网络的日期,并要求它在传播中保持不变。这个不变量很重要:每一跳都不能把文章的开端悄悄改成自己的接收时刻。

后来的 RFC 5322 更准确地界定了创作者的时钟。origination date 指创作者表示消息已经完成、准备进入投递系统的时间,不是实际运输发生的时间。规范特意举出便携电脑离线排队的例子:日期属于用户排队之时,不属于以后联网之时。

这一定义保护了文章自身的历史,也说明它为何不适合作为入网证据。数值可以在长时间等待前生成,依赖创作者设备的时钟,也可能出错或被故意伪造。即使完全诚实,它回答的仍不是中继需要回答的问题。

去重把时间变成了内存边界

Netnews 依靠相互独立的 relaying agent 与 serving agent 扩散文章。服务器不得反复接纳同一篇文章。RFC 5537 因而要求它们维护已经见过的文章历史,并拒绝重复提交。

Message-ID 提供比较键,但永久保存每一个标识会让数据库无限增长。规范允许设置 cutoff:早于保留区间的文章可以被拒绝,相应的旧历史项也能删除,因为它若再次出现,会先被日期规则挡下。RFC 5537 把不少于七天称为 Usenet 的惯例,同时警告区间若短于正常传播时间,服务器可能拒绝一篇从未见过的文章。

日期本身并不证明重复。它只帮助运营者决定去重证据要留多久。短区间更快释放资源,却把延迟传播推向误拒;长区间保护慢路径,却增加存储和查询成本。

当唯一时钟是写作时间,这个权衡便混入了不属于网络的等待。认真保留旧稿日期的作者,看起来会和历史记录消失后重新循环的旧文章一样。

第二个时钟只拥有更窄的权力

RFC 5536 把 Injection-Date 定义为文章注入网络的日期与时间。目的非常具体:服务器判断 stale article 时,应优先使用新闻服务器在 injection 时添加的时间,而不是 user agent 在写作时添加的时间。

规范要求注入时写入这个字段,但为了兼容旧软件,也要求接收缺少该字段的文章。没有它时,RFC 5537 才回退使用 Date。迁移因此允许新旧系统继续互通,却没有假装所有节点同时获得了新语义。

更关键的是,增加第二个字段不赋予修改第一个字段的权力。RFC 5536 明确要求添加 Injection-Date 时不得改变已有 Date。它还提醒,不同 agent 的时钟未必同步,所以入网时间的数值甚至可能早于写作时间。字段先后不能证明时钟一致。

这个标准字段取代了当时已被使用却没有文档约束的 NNTP-Posting-Date,后者被标为 deprecated。登记统一了名称和语义边界,却没有发明全球统一时钟。

第二日期怎样改变历史保留

RFC 5537 在常见历史优化中定义“文章日期”:有 Injection-Date 就用它,没有才用 Date。中继和服务端检查它是否过度超前;采用 cutoff 策略时,也用它决定文章是否落在保留区间之外。

另一种办法按本服务器第一次见到文章的时间淘汰历史项。按照规范给出的规则,这种保留期至少要比 cutoff 多 24 小时,用于容纳允许的未来日期误差。至此已经出现第三种视角:文章何时写完、何时首次入网,以及何时抵达这台服务器。

RFC 3977 把本地视角写得更清楚。NNTP 服务器保存 arrival timestamp,并按到达顺序分配本地文章编号。这个时间属于一台服务器,不替代共享的 injection 时间;后者也不替代写作时间。

三个时钟并非重复:

  • Date 说明创作者何时声明文章可提交;
  • Injection-Date 说明它何时按规则进入 Netnews;
  • arrival time 说明某台服务器何时收到它,并支撑本地排序。

若把它们压成一个数,本地延迟会被误写成作者行为,作者的离线等待也会被误写成网络回流。

多入口仍然只能有一段历史

Netnews 还允许出于冗余或网络分离,把同一篇文章交给多个 injection point。目标不是制造多篇文章,而是让路径会合时依靠 Message-ID 去重,只接纳一次。

因此 RFC 5537 要求多点注入的各份 proto-article 使用完全相同的 Message-ID、Date 与 Injection-Date。若把已注入的文章重新整理后交给另一网络,这三个字段仍须原样保留。第二日期不能在每个入口刷新,否则同一篇文章会一次次显得刚刚诞生。

这条规则揭示了字段的范围。它虽由入网边界产生,却不是后来每个 gateway 都能随意改成“现在”的装饰。多入口场景中,它成为让几条进入路径合并而不重置年龄的稳定证据。

兼容性没有立即消除旧歧义

新字段无法让旧做法瞬间消失。RFC 5537 说明,较早实现会忽略 Injection-Date,仍拿 Date 执行陈旧检查。写作日期明显偏旧的文章,即使携带正确入网字段,也可能在这些节点传播不佳。

当 Message-ID 和 Date 已经存在时,posting agent 在若干情况下应在提交前加上 Injection-Date:写完超过一天时应该添加,多点注入时必须添加。injecting agent 负责检查过早、过晚的值,并在协议条件要求时写入当前入网时间。

把检查放在靠近作者的一侧,能让拒绝得到更清楚的解释,却不能强迫所有下游理解新字段。向后兼容通过并存新旧证据保存互通,也保留了一段相同文章可能被不同节点作出不同判断的时期。

第二日期不是认证凭证

Injection-Date 是入网边界 agent 的时间声明,不是加密签名,不证明作者,也不保证时钟准确。RFC 5536 已预见时钟不一致。它也不说明每台服务器何时收到文章、moderator 何时批准、读者何时看到,或本地保留策略何时删除文章。

当前 IANA 消息头字段登记表 把 Injection-Date 列为 Netnews 标准字段,并指向 RFC 5536。登记给实现者一个稳定名称,不替某个具体数值背书,也不证明所有系统都已部署。

真正的历史成就更窄,也更耐久:Netnews 认识到,诚实的写作历史和可执行的接纳判断不必争夺一个字段。创作者保留第一日期,网络增加第二日期,后续每台服务器仍保存自己的到达证据。可靠性来自让每个时钟只支持它真正能支持的决定。