1//
2// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
3//
4// Distributed under the Boost Software License, Version 1.0. (See accompanying
5// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6//
7// Official repository: https://github.com/boostorg/beast
8//
9
10// Test that header file is self-contained.
11#include <boost/beast/http/chunk_encode.hpp>
12
13#include "message_fuzz.hpp"
14
15#include <boost/beast/core/buffers_to_string.hpp>
16#include <boost/beast/core/static_string.hpp>
17#include <boost/beast/http/fields.hpp>
18#include <boost/beast/test/fuzz.hpp>
19#include <boost/beast/_experimental/unit_test/suite.hpp>
20#include <boost/optional.hpp>
21#include <random>
22
23namespace boost {
24namespace beast {
25namespace http {
26
27class chunk_encode_test
28 : public beast::unit_test::suite
29{
30public:
31 struct not_chunk_extensions {};
32
33 BOOST_STATIC_ASSERT(
34 detail::is_chunk_extensions<chunk_extensions>::value);
35
36 BOOST_STATIC_ASSERT(
37 ! detail::is_chunk_extensions<not_chunk_extensions>::value);
38
39 template<class T, class... Args>
40 void
41 check(string_view match, Args&&... args)
42 {
43 T t(std::forward<Args>(args)...);
44 BEAST_EXPECT(buffers_to_string(t) == match);
45 T t2(t);
46 BEAST_EXPECT(buffers_to_string(t2) == match);
47 T t3(std::move(t2));
48 BEAST_EXPECT(buffers_to_string(t3) == match);
49 }
50
51 template<class T, class... Args>
52 void
53 check_fwd(string_view match, Args&&... args)
54 {
55 T t(std::forward<Args>(args)...);
56 BEAST_EXPECT(buffers_to_string(t) == match);
57 T t2(t);
58 BEAST_EXPECT(buffers_to_string(t2) == match);
59 T t3(std::move(t2));
60 BEAST_EXPECT(buffers_to_string(t3) == match);
61 }
62
63 using cb_t = net::const_buffer;
64
65 static
66 cb_t
67 cb(string_view s)
68 {
69 return {s.data(), s.size()};
70 }
71
72 void
73 testChunkCRLF()
74 {
75 #if ! defined(BOOST_GCC) || BOOST_GCC >= 50000
76 check<chunk_crlf>(match: "\r\n");
77 #endif
78 }
79
80 void
81 testChunkHeader()
82 {
83 check<chunk_header>(match: "10\r\n", args: 16u);
84
85 check<chunk_header>(match: "20;x\r\n", args: 32u, args: ";x");
86
87 chunk_extensions exts;
88 exts.insert(name: "y");
89 exts.insert(name: "z");
90
91 check<chunk_header>(match: "30;y;z\r\n", args: 48u, args&: exts);
92
93 {
94 auto exts2 = exts;
95
96 check_fwd<chunk_header>(
97 match: "30;y;z\r\n", args: 48u, args: std::move(exts2));
98 }
99
100 check<chunk_header>(match: "30;y;z\r\n", args: 48u, args&: exts,
101 args: std::allocator<double>{});
102
103 {
104 auto exts2 = exts;
105
106 check<chunk_header>(
107 match: "30;y;z\r\n", args: 48u, args: std::move(exts2),
108 args: std::allocator<double>{});
109 }
110 }
111
112 void
113 testChunkBody()
114 {
115 check<chunk_body<cb_t>>(
116 match: "3\r\n***\r\n", args: cb(s: "***"));
117
118 check<chunk_body<cb_t>>(
119 match: "3;x\r\n***\r\n", args: cb(s: "***"), args: ";x");
120
121 chunk_extensions exts;
122 exts.insert(name: "y");
123 exts.insert(name: "z");
124
125 check<chunk_body<cb_t>>(
126 match: "3;y;z\r\n***\r\n",
127 args: cb(s: "***"), args&: exts);
128
129 {
130 auto exts2 = exts;
131
132 check_fwd<chunk_body<cb_t>>(
133 match: "3;y;z\r\n***\r\n",
134 args: cb(s: "***"), args: std::move(exts2));
135 }
136
137 check<chunk_body<cb_t>>(
138 match: "3;y;z\r\n***\r\n",
139 args: cb(s: "***"), args&: exts, args: std::allocator<double>{});
140
141 {
142 auto exts2 = exts;
143
144 check_fwd<chunk_body<cb_t>>(
145 match: "3;y;z\r\n***\r\n",
146 args: cb(s: "***"), args: std::move(exts2),
147 args: std::allocator<double>{});
148 }
149 }
150
151 void
152 testChunkFinal()
153 {
154 check<chunk_last<>>(
155 match: "0\r\n\r\n");
156
157 check<chunk_last<cb_t>>(
158 match: "0\r\nMD5:ou812\r\n\r\n",
159 args: cb(s: "MD5:ou812\r\n\r\n"));
160
161 fields trailers;
162 trailers.set(name: field::content_md5, value: "ou812");
163
164 check<chunk_last<fields>>(
165 match: "0\r\nContent-MD5: ou812\r\n\r\n",
166 args&: trailers);
167
168 {
169 auto trailers2 = trailers;
170
171 check_fwd<chunk_last<fields>>(
172 match: "0\r\nContent-MD5: ou812\r\n\r\n",
173 args: std::move(trailers2));
174 }
175
176 check<chunk_last<fields>>(
177 match: "0\r\nContent-MD5: ou812\r\n\r\n",
178 args&: trailers, args: std::allocator<double>{});
179
180 {
181 auto trailers2 = trailers;
182
183 check<chunk_last<fields>>(
184 match: "0\r\nContent-MD5: ou812\r\n\r\n",
185 args: std::move(trailers2), args: std::allocator<double>{});
186 }
187 }
188
189 void
190 testChunkExtensions()
191 {
192 auto const str =
193 [](chunk_extensions const& ce)
194 {
195 std::string s;
196 for(auto const& v : ce)
197 {
198 s.append(str: std::string(v.first));
199 s.push_back(c: ',');
200 if(! v.second.empty())
201 {
202 s.append(str: std::string(v.second));
203 s.push_back(c: ',');
204 }
205 }
206 return s;
207 };
208 chunk_extensions ce;
209 ce.insert(name: "x");
210 BEAST_EXPECT(ce.str() == ";x");
211 BEAST_EXPECT(str(ce) == "x,");
212 ce.insert(name: "y", value: "z");
213 BEAST_EXPECT(ce.str() == ";x;y=z");
214 BEAST_EXPECT(str(ce) == "x,y,z,");
215 ce.insert(name: "z", value: R"(")");
216 BEAST_EXPECT(ce.str() == R"(;x;y=z;z="\"")");
217 BEAST_EXPECT(str(ce) == R"(x,y,z,z,",)");
218 ce.insert(name: "p", value: R"(\)");
219 BEAST_EXPECT(ce.str() == R"(;x;y=z;z="\"";p="\\")");
220 BEAST_EXPECT(str(ce) == R"(x,y,z,z,",p,\,)");
221 ce.insert(name: "q", value: R"(1"2\)");
222 BEAST_EXPECT(ce.str() == R"(;x;y=z;z="\"";p="\\";q="1\"2\\")");
223 BEAST_EXPECT(str(ce) == R"(x,y,z,z,",p,\,q,1"2\,)");
224 }
225
226 void
227 testParseChunkExtensions()
228 {
229 auto const grind =
230 [&](string_view s)
231 {
232 error_code ec;
233 static_string<200> ss(s.data(), s.size());
234 test::fuzz_rand r;
235 for(auto i = 3; i--;)
236 {
237 test::fuzz(ss, 5, 5, r,
238 [&](string_view s)
239 {
240 chunk_extensions c1;
241 c1.parse(s, ec);
242 if(ec)
243 {
244 pass();
245 return;
246 }
247 chunk_extensions c2;
248 c2.parse(c1.str(), ec);
249 if(! BEAST_EXPECTS(! ec, ec.message()))
250 return;
251 chunk_extensions c3;
252 for(auto const& v : c2)
253 if(v.second.empty())
254 c3.insert(v.first);
255 else
256 c3.insert(v.first, v.second);
257 BEAST_EXPECTS(c2.str() == c3.str(), c3.str());
258 });
259 }
260 };
261 auto const good =
262 [&](string_view s)
263 {
264 error_code ec;
265 chunk_extensions ce;
266 ce.parse(s, ec);
267 BEAST_EXPECTS(! ec, ec.message());
268 grind(s);
269 };
270 auto const bad =
271 [&](string_view s)
272 {
273 error_code ec;
274 chunk_extensions ce;
275 ce.parse(s, ec);
276 BEAST_EXPECT(ec);
277 grind(s);
278 };
279 chunkExtensionsTest(good, bad);
280 }
281
282 void
283 run() override
284 {
285 testChunkCRLF();
286 testChunkHeader();
287 testChunkBody();
288 testChunkFinal();
289 testChunkExtensions();
290 testParseChunkExtensions();
291 }
292};
293
294BEAST_DEFINE_TESTSUITE(beast,http,chunk_encode);
295
296} // http
297} // beast
298} // boost
299

source code of boost/libs/beast/test/beast/http/chunk_encode.cpp