[/
    Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)

    Distributed under the Boost Software License, Version 1.0. (See accompanying
    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

    Official repository: https://github.com/boostorg/beast
]

[section 分块传输编码]

对于无法预先确定大小的消息有效载荷，HTTP 版本 1.1 定义了 [@https://tools.ietf.org/html/rfc7230#section-4.1 分块] 传输编码。该编码由零个或多个 [@https://tools.ietf.org/html/rfc7230#section-4.1 分块体] 组成，后跟一个 [@https://tools.ietf.org/html/rfc7230#section-4.1 最后分块]。每个分块体可以包含可选的、由应用程序定义的、与连接相关的 [@https://tools.ietf.org/html/rfc7230#section-4.1.1 分块扩展]。最后分块可以包含一个称为 [@https://tools.ietf.org/html/rfc7230#section-4.1.2 分块尾部] 的部分，其中包含额外的 HTTP 字段值。这些字段值在头部中通过 [@https://tools.ietf.org/html/rfc7230#section-4.4 Trailer] 字段值以逗号分隔的字段名列表进行“承诺”。客户端通过在 [@https://tools.ietf.org/html/rfc7230#section-4.3 TE] 字段值中包含“trailers”标记来表示愿意接受尾部字段。

[heading 序列化分块数据]

当消息中的 [link beast.ref.boost__beast__http__message.chunked.overload1 `message::chunked`] 返回 `true` 时，__serializer__ 会自动应用分块传输编码。序列化器发出的分块之间的边界由实现定义，分块扩展和尾部字段会被省略。如果应用程序需要对分块边界、扩展和尾部字段进行精确控制，可以使用一组辅助类来手动发送采用分块编码的消息有效载荷。

使用这些辅助类时，首先通过标准接口序列化消息的头部部分，然后准备缓冲区、分块扩展以及所需的尾部字段，再配合以下辅助类进行使用：

[table 分块辅助类
[[名称][描述]]
[
    [[link beast.ref.boost__beast__http__chunk_body `chunk_body`]]
    [一个表示完整分块体的缓冲区序列。]
][
    [[link beast.ref.boost__beast__http__chunk_crlf `chunk_crlf`]]
    [一个表示 CRLF（`"\r\n"`）分隔符的缓冲区序列。该辅助类用于调用方希望将分块体分成两次或多次独立流操作发送的场景。]
][
    [
        [link beast.ref.boost__beast__http__chunk_extensions `chunk_extensions`]


        [link beast.ref.boost__beast__http__basic_chunk_extensions `basic_chunk_extensions`]
    ]
    [这是一个简单的、可分配内存的容器，能够让调用方轻松构建一组分块扩展。]
][
    [[link beast.ref.boost__beast__http__chunk_header `chunk_header`]]
    [一个表示十六进制编码的分块大小的缓冲区序列，并附带一组可选的分块扩展（含分块体前的终止 CRLF（`"\r\n"`）分隔符）。该辅助类用于调用方希望将分块体分成两次或多次独立流操作发送的场景。]
][
    [[link beast.ref.boost__beast__http__chunk_last `chunk_last`]]
    [一个表示最后分块的缓冲区序列。最后分块用于标识分块消息有效载荷的结束，并可以包含可选的尾部字段。]
][
    [
        [link beast.ref.boost__beast__http__make_chunk `make_chunk`]

        [link beast.ref.boost__beast__http__make_chunk_last `make_chunk_last`]
    ]
    [这些辅助函数用于在调用点直接构造分块或最后分块。]
]]

首先声明一个函数，用于返回下一个作为分块体的缓冲区序列，以此演示这些对象的用法：

[http_snippet_17]

本示例演示如何手动发送完整的分块消息有效载荷，过程中不发送分块扩展或尾部字段：

[http_snippet_18]

以下代码发送额外的分块，并使用辅助容器设置分块扩展。该容器在必要时会自动对序列化输出中的值进行引号处理：

[http_snippet_19]

调用方可以通过传递一个非拥有字符串来接管扩展缓冲区的生成和管理。需要注意的是，这要求字符串内容符合分块扩展的正确语法，包括对包含空格的字段值使用必要的双引号：

[http_snippet_20]

以下代码示例发送一个分块响应，该响应承诺携带两个尾部字段，并在最后分块中发送这些字段。实现会使用默认分配器或传入的分配器分配内存，用于保存序列化尾部所需的状态信息：

[http_snippet_21]

使用自定义分配器序列化最后分块：

[http_snippet_22]

或者，调用方也可以传入一个非拥有字符串，自行负责序列化尾部字段的生成及其生命周期管理：

[http_snippet_23]

若需要最高级别的控制，调用方可以手动组合分块：先发送一个带有正确分块体大小的头部，然后通过多次调用流写入函数来发送分块体。此时，调用方还需负责发送终止的 CRLF（`"\r\n"`）：

[http_snippet_24]

[heading 解析分块]

当分块传输编码位于编码列表的末尾时，__parser__ 会自动将其移除。但在此过程中，解析器会丢弃分块扩展，也不提供确定分块之间边界的方法。对于需要访问分块扩展或读取完整分块的高级应用，可以使用 __parser__ 提供的回调接口：

[table 分块解析回调接口
[[名称][描述]]
[
    [[link beast.ref.boost__beast__http__parser.on_chunk_header `on_chunk_header`]]
    [设置一个回调函数，在每次解析分块头部时调用。

该回调函数会对消息体中的每个分块调用一次，同时对最后一个分块也调用一次。调用时机在分块头部可用之后、分块体数据开始解析之前。

分块扩展以原始格式提供，且已经过验证。可以使用 [link beast.ref.boost__beast__http__basic_chunk_extensions.parse `chunk_extensions::parse`] 将扩展解析为结构化容器，便于访问。该实现通过类型擦除处理回调，且无需动态分配内存，因此回调对象通过非常量引用传递。

回调函数对象的调用签名等效于：]
][
    [[link beast.ref.boost__beast__http__parser.on_chunk_body `on_chunk_body`]]
    [设置一个回调函数，在分块体数据到达时调用。

该回调函数会被调用一次或多次，用于提供当前分块体对应的缓冲区数据。回调函数会收到当前分块体中剩余的字节数（包含当前缓冲区中的字节）。

回调函数必须返回实际消耗的字节数。未被消耗的字节会在后续回调调用中再次提供。该实现通过类型擦除处理回调，且无需动态分配内存，因此回调对象通过非常量引用传递。

回调函数对象的调用签名等效于：]
]]

本示例将从流中读取消息头部，然后手动读取每个分块。示例能够识别分块边界，并在分块到达时输出其内容。所有分块扩展都会被打印，每个扩展单独占一行。最后，还会打印头部中承诺的尾部字段。

[example_chunk_parsing]

给定左侧的 HTTP 响应作为输入，上述函数的输出结果如右侧所示：

[table 分块解析示例输出
[[输入][输出]]
[
    [
    ```
    HTTP/1.1 200 OK\r\n
    Server: test\r\n
    Trailer: Expires, Content-MD5\r\n
    Transfer-Encoding: chunked\r\n
    \r\n
    5\r\n
    First\r\n
    d;quality=1.0\r\n
    Hello, world!\r\n
    e;file=abc.txt;quality=0.7\r\n
    The Next Chunk\r\n
    8;last\r\n
    Last one\r\n
    0\r\n
    Expires: never\r\n
    Content-MD5: f4a5c16584f03d90\r\n
    \r\n
    ```
    ]
    [
    ```
分块体：First
扩展：quality = 1.0
分块体：Hello, world!
扩展：file = abc.txt
扩展：quality = 0.7
分块体：The Next Chunk
扩展：last
分块体：Last one
Expires: never
Content-MD5: f4a5c16584f03d90
    ```
    ]
]]

[endsect]
