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/websocket/stream.hpp>
12
13#include <boost/beast/_experimental/test/stream.hpp>
14#include <boost/beast/_experimental/test/tcp.hpp>
15#include <boost/beast/_experimental/unit_test/suite.hpp>
16#include "test.hpp"
17#if BOOST_ASIO_HAS_CO_AWAIT
18#include <boost/asio/use_awaitable.hpp>
19#endif
20namespace boost {
21namespace beast {
22namespace websocket {
23
24class accept_test : public unit_test::suite //: public websocket_test_suite
25{
26public:
27 class res_decorator
28 {
29 bool& b_;
30
31 public:
32 res_decorator(res_decorator const&) = default;
33
34 explicit
35 res_decorator(bool& b)
36 : b_(b)
37 {
38 }
39
40 void
41 operator()(response_type&) const
42 {
43 this->b_ = true;
44 }
45 };
46
47 template<std::size_t N>
48 static
49 net::const_buffer
50 sbuf(const char (&s)[N])
51 {
52 return net::const_buffer(&s[0], N-1);
53 }
54
55 static
56 void
57 fail_loop(
58 std::function<void(
59 stream<test::basic_stream<net::io_context::executor_type>>&)>
60 f,
61 std::chrono::steady_clock::duration amount =
62 std::chrono::seconds(5))
63 {
64 using clock_type = std::chrono::steady_clock;
65 auto const expires_at =
66 clock_type::now() + amount;
67 net::io_context ioc;
68 for(std::size_t n = 0;;++n)
69 {
70 test::fail_count fc(n);
71 try
72 {
73 stream<test::basic_stream<net::io_context::executor_type>>
74 ws(ioc, fc);
75 auto tr = connect(to&: ws.next_layer());
76 f(ws);
77 break;
78 }
79 catch(system_error const& se)
80 {
81 // VFALCO Commented this out after the short
82 // read change, because it converts test_failure
83 // into http::partial_message
84 //
85 boost::ignore_unused(se);
86 #if 0
87 if(! BEAST_EXPECTS(
88 se.code() == test::error::test_failure,
89 se.code().message()))
90 throw;
91 #endif
92 if(! BEAST_EXPECTS(
93 clock_type::now() < expires_at,
94 "a test timeout occurred"))
95 break;
96 }
97 }
98 }
99
100 template<class Api>
101 void
102 testMatrix(Api api)
103 {
104 net::io_context ioc;
105
106 // request in stream
107 fail_loop(f: [&](stream<test::basic_stream<net::io_context::executor_type>>& ws)
108 {
109 ws.next_layer().append(
110 s: "GET / HTTP/1.1\r\n"
111 "Host: localhost\r\n"
112 "Upgrade: websocket\r\n"
113 "Connection: upgrade\r\n"
114 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
115 "Sec-WebSocket-Version: 13\r\n"
116 "\r\n");
117 ws.next_layer().read_size(n: 20);
118 api.accept(ws);
119 });
120
121 // request in stream, decorator
122 fail_loop(f: [&](stream<test::basic_stream<net::io_context::executor_type>>& ws)
123 {
124 ws.next_layer().append(
125 s: "GET / HTTP/1.1\r\n"
126 "Host: localhost\r\n"
127 "Upgrade: websocket\r\n"
128 "Connection: upgrade\r\n"
129 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
130 "Sec-WebSocket-Version: 13\r\n"
131 "\r\n");
132 ws.next_layer().read_size(n: 20);
133 bool called = false;
134 ws.set_option(stream_base::decorator(
135 res_decorator{called}));
136 api.accept(ws);
137 BEAST_EXPECT(called);
138 });
139
140 // request in buffers
141 fail_loop(f: [&](stream<test::basic_stream<net::io_context::executor_type>>& ws)
142 {
143 api.accept(ws, sbuf(
144 s: "GET / HTTP/1.1\r\n"
145 "Host: localhost\r\n"
146 "Upgrade: websocket\r\n"
147 "Connection: upgrade\r\n"
148 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
149 "Sec-WebSocket-Version: 13\r\n"
150 "\r\n"
151 ));
152 });
153
154 // request in buffers, decorator
155 fail_loop(f: [&](stream<test::basic_stream<net::io_context::executor_type>>& ws)
156 {
157 bool called = false;
158 ws.set_option(stream_base::decorator(
159 res_decorator{called}));
160 api.accept(ws, sbuf(
161 s: "GET / HTTP/1.1\r\n"
162 "Host: localhost\r\n"
163 "Upgrade: websocket\r\n"
164 "Connection: upgrade\r\n"
165 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
166 "Sec-WebSocket-Version: 13\r\n"
167 "\r\n"));
168 BEAST_EXPECT(called);
169 });
170
171 // request in buffers and stream
172 fail_loop(f: [&](stream<test::basic_stream<net::io_context::executor_type>>& ws)
173 {
174 ws.next_layer().append(
175 s: "Connection: upgrade\r\n"
176 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
177 "Sec-WebSocket-Version: 13\r\n"
178 "\r\n");
179 ws.next_layer().read_size(n: 16);
180 api.accept(ws, sbuf(
181 s: "GET / HTTP/1.1\r\n"
182 "Host: localhost\r\n"
183 "Upgrade: websocket\r\n"
184 ));
185 // VFALCO validate contents of ws.next_layer().str?
186 });
187
188 // request in buffers and stream, decorator
189 fail_loop(f: [&](stream<test::basic_stream<net::io_context::executor_type>>& ws)
190 {
191 ws.next_layer().append(
192 s: "Connection: upgrade\r\n"
193 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
194 "Sec-WebSocket-Version: 13\r\n"
195 "\r\n");
196 ws.next_layer().read_size(n: 16);
197 bool called = false;
198 ws.set_option(stream_base::decorator(
199 res_decorator{called}));
200 api.accept(ws, sbuf(
201 s: "GET / HTTP/1.1\r\n"
202 "Host: localhost\r\n"
203 "Upgrade: websocket\r\n"));
204 BEAST_EXPECT(called);
205 });
206
207 // request in message
208 {
209 request_type req;
210 req.method(v: http::verb::get);
211 req.target(s: "/");
212 req.version(value: 11);
213 req.insert(name: http::field::host, value: "localhost");
214 req.insert(name: http::field::upgrade, value: "websocket");
215 req.insert(name: http::field::connection, value: "upgrade");
216 req.insert(name: http::field::sec_websocket_key, value: "dGhlIHNhbXBsZSBub25jZQ==");
217 req.insert(name: http::field::sec_websocket_version, value: "13");
218
219 fail_loop(f: [&](stream<test::basic_stream<net::io_context::executor_type>>& ws)
220 {
221 api.accept(ws, req);
222 });
223 }
224
225 // request in message, decorator
226 {
227 request_type req;
228 req.method(v: http::verb::get);
229 req.target(s: "/");
230 req.version(value: 11);
231 req.insert(name: http::field::host, value: "localhost");
232 req.insert(name: http::field::upgrade, value: "websocket");
233 req.insert(name: http::field::connection, value: "upgrade");
234 req.insert(name: http::field::sec_websocket_key, value: "dGhlIHNhbXBsZSBub25jZQ==");
235 req.insert(name: http::field::sec_websocket_version, value: "13");
236
237 fail_loop(f: [&](stream<test::basic_stream<net::io_context::executor_type>>& ws)
238 {
239 bool called = false;
240 ws.set_option(stream_base::decorator(
241 res_decorator{called}));
242 api.accept(ws, req);
243 BEAST_EXPECT(called);
244 });
245 }
246
247 // request in message, close frame in stream
248 {
249 request_type req;
250 req.method(v: http::verb::get);
251 req.target(s: "/");
252 req.version(value: 11);
253 req.insert(name: http::field::host, value: "localhost");
254 req.insert(name: http::field::upgrade, value: "websocket");
255 req.insert(name: http::field::connection, value: "upgrade");
256 req.insert(name: http::field::sec_websocket_key, value: "dGhlIHNhbXBsZSBub25jZQ==");
257 req.insert(name: http::field::sec_websocket_version, value: "13");
258
259 fail_loop(f: [&](stream<test::basic_stream<net::io_context::executor_type>>& ws)
260 {
261 ws.next_layer().append(s: "\x88\x82\xff\xff\xff\xff\xfc\x17");
262 api.accept(ws, req);
263 try
264 {
265 static_buffer<1> b;
266 api.read(ws, b);
267 fail(reason: "success", __FILE__, __LINE__);
268 }
269 catch(system_error const& e)
270 {
271 if(e.code() != websocket::error::closed)
272 throw;
273 }
274 });
275 }
276
277 // failed handshake (missing Sec-WebSocket-Key)
278 fail_loop(f: [&](stream<test::basic_stream<net::io_context::executor_type>>& ws)
279 {
280 ws.next_layer().append(
281 s: "GET / HTTP/1.1\r\n"
282 "Host: localhost\r\n"
283 "Upgrade: websocket\r\n"
284 "Connection: upgrade\r\n"
285 "Sec-WebSocket-Version: 13\r\n"
286 "\r\n");
287 ws.next_layer().read_size(n: 20);
288 try
289 {
290 api.accept(ws);
291 BEAST_FAIL();
292 }
293 catch(system_error const& e)
294 {
295 if( e.code() != websocket::error::no_sec_key &&
296 e.code() != net::error::eof)
297 throw;
298 }
299 });
300 }
301
302 template<class Api>
303 void
304 testOversized(Api const& api)
305 {
306 net::io_context ioc;
307
308 auto const big = []
309 {
310 std::string s;
311 s += "X1: " + std::string(2000, '*') + "\r\n";
312 return s;
313 }();
314
315 // request in stream
316 {
317 stream<test::basic_stream<net::io_context::executor_type>> ws{ioc,
318 "GET / HTTP/1.1\r\n"
319 "Host: localhost\r\n"
320 "Upgrade: websocket\r\n"
321 "Connection: upgrade\r\n"
322 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
323 "Sec-WebSocket-Version: 13\r\n"
324 + big +
325 "\r\n"};
326 auto tr = connect(to&: ws.next_layer());
327 try
328 {
329 api.accept(ws);
330 BEAST_FAIL();
331 }
332 catch(system_error const& se)
333 {
334 // VFALCO Its the http error category...
335 BEAST_EXPECTS(
336 se.code() == http::error::buffer_overflow,
337 se.code().message());
338 }
339 }
340
341 // request in stream, decorator
342 {
343 stream<test::basic_stream<net::io_context::executor_type>> ws{ioc,
344 "GET / HTTP/1.1\r\n"
345 "Host: localhost\r\n"
346 "Upgrade: websocket\r\n"
347 "Connection: upgrade\r\n"
348 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
349 "Sec-WebSocket-Version: 13\r\n"
350 + big +
351 "\r\n"};
352 auto tr = connect(to&: ws.next_layer());
353 try
354 {
355 bool called = false;
356 ws.set_option(stream_base::decorator(
357 res_decorator{called}));
358 api.accept(ws);
359 BEAST_FAIL();
360 }
361 catch(system_error const& se)
362 {
363 // VFALCO Its the http error category...
364 BEAST_EXPECTS(
365 se.code() == http::error::buffer_overflow,
366 se.code().message());
367 }
368 }
369
370 // request in buffers
371 {
372 stream<test::basic_stream<net::io_context::executor_type>> ws{ioc};
373 auto tr = connect(to&: ws.next_layer());
374 try
375 {
376 api.accept(ws, net::buffer(
377 "GET / HTTP/1.1\r\n"
378 "Host: localhost\r\n"
379 "Upgrade: websocket\r\n"
380 "Connection: upgrade\r\n"
381 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
382 "Sec-WebSocket-Version: 13\r\n"
383 + big +
384 "\r\n"
385 ));
386 BEAST_FAIL();
387 }
388 catch(system_error const& se)
389 {
390 BEAST_EXPECTS(
391 se.code() == error::buffer_overflow,
392 se.code().message());
393 }
394 }
395
396 // request in buffers, decorator
397 {
398 stream<test::basic_stream<net::io_context::executor_type>> ws{ioc};
399 auto tr = connect(to&: ws.next_layer());
400 try
401 {
402 bool called = false;
403 ws.set_option(stream_base::decorator(
404 res_decorator{called}));
405 api.accept(ws, net::buffer(
406 "GET / HTTP/1.1\r\n"
407 "Host: localhost\r\n"
408 "Upgrade: websocket\r\n"
409 "Connection: upgrade\r\n"
410 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
411 "Sec-WebSocket-Version: 13\r\n"
412 + big +
413 "\r\n"));
414 BEAST_FAIL();
415 }
416 catch(system_error const& se)
417 {
418 BEAST_EXPECTS(
419 se.code() == error::buffer_overflow,
420 se.code().message());
421 }
422 }
423
424 // request in buffers and stream
425 {
426 stream<test::basic_stream<net::io_context::executor_type>> ws{ioc,
427 "Connection: upgrade\r\n"
428 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
429 "Sec-WebSocket-Version: 13\r\n"
430 + big +
431 "\r\n"};
432 auto tr = connect(to&: ws.next_layer());
433 try
434 {
435 api.accept(ws, websocket_test_suite::sbuf(
436 s: "GET / HTTP/1.1\r\n"
437 "Host: localhost\r\n"
438 "Upgrade: websocket\r\n"
439 ));
440 BEAST_FAIL();
441 }
442 catch(system_error const& se)
443 {
444 BEAST_EXPECTS(
445 se.code() == http::error::buffer_overflow,
446 se.code().message());
447 }
448 }
449
450 // request in buffers and stream, decorator
451 {
452 stream<test::basic_stream<net::io_context::executor_type>> ws{ioc,
453 "Connection: upgrade\r\n"
454 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
455 "Sec-WebSocket-Version: 13\r\n"
456 + big +
457 "\r\n"};
458 auto tr = connect(to&: ws.next_layer());
459 try
460 {
461 bool called = false;
462 ws.set_option(stream_base::decorator(
463 res_decorator{called}));
464 api.accept(ws, websocket_test_suite::sbuf(
465 s: "GET / HTTP/1.1\r\n"
466 "Host: localhost\r\n"
467 "Upgrade: websocket\r\n"));
468 BEAST_FAIL();
469 }
470 catch(system_error const& se)
471 {
472 BEAST_EXPECTS(
473 se.code() == http::error::buffer_overflow,
474 se.code().message());
475 }
476 }
477 }
478
479 void
480 testInvalidInputs()
481 {
482 net::io_context ioc;
483
484 auto const check =
485 [&](error_code ev, string_view s)
486 {
487 for(int i = 0; i < 3; ++i)
488 {
489 std::size_t n;
490 switch(i)
491 {
492 default:
493 case 0:
494 n = 1;
495 break;
496 case 1:
497 n = s.size() / 2;
498 break;
499 case 2:
500 n = s.size() - 1;
501 break;
502 }
503 stream<test::basic_stream<net::io_context::executor_type>> ws(ioc);
504 auto tr = connect(to&: ws.next_layer());
505 ws.next_layer().append(
506 s: s.substr(pos: n, n: s.size() - n));
507 tr.close();
508 try
509 {
510 ws.accept(buffers: net::buffer(data: s.data(), size_in_bytes: n));
511 BEAST_EXPECTS(! ev, ev.message());
512 }
513 catch(system_error const& se)
514 {
515 BEAST_EXPECTS(se.code() == ev, se.what());
516 }
517 }
518 };
519
520 // bad version
521 check(error::bad_http_version,
522 "GET / HTTP/1.0\r\n"
523 "Host: localhost:80\r\n"
524 "Upgrade: WebSocket\r\n"
525 "Connection: keep-alive,upgrade\r\n"
526 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
527 "Sec-WebSocket-Version: 13\r\n"
528 "\r\n"
529 );
530
531 // bad method
532 check(error::bad_method,
533 "POST / HTTP/1.1\r\n"
534 "Host: localhost:80\r\n"
535 "Upgrade: WebSocket\r\n"
536 "Connection: keep-alive,upgrade\r\n"
537 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
538 "Sec-WebSocket-Version: 13\r\n"
539 "\r\n"
540 );
541
542 // no Host
543 check(error::no_host,
544 "GET / HTTP/1.1\r\n"
545 "Upgrade: WebSocket\r\n"
546 "Connection: keep-alive,upgrade\r\n"
547 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
548 "Sec-WebSocket-Version: 13\r\n"
549 "\r\n"
550 );
551
552 // no Connection
553 check(error::no_connection,
554 "GET / HTTP/1.1\r\n"
555 "Host: localhost:80\r\n"
556 "Upgrade: WebSocket\r\n"
557 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
558 "Sec-WebSocket-Version: 13\r\n"
559 "\r\n"
560 );
561
562 // no Connection upgrade
563 check(error::no_connection_upgrade,
564 "GET / HTTP/1.1\r\n"
565 "Host: localhost:80\r\n"
566 "Upgrade: WebSocket\r\n"
567 "Connection: keep-alive\r\n"
568 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
569 "Sec-WebSocket-Version: 13\r\n"
570 "\r\n"
571 );
572
573 // no Upgrade
574 check(error::no_upgrade,
575 "GET / HTTP/1.1\r\n"
576 "Host: localhost:80\r\n"
577 "Connection: upgrade\r\n"
578 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
579 "Sec-WebSocket-Version: 13\r\n"
580 "\r\n"
581 );
582
583 // no Upgrade websocket
584 check(error::no_upgrade_websocket,
585 "GET / HTTP/1.1\r\n"
586 "Host: localhost:80\r\n"
587 "Upgrade: HTTP/2\r\n"
588 "Connection: upgrade\r\n"
589 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
590 "Sec-WebSocket-Version: 13\r\n"
591 "\r\n"
592 );
593
594 // no Sec-WebSocket-Key
595 check(error::no_sec_key,
596 "GET / HTTP/1.1\r\n"
597 "Host: localhost:80\r\n"
598 "Upgrade: WebSocket\r\n"
599 "Connection: keep-alive,upgrade\r\n"
600 "Sec-WebSocket-Version: 13\r\n"
601 "\r\n"
602 );
603
604 // bad Sec-WebSocket-Key
605 check(error::bad_sec_key,
606 "GET / HTTP/1.1\r\n"
607 "Host: localhost:80\r\n"
608 "Upgrade: WebSocket\r\n"
609 "Connection: upgrade\r\n"
610 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQdGhlIHNhbXBsZSBub25jZQ==\r\n"
611 "Sec-WebSocket-Version: 13\r\n"
612 "\r\n"
613 );
614
615 // no Sec-WebSocket-Version
616 check(error::no_sec_version,
617 "GET / HTTP/1.1\r\n"
618 "Host: localhost:80\r\n"
619 "Upgrade: WebSocket\r\n"
620 "Connection: keep-alive,upgrade\r\n"
621 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
622 "\r\n"
623 );
624
625 // bad Sec-WebSocket-Version
626 check(error::bad_sec_version,
627 "GET / HTTP/1.1\r\n"
628 "Host: localhost:80\r\n"
629 "Upgrade: WebSocket\r\n"
630 "Connection: keep-alive,upgrade\r\n"
631 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
632 "Sec-WebSocket-Version: 1\r\n"
633 "\r\n"
634 );
635
636 // bad Sec-WebSocket-Version
637 check(error::bad_sec_version,
638 "GET / HTTP/1.1\r\n"
639 "Host: localhost:80\r\n"
640 "Upgrade: WebSocket\r\n"
641 "Connection: upgrade\r\n"
642 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
643 "Sec-WebSocket-Version: 12\r\n"
644 "\r\n"
645 );
646
647 // valid request
648 check({},
649 "GET / HTTP/1.1\r\n"
650 "Host: localhost:80\r\n"
651 "Upgrade: WebSocket\r\n"
652 "Connection: upgrade\r\n"
653 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
654 "Sec-WebSocket-Version: 13\r\n"
655 "\r\n"
656 );
657 }
658
659 void
660 testEndOfStream()
661 {
662 net::io_context ioc;
663 {
664 stream<test::basic_stream<net::io_context::executor_type>> ws(ioc);
665 auto tr = connect(to&: ws.next_layer());
666 tr.close();
667 try
668 {
669 test_sync_api api;
670 api.accept(ws, buffers: net::const_buffer{});
671 BEAST_FAIL();
672 }
673 catch(system_error const& se)
674 {
675 BEAST_EXPECTS(
676 se.code() == error::closed,
677 se.code().message());
678 }
679 }
680 {
681 stream<test::basic_stream<net::io_context::executor_type>>
682 ws(ioc.get_executor());
683 auto tr = connect(to&: ws.next_layer());
684 tr.close();
685 try
686 {
687 test_async_api api;
688 api.accept(ws, buffers: net::const_buffer{});
689 BEAST_FAIL();
690 }
691 catch(system_error const& se)
692 {
693 BEAST_EXPECTS(
694 se.code() == error::closed,
695 se.code().message());
696 }
697 }
698 }
699
700 void
701 testAsync()
702 {
703 using tcp = net::ip::tcp;
704
705 net::io_context ioc;
706
707 // success, no timeout
708
709 {
710 stream<tcp::socket> ws1(ioc);
711 stream<tcp::socket> ws2(ioc);
712 test::connect(s1&: ws1.next_layer(), s2&: ws2.next_layer());
713
714 ws1.async_handshake(host: "test", target: "/", handler: test::success_handler());
715 ws2.async_accept(handler: test::success_handler());
716 test::run_for(ioc, elapsed: std::chrono::seconds(1));
717 }
718
719 {
720 stream<test::basic_stream<net::io_context::executor_type>> ws1(ioc);
721 stream<test::basic_stream<net::io_context::executor_type>> ws2(ioc);
722 test::connect(s1&: ws1.next_layer(), s2&: ws2.next_layer());
723
724 ws1.async_handshake(host: "test", target: "/", handler: test::success_handler());
725 ws2.async_accept(handler: test::success_handler());
726 test::run_for(ioc, elapsed: std::chrono::seconds(1));
727 }
728
729 // success, timeout enabled
730
731 {
732 stream<tcp::socket> ws1(ioc);
733 stream<tcp::socket> ws2(ioc);
734 test::connect(s1&: ws1.next_layer(), s2&: ws2.next_layer());
735
736 ws1.set_option(stream_base::timeout{
737 .handshake_timeout: std::chrono::milliseconds(50),
738 .idle_timeout: stream_base::none(),
739 .keep_alive_pings: false});
740 ws1.async_accept(handler: test::success_handler());
741 ws2.async_handshake(host: "test", target: "/", handler: test::success_handler());
742 test::run_for(ioc, elapsed: std::chrono::seconds(1));
743 }
744
745 {
746 stream<test::basic_stream<net::io_context::executor_type>> ws1(ioc);
747 stream<test::basic_stream<net::io_context::executor_type>> ws2(ioc);
748 test::connect(s1&: ws1.next_layer(), s2&: ws2.next_layer());
749
750 ws1.set_option(stream_base::timeout{
751 .handshake_timeout: std::chrono::milliseconds(50),
752 .idle_timeout: stream_base::none(),
753 .keep_alive_pings: false});
754 ws1.async_accept(handler: test::success_handler());
755 ws2.async_handshake(host: "test", target: "/", handler: test::success_handler());
756 test::run_for(ioc, elapsed: std::chrono::seconds(1));
757 }
758
759 // timeout
760
761 {
762 stream<tcp::socket> ws1(ioc);
763 stream<tcp::socket> ws2(ioc);
764 test::connect(s1&: ws1.next_layer(), s2&: ws2.next_layer());
765
766 ws1.set_option(stream_base::timeout{
767 .handshake_timeout: std::chrono::milliseconds(50),
768 .idle_timeout: stream_base::none(),
769 .keep_alive_pings: false});
770 ws1.async_accept(handler: test::fail_handler(ec: beast::error::timeout));
771 test::run_for(ioc, elapsed: std::chrono::seconds(1));
772 }
773
774 {
775 stream<test::basic_stream<net::io_context::executor_type>> ws1(ioc);
776 stream<test::basic_stream<net::io_context::executor_type>> ws2(ioc);
777 test::connect(s1&: ws1.next_layer(), s2&: ws2.next_layer());
778
779 ws1.set_option(stream_base::timeout{
780 .handshake_timeout: std::chrono::milliseconds(50),
781 .idle_timeout: stream_base::none(),
782 .keep_alive_pings: false});
783 ws1.async_accept(handler: test::fail_handler(ec: beast::error::timeout));
784 test::run_for(ioc, elapsed: std::chrono::seconds(1));
785 }
786
787 // abandoned operation
788
789 {
790 {
791 stream<tcp::socket> ws1(ioc);
792 ws1.async_accept(handler: test::fail_handler(
793 ec: net::error::operation_aborted));
794 }
795 test::run(ioc);
796 }
797
798 {
799 {
800 stream<tcp::socket> ws1(ioc);
801 string_view s =
802 "GET / HTTP/1.1\r\n"
803 "Host: localhost\r\n"
804 "Upgrade: websocket\r\n"
805 "Connection: upgrade\r\n"
806 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
807 "Sec-WebSocket-Version: 13\r\n"
808 "\r\n";
809 error_code ec;
810 http::request_parser<http::empty_body> p;
811 p.put(buffer: net::const_buffer(s.data(), s.size()), ec);
812 ws1.async_accept(req: p.get(), handler: test::fail_handler(
813 ec: net::error::operation_aborted));
814 }
815 test::run(ioc);
816 }
817 }
818
819 void testIssue264Sync()
820 {
821 net::io_context ioc;
822 using tcp = net::ip::tcp;
823
824 stream<tcp::socket> ws1(ioc);
825 tcp::socket s2(ioc);
826 test::connect(s1&: ws1.next_layer(), s2);
827
828 http::request<http::empty_body> req{http::verb::get, "/api", 11};
829 req.set(name: http::field::connection, value: "upgrade");
830 req.set(name: http::field::upgrade, value: "websocket");
831 req.set(name: http::field::expect, value: "100-continue");
832 req.set(name: http::field::host, value: "test");
833 req.set(name: http::field::sec_websocket_version, value: "13");
834 req.set(name: http::field::sec_websocket_key, value: "1234");
835
836 req.prepare_payload();
837
838 std::thread thr{
839 [&]
840 {
841 beast::error_code ec;
842 ws1.accept(ec);
843 BEAST_EXPECTS(!ec, ec.message());
844 }};
845
846 http::async_write(stream&: s2, msg: req, handler: test::success_handler());
847 http::response<http::empty_body> res1, res2;
848
849 flat_buffer buf;
850 http::async_read(stream&: s2, buffer&: buf, msg&: res1,
851 handler: [&](error_code ec, std::size_t)
852 {
853 BEAST_EXPECTS(!ec, ec.message());
854 BEAST_EXPECTS(res1.result() == http::status::continue_, obsolete_reason(res1.result()));
855 if (res1.result() == http::status::continue_)
856 http::async_read(stream&: s2, buffer&: buf, msg&: res2, handler: test::success_handler());
857 });
858
859 test::run_for(ioc, elapsed: std::chrono::seconds(1));
860 thr.join();
861 }
862
863
864 void testIssue264Async()
865 {
866 net::io_context ioc;
867 using tcp = net::ip::tcp;
868
869 stream<tcp::socket> ws1(ioc);
870 tcp::socket s2(ioc);
871 test::connect(s1&: ws1.next_layer(), s2);
872
873 http::request<http::empty_body> req{http::verb::get, "/api", 11};
874 req.set(name: http::field::connection, value: "upgrade");
875 req.set(name: http::field::upgrade, value: "websocket");
876 req.set(name: http::field::expect, value: "100-continue");
877 req.set(name: http::field::host, value: "test");
878 req.set(name: http::field::sec_websocket_version, value: "13");
879 req.set(name: http::field::sec_websocket_key, value: "1234");
880
881 req.prepare_payload();
882
883 http::async_write(stream&: s2, msg: req, handler: test::success_handler());
884 http::response<http::empty_body> res1, res2;
885
886 ws1.async_accept(handler: test::success_handler());
887 flat_buffer buf;
888 http::async_read(stream&: s2, buffer&: buf, msg&: res1,
889 handler: [&](error_code ec, std::size_t)
890 {
891 BEAST_EXPECTS(!ec, ec.message());
892 BEAST_EXPECTS(res1.result() == http::status::continue_, obsolete_reason(res1.result()));
893 if (res1.result() == http::status::continue_)
894 http::async_read(stream&: s2, buffer&: buf, msg&: res2, handler: test::success_handler());
895 });
896
897 test::run_for(ioc, elapsed: std::chrono::seconds(1));
898 }
899
900#if BOOST_ASIO_HAS_CO_AWAIT
901 void testAwaitableCompiles(
902 stream<net::ip::tcp::socket>& s,
903 http::request<http::empty_body>& req,
904 net::mutable_buffer buf
905 )
906 {
907 static_assert(std::is_same_v<
908 net::awaitable<void>, decltype(
909 s.async_accept(net::use_awaitable))>);
910
911 static_assert(std::is_same_v<
912 net::awaitable<void>, decltype(
913 s.async_accept(req, net::use_awaitable))>);
914
915 static_assert(std::is_same_v<
916 net::awaitable<void>, decltype(
917 s.async_accept(buf, net::use_awaitable))>);
918 }
919#endif
920
921 void
922 run() override
923 {
924 testMatrix(api: test_sync_api{});
925 testMatrix(api: test_async_api{});
926 testOversized(api: test_sync_api{});
927 testOversized(api: test_async_api{});
928 testInvalidInputs();
929 testEndOfStream();
930 testAsync();
931#if BOOST_ASIO_HAS_CO_AWAIT
932 boost::ignore_unused(&accept_test::testAwaitableCompiles);
933#endif
934 testIssue264Sync();
935 testIssue264Async();
936 }
937};
938
939BEAST_DEFINE_TESTSUITE(beast,websocket,accept);
940
941} // websocket
942} // beast
943} // boost
944

source code of boost/libs/beast/test/beast/websocket/accept.cpp