• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<html>
2<head>
3<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
4<title>Chunked Encoding</title>
5<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css">
6<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
7<link rel="home" href="../../index.html" title="Chapter 1. Boost.Beast">
8<link rel="up" href="../using_http.html" title="HTTP">
9<link rel="prev" href="buffer_oriented_parsing.html" title="Buffer-Oriented Parsing">
10<link rel="next" href="custom_body_types.html" title="Custom Body Types">
11</head>
12<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
13<table cellpadding="2" width="100%"><tr>
14<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td>
15<td align="center"><a href="../../../../../../index.html">Home</a></td>
16<td align="center"><a href="../../../../../../libs/libraries.htm">Libraries</a></td>
17<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
18<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
19<td align="center"><a href="../../../../../../more/index.htm">More</a></td>
20</tr></table>
21<hr>
22<div class="spirit-nav">
23<a accesskey="p" href="buffer_oriented_parsing.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../using_http.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="custom_body_types.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
24</div>
25<div class="section">
26<div class="titlepage"><div><div><h3 class="title">
27<a name="beast.using_http.chunked_encoding"></a><a class="link" href="chunked_encoding.html" title="Chunked Encoding">Chunked Encoding</a>
28</h3></div></div></div>
29<p>
30        For message payloads whose size is not known ahead of time, HTTP version
31        1.1 defines the <a href="https://tools.ietf.org/html/rfc7230#section-4.1" target="_top"><span class="emphasis"><em>chunked</em></span></a>
32        transfer coding. This coding consists of zero or more <a href="https://tools.ietf.org/html/rfc7230#section-4.1" target="_top"><span class="emphasis"><em>chunked
33        bodies</em></span></a>, followed by a <a href="https://tools.ietf.org/html/rfc7230#section-4.1" target="_top"><span class="emphasis"><em>last
34        chunk</em></span></a>. Each chunked body may contain optional application-defined,
35        connection-specific <a href="https://tools.ietf.org/html/rfc7230#section-4.1.1" target="_top"><span class="emphasis"><em>chunk-extensions</em></span></a>.
36        The last chunk may contain additional HTTP field values in a section of the
37        last chunk called a <a href="https://tools.ietf.org/html/rfc7230#section-4.1.2" target="_top"><span class="emphasis"><em>chunk-trailer</em></span></a>.
38        The field values are "promised" in the header as a comma delimited
39        list of field names in the <a href="https://tools.ietf.org/html/rfc7230#section-4.4" target="_top"><span class="bold"><strong>Trailer</strong></span></a> field value. Clients indicate their
40        willingness to accept trailers by including the "trailers" token
41        in the <a href="https://tools.ietf.org/html/rfc7230#section-4.3" target="_top"><span class="bold"><strong>TE</strong></span></a> field value.
42      </p>
43<h5>
44<a name="beast.using_http.chunked_encoding.h0"></a>
45        <span class="phrase"><a name="beast.using_http.chunked_encoding.serializing_chunks"></a></span><a class="link" href="chunked_encoding.html#beast.using_http.chunked_encoding.serializing_chunks">Serializing
46        Chunks</a>
47      </h5>
48<p>
49        The <a class="link" href="../ref/boost__beast__http__serializer.html" title="http::serializer"><code class="computeroutput"><span class="identifier">serializer</span></code></a> automatically applies
50        the chunked transfer encoding when a message returns <code class="computeroutput"><span class="keyword">true</span></code>
51        from <a class="link" href="../ref/boost__beast__http__message/chunked/overload1.html" title="http::message::chunked (1 of 2 overloads)"><code class="computeroutput"><span class="identifier">message</span><span class="special">::</span><span class="identifier">chunked</span></code></a>. The boundaries between
52        chunks emitted by the serializer are implementation defined. Chunk extensions
53        and trailers are omitted. Applications which need precise control over the
54        chunk boundaries, extensions, and trailers may use a set of helper classes
55        which enable manual emission of message payloads using chunk encoding.
56      </p>
57<p>
58        To use these helper classes, first serialize the header portion of the message
59        using the standard interface. Then prepare the buffers, chunk extensions,
60        and desired trailers, and use them with these helpers:
61      </p>
62<div class="table">
63<a name="beast.using_http.chunked_encoding.chunking_helpers"></a><p class="title"><b>Table 1.25. Chunking Helpers</b></p>
64<div class="table-contents"><table class="table" summary="Chunking Helpers">
65<colgroup>
66<col>
67<col>
68</colgroup>
69<thead><tr>
70<th>
71                <p>
72                  Name
73                </p>
74              </th>
75<th>
76                <p>
77                  Description
78                </p>
79              </th>
80</tr></thead>
81<tbody>
82<tr>
83<td>
84                <p>
85                  <a class="link" href="../ref/boost__beast__http__chunk_body.html" title="http::chunk_body"><code class="computeroutput"><span class="identifier">chunk_body</span></code></a>
86                </p>
87              </td>
88<td>
89                <p>
90                  A buffer sequence representing a complete chunk body.
91                </p>
92              </td>
93</tr>
94<tr>
95<td>
96                <p>
97                  <a class="link" href="../ref/boost__beast__http__chunk_crlf.html" title="http::chunk_crlf"><code class="computeroutput"><span class="identifier">chunk_crlf</span></code></a>
98                </p>
99              </td>
100<td>
101                <p>
102                  A buffer sequence representing the CRLF (<code class="computeroutput"><span class="string">"\r\n"</span></code>)
103                  delimiter. This class is used when the caller desires to emit the
104                  chunk body in two or more individual stream operations.
105                </p>
106              </td>
107</tr>
108<tr>
109<td>
110                <p>
111                  <a class="link" href="../ref/boost__beast__http__chunk_extensions.html" title="http::chunk_extensions"><code class="computeroutput"><span class="identifier">chunk_extensions</span></code></a>
112                </p>
113                <p>
114                  <a class="link" href="../ref/boost__beast__http__basic_chunk_extensions.html" title="http::basic_chunk_extensions"><code class="computeroutput"><span class="identifier">basic_chunk_extensions</span></code></a>
115                </p>
116              </td>
117<td>
118                <p>
119                  This is a simple, allocating container which lets callers easily
120                  build up a set of chunk extensions.
121                </p>
122              </td>
123</tr>
124<tr>
125<td>
126                <p>
127                  <a class="link" href="../ref/boost__beast__http__chunk_header.html" title="http::chunk_header"><code class="computeroutput"><span class="identifier">chunk_header</span></code></a>
128                </p>
129              </td>
130<td>
131                <p>
132                  A buffer sequence representing a hex-encoded chunk size, followed
133                  by an optional set of chunk extensions, including the terminating
134                  CRLF (<code class="computeroutput"><span class="string">"\r\n"</span></code>)
135                  delimiter which precedes the chunk body. This class is used when
136                  the caller desires to emit the chunk body in two or more individual
137                  stream operations.
138                </p>
139              </td>
140</tr>
141<tr>
142<td>
143                <p>
144                  <a class="link" href="../ref/boost__beast__http__chunk_last.html" title="http::chunk_last"><code class="computeroutput"><span class="identifier">chunk_last</span></code></a>
145                </p>
146              </td>
147<td>
148                <p>
149                  A buffer sequence representing a last chunk. The last chunk indicates
150                  the end of the chunked message payload, and may contain optional
151                  trailer fields.
152                </p>
153              </td>
154</tr>
155<tr>
156<td>
157                <p>
158                  <a class="link" href="../ref/boost__beast__http__make_chunk.html" title="http::make_chunk"><code class="computeroutput"><span class="identifier">make_chunk</span></code></a>
159                </p>
160                <p>
161                  <a class="link" href="../ref/boost__beast__http__make_chunk_last.html" title="http::make_chunk_last"><code class="computeroutput"><span class="identifier">make_chunk_last</span></code></a>
162                </p>
163              </td>
164<td>
165                <p>
166                  These helper functions are used to construct a chunk or last chunk
167                  directly at call sites.
168                </p>
169              </td>
170</tr>
171</tbody>
172</table></div>
173</div>
174<br class="table-break"><p>
175        We demonstrate the use of these objects first by declaring a function which
176        returns the next buffer sequence to use as a chunk body:
177      </p>
178<pre class="programlisting"><span class="comment">// This function returns the buffer containing the next chunk body</span>
179<span class="identifier">net</span><span class="special">::</span><span class="identifier">const_buffer</span> <span class="identifier">get_next_chunk_body</span><span class="special">();</span>
180</pre>
181<p>
182        This example demonstrates sending a complete chunked message payload manually.
183        No chunk extensions or trailers are emitted:
184      </p>
185<pre class="programlisting"><span class="comment">// Prepare an HTTP/1.1 response with a chunked body</span>
186<span class="identifier">response</span><span class="special">&lt;</span><span class="identifier">empty_body</span><span class="special">&gt;</span> <span class="identifier">res</span><span class="special">{</span><span class="identifier">status</span><span class="special">::</span><span class="identifier">ok</span><span class="special">,</span> <span class="number">11</span><span class="special">};</span>
187<span class="identifier">res</span><span class="special">.</span><span class="identifier">set</span><span class="special">(</span><span class="identifier">field</span><span class="special">::</span><span class="identifier">server</span><span class="special">,</span> <span class="string">"Beast"</span><span class="special">);</span>
188
189<span class="comment">// Set Transfer-Encoding to "chunked".</span>
190<span class="comment">// If a Content-Length was present, it is removed.</span>
191<span class="identifier">res</span><span class="special">.</span><span class="identifier">chunked</span><span class="special">(</span><span class="keyword">true</span><span class="special">);</span>
192
193<span class="comment">// Set up the serializer</span>
194<span class="identifier">response_serializer</span><span class="special">&lt;</span><span class="identifier">empty_body</span><span class="special">&gt;</span> <span class="identifier">sr</span><span class="special">{</span><span class="identifier">res</span><span class="special">};</span>
195
196<span class="comment">// Write the header first</span>
197<span class="identifier">write_header</span><span class="special">(</span><span class="identifier">sock</span><span class="special">,</span> <span class="identifier">sr</span><span class="special">);</span>
198
199<span class="comment">// Now manually emit three chunks:</span>
200<span class="identifier">net</span><span class="special">::</span><span class="identifier">write</span><span class="special">(</span><span class="identifier">sock</span><span class="special">,</span> <span class="identifier">make_chunk</span><span class="special">(</span><span class="identifier">get_next_chunk_body</span><span class="special">()));</span>
201<span class="identifier">net</span><span class="special">::</span><span class="identifier">write</span><span class="special">(</span><span class="identifier">sock</span><span class="special">,</span> <span class="identifier">make_chunk</span><span class="special">(</span><span class="identifier">get_next_chunk_body</span><span class="special">()));</span>
202<span class="identifier">net</span><span class="special">::</span><span class="identifier">write</span><span class="special">(</span><span class="identifier">sock</span><span class="special">,</span> <span class="identifier">make_chunk</span><span class="special">(</span><span class="identifier">get_next_chunk_body</span><span class="special">()));</span>
203
204<span class="comment">// We are responsible for sending the last chunk:</span>
205<span class="identifier">net</span><span class="special">::</span><span class="identifier">write</span><span class="special">(</span><span class="identifier">sock</span><span class="special">,</span> <span class="identifier">make_chunk_last</span><span class="special">());</span>
206</pre>
207<p>
208        The following code sends additional chunks, and sets chunk extensions using
209        the helper container. The container automatically quotes values in the serialized
210        output when necessary:
211      </p>
212<pre class="programlisting"><span class="comment">// Prepare a set of chunk extension to emit with the body</span>
213<span class="identifier">chunk_extensions</span> <span class="identifier">ext</span><span class="special">;</span>
214<span class="identifier">ext</span><span class="special">.</span><span class="identifier">insert</span><span class="special">(</span><span class="string">"mp3"</span><span class="special">);</span>
215<span class="identifier">ext</span><span class="special">.</span><span class="identifier">insert</span><span class="special">(</span><span class="string">"title"</span><span class="special">,</span> <span class="string">"Beale Street Blues"</span><span class="special">);</span>
216<span class="identifier">ext</span><span class="special">.</span><span class="identifier">insert</span><span class="special">(</span><span class="string">"artist"</span><span class="special">,</span> <span class="string">"W.C. Handy"</span><span class="special">);</span>
217
218<span class="comment">// Write the next chunk with the chunk extensions</span>
219<span class="comment">// The implementation will make a copy of the extensions object,</span>
220<span class="comment">// so the caller does not need to manage lifetime issues.</span>
221<span class="identifier">net</span><span class="special">::</span><span class="identifier">write</span><span class="special">(</span><span class="identifier">sock</span><span class="special">,</span> <span class="identifier">make_chunk</span><span class="special">(</span><span class="identifier">get_next_chunk_body</span><span class="special">(),</span> <span class="identifier">ext</span><span class="special">));</span>
222
223<span class="comment">// Write the next chunk with the chunk extensions</span>
224<span class="comment">// The implementation will make a copy of the extensions object, storing the copy</span>
225<span class="comment">// using the custom allocator, so the caller does not need to manage lifetime issues.</span>
226<span class="identifier">net</span><span class="special">::</span><span class="identifier">write</span><span class="special">(</span><span class="identifier">sock</span><span class="special">,</span> <span class="identifier">make_chunk</span><span class="special">(</span><span class="identifier">get_next_chunk_body</span><span class="special">(),</span> <span class="identifier">ext</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">allocator</span><span class="special">&lt;</span><span class="keyword">char</span><span class="special">&gt;{}));</span>
227
228<span class="comment">// Write the next chunk with the chunk extensions</span>
229<span class="comment">// The implementation allocates memory using the default allocator and takes ownership</span>
230<span class="comment">// of the extensions object, so the caller does not need to manage lifetime issues.</span>
231<span class="comment">// Note: ext is moved</span>
232<span class="identifier">net</span><span class="special">::</span><span class="identifier">write</span><span class="special">(</span><span class="identifier">sock</span><span class="special">,</span> <span class="identifier">make_chunk</span><span class="special">(</span><span class="identifier">get_next_chunk_body</span><span class="special">(),</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">ext</span><span class="special">)));</span>
233</pre>
234<p>
235        Callers can take over the generation and management of the extensions buffer
236        by passing a non-owning string. Note that this requires the string contents
237        to adhere to the correct syntax for chunk extensions, including the needed
238        double quotes for values which contain spaces:
239      </p>
240<pre class="programlisting"><span class="comment">// Manually specify the chunk extensions.</span>
241<span class="comment">// Some of the strings contain spaces and a period and must be quoted</span>
242<span class="identifier">net</span><span class="special">::</span><span class="identifier">write</span><span class="special">(</span><span class="identifier">sock</span><span class="special">,</span> <span class="identifier">make_chunk</span><span class="special">(</span><span class="identifier">get_next_chunk_body</span><span class="special">(),</span>
243    <span class="string">";mp3"</span>
244    <span class="string">";title=\"Danny Boy\""</span>
245    <span class="string">";artist=\"Fred E. Weatherly\""</span>
246    <span class="special">));</span>
247</pre>
248<p>
249        The next code sample emits a chunked response which promises two trailer
250        fields and delivers them in the last chunk. The implementation allocates
251        memory using the default or a passed-in allocator to hold the state information
252        required to serialize the trailer:
253      </p>
254<pre class="programlisting"><span class="comment">// Prepare a chunked HTTP/1.1 response with some trailer fields</span>
255<span class="identifier">response</span><span class="special">&lt;</span><span class="identifier">empty_body</span><span class="special">&gt;</span> <span class="identifier">res</span><span class="special">{</span><span class="identifier">status</span><span class="special">::</span><span class="identifier">ok</span><span class="special">,</span> <span class="number">11</span><span class="special">};</span>
256<span class="identifier">res</span><span class="special">.</span><span class="identifier">set</span><span class="special">(</span><span class="identifier">field</span><span class="special">::</span><span class="identifier">server</span><span class="special">,</span> <span class="string">"Beast"</span><span class="special">);</span>
257
258<span class="comment">// Inform the client of the trailer fields we will send</span>
259<span class="identifier">res</span><span class="special">.</span><span class="identifier">set</span><span class="special">(</span><span class="identifier">field</span><span class="special">::</span><span class="identifier">trailer</span><span class="special">,</span> <span class="string">"Content-MD5, Expires"</span><span class="special">);</span>
260
261<span class="identifier">res</span><span class="special">.</span><span class="identifier">chunked</span><span class="special">(</span><span class="keyword">true</span><span class="special">);</span>
262
263<span class="comment">// Serialize the header and two chunks</span>
264<span class="identifier">response_serializer</span><span class="special">&lt;</span><span class="identifier">empty_body</span><span class="special">&gt;</span> <span class="identifier">sr</span><span class="special">{</span><span class="identifier">res</span><span class="special">};</span>
265<span class="identifier">write_header</span><span class="special">(</span><span class="identifier">sock</span><span class="special">,</span> <span class="identifier">sr</span><span class="special">);</span>
266<span class="identifier">net</span><span class="special">::</span><span class="identifier">write</span><span class="special">(</span><span class="identifier">sock</span><span class="special">,</span> <span class="identifier">make_chunk</span><span class="special">(</span><span class="identifier">get_next_chunk_body</span><span class="special">()));</span>
267<span class="identifier">net</span><span class="special">::</span><span class="identifier">write</span><span class="special">(</span><span class="identifier">sock</span><span class="special">,</span> <span class="identifier">make_chunk</span><span class="special">(</span><span class="identifier">get_next_chunk_body</span><span class="special">()));</span>
268
269<span class="comment">// Prepare the trailer</span>
270<span class="identifier">fields</span> <span class="identifier">trailer</span><span class="special">;</span>
271<span class="identifier">trailer</span><span class="special">.</span><span class="identifier">set</span><span class="special">(</span><span class="identifier">field</span><span class="special">::</span><span class="identifier">content_md5</span><span class="special">,</span> <span class="string">"f4a5c16584f03d90"</span><span class="special">);</span>
272<span class="identifier">trailer</span><span class="special">.</span><span class="identifier">set</span><span class="special">(</span><span class="identifier">field</span><span class="special">::</span><span class="identifier">expires</span><span class="special">,</span> <span class="string">"never"</span><span class="special">);</span>
273
274<span class="comment">// Emit the trailer in the last chunk.</span>
275<span class="comment">// The implementation will use the default allocator to create the storage for holding</span>
276<span class="comment">// the serialized fields.</span>
277<span class="identifier">net</span><span class="special">::</span><span class="identifier">write</span><span class="special">(</span><span class="identifier">sock</span><span class="special">,</span> <span class="identifier">make_chunk_last</span><span class="special">(</span><span class="identifier">trailer</span><span class="special">));</span>
278</pre>
279<p>
280        Using a custom allocator to serialize the last chunk:
281      </p>
282<pre class="programlisting"><span class="comment">// Use a custom allocator for serializing the last chunk</span>
283<span class="identifier">fields</span> <span class="identifier">trailer</span><span class="special">;</span>
284<span class="identifier">trailer</span><span class="special">.</span><span class="identifier">set</span><span class="special">(</span><span class="identifier">field</span><span class="special">::</span><span class="identifier">approved</span><span class="special">,</span> <span class="string">"yes"</span><span class="special">);</span>
285<span class="identifier">net</span><span class="special">::</span><span class="identifier">write</span><span class="special">(</span><span class="identifier">sock</span><span class="special">,</span> <span class="identifier">make_chunk_last</span><span class="special">(</span><span class="identifier">trailer</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">allocator</span><span class="special">&lt;</span><span class="keyword">char</span><span class="special">&gt;{}));</span>
286</pre>
287<p>
288        Alternatively, callers can take over the generation and lifetime management
289        of the serialized trailer fields by passing in a non-owning string:
290      </p>
291<pre class="programlisting"><span class="comment">// Manually emit a trailer.</span>
292<span class="comment">// We are responsible for ensuring that the trailer format adheres to the specification.</span>
293<span class="identifier">string_view</span> <span class="identifier">ext</span> <span class="special">=</span>
294    <span class="string">"Content-MD5: f4a5c16584f03d90\r\n"</span>
295    <span class="string">"Expires: never\r\n"</span>
296    <span class="string">"\r\n"</span><span class="special">;</span>
297<span class="identifier">net</span><span class="special">::</span><span class="identifier">write</span><span class="special">(</span><span class="identifier">sock</span><span class="special">,</span> <span class="identifier">make_chunk_last</span><span class="special">(</span><span class="identifier">net</span><span class="special">::</span><span class="identifier">const_buffer</span><span class="special">{</span><span class="identifier">ext</span><span class="special">.</span><span class="identifier">data</span><span class="special">(),</span> <span class="identifier">ext</span><span class="special">.</span><span class="identifier">size</span><span class="special">()}));</span>
298</pre>
299<p>
300        For the ultimate level of control, a caller can manually compose the chunk
301        itself by first emitting a header with the correct chunk body size, and then
302        by emitting the chunk body in multiple calls to the stream write function.
303        In this case the caller is responsible for also emitting the terminating
304        CRLF (<code class="computeroutput"><span class="string">"\r\n"</span></code>):
305      </p>
306<pre class="programlisting"><span class="comment">// Prepare a chunked HTTP/1.1 response and send the header</span>
307<span class="identifier">response</span><span class="special">&lt;</span><span class="identifier">empty_body</span><span class="special">&gt;</span> <span class="identifier">res</span><span class="special">{</span><span class="identifier">status</span><span class="special">::</span><span class="identifier">ok</span><span class="special">,</span> <span class="number">11</span><span class="special">};</span>
308<span class="identifier">res</span><span class="special">.</span><span class="identifier">set</span><span class="special">(</span><span class="identifier">field</span><span class="special">::</span><span class="identifier">server</span><span class="special">,</span> <span class="string">"Beast"</span><span class="special">);</span>
309<span class="identifier">res</span><span class="special">.</span><span class="identifier">chunked</span><span class="special">(</span><span class="keyword">true</span><span class="special">);</span>
310<span class="identifier">response_serializer</span><span class="special">&lt;</span><span class="identifier">empty_body</span><span class="special">&gt;</span> <span class="identifier">sr</span><span class="special">{</span><span class="identifier">res</span><span class="special">};</span>
311<span class="identifier">write_header</span><span class="special">(</span><span class="identifier">sock</span><span class="special">,</span> <span class="identifier">sr</span><span class="special">);</span>
312
313<span class="comment">// Obtain three body buffers up front</span>
314<span class="keyword">auto</span> <span class="keyword">const</span> <span class="identifier">cb1</span> <span class="special">=</span> <span class="identifier">get_next_chunk_body</span><span class="special">();</span>
315<span class="keyword">auto</span> <span class="keyword">const</span> <span class="identifier">cb2</span> <span class="special">=</span> <span class="identifier">get_next_chunk_body</span><span class="special">();</span>
316<span class="keyword">auto</span> <span class="keyword">const</span> <span class="identifier">cb3</span> <span class="special">=</span> <span class="identifier">get_next_chunk_body</span><span class="special">();</span>
317
318<span class="comment">// Manually emit a chunk by first writing the chunk-size header with the correct size</span>
319<span class="identifier">net</span><span class="special">::</span><span class="identifier">write</span><span class="special">(</span><span class="identifier">sock</span><span class="special">,</span> <span class="identifier">chunk_header</span><span class="special">{</span>
320    <span class="identifier">buffer_bytes</span><span class="special">(</span><span class="identifier">cb1</span><span class="special">)</span> <span class="special">+</span>
321    <span class="identifier">buffer_bytes</span><span class="special">(</span><span class="identifier">cb2</span><span class="special">)</span> <span class="special">+</span>
322    <span class="identifier">buffer_bytes</span><span class="special">(</span><span class="identifier">cb3</span><span class="special">)});</span>
323
324<span class="comment">// And then output the chunk body in three pieces ("chunk the chunk")</span>
325<span class="identifier">net</span><span class="special">::</span><span class="identifier">write</span><span class="special">(</span><span class="identifier">sock</span><span class="special">,</span> <span class="identifier">cb1</span><span class="special">);</span>
326<span class="identifier">net</span><span class="special">::</span><span class="identifier">write</span><span class="special">(</span><span class="identifier">sock</span><span class="special">,</span> <span class="identifier">cb2</span><span class="special">);</span>
327<span class="identifier">net</span><span class="special">::</span><span class="identifier">write</span><span class="special">(</span><span class="identifier">sock</span><span class="special">,</span> <span class="identifier">cb3</span><span class="special">);</span>
328
329<span class="comment">// When we go this deep, we are also responsible for the terminating CRLF</span>
330<span class="identifier">net</span><span class="special">::</span><span class="identifier">write</span><span class="special">(</span><span class="identifier">sock</span><span class="special">,</span> <span class="identifier">chunk_crlf</span><span class="special">{});</span>
331</pre>
332<h5>
333<a name="beast.using_http.chunked_encoding.h1"></a>
334        <span class="phrase"><a name="beast.using_http.chunked_encoding.parsing_chunks"></a></span><a class="link" href="chunked_encoding.html#beast.using_http.chunked_encoding.parsing_chunks">Parsing
335        Chunks</a>
336      </h5>
337<p>
338        The <a class="link" href="../ref/boost__beast__http__parser.html" title="http::parser"><code class="computeroutput"><span class="identifier">parser</span></code></a>
339        automatically removes the chunked transfer coding when it is the last encoding
340        in the list. However, it also discards the chunk extensions and does not
341        provide a way to determine the boundaries between chunks. Advanced applications
342        which need to access the chunk extensions or read complete individual chunks
343        may use a callback interface provided by <a class="link" href="../ref/boost__beast__http__parser.html" title="http::parser"><code class="computeroutput"><span class="identifier">parser</span></code></a>:
344      </p>
345<div class="table">
346<a name="beast.using_http.chunked_encoding.chunking_parse_callbacks"></a><p class="title"><b>Table 1.26. Chunking Parse Callbacks</b></p>
347<div class="table-contents"><table class="table" summary="Chunking Parse Callbacks">
348<colgroup>
349<col>
350<col>
351</colgroup>
352<thead><tr>
353<th>
354                <p>
355                  Name
356                </p>
357              </th>
358<th>
359                <p>
360                  Description
361                </p>
362              </th>
363</tr></thead>
364<tbody>
365<tr>
366<td>
367                <p>
368                  <a class="link" href="../ref/boost__beast__http__parser/on_chunk_header.html" title="http::parser::on_chunk_header"><code class="computeroutput"><span class="identifier">on_chunk_header</span></code></a>
369                </p>
370              </td>
371<td>
372                <p>
373                  Set a callback to be invoked on each chunk header.
374                </p>
375                <p>
376                  The callback will be invoked once for every chunk in the message
377                  payload, as well as once for the last chunk. The invocation happens
378                  after the chunk header is available but before any body octets
379                  have been parsed.
380                </p>
381                <p>
382                  The extensions are provided in raw, validated form, use <a class="link" href="../ref/boost__beast__http__basic_chunk_extensions/parse.html" title="http::basic_chunk_extensions::parse"><code class="computeroutput"><span class="identifier">chunk_extensions</span><span class="special">::</span><span class="identifier">parse</span></code></a> to parse the extensions
383                  into a structured container for easier access. The implementation
384                  type-erases the callback without requiring a dynamic allocation.
385                  For this reason, the callback object is passed by a non-constant
386                  reference.
387                </p>
388                <p>
389                  The function object will be called with this equivalent signature:
390                </p>
391<pre class="programlisting"><span class="keyword">void</span>
392<span class="identifier">callback</span><span class="special">(</span>
393    <span class="identifier">std</span><span class="special">::</span><span class="identifier">uint64_t</span> <span class="identifier">size</span><span class="special">,</span>         <span class="comment">// Size of the chunk, zero for the last chunk</span>
394    <span class="identifier">string_view</span> <span class="identifier">extensions</span><span class="special">,</span>     <span class="comment">// The chunk-extensions in raw form</span>
395    <span class="identifier">error_code</span><span class="special">&amp;</span> <span class="identifier">ec</span><span class="special">);</span>            <span class="comment">// May be set by the callback to indicate an error</span>
396</pre>
397              </td>
398</tr>
399<tr>
400<td>
401                <p>
402                  <a class="link" href="../ref/boost__beast__http__parser/on_chunk_body.html" title="http::parser::on_chunk_body"><code class="computeroutput"><span class="identifier">on_chunk_body</span></code></a>
403                </p>
404              </td>
405<td>
406                <p>
407                  Set a callback to be invoked on chunk body data.
408                </p>
409                <p>
410                  The callback will be invoked one or more times to provide buffers
411                  corresponding to the chunk body for the current chunk. The callback
412                  receives the number of octets remaining in this chunk body including
413                  the octets in the buffer provided.
414                </p>
415                <p>
416                  The callback must return the number of octets actually consumed.
417                  Any octets not consumed will be presented again in a subsequent
418                  invocation of the callback. The implementation type-erases the
419                  callback without requiring a dynamic allocation. For this reason,
420                  the callback object is passed by a non-constant reference.
421                </p>
422                <p>
423                  The function object will be called with this equivalent signature:
424                </p>
425<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span>
426<span class="identifier">callback</span><span class="special">(</span>
427    <span class="identifier">std</span><span class="special">::</span><span class="identifier">uint64_t</span> <span class="identifier">remain</span><span class="special">,</span>       <span class="comment">// Octets remaining in this chunk, includes `body`</span>
428    <span class="identifier">string_view</span> <span class="identifier">body</span><span class="special">,</span>           <span class="comment">// A buffer holding some or all of the remainder of the chunk body</span>
429    <span class="identifier">error_code</span><span class="special">&amp;</span> <span class="identifier">ec</span><span class="special">);</span>            <span class="comment">// May be set by the callback to indicate an error</span>
430</pre>
431              </td>
432</tr>
433</tbody>
434</table></div>
435</div>
436<br class="table-break"><p>
437        This example will read a message header from the stream, and then manually
438        read each chunk. It recognizes the chunk boundaries and outputs the contents
439        of each chunk as it comes in. Any chunk extensions are printed, each extension
440        on its own line. Finally, any trailers promised in the header are printed.
441      </p>
442<pre class="programlisting"><span class="comment">/** Read a message with a chunked body and print the chunks and extensions
443*/</span>
444<span class="keyword">template</span><span class="special">&lt;</span>
445    <span class="keyword">bool</span> <span class="identifier">isRequest</span><span class="special">,</span>
446    <span class="keyword">class</span> <span class="identifier">SyncReadStream</span><span class="special">,</span>
447    <span class="keyword">class</span> <span class="identifier">DynamicBuffer</span><span class="special">&gt;</span>
448<span class="keyword">void</span>
449<span class="identifier">print_chunked_body</span><span class="special">(</span>
450    <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span><span class="special">&amp;</span> <span class="identifier">os</span><span class="special">,</span>
451    <span class="identifier">SyncReadStream</span><span class="special">&amp;</span> <span class="identifier">stream</span><span class="special">,</span>
452    <span class="identifier">DynamicBuffer</span><span class="special">&amp;</span> <span class="identifier">buffer</span><span class="special">,</span>
453    <span class="identifier">error_code</span><span class="special">&amp;</span> <span class="identifier">ec</span><span class="special">)</span>
454<span class="special">{</span>
455    <span class="comment">// Declare the parser with an empty body since</span>
456    <span class="comment">// we plan on capturing the chunks ourselves.</span>
457    <span class="identifier">parser</span><span class="special">&lt;</span><span class="identifier">isRequest</span><span class="special">,</span> <span class="identifier">empty_body</span><span class="special">&gt;</span> <span class="identifier">p</span><span class="special">;</span>
458
459    <span class="comment">// First read the complete header</span>
460    <span class="identifier">read_header</span><span class="special">(</span><span class="identifier">stream</span><span class="special">,</span> <span class="identifier">buffer</span><span class="special">,</span> <span class="identifier">p</span><span class="special">,</span> <span class="identifier">ec</span><span class="special">);</span>
461    <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span><span class="special">)</span>
462        <span class="keyword">return</span><span class="special">;</span>
463
464    <span class="comment">// This container will hold the extensions for each chunk</span>
465    <span class="identifier">chunk_extensions</span> <span class="identifier">ce</span><span class="special">;</span>
466
467    <span class="comment">// This string will hold the body of each chunk</span>
468    <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">chunk</span><span class="special">;</span>
469
470    <span class="comment">// Declare our chunk header callback  This is invoked</span>
471    <span class="comment">// after each chunk header and also after the last chunk.</span>
472    <span class="keyword">auto</span> <span class="identifier">header_cb</span> <span class="special">=</span>
473    <span class="special">[&amp;](</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">uint64_t</span> <span class="identifier">size</span><span class="special">,</span>         <span class="comment">// Size of the chunk, or zero for the last chunk</span>
474        <span class="identifier">string_view</span> <span class="identifier">extensions</span><span class="special">,</span>     <span class="comment">// The raw chunk-extensions string. Already validated.</span>
475        <span class="identifier">error_code</span><span class="special">&amp;</span> <span class="identifier">ev</span><span class="special">)</span>             <span class="comment">// We can set this to indicate an error</span>
476    <span class="special">{</span>
477        <span class="comment">// Parse the chunk extensions so we can access them easily</span>
478        <span class="identifier">ce</span><span class="special">.</span><span class="identifier">parse</span><span class="special">(</span><span class="identifier">extensions</span><span class="special">,</span> <span class="identifier">ev</span><span class="special">);</span>
479        <span class="keyword">if</span><span class="special">(</span><span class="identifier">ev</span><span class="special">)</span>
480            <span class="keyword">return</span><span class="special">;</span>
481
482        <span class="comment">// See if the chunk is too big</span>
483        <span class="keyword">if</span><span class="special">(</span><span class="identifier">size</span> <span class="special">&gt;</span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">numeric_limits</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span><span class="special">&gt;::</span><span class="identifier">max</span><span class="special">)())</span>
484        <span class="special">{</span>
485            <span class="identifier">ev</span> <span class="special">=</span> <span class="identifier">error</span><span class="special">::</span><span class="identifier">body_limit</span><span class="special">;</span>
486            <span class="keyword">return</span><span class="special">;</span>
487        <span class="special">}</span>
488
489        <span class="comment">// Make sure we have enough storage, and</span>
490        <span class="comment">// reset the container for the upcoming chunk</span>
491        <span class="identifier">chunk</span><span class="special">.</span><span class="identifier">reserve</span><span class="special">(</span><span class="keyword">static_cast</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span><span class="special">&gt;(</span><span class="identifier">size</span><span class="special">));</span>
492        <span class="identifier">chunk</span><span class="special">.</span><span class="identifier">clear</span><span class="special">();</span>
493    <span class="special">};</span>
494
495    <span class="comment">// Set the callback. The function requires a non-const reference so we</span>
496    <span class="comment">// use a local variable, since temporaries can only bind to const refs.</span>
497    <span class="identifier">p</span><span class="special">.</span><span class="identifier">on_chunk_header</span><span class="special">(</span><span class="identifier">header_cb</span><span class="special">);</span>
498
499    <span class="comment">// Declare the chunk body callback. This is called one or</span>
500    <span class="comment">// more times for each piece of a chunk body.</span>
501    <span class="keyword">auto</span> <span class="identifier">body_cb</span> <span class="special">=</span>
502    <span class="special">[&amp;](</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">uint64_t</span> <span class="identifier">remain</span><span class="special">,</span>   <span class="comment">// The number of bytes left in this chunk</span>
503        <span class="identifier">string_view</span> <span class="identifier">body</span><span class="special">,</span>       <span class="comment">// A buffer holding chunk body data</span>
504        <span class="identifier">error_code</span><span class="special">&amp;</span> <span class="identifier">ec</span><span class="special">)</span>         <span class="comment">// We can set this to indicate an error</span>
505    <span class="special">{</span>
506        <span class="comment">// If this is the last piece of the chunk body,</span>
507        <span class="comment">// set the error so that the call to `read` returns</span>
508        <span class="comment">// and we can process the chunk.</span>
509        <span class="keyword">if</span><span class="special">(</span><span class="identifier">remain</span> <span class="special">==</span> <span class="identifier">body</span><span class="special">.</span><span class="identifier">size</span><span class="special">())</span>
510            <span class="identifier">ec</span> <span class="special">=</span> <span class="identifier">error</span><span class="special">::</span><span class="identifier">end_of_chunk</span><span class="special">;</span>
511
512        <span class="comment">// Append this piece to our container</span>
513        <span class="identifier">chunk</span><span class="special">.</span><span class="identifier">append</span><span class="special">(</span><span class="identifier">body</span><span class="special">.</span><span class="identifier">data</span><span class="special">(),</span> <span class="identifier">body</span><span class="special">.</span><span class="identifier">size</span><span class="special">());</span>
514
515        <span class="comment">// The return value informs the parser of how much of the body we</span>
516        <span class="comment">// consumed. We will indicate that we consumed everything passed in.</span>
517        <span class="keyword">return</span> <span class="identifier">body</span><span class="special">.</span><span class="identifier">size</span><span class="special">();</span>
518    <span class="special">};</span>
519    <span class="identifier">p</span><span class="special">.</span><span class="identifier">on_chunk_body</span><span class="special">(</span><span class="identifier">body_cb</span><span class="special">);</span>
520
521    <span class="keyword">while</span><span class="special">(!</span> <span class="identifier">p</span><span class="special">.</span><span class="identifier">is_done</span><span class="special">())</span>
522    <span class="special">{</span>
523        <span class="comment">// Read as much as we can. When we reach the end of the chunk, the chunk</span>
524        <span class="comment">// body callback will make the read return with the end_of_chunk error.</span>
525        <span class="identifier">read</span><span class="special">(</span><span class="identifier">stream</span><span class="special">,</span> <span class="identifier">buffer</span><span class="special">,</span> <span class="identifier">p</span><span class="special">,</span> <span class="identifier">ec</span><span class="special">);</span>
526        <span class="keyword">if</span><span class="special">(!</span> <span class="identifier">ec</span><span class="special">)</span>
527            <span class="keyword">continue</span><span class="special">;</span>
528        <span class="keyword">else</span> <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span> <span class="special">!=</span> <span class="identifier">error</span><span class="special">::</span><span class="identifier">end_of_chunk</span><span class="special">)</span>
529            <span class="keyword">return</span><span class="special">;</span>
530        <span class="keyword">else</span>
531            <span class="identifier">ec</span> <span class="special">=</span> <span class="special">{};</span>
532
533        <span class="comment">// We got a whole chunk, print the extensions:</span>
534        <span class="keyword">for</span><span class="special">(</span><span class="keyword">auto</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">extension</span> <span class="special">:</span> <span class="identifier">ce</span><span class="special">)</span>
535        <span class="special">{</span>
536            <span class="identifier">os</span> <span class="special">&lt;&lt;</span> <span class="string">"Extension: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">extension</span><span class="special">.</span><span class="identifier">first</span><span class="special">;</span>
537            <span class="keyword">if</span><span class="special">(!</span> <span class="identifier">extension</span><span class="special">.</span><span class="identifier">second</span><span class="special">.</span><span class="identifier">empty</span><span class="special">())</span>
538                <span class="identifier">os</span> <span class="special">&lt;&lt;</span> <span class="string">" = "</span> <span class="special">&lt;&lt;</span> <span class="identifier">extension</span><span class="special">.</span><span class="identifier">second</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
539            <span class="keyword">else</span>
540                <span class="identifier">os</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
541        <span class="special">}</span>
542
543        <span class="comment">// Now print the chunk body</span>
544        <span class="identifier">os</span> <span class="special">&lt;&lt;</span> <span class="string">"Chunk Body: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">chunk</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
545    <span class="special">}</span>
546
547    <span class="comment">// Get a reference to the parsed message, this is for convenience</span>
548    <span class="keyword">auto</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">msg</span> <span class="special">=</span> <span class="identifier">p</span><span class="special">.</span><span class="identifier">get</span><span class="special">();</span>
549
550    <span class="comment">// Check each field promised in the "Trailer" header and output it</span>
551    <span class="keyword">for</span><span class="special">(</span><span class="keyword">auto</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">name</span> <span class="special">:</span> <span class="identifier">token_list</span><span class="special">{</span><span class="identifier">msg</span><span class="special">[</span><span class="identifier">field</span><span class="special">::</span><span class="identifier">trailer</span><span class="special">]})</span>
552    <span class="special">{</span>
553        <span class="comment">// Find the trailer field</span>
554        <span class="keyword">auto</span> <span class="identifier">it</span> <span class="special">=</span> <span class="identifier">msg</span><span class="special">.</span><span class="identifier">find</span><span class="special">(</span><span class="identifier">name</span><span class="special">);</span>
555        <span class="keyword">if</span><span class="special">(</span><span class="identifier">it</span> <span class="special">==</span> <span class="identifier">msg</span><span class="special">.</span><span class="identifier">end</span><span class="special">())</span>
556        <span class="special">{</span>
557            <span class="comment">// Oops! They promised the field but failed to deliver it</span>
558            <span class="identifier">os</span> <span class="special">&lt;&lt;</span> <span class="string">"Missing Trailer: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">name</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
559            <span class="keyword">continue</span><span class="special">;</span>
560        <span class="special">}</span>
561        <span class="identifier">os</span> <span class="special">&lt;&lt;</span> <span class="identifier">it</span><span class="special">-&gt;</span><span class="identifier">name</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">": "</span> <span class="special">&lt;&lt;</span> <span class="identifier">it</span><span class="special">-&gt;</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
562    <span class="special">}</span>
563<span class="special">}</span>
564</pre>
565<p>
566        Given the HTTP response as input on the left, the output of the function
567        shown above is shown on the right:
568      </p>
569<div class="table">
570<a name="beast.using_http.chunked_encoding.chunk_parsing_example_output"></a><p class="title"><b>Table 1.27. Chunk Parsing Example Output</b></p>
571<div class="table-contents"><table class="table" summary="Chunk Parsing Example Output">
572<colgroup>
573<col>
574<col>
575</colgroup>
576<thead><tr>
577<th>
578                <p>
579                  Input
580                </p>
581              </th>
582<th>
583                <p>
584                  Output
585                </p>
586              </th>
587</tr></thead>
588<tbody><tr>
589<td>
590<pre class="programlisting"><span class="identifier">HTTP</span><span class="special">/</span><span class="number">1.1</span> <span class="number">200</span> <span class="identifier">OK</span><span class="special">\</span><span class="identifier">r</span><span class="special">\</span><span class="identifier">n</span>
591<span class="identifier">Server</span><span class="special">:</span> <span class="identifier">test</span><span class="special">\</span><span class="identifier">r</span><span class="special">\</span><span class="identifier">n</span>
592<span class="identifier">Trailer</span><span class="special">:</span> <span class="identifier">Expires</span><span class="special">,</span> <span class="identifier">Content</span><span class="special">-</span><span class="identifier">MD5</span><span class="special">\</span><span class="identifier">r</span><span class="special">\</span><span class="identifier">n</span>
593<span class="identifier">Transfer</span><span class="special">-</span><span class="identifier">Encoding</span><span class="special">:</span> <span class="identifier">chunked</span><span class="special">\</span><span class="identifier">r</span><span class="special">\</span><span class="identifier">n</span>
594<span class="special">\</span><span class="identifier">r</span><span class="special">\</span><span class="identifier">n</span>
595<span class="number">5</span><span class="special">\</span><span class="identifier">r</span><span class="special">\</span><span class="identifier">n</span>
596<span class="identifier">First</span><span class="special">\</span><span class="identifier">r</span><span class="special">\</span><span class="identifier">n</span>
597<span class="identifier">d</span><span class="special">;</span><span class="identifier">quality</span><span class="special">=</span><span class="number">1.0</span><span class="special">\</span><span class="identifier">r</span><span class="special">\</span><span class="identifier">n</span>
598<span class="identifier">Hello</span><span class="special">,</span> <span class="identifier">world</span><span class="special">!\</span><span class="identifier">r</span><span class="special">\</span><span class="identifier">n</span>
599<span class="identifier">e</span><span class="special">;</span><span class="identifier">file</span><span class="special">=</span><span class="identifier">abc</span><span class="special">.</span><span class="identifier">txt</span><span class="special">;</span><span class="identifier">quality</span><span class="special">=</span><span class="number">0.7</span><span class="special">\</span><span class="identifier">r</span><span class="special">\</span><span class="identifier">n</span>
600<span class="identifier">The</span> <span class="identifier">Next</span> <span class="identifier">Chunk</span><span class="special">\</span><span class="identifier">r</span><span class="special">\</span><span class="identifier">n</span>
601<span class="number">8</span><span class="special">;</span><span class="identifier">last</span><span class="special">\</span><span class="identifier">r</span><span class="special">\</span><span class="identifier">n</span>
602<span class="identifier">Last</span> <span class="identifier">one</span><span class="special">\</span><span class="identifier">r</span><span class="special">\</span><span class="identifier">n</span>
603<span class="number">0</span><span class="special">\</span><span class="identifier">r</span><span class="special">\</span><span class="identifier">n</span>
604<span class="identifier">Expires</span><span class="special">:</span> <span class="identifier">never</span><span class="special">\</span><span class="identifier">r</span><span class="special">\</span><span class="identifier">n</span>
605<span class="identifier">Content</span><span class="special">-</span><span class="identifier">MD5</span><span class="special">:</span> <span class="identifier">f4a5c16584f03d90</span><span class="special">\</span><span class="identifier">r</span><span class="special">\</span><span class="identifier">n</span>
606<span class="special">\</span><span class="identifier">r</span><span class="special">\</span><span class="identifier">n</span>
607</pre>
608              </td>
609<td>
610<pre class="programlisting"><span class="identifier">Chunk</span> <span class="identifier">Body</span><span class="special">:</span> <span class="identifier">First</span>
611<span class="identifier">Extension</span><span class="special">:</span> <span class="identifier">quality</span> <span class="special">=</span> <span class="number">1.0</span>
612<span class="identifier">Chunk</span> <span class="identifier">Body</span><span class="special">:</span> <span class="identifier">Hello</span><span class="special">,</span> <span class="identifier">world</span><span class="special">!</span>
613<span class="identifier">Extension</span><span class="special">:</span> <span class="identifier">file</span> <span class="special">=</span> <span class="identifier">abc</span><span class="special">.</span><span class="identifier">txt</span>
614<span class="identifier">Extension</span><span class="special">:</span> <span class="identifier">quality</span> <span class="special">=</span> <span class="number">0.7</span>
615<span class="identifier">Chunk</span> <span class="identifier">Body</span><span class="special">:</span> <span class="identifier">The</span> <span class="identifier">Next</span> <span class="identifier">Chunk</span>
616<span class="identifier">Extension</span><span class="special">:</span> <span class="identifier">last</span>
617<span class="identifier">Chunk</span> <span class="identifier">Body</span><span class="special">:</span> <span class="identifier">Last</span> <span class="identifier">one</span>
618<span class="identifier">Expires</span><span class="special">:</span> <span class="identifier">never</span>
619<span class="identifier">Content</span><span class="special">-</span><span class="identifier">MD5</span><span class="special">:</span> <span class="identifier">f4a5c16584f03d90</span>
620</pre>
621              </td>
622</tr></tbody>
623</table></div>
624</div>
625<br class="table-break">
626</div>
627<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
628<td align="left"></td>
629<td align="right"><div class="copyright-footer">Copyright © 2016-2019 Vinnie
630      Falco<p>
631        Distributed under the Boost Software License, Version 1.0. (See accompanying
632        file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
633      </p>
634</div></td>
635</tr></table>
636<hr>
637<div class="spirit-nav">
638<a accesskey="p" href="buffer_oriented_parsing.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../using_http.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="custom_body_types.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
639</div>
640</body>
641</html>
642