Squid Web Cache Wiki

Squid Web Cache 文档

🔗 HTTP 标头

文件

HttpHeader 类封装了 HTTP 标头操作的方法和数据。 HttpHeader 可以被视为一个 HTTP 标头字段的集合,并提供诸如添加、删除和查找等常见操作。 与 ASCII “字符串”表示相比,HttpHeader 在执行这些操作时无需从头开始重建底层结构或搜索整个“字符串”。

🔗 一般说明

HttpHeader 是 HTTP 标头字段的集合(或数组)。 标头字段由 HttpHeaderEntry 对象表示。 HttpHeaderEntry 是一个(id、name、value)三元组。 对于“已知”的标头字段,如“Connection”或“Content-Length”,定义了有意义的“Id”。 当 Squid 无法识别某个字段时,它会使用特殊的“id”HDR_OTHER。 标识符是通过将相应的 HTTP 标头字段名称大写并用下划线 ('_') 替换连字符 ('-') 来形成的。

HttpHeader 的大多数操作都需要一个“已知”的 id 作为参数。 这种限制的理由是 Squid 程序员应该只操作“已知”字段。 如果要向标头处理添加新字段,则必须为其分配一个 id。

🔗 生命周期

HttpHeader 遵循对象初始化和清理的通用模式。

    /* declare */
    HttpHeader hdr;

    /* initialize (as an HTTP Request header) */
    httpHeaderInit(&hdr, hoRequest);

    /* do something */
    ...

    /* cleanup */
    httpHeaderClean(&hdr);

在使用之前,必须初始化 HttpHeader。 程序员必须指定标头属于请求还是回复消息。“所有权”信息主要用于统计目的。

初始化后,HttpHeader 对象**必须**最终被清理。 否则将导致内存泄漏。

请注意,没有用于“创建”或“销毁”“动态”HttpHeader 对象的函数。 标头似乎总是作为另一个对象的一部分或作为临时变量存储。 因此,不需要动态分配标头。

🔗 标头操作

对 HTTP 标头的最常见操作是测试特定标头字段(httpHeaderHas())、提取字段值(httpHeaderGet*())和添加新字段(httpHeaderPut*())。

httpHeaderHas(hdr, id) 如果存在至少一个由“id”指定的标头字段,则返回 true。 请注意,禁止使用 HDR_OTHER 作为 id。 通常没有理由知道标头中是否存在“其他”标头字段。

httpHeaderGet<Type>(hdr, id) 返回指定标头字段的值。“Type”必须与标头字段类型匹配。 如果标头不存在,则返回“null”值。“Null”值取决于字段类型。

当标头中存在多个具有相同 id 的标头字段时,必须特别注意。 如果 HTTP 协议每个标头只允许一个指定字段(例如,“Content-Length”),httpHeaderGet<Type>() 将返回其中一个字段值(半随机选择)。 如果 HTTP 协议允许多个值(例如,“Accept”),则会返回一个“字符串列表”。

禁止在只允许一个值的情况下要求一个值列表,反之亦然。 这种限制可以防止程序员在忽略其他有效值的情况下处理标头字段的一个值。

httpHeaderPut<Type>(hdr, id, value) 将添加一个具有指定字段名称(基于“id”)和字段值的标头字段。 新添加字段在标头数组中的位置未定义,但保证在所有具有相同“id”的字段之后(如果存在)。 请注意,旧的具有相同 id 的标头字段(如果存在)不会以任何方式被修改。

使用 httpHeaderPut() 方法之一进行放置的值将被转换为并存储为 String 对象。

示例

    /* add our own Age field if none was added before */
    int age = ...
    if (!httpHeaderHas(hdr, HDR_AGE))
        httpHeaderPutInt(hdr, HDR_AGE, age);

有两种方法可以从标头中删除字段。 要删除一个“已知”字段(id 不是 HDR_OTHER 的字段),请使用 httpHeaderDelById() 函数。 有时,使用 httpHeaderDelByName() 方法删除所有具有给定名称(“已知”或否)的字段会很方便。 两种方法都会删除**所有**指定的字段。

httpHeaderGetEntry(hdr, pos) 函数可用于迭代给定标头中的所有字段。 迭代由 pos 参数控制。 因此,可以同时对一个 hdr 进行多次迭代。 在迭代进行中删除/添加字段到/从 hdr 也是安全的。

    /* delete all fields with a given name */
    HttpHeaderPos pos = HttpHeaderInitPos;
    HttpHeaderEntry *e;
    while ((e = httpHeaderGetEntry(hdr, &amp;pos))) {
            if (!strCaseCmp(e->name, name))
                    ... /* delete entry */
    }

请注意,httpHeaderGetEntry() 是一个低级函数,如果存在高级替代方案,则不应使用它。 例如,要删除具有给定名称的条目,请使用 httpHeaderDelByName() 函数而不是上面的循环。

🔗 I/O 和标头

要将标头存储到文件或套接字中,请使用 httpHeaderPackInto() 方法和相应的“Packer”进行打包。 请注意,httpHeaderPackInto 只会打包标头字段; 请求行和状态行不会被预置,CRLF 也不会被追加。 请记住,根据 HTTP 协议的定义,这两者都不是 HTTP 消息标头的一部分。

🔗 添加新的标头字段 ID

添加新 ID 很简单。 首先,将新的 HDR_ 条目添加到 enums.h 中的 http_hdr_type 枚举中。 然后,在 HttpHeader.c 中的 HeadersAttrs 数组中描述新的标头字段属性。 最后一个属性指定字段类型。 支持五种类型:整数(ftInt)、字符串(ftStr)、RFC 1123 格式的日期(ftDate_1123)、缓存控制字段(ftPCc)、范围字段(ftPRange)和内容范围字段(ftPContRange)。 Squid 使用类型信息将字段的内部二进制表示转换为其字符串表示(httpHeaderPut 函数)反之亦然(httpHeaderGet 函数)。

最后,将新的 id 添加到以下数组之一:GeneralHeadersArrEntityHeadersArrReplyHeadersArrRequestHeadersArr。 使用 HTTP 规范来确定适用的数组。 如果您的标头字段是“扩展标头”,则它应该放在 ReplyHeadersArr 和/或 RequestHeadersArr 中。 您也可以将 EntityHeadersArr 用于“扩展标头”,这些标头可用于回复和请求。 非“扩展标头”的标头字段必须放在上述数组之一且仅一个中。

此外,如果新字段是“列表”标头,请将其添加到 ListHeadersArr 数组。 “列表”字段标头是指使用 HTTP 规范中描述的“\&num;”BNF 构造定义(或可以定义)的字段。 本质上,一个字段在一个标头中可能具有多个有效字段值,就是一个“列表”字段。

在大多数情况下,如果您忘记将新的字段 ID 包含在必需的数组之一中,您将收到运行时断言。 然而,对于很少使用的字段,断言可能需要很长时间才能触发。

Squid 支持的字段数量几乎没有限制。 如果当前的掩码大小无法容纳所有 ID(如果发生这种情况,您将收到断言),只需在 typedefs.h 中将 HttpHeaderMask 类型扩大即可。

🔗 关于效率的说明

httpHeaderHas() 是一个非常便宜(快速)的操作,通过位掩码查找实现。

添加新字段在需要复杂转换为字符串时会有些昂贵。

删除现有字段需要扫描所有条目并比较它们的“id”(较快)或“名称”(较慢)与指定的删除项。

大多数操作比它们的“ASCII 字符串”等效操作要快。

类别:内部

导航:网站搜索网站页面分类🔼 向上