]> git.proxmox.com Git - ceph.git/blob - ceph/src/Beast/test/http/read.cpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / Beast / test / http / read.cpp
1 //
2 // Copyright (c) 2013-2017 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
8 // Test that header file is self-contained.
9 #include <beast/http/read.hpp>
10
11 #include "test_parser.hpp"
12
13 #include <beast/http/fields.hpp>
14 #include <beast/http/header_parser.hpp>
15 #include <beast/http/streambuf_body.hpp>
16 #include <beast/http/string_body.hpp>
17 #include <beast/test/fail_stream.hpp>
18 #include <beast/test/string_istream.hpp>
19 #include <beast/test/yield_to.hpp>
20 #include <beast/unit_test/suite.hpp>
21 #include <boost/asio/spawn.hpp>
22 #include <atomic>
23
24 namespace beast {
25 namespace http {
26
27 class read_test
28 : public beast::unit_test::suite
29 , public test::enable_yield_to
30 {
31 public:
32 template<bool isRequest>
33 void
34 failMatrix(char const* s, yield_context do_yield)
35 {
36 using boost::asio::buffer;
37 using boost::asio::buffer_copy;
38 static std::size_t constexpr limit = 100;
39 std::size_t n;
40 auto const len = strlen(s);
41 for(n = 0; n < limit; ++n)
42 {
43 streambuf sb;
44 sb.commit(buffer_copy(
45 sb.prepare(len), buffer(s, len)));
46 test::fail_counter fc(n);
47 test::fail_stream<
48 test::string_istream> fs{fc, ios_, ""};
49 test_parser<isRequest> p(fc);
50 error_code ec;
51 read(fs, sb, p, ec);
52 if(! ec)
53 break;
54 }
55 BEAST_EXPECT(n < limit);
56 for(n = 0; n < limit; ++n)
57 {
58 static std::size_t constexpr pre = 10;
59 streambuf sb;
60 sb.commit(buffer_copy(
61 sb.prepare(pre), buffer(s, pre)));
62 test::fail_counter fc(n);
63 test::fail_stream<test::string_istream> fs{
64 fc, ios_, std::string{s + pre, len - pre}};
65 test_parser<isRequest> p(fc);
66 error_code ec;
67 read(fs, sb, p, ec);
68 if(! ec)
69 break;
70 }
71 BEAST_EXPECT(n < limit);
72 for(n = 0; n < limit; ++n)
73 {
74 streambuf sb;
75 sb.commit(buffer_copy(
76 sb.prepare(len), buffer(s, len)));
77 test::fail_counter fc(n);
78 test::fail_stream<
79 test::string_istream> fs{fc, ios_, ""};
80 test_parser<isRequest> p(fc);
81 error_code ec;
82 async_read(fs, sb, p, do_yield[ec]);
83 if(! ec)
84 break;
85 }
86 BEAST_EXPECT(n < limit);
87 for(n = 0; n < limit; ++n)
88 {
89 static std::size_t constexpr pre = 10;
90 streambuf sb;
91 sb.commit(buffer_copy(
92 sb.prepare(pre), buffer(s, pre)));
93 test::fail_counter fc(n);
94 test::fail_stream<test::string_istream> fs{
95 fc, ios_, std::string{s + pre, len - pre}};
96 test_parser<isRequest> p(fc);
97 error_code ec;
98 async_read(fs, sb, p, do_yield[ec]);
99 if(! ec)
100 break;
101 }
102 BEAST_EXPECT(n < limit);
103 }
104
105 void testThrow()
106 {
107 try
108 {
109 streambuf sb;
110 test::string_istream ss(ios_, "GET / X");
111 message_parser<true, streambuf_body, fields> p;
112 read(ss, sb, p);
113 fail();
114 }
115 catch(std::exception const&)
116 {
117 pass();
118 }
119 }
120
121 void testFailures(yield_context do_yield)
122 {
123 char const* req[] = {
124 "GET / HTTP/1.0\r\n"
125 "Host: localhost\r\n"
126 "User-Agent: test\r\n"
127 "Empty:\r\n"
128 "\r\n"
129 ,
130 "GET / HTTP/1.1\r\n"
131 "Host: localhost\r\n"
132 "User-Agent: test\r\n"
133 "Content-Length: 2\r\n"
134 "\r\n"
135 "**"
136 ,
137 "GET / HTTP/1.1\r\n"
138 "Host: localhost\r\n"
139 "User-Agent: test\r\n"
140 "Transfer-Encoding: chunked\r\n"
141 "\r\n"
142 "10\r\n"
143 "****************\r\n"
144 "0\r\n\r\n"
145 ,
146 nullptr
147 };
148
149 char const* res[] = {
150 "HTTP/1.0 200 OK\r\n"
151 "Server: test\r\n"
152 "\r\n"
153 ,
154 "HTTP/1.0 200 OK\r\n"
155 "Server: test\r\n"
156 "\r\n"
157 "***"
158 ,
159 "HTTP/1.1 200 OK\r\n"
160 "Server: test\r\n"
161 "Content-Length: 3\r\n"
162 "\r\n"
163 "***"
164 ,
165 "HTTP/1.1 200 OK\r\n"
166 "Server: test\r\n"
167 "Transfer-Encoding: chunked\r\n"
168 "\r\n"
169 "10\r\n"
170 "****************\r\n"
171 "0\r\n\r\n"
172 ,
173 nullptr
174 };
175
176 for(std::size_t i = 0; req[i]; ++i)
177 failMatrix<true>(req[i], do_yield);
178
179 for(std::size_t i = 0; res[i]; ++i)
180 failMatrix<false>(res[i], do_yield);
181 }
182
183 void testRead(yield_context do_yield)
184 {
185 static std::size_t constexpr limit = 100;
186 std::size_t n;
187
188 for(n = 0; n < limit; ++n)
189 {
190 test::fail_stream<test::string_istream> fs(n, ios_,
191 "GET / HTTP/1.1\r\n"
192 "Host: localhost\r\n"
193 "User-Agent: test\r\n"
194 "Content-Length: 0\r\n"
195 "\r\n"
196 );
197 request<streambuf_body> m;
198 try
199 {
200 streambuf sb;
201 read(fs, sb, m);
202 break;
203 }
204 catch(std::exception const&)
205 {
206 }
207 }
208 BEAST_EXPECT(n < limit);
209
210 for(n = 0; n < limit; ++n)
211 {
212 test::fail_stream<test::string_istream> fs(n, ios_,
213 "GET / HTTP/1.1\r\n"
214 "Host: localhost\r\n"
215 "User-Agent: test\r\n"
216 "Content-Length: 0\r\n"
217 "\r\n"
218 );
219 request<streambuf_body> m;
220 error_code ec;
221 streambuf sb;
222 read(fs, sb, m, ec);
223 if(! ec)
224 break;
225 }
226 BEAST_EXPECT(n < limit);
227
228 for(n = 0; n < limit; ++n)
229 {
230 test::fail_stream<test::string_istream> fs(n, ios_,
231 "GET / HTTP/1.1\r\n"
232 "Host: localhost\r\n"
233 "User-Agent: test\r\n"
234 "Content-Length: 0\r\n"
235 "\r\n"
236 );
237 request<streambuf_body> m;
238 error_code ec;
239 streambuf sb;
240 async_read(fs, sb, m, do_yield[ec]);
241 if(! ec)
242 break;
243 }
244 BEAST_EXPECT(n < limit);
245 }
246
247 void
248 testEof(yield_context do_yield)
249 {
250 {
251 streambuf sb;
252 test::string_istream ss(ios_, "");
253 message_parser<true, streambuf_body, fields> p;
254 error_code ec;
255 read(ss, sb, p, ec);
256 BEAST_EXPECT(ec == boost::asio::error::eof);
257 }
258 {
259 streambuf sb;
260 test::string_istream ss(ios_, "");
261 message_parser<true, streambuf_body, fields> p;
262 error_code ec;
263 async_read(ss, sb, p, do_yield[ec]);
264 BEAST_EXPECT(ec == boost::asio::error::eof);
265 }
266 }
267
268 // Ensure completion handlers are not leaked
269 struct handler
270 {
271 static std::atomic<std::size_t>&
272 count() { static std::atomic<std::size_t> n; return n; }
273 handler() { ++count(); }
274 ~handler() { --count(); }
275 handler(handler const&) { ++count(); }
276 void operator()(error_code const&) const {}
277 };
278
279 void
280 testIoService()
281 {
282 {
283 // Make sure handlers are not destroyed
284 // after calling io_service::stop
285 boost::asio::io_service ios;
286 test::string_istream is{ios,
287 "GET / HTTP/1.1\r\n\r\n"};
288 BEAST_EXPECT(handler::count() == 0);
289 streambuf sb;
290 message<true, streambuf_body, fields> m;
291 async_read(is, sb, m, handler{});
292 BEAST_EXPECT(handler::count() > 0);
293 ios.stop();
294 BEAST_EXPECT(handler::count() > 0);
295 ios.reset();
296 BEAST_EXPECT(handler::count() > 0);
297 ios.run_one();
298 BEAST_EXPECT(handler::count() == 0);
299 }
300 {
301 // Make sure uninvoked handlers are
302 // destroyed when calling ~io_service
303 {
304 boost::asio::io_service ios;
305 test::string_istream is{ios,
306 "GET / HTTP/1.1\r\n\r\n"};
307 BEAST_EXPECT(handler::count() == 0);
308 streambuf sb;
309 message<true, streambuf_body, fields> m;
310 async_read(is, sb, m, handler{});
311 BEAST_EXPECT(handler::count() > 0);
312 }
313 BEAST_EXPECT(handler::count() == 0);
314 }
315 }
316
317 void
318 run() override
319 {
320 testThrow();
321
322 yield_to(&read_test::testFailures, this);
323 yield_to(&read_test::testRead, this);
324 yield_to(&read_test::testEof, this);
325
326 testIoService();
327 }
328 };
329
330 BEAST_DEFINE_TESTSUITE(read,http,beast);
331
332 } // http
333 } // beast