]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/beast/test/beast/websocket/write.cpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / libs / beast / test / beast / websocket / write.cpp
1 //
2 // Copyright (w) 2016-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 // Official repository: https://github.com/boostorg/beast
8 //
9
10 // Test that header file is self-contained.
11 #include <boost/beast/websocket/stream.hpp>
12
13 #include "test.hpp"
14
15 namespace boost {
16 namespace beast {
17 namespace websocket {
18
19 class write_test : public websocket_test_suite
20 {
21 public:
22 template<class Wrap>
23 void
24 doTestWrite(Wrap const& w)
25 {
26 using boost::asio::buffer;
27
28 permessage_deflate pmd;
29 pmd.client_enable = false;
30 pmd.server_enable = false;
31
32 // already closed
33 {
34 echo_server es{log};
35 stream<test::stream> ws{ioc_};
36 ws.next_layer().connect(es.stream());
37 ws.handshake("localhost", "/");
38 ws.close({});
39 try
40 {
41 w.write(ws, sbuf(""));
42 fail("", __FILE__, __LINE__);
43 }
44 catch(system_error const& se)
45 {
46 BEAST_EXPECTS(
47 se.code() == boost::asio::error::operation_aborted,
48 se.code().message());
49 }
50 }
51
52 // message
53 doTest(pmd, [&](ws_type& ws)
54 {
55 ws.auto_fragment(false);
56 ws.binary(false);
57 std::string const s = "Hello, world!";
58 w.write(ws, buffer(s));
59 multi_buffer b;
60 w.read(ws, b);
61 BEAST_EXPECT(ws.got_text());
62 BEAST_EXPECT(to_string(b.data()) == s);
63 });
64
65 // empty message
66 doTest(pmd, [&](ws_type& ws)
67 {
68 ws.text(true);
69 w.write(ws, boost::asio::null_buffers{});
70 multi_buffer b;
71 w.read(ws, b);
72 BEAST_EXPECT(ws.got_text());
73 BEAST_EXPECT(b.size() == 0);
74 });
75
76 // fragmented message
77 doTest(pmd, [&](ws_type& ws)
78 {
79 ws.auto_fragment(false);
80 ws.binary(false);
81 std::string const s = "Hello, world!";
82 w.write_some(ws, false, buffer(s.data(), 5));
83 w.write_some(ws, true, buffer(s.data() + 5, s.size() - 5));
84 multi_buffer b;
85 w.read(ws, b);
86 BEAST_EXPECT(ws.got_text());
87 BEAST_EXPECT(to_string(b.data()) == s);
88 });
89
90 // continuation
91 doTest(pmd, [&](ws_type& ws)
92 {
93 std::string const s = "Hello";
94 std::size_t const chop = 3;
95 BOOST_ASSERT(chop < s.size());
96 w.write_some(ws, false,
97 buffer(s.data(), chop));
98 w.write_some(ws, true, buffer(
99 s.data() + chop, s.size() - chop));
100 flat_buffer b;
101 w.read(ws, b);
102 BEAST_EXPECT(to_string(b.data()) == s);
103 });
104
105 // mask
106 doTest(pmd, [&](ws_type& ws)
107 {
108 ws.auto_fragment(false);
109 std::string const s = "Hello";
110 w.write(ws, buffer(s));
111 flat_buffer b;
112 w.read(ws, b);
113 BEAST_EXPECT(to_string(b.data()) == s);
114 });
115
116 // mask (large)
117 doTest(pmd, [&](ws_type& ws)
118 {
119 ws.auto_fragment(false);
120 ws.write_buffer_size(16);
121 std::string const s(32, '*');
122 w.write(ws, buffer(s));
123 flat_buffer b;
124 w.read(ws, b);
125 BEAST_EXPECT(to_string(b.data()) == s);
126 });
127
128 // mask, autofrag
129 doTest(pmd, [&](ws_type& ws)
130 {
131 ws.auto_fragment(true);
132 std::string const s(16384, '*');
133 w.write(ws, buffer(s));
134 flat_buffer b;
135 w.read(ws, b);
136 BEAST_EXPECT(to_string(b.data()) == s);
137 });
138
139 // nomask
140 doStreamLoop([&](test::stream& ts)
141 {
142 echo_server es{log, kind::async_client};
143 ws_type ws{ts};
144 ws.next_layer().connect(es.stream());
145 try
146 {
147 es.async_handshake();
148 w.accept(ws);
149 ws.auto_fragment(false);
150 std::string const s = "Hello";
151 w.write(ws, buffer(s));
152 flat_buffer b;
153 w.read(ws, b);
154 BEAST_EXPECT(to_string(b.data()) == s);
155 w.close(ws, {});
156 }
157 catch(...)
158 {
159 ts.close();
160 throw;
161 }
162 ts.close();
163 });
164
165 // nomask, autofrag
166 doStreamLoop([&](test::stream& ts)
167 {
168 echo_server es{log, kind::async_client};
169 ws_type ws{ts};
170 ws.next_layer().connect(es.stream());
171 try
172 {
173 es.async_handshake();
174 w.accept(ws);
175 ws.auto_fragment(true);
176 std::string const s(16384, '*');
177 w.write(ws, buffer(s));
178 flat_buffer b;
179 w.read(ws, b);
180 BEAST_EXPECT(to_string(b.data()) == s);
181 w.close(ws, {});
182 }
183 catch(...)
184 {
185 ts.close();
186 throw;
187 }
188 ts.close();
189 });
190
191 pmd.client_enable = true;
192 pmd.server_enable = true;
193 pmd.compLevel = 1;
194
195 // deflate
196 doTest(pmd, [&](ws_type& ws)
197 {
198 auto const& s = random_string();
199 ws.binary(true);
200 w.write(ws, buffer(s));
201 flat_buffer b;
202 w.read(ws, b);
203 BEAST_EXPECT(to_string(b.data()) == s);
204 });
205
206 // deflate, continuation
207 doTest(pmd, [&](ws_type& ws)
208 {
209 std::string const s = "Hello";
210 std::size_t const chop = 3;
211 BOOST_ASSERT(chop < s.size());
212 // This call should produce no
213 // output due to compression latency.
214 w.write_some(ws, false,
215 buffer(s.data(), chop));
216 w.write_some(ws, true, buffer(
217 s.data() + chop, s.size() - chop));
218 flat_buffer b;
219 w.read(ws, b);
220 BEAST_EXPECT(to_string(b.data()) == s);
221 });
222
223 // deflate, no context takeover
224 pmd.client_no_context_takeover = true;
225 doTest(pmd, [&](ws_type& ws)
226 {
227 auto const& s = random_string();
228 ws.binary(true);
229 w.write(ws, buffer(s));
230 flat_buffer b;
231 w.read(ws, b);
232 BEAST_EXPECT(to_string(b.data()) == s);
233 });
234 }
235
236 void
237 testWrite()
238 {
239 using boost::asio::buffer;
240
241 doTestWrite(SyncClient{});
242
243 yield_to([&](yield_context yield)
244 {
245 doTestWrite(AsyncClient{yield});
246 });
247 }
248
249 void
250 testWriteSuspend()
251 {
252 using boost::asio::buffer;
253
254 // suspend on ping
255 doFailLoop([&](test::fail_counter& fc)
256 {
257 echo_server es{log};
258 boost::asio::io_context ioc;
259 stream<test::stream> ws{ioc, fc};
260 ws.next_layer().connect(es.stream());
261 ws.handshake("localhost", "/");
262 std::size_t count = 0;
263 ws.async_ping("",
264 [&](error_code ec)
265 {
266 ++count;
267 if(ec)
268 BOOST_THROW_EXCEPTION(
269 system_error{ec});
270 });
271 BEAST_EXPECT(ws.wr_block_);
272 BEAST_EXPECT(count == 0);
273 ws.async_write(sbuf("*"),
274 [&](error_code ec, std::size_t n)
275 {
276 ++count;
277 if(ec)
278 BOOST_THROW_EXCEPTION(
279 system_error{ec});
280 BEAST_EXPECT(n == 1);
281 });
282 BEAST_EXPECT(count == 0);
283 ioc.run();
284 BEAST_EXPECT(count == 2);
285 });
286
287 // suspend on close
288 doFailLoop([&](test::fail_counter& fc)
289 {
290 echo_server es{log};
291 boost::asio::io_context ioc;
292 stream<test::stream> ws{ioc, fc};
293 ws.next_layer().connect(es.stream());
294 ws.handshake("localhost", "/");
295 std::size_t count = 0;
296 ws.async_close({},
297 [&](error_code ec)
298 {
299 ++count;
300 if(ec)
301 BOOST_THROW_EXCEPTION(
302 system_error{ec});
303 });
304 BEAST_EXPECT(ws.wr_block_);
305 BEAST_EXPECT(count == 0);
306 ws.async_write(sbuf("*"),
307 [&](error_code ec, std::size_t)
308 {
309 ++count;
310 if(ec != boost::asio::error::operation_aborted)
311 BOOST_THROW_EXCEPTION(
312 system_error{ec});
313 });
314 BEAST_EXPECT(count == 0);
315 ioc.run();
316 BEAST_EXPECT(count == 2);
317 });
318
319 // suspend on read ping + message
320 doFailLoop([&](test::fail_counter& fc)
321 {
322 echo_server es{log};
323 boost::asio::io_context ioc;
324 stream<test::stream> ws{ioc, fc};
325 ws.next_layer().connect(es.stream());
326 ws.handshake("localhost", "/");
327 // add a ping and message to the input
328 ws.next_layer().append(string_view{
329 "\x89\x00" "\x81\x01*", 5});
330 std::size_t count = 0;
331 multi_buffer b;
332 ws.async_read(b,
333 [&](error_code ec, std::size_t)
334 {
335 ++count;
336 if(ec)
337 BOOST_THROW_EXCEPTION(
338 system_error{ec});
339 });
340 while(! ws.wr_block_)
341 {
342 ioc.run_one();
343 if(! BEAST_EXPECT(! ioc.stopped()))
344 break;
345 }
346 BEAST_EXPECT(count == 0);
347 ws.async_write(sbuf("*"),
348 [&](error_code ec, std::size_t n)
349 {
350 ++count;
351 if(ec)
352 BOOST_THROW_EXCEPTION(
353 system_error{ec});
354 BEAST_EXPECT(n == 1);
355 });
356 BEAST_EXPECT(count == 0);
357 ioc.run();
358 BEAST_EXPECT(count == 2);
359 });
360
361 // suspend on ping: nomask, nofrag
362 doFailLoop([&](test::fail_counter& fc)
363 {
364 echo_server es{log, kind::async_client};
365 boost::asio::io_context ioc;
366 stream<test::stream> ws{ioc, fc};
367 ws.next_layer().connect(es.stream());
368 es.async_handshake();
369 ws.accept();
370 std::size_t count = 0;
371 std::string const s(16384, '*');
372 ws.auto_fragment(false);
373 ws.async_write(buffer(s),
374 [&](error_code ec, std::size_t n)
375 {
376 ++count;
377 if(ec)
378 BOOST_THROW_EXCEPTION(
379 system_error{ec});
380 BEAST_EXPECT(n == 16384);
381 });
382 BEAST_EXPECT(ws.wr_block_);
383 ws.async_ping("",
384 [&](error_code ec)
385 {
386 ++count;
387 if(ec)
388 BOOST_THROW_EXCEPTION(
389 system_error{ec});
390 });
391 ioc.run();
392 BEAST_EXPECT(count == 2);
393 });
394
395 // suspend on ping: nomask, frag
396 doFailLoop([&](test::fail_counter& fc)
397 {
398 echo_server es{log, kind::async_client};
399 boost::asio::io_context ioc;
400 stream<test::stream> ws{ioc, fc};
401 ws.next_layer().connect(es.stream());
402 es.async_handshake();
403 ws.accept();
404 std::size_t count = 0;
405 std::string const s(16384, '*');
406 ws.auto_fragment(true);
407 ws.async_write(buffer(s),
408 [&](error_code ec, std::size_t n)
409 {
410 ++count;
411 if(ec)
412 BOOST_THROW_EXCEPTION(
413 system_error{ec});
414 BEAST_EXPECT(n == 16384);
415 });
416 BEAST_EXPECT(ws.wr_block_);
417 ws.async_ping("",
418 [&](error_code ec)
419 {
420 ++count;
421 if(ec)
422 BOOST_THROW_EXCEPTION(
423 system_error{ec});
424 });
425 ioc.run();
426 BEAST_EXPECT(count == 2);
427 });
428
429 // suspend on ping: mask, nofrag
430 doFailLoop([&](test::fail_counter& fc)
431 {
432 echo_server es{log};
433 error_code ec;
434 boost::asio::io_context ioc;
435 stream<test::stream> ws{ioc, fc};
436 ws.next_layer().connect(es.stream());
437 ws.handshake("localhost", "/");
438 std::size_t count = 0;
439 std::string const s(16384, '*');
440 ws.auto_fragment(false);
441 ws.async_write(buffer(s),
442 [&](error_code ec, std::size_t n)
443 {
444 ++count;
445 if(ec)
446 BOOST_THROW_EXCEPTION(
447 system_error{ec});
448 BEAST_EXPECT(n == 16384);
449 });
450 BEAST_EXPECT(ws.wr_block_);
451 ws.async_ping("",
452 [&](error_code ec)
453 {
454 ++count;
455 if(ec)
456 BOOST_THROW_EXCEPTION(
457 system_error{ec});
458 });
459 ioc.run();
460 });
461
462 // suspend on ping: mask, frag
463 doFailLoop([&](test::fail_counter& fc)
464 {
465 echo_server es{log};
466 error_code ec;
467 boost::asio::io_context ioc;
468 stream<test::stream> ws{ioc, fc};
469 ws.next_layer().connect(es.stream());
470 ws.handshake("localhost", "/");
471 std::size_t count = 0;
472 std::string const s(16384, '*');
473 ws.auto_fragment(true);
474 ws.async_write(buffer(s),
475 [&](error_code ec, std::size_t n)
476 {
477 ++count;
478 if(ec)
479 BOOST_THROW_EXCEPTION(
480 system_error{ec});
481 BEAST_EXPECT(n == 16384);
482 });
483 BEAST_EXPECT(ws.wr_block_);
484 ws.async_ping("",
485 [&](error_code ec)
486 {
487 ++count;
488 if(ec)
489 BOOST_THROW_EXCEPTION(
490 system_error{ec});
491 });
492 ioc.run();
493 });
494
495 // suspend on ping: deflate
496 doFailLoop([&](test::fail_counter& fc)
497 {
498 echo_server es{log, kind::async};
499 boost::asio::io_context ioc;
500 stream<test::stream> ws{ioc, fc};
501 {
502 permessage_deflate pmd;
503 pmd.client_enable = true;
504 pmd.compLevel = 1;
505 ws.set_option(pmd);
506 }
507 ws.next_layer().connect(es.stream());
508 ws.handshake("localhost", "/");
509 std::size_t count = 0;
510 auto const& s = random_string();
511 ws.binary(true);
512 ws.async_write(buffer(s),
513 [&](error_code ec, std::size_t n)
514 {
515 ++count;
516 if(ec)
517 BOOST_THROW_EXCEPTION(
518 system_error{ec});
519 BEAST_EXPECT(n == s.size());
520 });
521 BEAST_EXPECT(ws.wr_block_);
522 ws.async_ping("",
523 [&](error_code ec)
524 {
525 ++count;
526 if(ec)
527 BOOST_THROW_EXCEPTION(
528 system_error{ec});
529 });
530 ioc.run();
531 });
532 }
533
534 void
535 testAsyncWriteFrame()
536 {
537 for(int i = 0; i < 2; ++i)
538 {
539 for(;;)
540 {
541 echo_server es{log, i==1 ?
542 kind::async : kind::sync};
543 boost::asio::io_context ioc;
544 stream<test::stream> ws{ioc};
545 ws.next_layer().connect(es.stream());
546
547 error_code ec;
548 ws.handshake("localhost", "/", ec);
549 if(! BEAST_EXPECTS(! ec, ec.message()))
550 break;
551 ws.async_write_some(false,
552 boost::asio::null_buffers{},
553 [&](error_code, std::size_t)
554 {
555 fail();
556 });
557 if(! BEAST_EXPECTS(! ec, ec.message()))
558 break;
559 //
560 // Destruction of the io_context will cause destruction
561 // of the write_some_op without invoking the final handler.
562 //
563 break;
564 }
565 }
566 }
567
568 /*
569 https://github.com/boostorg/beast/issues/300
570
571 Write a message as two individual frames
572 */
573 void
574 testIssue300()
575 {
576 for(int i = 0; i < 2; ++i )
577 {
578 echo_server es{log, i==1 ?
579 kind::async : kind::sync};
580 boost::asio::io_context ioc;
581 stream<test::stream> ws{ioc};
582 ws.next_layer().connect(es.stream());
583
584 error_code ec;
585 ws.handshake("localhost", "/", ec);
586 if(! BEAST_EXPECTS(! ec, ec.message()))
587 return;
588 ws.write_some(false, sbuf("u"));
589 ws.write_some(true, sbuf("v"));
590 multi_buffer b;
591 ws.read(b, ec);
592 BEAST_EXPECTS(! ec, ec.message());
593 }
594 }
595
596 void
597 testContHook()
598 {
599 struct handler
600 {
601 void operator()(error_code) {}
602 };
603
604 char buf[32];
605 stream<test::stream> ws{ioc_};
606 stream<test::stream>::write_some_op<
607 boost::asio::const_buffer,
608 handler> op{handler{}, ws, true,
609 boost::asio::const_buffer{
610 buf, sizeof(buf)}};
611 using boost::asio::asio_handler_is_continuation;
612 asio_handler_is_continuation(&op);
613 }
614
615 void
616 run() override
617 {
618 testWrite();
619 testWriteSuspend();
620 testAsyncWriteFrame();
621 testIssue300();
622 testContHook();
623 }
624 };
625
626 BEAST_DEFINE_TESTSUITE(beast,websocket,write);
627
628 } // websocket
629 } // beast
630 } // boost