]>
Commit | Line | Data |
---|---|---|
b32b8144 | 1 | // |
92f5a8d4 | 2 | // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) |
b32b8144 FG |
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 | ||
92f5a8d4 TL |
13 | #include <boost/beast/_experimental/test/stream.hpp> |
14 | #include <boost/beast/_experimental/test/tcp.hpp> | |
b32b8144 FG |
15 | #include "test.hpp" |
16 | ||
92f5a8d4 | 17 | #include <boost/asio/io_context.hpp> |
11fdf7f2 TL |
18 | #include <boost/asio/strand.hpp> |
19 | ||
b32b8144 FG |
20 | namespace boost { |
21 | namespace beast { | |
22 | namespace websocket { | |
23 | ||
24 | class close_test : public websocket_test_suite | |
25 | { | |
26 | public: | |
27 | template<class Wrap> | |
28 | void | |
29 | doTestClose(Wrap const& w) | |
30 | { | |
31 | permessage_deflate pmd; | |
32 | pmd.client_enable = false; | |
33 | pmd.server_enable = false; | |
34 | ||
35 | // close | |
36 | doTest(pmd, [&](ws_type& ws) | |
37 | { | |
38 | w.close(ws, {}); | |
39 | }); | |
40 | ||
41 | // close with code | |
42 | doTest(pmd, [&](ws_type& ws) | |
43 | { | |
44 | w.close(ws, close_code::going_away); | |
45 | }); | |
46 | ||
47 | // close with code and reason | |
48 | doTest(pmd, [&](ws_type& ws) | |
49 | { | |
50 | w.close(ws, { | |
51 | close_code::going_away, | |
52 | "going away"}); | |
53 | }); | |
54 | ||
55 | // already closed | |
56 | { | |
57 | echo_server es{log}; | |
58 | stream<test::stream> ws{ioc_}; | |
59 | ws.next_layer().connect(es.stream()); | |
60 | w.handshake(ws, "localhost", "/"); | |
61 | w.close(ws, {}); | |
62 | try | |
63 | { | |
64 | w.close(ws, {}); | |
65 | fail("", __FILE__, __LINE__); | |
66 | } | |
67 | catch(system_error const& se) | |
68 | { | |
69 | BEAST_EXPECTS( | |
92f5a8d4 | 70 | se.code() == net::error::operation_aborted, |
b32b8144 FG |
71 | se.code().message()); |
72 | } | |
73 | } | |
74 | ||
75 | // drain a message after close | |
76 | doTest(pmd, [&](ws_type& ws) | |
77 | { | |
78 | ws.next_layer().append("\x81\x01\x2a"); | |
79 | w.close(ws, {}); | |
80 | }); | |
81 | ||
82 | // drain a big message after close | |
83 | { | |
84 | std::string s; | |
85 | s = "\x81\x7e\x10\x01"; | |
86 | s.append(4097, '*'); | |
87 | doTest(pmd, [&](ws_type& ws) | |
88 | { | |
89 | ws.next_layer().append(s); | |
90 | w.close(ws, {}); | |
91 | }); | |
92 | } | |
93 | ||
94 | // drain a ping after close | |
95 | doTest(pmd, [&](ws_type& ws) | |
96 | { | |
97 | ws.next_layer().append("\x89\x01*"); | |
98 | w.close(ws, {}); | |
99 | }); | |
100 | ||
101 | // drain invalid message frame after close | |
102 | { | |
103 | echo_server es{log}; | |
104 | stream<test::stream> ws{ioc_}; | |
105 | ws.next_layer().connect(es.stream()); | |
106 | w.handshake(ws, "localhost", "/"); | |
107 | ws.next_layer().append("\x81\x81\xff\xff\xff\xff*"); | |
108 | try | |
109 | { | |
110 | w.close(ws, {}); | |
111 | fail("", __FILE__, __LINE__); | |
112 | } | |
113 | catch(system_error const& se) | |
114 | { | |
115 | BEAST_EXPECTS( | |
11fdf7f2 | 116 | se.code() == error::bad_masked_frame, |
b32b8144 FG |
117 | se.code().message()); |
118 | } | |
119 | } | |
120 | ||
121 | // drain invalid close frame after close | |
122 | { | |
123 | echo_server es{log}; | |
124 | stream<test::stream> ws{ioc_}; | |
125 | ws.next_layer().connect(es.stream()); | |
126 | w.handshake(ws, "localhost", "/"); | |
127 | ws.next_layer().append("\x88\x01*"); | |
128 | try | |
129 | { | |
130 | w.close(ws, {}); | |
131 | fail("", __FILE__, __LINE__); | |
132 | } | |
133 | catch(system_error const& se) | |
134 | { | |
135 | BEAST_EXPECTS( | |
11fdf7f2 | 136 | se.code() == error::bad_close_size, |
b32b8144 FG |
137 | se.code().message()); |
138 | } | |
139 | } | |
140 | ||
141 | // drain masked close frame | |
142 | { | |
143 | echo_server es{log, kind::async_client}; | |
144 | stream<test::stream> ws{ioc_}; | |
145 | ws.next_layer().connect(es.stream()); | |
146 | ws.set_option(pmd); | |
147 | es.async_handshake(); | |
148 | ws.accept(); | |
149 | w.close(ws, {}); | |
150 | } | |
151 | ||
152 | // close with incomplete read message | |
153 | doTest(pmd, [&](ws_type& ws) | |
154 | { | |
155 | ws.next_layer().append("\x81\x02**"); | |
156 | static_buffer<1> b; | |
157 | w.read_some(ws, 1, b); | |
158 | w.close(ws, {}); | |
159 | }); | |
160 | } | |
161 | ||
162 | void | |
163 | testClose() | |
164 | { | |
165 | doTestClose(SyncClient{}); | |
166 | ||
167 | yield_to([&](yield_context yield) | |
168 | { | |
169 | doTestClose(AsyncClient{yield}); | |
170 | }); | |
171 | } | |
172 | ||
173 | void | |
92f5a8d4 | 174 | testTimeout() |
b32b8144 | 175 | { |
92f5a8d4 TL |
176 | using tcp = net::ip::tcp; |
177 | ||
178 | net::io_context ioc; | |
179 | ||
180 | // success | |
181 | ||
182 | { | |
183 | stream<tcp::socket> ws1(ioc); | |
184 | stream<tcp::socket> ws2(ioc); | |
185 | test::connect(ws1.next_layer(), ws2.next_layer()); | |
186 | ws1.async_handshake("test", "/", test::success_handler()); | |
187 | ws2.async_accept(test::success_handler()); | |
188 | test::run(ioc); | |
189 | ||
190 | ws1.async_close({}, test::success_handler()); | |
191 | ws2.async_close({}, test::success_handler()); | |
192 | test::run(ioc); | |
193 | } | |
194 | ||
195 | { | |
196 | stream<test::stream> ws1(ioc); | |
197 | stream<test::stream> ws2(ioc); | |
198 | test::connect(ws1.next_layer(), ws2.next_layer()); | |
199 | ws1.async_handshake("test", "/", test::success_handler()); | |
200 | ws2.async_accept(test::success_handler()); | |
201 | test::run(ioc); | |
202 | ||
203 | ws1.async_close({}, test::success_handler()); | |
204 | ws2.async_close({}, test::success_handler()); | |
205 | test::run(ioc); | |
206 | } | |
207 | ||
208 | // success, timeout enabled | |
209 | ||
210 | { | |
211 | stream<tcp::socket> ws1(ioc); | |
212 | stream<tcp::socket> ws2(ioc); | |
213 | test::connect(ws1.next_layer(), ws2.next_layer()); | |
214 | ws1.async_handshake("test", "/", test::success_handler()); | |
215 | ws2.async_accept(test::success_handler()); | |
216 | test::run(ioc); | |
217 | ||
218 | ws1.set_option(stream_base::timeout{ | |
219 | std::chrono::milliseconds(50), | |
220 | stream_base::none(), | |
221 | false}); | |
222 | ws1.async_close({}, test::success_handler()); | |
223 | ws2.async_close({}, test::success_handler()); | |
224 | test::run(ioc); | |
225 | } | |
226 | ||
227 | { | |
228 | stream<test::stream> ws1(ioc); | |
229 | stream<test::stream> ws2(ioc); | |
230 | test::connect(ws1.next_layer(), ws2.next_layer()); | |
231 | ws1.async_handshake("test", "/", test::success_handler()); | |
232 | ws2.async_accept(test::success_handler()); | |
233 | test::run(ioc); | |
234 | ||
235 | ws1.set_option(stream_base::timeout{ | |
236 | std::chrono::milliseconds(50), | |
237 | stream_base::none(), | |
238 | false}); | |
239 | ws1.async_close({}, test::success_handler()); | |
240 | ws2.async_close({}, test::success_handler()); | |
241 | test::run(ioc); | |
242 | } | |
b32b8144 | 243 | |
92f5a8d4 TL |
244 | // timeout |
245 | ||
246 | { | |
247 | stream<tcp::socket> ws1(ioc); | |
248 | stream<tcp::socket> ws2(ioc); | |
249 | test::connect(ws1.next_layer(), ws2.next_layer()); | |
250 | ws1.async_handshake("test", "/", test::success_handler()); | |
251 | ws2.async_accept(test::success_handler()); | |
252 | test::run(ioc); | |
253 | ||
254 | ws1.set_option(stream_base::timeout{ | |
255 | std::chrono::milliseconds(50), | |
256 | stream_base::none(), | |
257 | false}); | |
258 | ws1.async_close({}, test::fail_handler( | |
259 | beast::error::timeout)); | |
260 | test::run(ioc); | |
261 | } | |
262 | ||
263 | { | |
264 | stream<test::stream> ws1(ioc); | |
265 | stream<test::stream> ws2(ioc); | |
266 | test::connect(ws1.next_layer(), ws2.next_layer()); | |
267 | ws1.async_handshake("test", "/", test::success_handler()); | |
268 | ws2.async_accept(test::success_handler()); | |
269 | test::run(ioc); | |
270 | ||
271 | ws1.set_option(stream_base::timeout{ | |
272 | std::chrono::milliseconds(50), | |
273 | stream_base::none(), | |
274 | false}); | |
275 | ws1.async_close({}, test::fail_handler( | |
276 | beast::error::timeout)); | |
277 | test::run(ioc); | |
278 | } | |
279 | } | |
280 | ||
281 | void | |
282 | testSuspend() | |
283 | { | |
b32b8144 | 284 | // suspend on ping |
92f5a8d4 | 285 | doFailLoop([&](test::fail_count& fc) |
b32b8144 FG |
286 | { |
287 | echo_server es{log}; | |
92f5a8d4 | 288 | net::io_context ioc; |
b32b8144 FG |
289 | stream<test::stream> ws{ioc, fc}; |
290 | ws.next_layer().connect(es.stream()); | |
291 | ws.handshake("localhost", "/"); | |
292 | std::size_t count = 0; | |
293 | ws.async_ping("", | |
294 | [&](error_code ec) | |
295 | { | |
296 | ++count; | |
297 | if(ec) | |
298 | BOOST_THROW_EXCEPTION( | |
299 | system_error{ec}); | |
300 | }); | |
92f5a8d4 | 301 | BEAST_EXPECT(ws.impl_->wr_block.is_locked()); |
b32b8144 FG |
302 | BEAST_EXPECT(count == 0); |
303 | ws.async_close({}, | |
304 | [&](error_code ec) | |
305 | { | |
306 | ++count; | |
307 | if(ec) | |
308 | BOOST_THROW_EXCEPTION( | |
309 | system_error{ec}); | |
310 | }); | |
311 | BEAST_EXPECT(count == 0); | |
312 | ioc.run(); | |
313 | BEAST_EXPECT(count == 2); | |
314 | }); | |
315 | ||
316 | // suspend on write | |
92f5a8d4 | 317 | doFailLoop([&](test::fail_count& fc) |
b32b8144 FG |
318 | { |
319 | echo_server es{log}; | |
92f5a8d4 | 320 | net::io_context ioc; |
b32b8144 FG |
321 | stream<test::stream> ws{ioc, fc}; |
322 | ws.next_layer().connect(es.stream()); | |
323 | ws.handshake("localhost", "/"); | |
324 | std::size_t count = 0; | |
325 | ws.async_write(sbuf("*"), | |
326 | [&](error_code ec, std::size_t n) | |
327 | { | |
328 | ++count; | |
329 | if(ec) | |
330 | BOOST_THROW_EXCEPTION( | |
331 | system_error{ec}); | |
332 | BEAST_EXPECT(n == 1); | |
333 | }); | |
92f5a8d4 | 334 | BEAST_EXPECT(ws.impl_->wr_block.is_locked()); |
b32b8144 FG |
335 | BEAST_EXPECT(count == 0); |
336 | ws.async_close({}, | |
337 | [&](error_code ec) | |
338 | { | |
339 | ++count; | |
340 | if(ec) | |
341 | BOOST_THROW_EXCEPTION( | |
342 | system_error{ec}); | |
343 | }); | |
344 | BEAST_EXPECT(count == 0); | |
345 | ioc.run(); | |
346 | BEAST_EXPECT(count == 2); | |
347 | }); | |
348 | ||
349 | // suspend on read ping + message | |
92f5a8d4 | 350 | doFailLoop([&](test::fail_count& fc) |
b32b8144 FG |
351 | { |
352 | echo_server es{log}; | |
92f5a8d4 TL |
353 | multi_buffer b; |
354 | net::io_context ioc; | |
b32b8144 FG |
355 | stream<test::stream> ws{ioc, fc}; |
356 | ws.next_layer().connect(es.stream()); | |
357 | ws.handshake("localhost", "/"); | |
358 | // add a ping and message to the input | |
359 | ws.next_layer().append(string_view{ | |
360 | "\x89\x00" "\x81\x01*", 5}); | |
361 | std::size_t count = 0; | |
b32b8144 FG |
362 | ws.async_read(b, |
363 | [&](error_code ec, std::size_t) | |
364 | { | |
365 | ++count; | |
366 | if(ec) | |
367 | BOOST_THROW_EXCEPTION( | |
368 | system_error{ec}); | |
369 | }); | |
92f5a8d4 | 370 | while(! ws.impl_->wr_block.is_locked()) |
b32b8144 FG |
371 | { |
372 | ioc.run_one(); | |
373 | if(! BEAST_EXPECT(! ioc.stopped())) | |
374 | break; | |
375 | } | |
376 | BEAST_EXPECT(count == 0); | |
377 | ws.async_close({}, | |
378 | [&](error_code ec) | |
379 | { | |
380 | ++count; | |
381 | if(ec) | |
382 | BOOST_THROW_EXCEPTION( | |
383 | system_error{ec}); | |
384 | }); | |
385 | BEAST_EXPECT(count == 0); | |
386 | ioc.run(); | |
387 | BEAST_EXPECT(count == 2); | |
388 | }); | |
389 | ||
390 | // suspend on read bad message | |
92f5a8d4 | 391 | doFailLoop([&](test::fail_count& fc) |
b32b8144 FG |
392 | { |
393 | echo_server es{log}; | |
92f5a8d4 TL |
394 | multi_buffer b; |
395 | net::io_context ioc; | |
b32b8144 FG |
396 | stream<test::stream> ws{ioc, fc}; |
397 | ws.next_layer().connect(es.stream()); | |
398 | ws.handshake("localhost", "/"); | |
399 | // add an invalid frame to the input | |
400 | ws.next_layer().append(string_view{ | |
401 | "\x09\x00", 2}); | |
402 | std::size_t count = 0; | |
b32b8144 FG |
403 | ws.async_read(b, |
404 | [&](error_code ec, std::size_t) | |
405 | { | |
11fdf7f2 | 406 | if(ec != error::bad_control_fragment) |
b32b8144 FG |
407 | BOOST_THROW_EXCEPTION( |
408 | system_error{ec}); | |
409 | BEAST_EXPECT(++count == 1); | |
410 | }); | |
92f5a8d4 | 411 | while(! ws.impl_->wr_block.is_locked()) |
b32b8144 FG |
412 | { |
413 | ioc.run_one(); | |
414 | if(! BEAST_EXPECT(! ioc.stopped())) | |
415 | break; | |
416 | } | |
417 | BEAST_EXPECT(count == 0); | |
418 | ws.async_close({}, | |
419 | [&](error_code ec) | |
420 | { | |
92f5a8d4 | 421 | if(ec != net::error::operation_aborted) |
b32b8144 FG |
422 | BOOST_THROW_EXCEPTION( |
423 | system_error{ec}); | |
424 | BEAST_EXPECT(++count == 2); | |
425 | }); | |
426 | BEAST_EXPECT(count == 0); | |
427 | ioc.run(); | |
428 | BEAST_EXPECT(count == 2); | |
429 | }); | |
430 | ||
431 | // suspend on read close #1 | |
92f5a8d4 | 432 | doFailLoop([&](test::fail_count& fc) |
b32b8144 FG |
433 | { |
434 | echo_server es{log}; | |
92f5a8d4 TL |
435 | multi_buffer b; |
436 | net::io_context ioc; | |
b32b8144 FG |
437 | stream<test::stream> ws{ioc, fc}; |
438 | ws.next_layer().connect(es.stream()); | |
439 | ws.handshake("localhost", "/"); | |
440 | // add a close frame to the input | |
441 | ws.next_layer().append(string_view{ | |
442 | "\x88\x00", 2}); | |
443 | std::size_t count = 0; | |
b32b8144 FG |
444 | ws.async_read(b, |
445 | [&](error_code ec, std::size_t) | |
446 | { | |
447 | if(ec != error::closed) | |
448 | BOOST_THROW_EXCEPTION( | |
449 | system_error{ec}); | |
450 | BEAST_EXPECT(++count == 1); | |
451 | }); | |
92f5a8d4 | 452 | while(! ws.impl_->wr_block.is_locked()) |
b32b8144 FG |
453 | { |
454 | ioc.run_one(); | |
455 | if(! BEAST_EXPECT(! ioc.stopped())) | |
456 | break; | |
457 | } | |
458 | BEAST_EXPECT(count == 0); | |
459 | ws.async_close({}, | |
460 | [&](error_code ec) | |
461 | { | |
92f5a8d4 | 462 | if(ec != net::error::operation_aborted) |
b32b8144 FG |
463 | BOOST_THROW_EXCEPTION( |
464 | system_error{ec}); | |
465 | BEAST_EXPECT(++count == 2); | |
466 | }); | |
467 | BEAST_EXPECT(count == 0); | |
468 | ioc.run(); | |
469 | BEAST_EXPECT(count == 2); | |
470 | }); | |
471 | ||
472 | // teardown on received close | |
92f5a8d4 | 473 | doFailLoop([&](test::fail_count& fc) |
b32b8144 FG |
474 | { |
475 | echo_server es{log}; | |
92f5a8d4 TL |
476 | std::string const s = "Hello, world!"; |
477 | multi_buffer b; | |
478 | net::io_context ioc; | |
b32b8144 FG |
479 | stream<test::stream> ws{ioc, fc}; |
480 | ws.next_layer().connect(es.stream()); | |
481 | ws.handshake("localhost", "/"); | |
482 | // add a close frame to the input | |
483 | ws.next_layer().append(string_view{ | |
484 | "\x88\x00", 2}); | |
485 | std::size_t count = 0; | |
92f5a8d4 | 486 | ws.async_write(net::buffer(s), |
b32b8144 FG |
487 | [&](error_code ec, std::size_t n) |
488 | { | |
489 | if(ec) | |
490 | BOOST_THROW_EXCEPTION( | |
491 | system_error{ec}); | |
492 | BEAST_EXPECT(n == s.size()); | |
493 | BEAST_EXPECT(++count == 1); | |
494 | }); | |
b32b8144 FG |
495 | ws.async_read(b, |
496 | [&](error_code ec, std::size_t) | |
497 | { | |
92f5a8d4 | 498 | if(ec != net::error::operation_aborted) |
b32b8144 FG |
499 | BOOST_THROW_EXCEPTION( |
500 | system_error{ec}); | |
501 | BEAST_EXPECT(++count == 3); | |
502 | }); | |
503 | ws.async_close({}, | |
504 | [&](error_code ec) | |
505 | { | |
506 | if(ec) | |
507 | BOOST_THROW_EXCEPTION( | |
508 | system_error{ec}); | |
509 | BEAST_EXPECT(++count == 2); | |
510 | }); | |
511 | BEAST_EXPECT(count == 0); | |
512 | ioc.run(); | |
513 | BEAST_EXPECT(count == 3); | |
514 | }); | |
515 | ||
516 | // check for deadlock | |
92f5a8d4 | 517 | doFailLoop([&](test::fail_count& fc) |
b32b8144 FG |
518 | { |
519 | echo_server es{log}; | |
92f5a8d4 TL |
520 | multi_buffer b; |
521 | std::string const s = "Hello, world!"; | |
522 | net::io_context ioc; | |
b32b8144 FG |
523 | stream<test::stream> ws{ioc, fc}; |
524 | ws.next_layer().connect(es.stream()); | |
525 | ws.handshake("localhost", "/"); | |
526 | // add a ping frame to the input | |
527 | ws.next_layer().append(string_view{ | |
528 | "\x89\x00", 2}); | |
529 | std::size_t count = 0; | |
92f5a8d4 | 530 | ws.async_write(net::buffer(s), |
b32b8144 FG |
531 | [&](error_code ec, std::size_t n) |
532 | { | |
533 | if(ec) | |
534 | BOOST_THROW_EXCEPTION( | |
535 | system_error{ec}); | |
536 | BEAST_EXPECT(n == s.size()); | |
537 | BEAST_EXPECT(++count == 1); | |
538 | }); | |
539 | ws.async_read(b, | |
540 | [&](error_code ec, std::size_t) | |
541 | { | |
92f5a8d4 | 542 | if(ec != net::error::operation_aborted) |
b32b8144 FG |
543 | BOOST_THROW_EXCEPTION( |
544 | system_error{ec}); | |
545 | BEAST_EXPECT(++count == 3); | |
546 | }); | |
92f5a8d4 | 547 | BEAST_EXPECT(ws.impl_->rd_block.is_locked()); |
b32b8144 FG |
548 | ws.async_close({}, |
549 | [&](error_code ec) | |
550 | { | |
551 | if(ec) | |
552 | BOOST_THROW_EXCEPTION( | |
553 | system_error{ec}); | |
554 | BEAST_EXPECT(++count == 2); | |
555 | }); | |
556 | BEAST_EXPECT(ws.is_open()); | |
92f5a8d4 | 557 | BEAST_EXPECT(ws.impl_->wr_block.is_locked()); |
b32b8144 FG |
558 | BEAST_EXPECT(count == 0); |
559 | ioc.run(); | |
560 | BEAST_EXPECT(count == 3); | |
561 | }); | |
562 | ||
563 | // Four-way: close, read, write, ping | |
92f5a8d4 | 564 | doFailLoop([&](test::fail_count& fc) |
b32b8144 FG |
565 | { |
566 | echo_server es{log}; | |
92f5a8d4 TL |
567 | std::string const s = "Hello, world!"; |
568 | multi_buffer b; | |
569 | net::io_context ioc; | |
b32b8144 FG |
570 | stream<test::stream> ws{ioc, fc}; |
571 | ws.next_layer().connect(es.stream()); | |
572 | ws.handshake("localhost", "/"); | |
573 | std::size_t count = 0; | |
b32b8144 FG |
574 | ws.async_close({}, |
575 | [&](error_code ec) | |
576 | { | |
577 | if(ec) | |
578 | BOOST_THROW_EXCEPTION( | |
579 | system_error{ec}); | |
580 | BEAST_EXPECT(++count == 1); | |
581 | }); | |
582 | ws.async_read(b, | |
583 | [&](error_code ec, std::size_t) | |
584 | { | |
92f5a8d4 | 585 | if(ec != net::error::operation_aborted) |
b32b8144 FG |
586 | BOOST_THROW_EXCEPTION( |
587 | system_error{ec}); | |
588 | ++count; | |
589 | }); | |
92f5a8d4 | 590 | ws.async_write(net::buffer(s), |
b32b8144 FG |
591 | [&](error_code ec, std::size_t) |
592 | { | |
92f5a8d4 | 593 | if(ec != net::error::operation_aborted) |
b32b8144 FG |
594 | BOOST_THROW_EXCEPTION( |
595 | system_error{ec}); | |
596 | ++count; | |
597 | }); | |
598 | ws.async_ping({}, | |
599 | [&](error_code ec) | |
600 | { | |
92f5a8d4 | 601 | if(ec != net::error::operation_aborted) |
b32b8144 FG |
602 | BOOST_THROW_EXCEPTION( |
603 | system_error{ec}); | |
604 | ++count; | |
605 | }); | |
606 | BEAST_EXPECT(count == 0); | |
607 | ioc.run(); | |
608 | BEAST_EXPECT(count == 4); | |
609 | }); | |
610 | ||
611 | // Four-way: read, write, ping, close | |
92f5a8d4 | 612 | doFailLoop([&](test::fail_count& fc) |
b32b8144 FG |
613 | { |
614 | echo_server es{log}; | |
92f5a8d4 TL |
615 | multi_buffer b; |
616 | std::string const s = "Hello, world!"; | |
617 | net::io_context ioc; | |
b32b8144 FG |
618 | stream<test::stream> ws{ioc, fc}; |
619 | ws.next_layer().connect(es.stream()); | |
620 | ws.handshake("localhost", "/"); | |
621 | std::size_t count = 0; | |
b32b8144 FG |
622 | ws.async_read(b, |
623 | [&](error_code ec, std::size_t) | |
624 | { | |
92f5a8d4 | 625 | if(ec && ec != net::error::operation_aborted) |
b32b8144 FG |
626 | { |
627 | BEAST_EXPECTS(ec, ec.message()); | |
628 | BOOST_THROW_EXCEPTION( | |
629 | system_error{ec}); | |
630 | } | |
631 | if(! ec) | |
92f5a8d4 | 632 | BEAST_EXPECT(buffers_to_string(b.data()) == s); |
b32b8144 FG |
633 | ++count; |
634 | if(count == 4) | |
635 | BEAST_EXPECT( | |
92f5a8d4 | 636 | ec == net::error::operation_aborted); |
b32b8144 | 637 | }); |
92f5a8d4 | 638 | ws.async_write(net::buffer(s), |
b32b8144 FG |
639 | [&](error_code ec, std::size_t n) |
640 | { | |
641 | if(ec) | |
642 | BOOST_THROW_EXCEPTION( | |
643 | system_error{ec}); | |
644 | BEAST_EXPECT(n == s.size()); | |
645 | BEAST_EXPECT(++count == 1); | |
646 | }); | |
647 | ws.async_ping({}, | |
648 | [&](error_code ec) | |
649 | { | |
92f5a8d4 | 650 | if(ec != net::error::operation_aborted) |
b32b8144 FG |
651 | { |
652 | BEAST_EXPECTS(ec, ec.message()); | |
653 | BOOST_THROW_EXCEPTION( | |
654 | system_error{ec}); | |
655 | } | |
656 | ++count; | |
657 | }); | |
658 | ws.async_close({}, | |
659 | [&](error_code ec) | |
660 | { | |
661 | if(ec) | |
662 | BOOST_THROW_EXCEPTION( | |
663 | system_error{ec}); | |
664 | ++count; | |
665 | BEAST_EXPECT(count == 2 || count == 3); | |
666 | }); | |
667 | BEAST_EXPECT(count == 0); | |
668 | ioc.run(); | |
669 | BEAST_EXPECT(count == 4); | |
670 | }); | |
671 | ||
672 | // Four-way: ping, read, write, close | |
92f5a8d4 | 673 | doFailLoop([&](test::fail_count& fc) |
b32b8144 FG |
674 | { |
675 | echo_server es{log}; | |
92f5a8d4 TL |
676 | multi_buffer b; |
677 | std::string const s = "Hello, world!"; | |
678 | net::io_context ioc; | |
b32b8144 FG |
679 | stream<test::stream> ws{ioc, fc}; |
680 | ws.next_layer().connect(es.stream()); | |
681 | ws.handshake("localhost", "/"); | |
682 | std::size_t count = 0; | |
b32b8144 FG |
683 | ws.async_ping({}, |
684 | [&](error_code ec) | |
685 | { | |
686 | if(ec) | |
687 | BOOST_THROW_EXCEPTION( | |
688 | system_error{ec}); | |
689 | BEAST_EXPECT(++count == 1); | |
690 | }); | |
691 | ws.async_read(b, | |
692 | [&](error_code ec, std::size_t) | |
693 | { | |
92f5a8d4 | 694 | if(ec != net::error::operation_aborted) |
b32b8144 FG |
695 | BOOST_THROW_EXCEPTION( |
696 | system_error{ec}); | |
697 | ++count; | |
698 | }); | |
92f5a8d4 | 699 | ws.async_write(net::buffer(s), |
b32b8144 FG |
700 | [&](error_code ec, std::size_t) |
701 | { | |
92f5a8d4 | 702 | if(ec != net::error::operation_aborted) |
b32b8144 FG |
703 | BOOST_THROW_EXCEPTION( |
704 | system_error{ec}); | |
705 | ++count; | |
706 | }); | |
707 | ws.async_close({}, | |
708 | [&](error_code ec) | |
709 | { | |
710 | if(ec) | |
711 | BOOST_THROW_EXCEPTION( | |
712 | system_error{ec}); | |
713 | BEAST_EXPECT(++count == 2); | |
714 | }); | |
715 | BEAST_EXPECT(count == 0); | |
716 | ioc.run(); | |
717 | BEAST_EXPECT(count == 4); | |
718 | }); | |
719 | } | |
720 | ||
11fdf7f2 TL |
721 | void |
722 | testMoveOnly() | |
723 | { | |
92f5a8d4 | 724 | net::io_context ioc; |
11fdf7f2 TL |
725 | stream<test::stream> ws{ioc}; |
726 | ws.async_close({}, move_only_handler{}); | |
727 | } | |
728 | ||
729 | struct copyable_handler | |
730 | { | |
731 | template<class... Args> | |
732 | void | |
733 | operator()(Args&&...) const | |
734 | { | |
735 | } | |
736 | }; | |
737 | ||
b32b8144 FG |
738 | void |
739 | run() override | |
740 | { | |
741 | testClose(); | |
92f5a8d4 | 742 | testTimeout(); |
b32b8144 | 743 | testSuspend(); |
11fdf7f2 | 744 | testMoveOnly(); |
b32b8144 FG |
745 | } |
746 | }; | |
747 | ||
748 | BEAST_DEFINE_TESTSUITE(beast,websocket,close); | |
749 | ||
750 | } // websocket | |
751 | } // beast | |
752 | } // boost |