参考自 docs.google.com/document/d/… —— Adam Rice ricea@chromium.org 关于 WebSocketBasicHandshakeStream 的设计备忘录
目标
一句话描述清楚要做什么,是为了什么,可以分点陈述
尽可能合理地将处理 WebSocket HTTP-Upgrade 握手的代码和 WebSocket 协议的其余部分分开。
通过最小的改动重用 Chrome 现有的 HTTP 握手实现。
背景
讲清楚做这件事的详细背景
WebSocket 连接由两个不同的阶段组成:握手(使用 HTTP 语义并借助 HTTP 机制进行身份验证和 cookie 使用)和 WebSocket协议本身(作为 TCP/IP 之上的薄层)二进制或文本消息的双向流。
Chrome 中 WebSocket 的实现是基于 Blink 内部完整协议的实现,浏览器进程向该协议公开类似于低阶 TCP/IP socket 的内容。虽然原理上很简单,但在浏览器进程中添加 cookie 和身份验证信息的需要会导致巨大的复杂性。通过这种实现来实现多路复用是一项艰巨的挑战。
为了解决这个问题,2012 年开始了新的实现,浏览器为渲染进程提供了一个高阶接口,类似于 Chrome 中其他网络协议的实现方式。
这个新设计的一部分是 net::WebSocketStream 接口,最初设想该接口用于处理 WebSocket 协议的两个阶段。
挑战
简明扼要写清难点
为了复用现有握手的 HTTP 代码,需要提供大量 net::HttpBasicStream 的接口和功能。这不仅是一个 WebSocket 实现的其余部分不关心的大型 API 内容,而且一旦握手完成,这些都会变得完全无关(不再需要)。
拟定设计
关于技术设计的描述,可以分概要设计和详细设计,最好有图示进行辅助描述
高阶概述
我们建议引入一个新的具体类 net::WebSocketBasicHandshakeStream。
这个类创建的对象用于执行握手,然后当握手完成时,将创建 WebSocketStream 的实现来接管 socket 的所有权。WebSocketStream 中当前存在的 HTTP 相关接口可以被移除。
这种职责划分将需要对类层次结构进行更改。
所有这些类都在 net 命名空间中。灰色的类是接口,蓝色的类是具体实现。
使 WebSocketStreamBase 继承 net::HttpStreamBase 意味着它可以由 net::HttpNetworkTransaction 类保持原样。这给 WebSocketStreamBase 留下了一个奇怪的名字。我们将其重命名为 WebSocketHandshakeStreamBase。
对已有类的改动
讲清楚对于已有模块或组件的改动,这部分是对于潜在影响范围的声明
SendHandshakeRequest 和 ReadHandshakeResponse 方法将从 WebSocketStream 和 WebSocketBasicStream 中移除。sub_protocol_、extensions_ 和 http_read_buffer_ 成员变量的初始化将被添加到 WebSocketBasicStream 构造函数中,因为对象现在不会被构造,直到这些可用。
WebSocketStreamBase 将成为 HttpStreamBase 的子类,并更名为 WebSocketHandshakeStreamBase。可能需要对 WebSocketHandshakeStreamBase::Factory 接口进行一些更改。AsWebSocketStream() 虚拟方法将被删除。
net::UrlRequestHttpJob 需要更新以接受除了http 和 https 之外的 ws 和 wss scheme。只有在 URLRequest 对象上提供 WebSocketHandshakeStreamBase::Factory 对象时,这些才会起作用。在 URL 栏上输入带有 ws 或 wss scheme 的 URL 将给出一个不允许的协议错误(截至目前,它们仍被视为无法识别的协议)。
当 url scheme 是 ws 或 wss 时,net::HttpNetworkTransaction::DoCreateStream() 将被修改为调用 session_->websocket_stream_factory() 而不是 http_stream_factory() 。它需要实现 OnWebSocketStreamReady() 方法,并将结果流存储到它的 stream_ 成员变量中。需要一个 WebSocketHandshakeStreamBase::Factory 对象来创建 WebSocketHandshakeStreamBase 对象。它携带专门用于此连接的信息,比如子协议列表。一个额外的方法 SetWebSocketStreamFactory() 将被添加到 HttpTransaction 和 HttpNetworkTransaction。
URLRequest 对象可以通过 base::SupportsUserData 基础类存储任意数据。URLRequestHttpJob 将从这个存储中检索 WebSocketHandshakeStreamBase::Factory 对象,并将其设置在 HttpNetworkTransaction 对象上。
新增类
用于实现功能而新增的核心模块
WebSocketBasicHandshakeStream 与 HttpBasicStream 非常类似,除了
- 对 WebSocket 相关 header 特殊处理
- 将其连接和剩余缓冲数据传输到新的 WebSockeBasicStream 的能力
我们期望将 WebSocketBasicHandshakeStream 和 HttpBasicStream 中的公共成员变量和代码提取到一个新类中,暂时称为 HttpBasicState。HttpBasicStream 将把它的大部分功能委托给 HttpBasicState。
连接建立流程
核心流程图示或描述
代码位置
声明改动的代码位置
- net/websockets
- net/url_request
- net/http
讨论
一些技术调研或评审阶段的讨论,可能包含待解决问题
SPDY / HTTP/2.0 传输
可能需要一个 WebSocketSpdyHandshakeStream 作为 SPDY 的 WebSocketBasicHandshakeStream 平替。目前还不完全清楚这将如何发挥作用。
修订记录
文档主要变更的记录
- 2013-09-13:初稿
- 2013-09-20:增加内容建立流程
- 2013-11-01:次版本更新,首次公开版本
- 2013-11-05:更新“连接建立流程”,以反映 WebSocketBasicStream 现在由 WebSocketHandshakeBasicStream::Upgrade() 创建的事实
- 2013-11-07:记录 WebSocketStreamBase 在继承层次结构中的重命名。修复 “连接建立流程图” 中一些错误