Squid Web Cache Wiki

Squid Web Cache 文档

🔗 特性:更快的 HTTP 解析器

🔗 详细信息

避免多次解析相同的 HTTP 标头。实现增量式标头解析。

该特性以及 StringNg 预期带来的主要好处之一是提高 HTTP 解析的清晰度和性能。HTTP 解析器(截至 Squid-3.1)的实现(如下文“基线情况”所述)有点复杂,也需要进行改造。代码显示过去曾尝试过但未完成。

🔗 代码架构

解析由一个 Http::Parser 子类处理,该子类拥有一个 SBuf 缓冲区和一个虚拟的 parse 方法,该方法将缓冲区内容分割成消息段以供后续处理。

目前,MIME 标头块的解析是由 HttpMsg 对象以 char* 字符串的形式处理的,该对象依次使用 {HttpHeader 对象,这些对象位于 Parser 层级结构之外。此对象及其使用的所有逻辑都需要重构,以便在 Http::One::Parser 方法 mimeHeaders 提供的 SBuf 上操作。

当前的 HttpMsg 层级结构对象承载了两个目的;

  1. 作为通用 HTTP 消息状态存储对象
  2. 作为 HTTP 和 ICAP 响应消息解析对象

🔗 未来计划

审议中

进行中

待办事项

🔗 当前状态

在对 Http::Parser 层级结构进行初步的结构更新之后。

:information_source: 栈是异步的,现在在读取操作之后,解析检查点可以在读取后恢复。

Squid-3.6+ 中的请求解析系统 Http1::RequestParser::parse 如下所示

  1. 扫描以跳过垃圾前缀
  2. 任何停止点都是增量检查点(请求行开始或缓冲区为空时)
  3. 扫描以查找方法
  4. 方法结束时的增量检查点
  5. 扫描以查找 URI 和版本
    • 在宽松解析器中,扫描以查找 LF,然后向后工作
    • 在严格解析器中,扫描 SP 分隔符,并在 URI 后设置额外检查点
    • 请求行结束时的增量检查点
  6. char* 循环扫描标头块的结束位置 (Http1::Parser::findMimeBlock / headersEnd)
  7. MIME 标头块结束时的增量检查点
  8. strcmp / scanf / char* 循环解析 URL (urlParse)
  9. char* 循环扫描每个标头行的结束位置 (HttpHeader::parse)
  10. strcmp 扫描标头名称的 : 分隔符并生成标头对象
  11. strListGet 扫描以解析标头内容选项

响应解析系统 Squid-3.6+ 中的 Http1::ResponseParser::parse 如下所示

  1. 扫描消息版本字段
    • 接受“HTTP/1.x”和“ICY”协议版本
    • 如果需要,生成一个假的 HTTP/0.9 回复并终止解析。
  2. 版本标签结束时的增量检查点
  3. 扫描消息状态码字段
  4. 状态码结束时的增量检查点
  5. 扫描第一行的结束位置
  6. 行结束时的增量检查点
  7. char* 循环扫描标头块的结束位置 (Http1::Parser::findMimeBlock / headersEnd)
  8. MIME 标头块结束时的增量检查点
  9. char* 循环扫描标头块的结束位置 (HttpMsg::httpMsgIsolateStart)
  10. strcmp 扫描标头名称的 : 分隔符并生成标头对象 (HttpHeader::parse)
  11. strListGet 扫描以解析标头内容选项

parser-ng-icap-pt2 分支中 ICAP 响应解析系统 Adaptation::Icap::ResponseParser::parse 如下所示

:information_source: 类继承自 Http1::ResponseParser 解析器,但用 ICAP 特定的扫描替换了阶段 1 的版本扫描。

  1. 扫描消息版本字段
    • 仅接受“ICAP/1.0”协议版本
    • 版本标签结束时的增量检查点
  2. 扫描消息状态码字段
  3. 状态码结束时的增量检查点
  4. 扫描第一行的结束位置
  5. 行结束时的增量检查点
  6. char* 循环扫描标头块的结束位置 (Http1::Parser::findMimeBlock / headersEnd)
  7. MIME 标头块结束时的增量检查点
  8. char* 循环扫描标头块的结束位置 (HttpMsg::httpMsgIsolateStart)
  9. strcmp 扫描标头名称的 : 分隔符并生成标头对象 (HttpHeader::parse)
  10. strListGet 扫描以解析标头内容选项

:warning: 注意:ICAP 响应消息和有效载荷段的解析仍然使用下面记录的 HTTP 响应的旧 HttpMsg API,当有效载荷段是请求时,它使用 HttpMsg::parse 请求行代码路径。

🔗 基线情况

对 Squid-3 中的请求解析系统的初步分析显示解析器栈如下

:warning: 整个栈是异步的,在读取操作(消息未完整接收)后,会完全重置到步骤 1。

  1. 扫描以跳过垃圾前缀

  2. 解析请求行以查找 LF,以及无效的 CR 和 NIL (HttpParser::parseRequestLine)

    • 丢弃先前的解析信息!!
  3. 再次,解析请求行以查找 SP 位置 (HttpParser::parseRequestLine)

    • 丢弃先前的解析信息!!
  4. 解析请求行内的每个令牌以检查方法/URL/版本语法 (HttpParser::parseRequestLine)

    • 丢弃先前的解析信息!!
  5. char* 循环扫描标头块的结束位置 (headersEnd)

  6. sscanf 重新扫描并进行请求行和(HttpRequest::sanityCheck)的完整性检查

    • 不完整,重复步骤 2 和 3,部分重复步骤 5。
  7. strcmp 解析出请求方法、URL、版本 (HttpRequest::parseFirstLine)

    • 重复步骤 3 和 4
  8. strcmp / scanf / char* 循环解析 URL (urlParse)

  9. char* 循环扫描每个标头行的结束位置 (headersEnd)

  10. strcmp 扫描标头名称的 : 分隔符并生成标头对象

  11. strListGet 扫描以解析标头内容选项

解析序列在标头行解析(步骤 6)处连接,在完整性检查(步骤 3)处有一些交叉。响应解析如下

  1. processReplyHeader 调用 HttpMsg::parse

    • 丢弃所有先前的解析信息!!

    1. char* 循环扫描标头块的结束位置 (headersEnd)

    2. sscanf 重新扫描并进行第一行的完整性检查 (HttpReply::sanityCheck)

      • 失败时跳至下面的阶段 ii
    3. strcspn 扫描以查找标头行的结束位置

    4. char* 循环扫描标头块的结束位置 (HttpMSg::httpMsgIsolateStart)

    5. strcmp 解析出响应版本、状态消息 (HttpReply::parseFirstLine)

    6. strcspn 扫描以查找标头行的结束位置

    7. char* 循环扫描标头块的结束位置(哇,6 次!)(HttpMSg::httpMsgIsolateStart)

    8. strcmp 扫描标头名称的 : 分隔符并生成标头对象

    9. strListGet 扫描以解析标头内容选项

    ii. 检查特殊情况,缺少“HTTP”和“ICY”协议版本

    • 生成一个假的 HTTP/0.9 回复

    • 将其打包到缓冲区

    • 解析假的回复!!

      • 丢弃所有先前的解析信息!!

      • 重复阶段 i 的所有内容

    iii. char* 循环扫描标头块的结束位置 (headersEnd)

    • 因为我们在阶段 i 中扫描的次数似乎不够

待办事项:记录 ICAP 响应解析序列。尽管有明显努力使其简单化,但由于需要运行上述整个响应和请求解析链来自动检测哪个将成功,因此比 HTTP 响应解析更糟糕。

分类: WantedFeature

导航:站点搜索站点页面类别🔼 向上