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"><</span><span class="identifier">empty_body</span><span class="special">></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"><</span><span class="identifier">empty_body</span><span class="special">></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"><</span><span class="keyword">char</span><span class="special">>{}));</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"><</span><span class="identifier">empty_body</span><span class="special">></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"><</span><span class="identifier">empty_body</span><span class="special">></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"><</span><span class="keyword">char</span><span class="special">>{}));</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"><</span><span class="identifier">empty_body</span><span class="special">></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"><</span><span class="identifier">empty_body</span><span class="special">></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">&</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">&</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"><</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">></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">&</span> <span class="identifier">os</span><span class="special">,</span> 451 <span class="identifier">SyncReadStream</span><span class="special">&</span> <span class="identifier">stream</span><span class="special">,</span> 452 <span class="identifier">DynamicBuffer</span><span class="special">&</span> <span class="identifier">buffer</span><span class="special">,</span> 453 <span class="identifier">error_code</span><span class="special">&</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"><</span><span class="identifier">isRequest</span><span class="special">,</span> <span class="identifier">empty_body</span><span class="special">></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">[&](</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">&</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">></span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">numeric_limits</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span><span class="special">>::</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"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span><span class="special">>(</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">[&](</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">&</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">&</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"><<</span> <span class="string">"Extension: "</span> <span class="special"><<</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"><<</span> <span class="string">" = "</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">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"><<</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"><<</span> <span class="string">"Chunk Body: "</span> <span class="special"><<</span> <span class="identifier">chunk</span> <span class="special"><<</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">&</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">&</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"><<</span> <span class="string">"Missing Trailer: "</span> <span class="special"><<</span> <span class="identifier">name</span> <span class="special"><<</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"><<</span> <span class="identifier">it</span><span class="special">-></span><span class="identifier">name</span><span class="special">()</span> <span class="special"><<</span> <span class="string">": "</span> <span class="special"><<</span> <span class="identifier">it</span><span class="special">-></span><span class="identifier">value</span><span class="special">()</span> <span class="special"><<</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