1 /*
2 	restinio
3 */
4 
5 /*!
6 	Test upgrade request.
7 */
8 
9 #include <catch2/catch.hpp>
10 
11 #include <restinio/all.hpp>
12 #include <restinio/websocket/websocket.hpp>
13 #include <restinio/utils/base64.hpp>
14 #include <restinio/utils/sha1.hpp>
15 
16 #include <test/common/utest_logger.hpp>
17 #include <test/common/pub.hpp>
18 #include <test/websocket/common/pub.hpp>
19 
20 #include <so_5/all.hpp>
21 
22 namespace rws = restinio::websocket::basic;
23 
24 using traits_t =
25 	restinio::traits_t<
26 		restinio::asio_timer_manager_t,
27 		utest_logger_t >;
28 
29 using http_server_t = restinio::http_server_t< traits_t >;
30 
31 struct upgrade_request_t : public so_5::message_t
32 {
upgrade_request_tupgrade_request_t33 	upgrade_request_t( restinio::request_handle_t req )
34 		:	m_req{ std::move( req ) }
35 	{}
36 
37 	restinio::request_handle_t m_req;
38 };
39 
40 struct msg_ws_message_t : public so_5::message_t
41 {
msg_ws_message_tmsg_ws_message_t42 	msg_ws_message_t( rws::message_handle_t msg )
43 		:	m_msg{ msg }
44 	{}
45 
46 	rws::message_handle_t m_msg;
47 };
48 
49 struct server_started_t : public so_5::signal_t {};
50 
51 //
52 // g_last_close_code
53 //
54 
55 std::atomic< std::uint16_t > g_last_close_code{ 0 };
56 std::atomic< std::uint16_t > g_message_handled{ 0 };
57 
58 //
59 // a_server_t
60 //
61 
62 //! Agent running ws server logic.
63 class a_server_t
64 	:	public so_5::agent_t
65 {
66 		using so_base_type_t = so_5::agent_t;
67 
68 	public:
a_server_t(context_t ctx,so_5::mchain_t server_started_mchain)69 		a_server_t(
70 			context_t ctx,
71 			so_5::mchain_t server_started_mchain )
72 			:	so_base_type_t{ ctx }
73 			,	m_server_started_mchain( std::move(server_started_mchain) )
74 			,	m_http_server{
75 					restinio::own_io_context(),
__anon6e6555c40102( )76 					[this]( auto & settings ){
77 						auto mbox = this->so_direct_mbox();
78 						settings
79 							.port( utest_default_port() )
80 							.address( "127.0.0.1" )
81 							.request_handler(
82 								[mbox]( auto req ){
83 									if( restinio::http_connection_header_t::upgrade ==
84 										req->header().connection() )
85 									{
86 										++g_message_handled;
87 										so_5::send< upgrade_request_t >( mbox, std::move( req ) );
88 
89 										return restinio::request_accepted();
90 									}
91 
92 									return restinio::request_rejected();
93 								} );
94 					} }
95 			,	m_other_thread{ m_http_server }
96 		{
97 			g_last_close_code = 0;
98 			g_message_handled = 0;
99 		}
100 
101 		virtual void
so_define_agent()102 		so_define_agent() override
103 		{
104 			so_subscribe_self()
105 				.event( &a_server_t::evt_upgrade_request )
106 				.event( &a_server_t::evt_ws_message );
107 		}
108 
109 		virtual void
so_evt_start()110 		so_evt_start() override
111 		{
112 			m_other_thread.run();
113 			so_5::send<server_started_t>( m_server_started_mchain );
114 		}
115 
116 		virtual void
so_evt_finish()117 		so_evt_finish() override
118 		{
119 			m_ws.reset();
120 			m_other_thread.stop_and_join();
121 		}
122 
123 	private:
124 		void
evt_upgrade_request(const upgrade_request_t & msg)125 		evt_upgrade_request( const upgrade_request_t & msg )
126 		{
127 			auto req = msg.m_req;
128 
129 			m_ws =
130 				rws::upgrade< traits_t >(
131 					*req,
132 					rws::activation_t::immediate,
133 					[mbox = so_direct_mbox()]( auto /* ws_handle*/, rws::message_handle_t m ){
134 						so_5::send< msg_ws_message_t >( mbox, m );
135 					} );
136 		}
137 
138 		void
evt_ws_message(const msg_ws_message_t & msg)139 		evt_ws_message( const msg_ws_message_t & msg )
140 		{
141 			if( m_ws )
142 			{
143 				auto & req = *(msg.m_msg);
144 
145 				if( rws::opcode_t::text_frame == req.opcode() ||
146 					rws::opcode_t::binary_frame == req.opcode() )
147 				{
148 					if( req.payload() == "close" )
149 					{
150 						m_ws->send_message(
151 							rws::final_frame,
152 							rws::opcode_t::connection_close_frame,
153 							rws::status_code_to_bin( rws::status_code_t::normal_closure ) );
154 					}
155 					else if( req.payload() == "shutdown" )
156 					{
157 						m_ws->shutdown();
158 						m_ws.reset();
159 					}
160 					else if( req.payload() == "kill" )
161 					{
162 						m_ws->kill();
163 						m_ws.reset();
164 					}
165 					else
166 					{
167 						auto resp = req;
168 						m_ws->send_message( resp );
169 					}
170 				}
171 				else if( rws::opcode_t::ping_frame == req.opcode() )
172 				{
173 					auto resp = req;
174 					resp.set_opcode( rws::opcode_t::pong_frame );
175 					m_ws->send_message( resp );
176 				}
177 				// else if( rws::opcode_t::pong_frame == req.opcode() )
178 				// {
179 				// 	// ?
180 				// }
181 				else if( rws::opcode_t::connection_close_frame == req.opcode() )
182 				{
183 					g_last_close_code = (std::uint16_t)rws::status_code_from_bin( req.payload() );
184 					std::cout << "CLOSE FRAME: " << g_last_close_code << std::endl;
185 					m_ws.reset();
186 				}
187 			}
188 		}
189 
190 		const so_5::mchain_t m_server_started_mchain;
191 		http_server_t m_http_server;
192 		other_work_thread_for_server_t<http_server_t> m_other_thread;
193 		rws::ws_handle_t m_ws;
194 };
195 
196 const std::string upgrade_request{
197 	"GET /chat HTTP/1.1\r\n"
198 	"Host: 127.0.0.1\r\n"
199 	"Upgrade: websocket\r\n"
200 	"Connection: Upgrade\r\n"
201 	"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
202 	"Sec-WebSocket-Protocol: chat\r\n"
203 	"Sec-WebSocket-Version: 1\r\n"
204 	"User-Agent: unit-test\r\n"
205 	"\r\n" };
206 
207 class sobj_t
208 {
209 	so_5::wrapped_env_t m_sobj;
210 
211 	static void
init(so_5::environment_t & env)212 	init( so_5::environment_t & env )
213 	{
214 		auto server_started_mchain = so_5::create_mchain(env);
215 		const auto binder_maker = [](auto & env) {
216 #if !defined(SO_5_VERSION) || SO_5_VERSION < SO_5_VERSION_MAKE(6ull, 0ull, 0ull)
217 			return so_5::disp::active_obj::create_private_disp(env)->binder();
218 #else
219 			return so_5::disp::active_obj::make_dispatcher(env).binder();
220 #endif
221 		};
222 
223 		// Launch server as separate coop.
224 		env.introduce_coop(
225 			binder_maker(env),
226 			[&]( so_5::coop_t & coop ) {
227 				coop.make_agent< a_server_t >(server_started_mchain);
228 			} );
229 		// Wait acknowledgement about successful server start.
230 		so_5::receive(
231 				from(server_started_mchain)
232 					.handle_n(1u)
233 					.empty_timeout(std::chrono::seconds(5)),
234 				[](so_5::mhood_t<server_started_t>) {});
235 	}
236 
237 public :
238 	sobj_t( const sobj_t & ) = delete;
239 	sobj_t( sobj_t && ) = delete;
240 
sobj_t()241 	sobj_t()
242 	{
243 		init( m_sobj.environment() );
244 	}
245 
246 	void
stop_and_join()247 	stop_and_join()
248 	{
249 		m_sobj.stop();
250 		m_sobj.join();
251 	}
252 };
253 
254 template < typename Socket >
255 void
fragmented_send(Socket & socket,void * buf,std::size_t n)256 fragmented_send( Socket & socket, void * buf, std::size_t n )
257 {
258 	const auto * b = static_cast< std::uint8_t * >( buf );
259 	while( n-- )
260 	{
261 		restinio::asio_ns::write( socket, restinio::asio_ns::buffer( b++, 1 ) );
262 		if( 0 < n )
263 			std::this_thread::sleep_for( std::chrono::milliseconds( n ) );
264 	}
265 }
266 
267 TEST_CASE( "Simple echo" , "[ws_connection][echo][normal_close]" )
268 {
269 	sobj_t sobj;
270 
271 	do_with_socket(
__anon6e6555c40702( auto & socket, auto & )272 		[&]( auto & socket, auto & /*io_context*/ ){
273 			REQUIRE_NOTHROW(
274 				restinio::asio_ns::write(
275 					socket, restinio::asio_ns::buffer( upgrade_request.data(), upgrade_request.size() ) )
276 			);
277 
278 			std::array< std::uint8_t, 1024 > data;
279 
280 			std::size_t len{ 0 };
281 			REQUIRE_NOTHROW(
282 				len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ) )
283 			);
284 
285 			std::vector< std::uint8_t > msg_frame =
286 					{ 0x81, 0x85, 0xAA,0xBB,0xCC,0xDD,
287 					  0xAA ^ 'H', 0xBB ^ 'e', 0xCC ^ 'l', 0xDD ^ 'l', 0xAA ^ 'o' };
288 			SECTION( "simple msg_frame")
289 			{
290 				REQUIRE_NOTHROW(
291 					restinio::asio_ns::write( socket, restinio::asio_ns::buffer( msg_frame.data(), msg_frame.size() ) )
292 				);
293 			}
294 			SECTION( "fragmentated msg_frame")
295 			{
296 				REQUIRE_NOTHROW(
297 					fragmented_send( socket, msg_frame.data(), msg_frame.size() )
298 				);
299 			}
300 
301 			REQUIRE_NOTHROW(
302 				len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ) )
303 			);
304 
305 			REQUIRE( 7 == len );
306 			REQUIRE( 0x81 == data[ 0 ] );
307 			REQUIRE( 0x05 == data[ 1 ] );
308 			REQUIRE( 'H' == data[ 2 ] );
309 			REQUIRE( 'e' == data[ 3 ] );
310 			REQUIRE( 'l' == data[ 4 ] );
311 			REQUIRE( 'l' == data[ 5 ] );
312 			REQUIRE( 'o' == data[ 6 ] );
313 
314 			std::vector< std::uint8_t > close_frame =
315 				{0x88, 0x82, 0xFF,0xFF,0xFF,0xFF, 0xFF ^ 0x03, 0xFF ^ 0xe8 };
316 
317 			REQUIRE_NOTHROW(
318 				restinio::asio_ns::write(
319 					socket, restinio::asio_ns::buffer( close_frame.data(), close_frame.size() ) )
320 			);
321 
322 			REQUIRE_NOTHROW(
323 					len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ) )
324 				);
325 			REQUIRE( 4 == len );
326 			REQUIRE( 0x88 == data[ 0 ] );
327 			REQUIRE( 0x02 == data[ 1 ] );
328 			REQUIRE( 0x03 == data[ 2 ] );
329 			REQUIRE( 0xe8 == data[ 3 ] );
330 
331 			restinio::asio_ns::error_code ec;
332 			len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ), ec );
333 			REQUIRE( ec );
334 			REQUIRE( restinio::asio_ns::error::eof == ec.value() );
335 
336 		} );
337 
338 	sobj.stop_and_join();
339 
340 	REQUIRE( 1000 == g_last_close_code );
341 }
342 
343 TEST_CASE( "Ping" , "[ws_connection][ping][normal_close]" )
344 {
345 	sobj_t sobj;
346 
347 	do_with_socket(
__anon6e6555c40802( auto & socket, auto & )348 		[&]( auto & socket, auto & /*io_context*/ ){
349 			REQUIRE_NOTHROW(
350 				restinio::asio_ns::write(
351 					socket, restinio::asio_ns::buffer( upgrade_request.data(), upgrade_request.size() ) )
352 			);
353 
354 			std::array< std::uint8_t, 1024 > data;
355 
356 			std::size_t len{ 0 };
357 			REQUIRE_NOTHROW(
358 				len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ) )
359 			);
360 
361 			std::vector< std::uint8_t > msg_frame =
362 					{ 0x89, 0x84, 0x0A,0xB0,0x0C,0xD0,
363 					  0x0A ^ 'P', 0xB0 ^ 'i', 0x0C ^ 'n', 0xD0 ^ 'g' };
364 
365 			SECTION( "simple msg_frame")
366 			{
367 				REQUIRE_NOTHROW(
368 					restinio::asio_ns::write( socket, restinio::asio_ns::buffer( msg_frame.data(), msg_frame.size() ) )
369 				);
370 			}
371 			SECTION( "fragmentated msg_frame")
372 			{
373 				REQUIRE_NOTHROW(
374 					fragmented_send( socket, msg_frame.data(), msg_frame.size() )
375 				);
376 			}
377 
378 			REQUIRE_NOTHROW(
379 				len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ) )
380 			);
381 
382 			REQUIRE( 6 == len );
383 			REQUIRE( 0x8A == data[ 0 ] );
384 			REQUIRE( 0x04 == data[ 1 ] );
385 			REQUIRE( 'P' == data[ 2 ] );
386 			REQUIRE( 'i' == data[ 3 ] );
387 			REQUIRE( 'n' == data[ 4 ] );
388 			REQUIRE( 'g' == data[ 5 ] );
389 
390 			std::vector< std::uint8_t > close_frame =
391 				{0x88, 0x82, 0xFF,0xFF,0xFF,0xFF, 0xFF ^ 0x03, 0xFF ^ 0xe8 };
392 
393 			REQUIRE_NOTHROW(
394 				restinio::asio_ns::write(
395 					socket, restinio::asio_ns::buffer( close_frame.data(), close_frame.size() ) )
396 			);
397 
398 			REQUIRE_NOTHROW(
399 				len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ) )
400 			);
401 			REQUIRE( 4 == len );
402 			REQUIRE( 0x88 == data[ 0 ] );
403 			REQUIRE( 0x02 == data[ 1 ] );
404 			REQUIRE( 0x03 == data[ 2 ] );
405 			REQUIRE( 0xe8 == data[ 3 ] );
406 
407 			restinio::asio_ns::error_code ec;
408 			len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ), ec );
409 			REQUIRE( ec );
410 			REQUIRE( restinio::asio_ns::error::eof == ec.value() );
411 		} );
412 
413 	sobj.stop_and_join();
414 
415 	REQUIRE( 1000 == g_last_close_code );
416 }
417 
418 TEST_CASE( "Close" , "[ws_connection][close][normal_close]" )
419 {
420 	sobj_t sobj;
421 
422 	do_with_socket(
__anon6e6555c40902( auto & socket, auto & )423 		[&]( auto & socket, auto & /*io_context*/ ){
424 
425 			REQUIRE_NOTHROW(
426 				restinio::asio_ns::write(
427 					socket, restinio::asio_ns::buffer( upgrade_request.data(), upgrade_request.size() ) )
428 			);
429 
430 			std::array< std::uint8_t, 1024 > data;
431 
432 			std::size_t len{ 0 };
433 			REQUIRE_NOTHROW(
434 				len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ) )
435 			);
436 
437 			std::vector< std::uint8_t > msg_frame =
438 					{ 0x81, 0x85, 0x0A,0xB0,0x0C,0xD0,
439 					  0x0A ^ 'c', 0xB0 ^ 'l', 0x0C ^ 'o', 0xD0 ^ 's', 0x0A ^ 'e' };
440 
441 			SECTION( "simple msg_frame")
442 			{
443 				REQUIRE_NOTHROW(
444 					restinio::asio_ns::write( socket, restinio::asio_ns::buffer( msg_frame.data(), msg_frame.size() ) )
445 				);
446 			}
447 			SECTION( "fragmentated msg_frame")
448 			{
449 				REQUIRE_NOTHROW(
450 					fragmented_send( socket, msg_frame.data(), msg_frame.size() )
451 				);
452 			}
453 
454 			REQUIRE_NOTHROW(
455 				len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ) )
456 			);
457 
458 			REQUIRE( 4 == len );
459 			REQUIRE( 0x88 == data[ 0 ] );
460 			REQUIRE( 0x02 == data[ 1 ] );
461 			REQUIRE( 0x03 == data[ 2 ] );
462 			REQUIRE( 0xe8 == data[ 3 ] );
463 
464 			std::vector< std::uint8_t > close_frame =
465 				{0x88, 0x82, 0xFF,0xFF,0xFF,0xFF, 0xFF ^ 0x03, 0xFF ^ 0xe8 };
466 
467 			REQUIRE_NOTHROW(
468 				restinio::asio_ns::write(
469 					socket, restinio::asio_ns::buffer( close_frame.data(), close_frame.size() ) )
470 			);
471 
472 			restinio::asio_ns::error_code ec;
473 			len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ), ec );
474 			REQUIRE( 0 == len );
475 			REQUIRE( ec );
476 			REQUIRE( restinio::asio_ns::error::eof == ec.value() );
477 		} );
478 
479 	sobj.stop_and_join();
480 
481 	// User initiates close.
482 	REQUIRE( 0 == g_last_close_code );
483 }
484 
485 TEST_CASE( "Shutdown" , "[ws_connection][shutdown][normal_close]" )
486 {
487 	sobj_t sobj;
488 
489 	do_with_socket(
__anon6e6555c40a02( auto & socket, auto & )490 		[&]( auto & socket, auto & /*io_context*/ ){
491 			REQUIRE_NOTHROW(
492 				restinio::asio_ns::write(
493 					socket, restinio::asio_ns::buffer( upgrade_request.data(), upgrade_request.size() ) )
494 			);
495 
496 			std::array< std::uint8_t, 1024 > data;
497 
498 			std::size_t len{ 0 };
499 			REQUIRE_NOTHROW(
500 				len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ) )
501 			);
502 
503 			std::vector< std::uint8_t > msg_frame =
504 					{ 0x81, 0x88, 0x0A,0xB0,0x0C,0xD0,
505 					  0x0A ^ 's', 0xB0 ^ 'h', 0x0C ^ 'u', 0xD0 ^ 't',
506 					  0x0A ^ 'd', 0xB0 ^ 'o', 0x0C ^ 'w', 0xD0 ^ 'n' };
507 
508 			REQUIRE_NOTHROW(
509 				restinio::asio_ns::write( socket, restinio::asio_ns::buffer( msg_frame.data(), msg_frame.size() ) )
510 			);
511 
512 			REQUIRE_NOTHROW(
513 				len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ) )
514 			);
515 
516 			REQUIRE( 4 == len );
517 			REQUIRE( 0x88 == data[ 0 ] );
518 			REQUIRE( 0x02 == data[ 1 ] );
519 			REQUIRE( 0x03 == data[ 2 ] );
520 			REQUIRE( 0xe8 == data[ 3 ] );
521 
522 			std::vector< std::uint8_t > close_frame =
523 				{0x88, 0x82, 0xFF,0xFF,0xFF,0xFF, 0xFF ^ 0x03, 0xFF ^ 0xe8 };
524 
525 			SECTION( "simple close_frame")
526 			{
527 				REQUIRE_NOTHROW(
528 					restinio::asio_ns::write(
529 						socket, restinio::asio_ns::buffer( close_frame.data(), close_frame.size() ) )
530 				);
531 			}
532 			SECTION( "fragmentated close_frame")
533 			{
534 				REQUIRE_NOTHROW(
535 					fragmented_send( socket, close_frame.data(), close_frame.size() )
536 				);
537 			}
538 
539 			restinio::asio_ns::error_code ec;
540 			len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ), ec );
541 			REQUIRE( 0 == len );
542 			REQUIRE( ec );
543 			REQUIRE( restinio::asio_ns::error::eof == ec.value() );
544 		} );
545 
546 	sobj.stop_and_join();
547 
548 	// User initiates close via shutdown.
549 	REQUIRE( 0 == g_last_close_code );
550 }
551 
552 TEST_CASE( "Kill" , "[ws_connection][kill][abnormal_close]" )
553 {
554 	sobj_t sobj;
555 
556 	do_with_socket(
__anon6e6555c40b02( auto & socket, auto & )557 		[&]( auto & socket, auto & /*io_context*/ ){
558 			REQUIRE_NOTHROW(
559 					restinio::asio_ns::write(
560 						socket, restinio::asio_ns::buffer( upgrade_request.data(), upgrade_request.size() ) )
561 				);
562 
563 			std::array< std::uint8_t, 1024 > data;
564 
565 			std::size_t len{ 0 };
566 			REQUIRE_NOTHROW(
567 					len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ) )
568 				);
569 
570 			std::vector< std::uint8_t > msg_frame =
571 					{ 0x81, 0x84, 0x0A,0xB0,0x0C,0xD0,
572 					  0x0A ^ 'k', 0xB0 ^ 'i', 0x0C ^ 'l', 0xD0 ^ 'l' };
573 
574 			SECTION( "simple msg_frame")
575 			{
576 				REQUIRE_NOTHROW(
577 						restinio::asio_ns::write( socket, restinio::asio_ns::buffer( msg_frame.data(), msg_frame.size() ) )
578 					);
579 			}
580 			SECTION( "fragmentated msg_frame")
581 			{
582 				REQUIRE_NOTHROW(
583 					fragmented_send( socket, msg_frame.data(), msg_frame.size() )
584 				);
585 			}
586 
587 			restinio::asio_ns::error_code ec;
588 			len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ), ec );
589 			REQUIRE( 0 == len );
590 			REQUIRE( ec );
591 			REQUIRE( restinio::asio_ns::error::eof == ec.value() );
592 		} );
593 
594 	sobj.stop_and_join();
595 
596 	REQUIRE( 0 == g_last_close_code );
597 }
598 
599 TEST_CASE( "Invalid header", "[ws_connection][error_close]" )
600 {
601 	sobj_t sobj;
602 
603 	do_with_socket(
__anon6e6555c40c02( auto & socket, auto & )604 		[&]( auto & socket, auto & /*io_context*/ ){
605 			REQUIRE_NOTHROW(
606 				restinio::asio_ns::write(
607 					socket, restinio::asio_ns::buffer( upgrade_request.data(), upgrade_request.size() ) )
608 			);
609 
610 			std::array< std::uint8_t, 1024 > data;
611 
612 			std::size_t len{ 0 };
613 			REQUIRE_NOTHROW(
614 				len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ) )
615 			);
616 
617 			std::vector< std::uint8_t > msg_frame;
618 			SECTION( "No mask" )
619 			{
620 				msg_frame.assign( { 0x81, 0x05, 'H', 'e', 'l', 'l', 'o'} );
621 			}
622 			SECTION( "No rsv1" )
623 			{
624 				msg_frame.assign(
625 					{ 0x81 + 0x40, 0x85, 0xAA,0xBB,0xCC,0xDD,
626 					  0xAA ^ 'H', 0xBB ^ 'e', 0xCC ^ 'l', 0xDD ^ 'l', 0xAA ^ 'o'} );
627 			}
628 			SECTION( "No rsv2" )
629 			{
630 				msg_frame.assign(
631 					{ 0x81 + 0x20, 0x85, 0xAA,0xBB,0xCC,0xDD,
632 					  0xAA ^ 'H', 0xBB ^ 'e', 0xCC ^ 'l', 0xDD ^ 'l', 0xAA ^ 'o'} );
633 			}
634 			SECTION( "No rsv3" )
635 			{
636 				msg_frame.assign(
637 					{ 0x81 + 0x10, 0x85, 0xAA,0xBB,0xCC,0xDD,
638 					  0xAA ^ 'H', 0xBB ^ 'e', 0xCC ^ 'l', 0xDD ^ 'l', 0xAA ^ 'o'} );
639 			}
640 
641 			REQUIRE_NOTHROW(
642 				restinio::asio_ns::write( socket, restinio::asio_ns::buffer( msg_frame.data(), msg_frame.size() ) )
643 			);
644 
645 			// Validation would fail, close frame in return.
646 			REQUIRE_NOTHROW(
647 				len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ) )
648 			);
649 			REQUIRE( 4 == len );
650 			REQUIRE( 0x88 == data[ 0 ] );
651 			REQUIRE( 0x02 == data[ 1 ] );
652 			REQUIRE( (1002 >> 8) == data[ 2 ] );
653 			REQUIRE( (1002 & 0xFF) == data[ 3 ] );
654 
655 			restinio::asio_ns::error_code ec;
656 			len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ), ec );
657 			REQUIRE( ec );
658 			REQUIRE( restinio::asio_ns::error::eof == ec.value() );
659 		} );
660 
661 	sobj.stop_and_join();
662 
663 	REQUIRE( 1002 == g_last_close_code );
664 }
665 
666 TEST_CASE( "Invalid payload" , "[ws_connection][error_close]" )
667 {
668 	sobj_t sobj;
669 
670 	do_with_socket(
__anon6e6555c40d02( auto & socket, auto & )671 		[&]( auto & socket, auto & /*io_context*/ ){
672 
673 			REQUIRE_NOTHROW(
674 				restinio::asio_ns::write(
675 					socket, restinio::asio_ns::buffer( upgrade_request.data(), upgrade_request.size() ) )
676 			);
677 
678 			std::array< std::uint8_t, 1024 > data;
679 
680 			std::size_t len{ 0 };
681 			REQUIRE_NOTHROW(
682 				len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ) )
683 			);
684 
685 			std::vector< std::uint8_t > msg_frame =
686 					{ 0x81, 0x85, 0x37, 0xfa, 0x21, 0x3d, 'H', 'e', 'l', 'l', 'o' };
687 
688 			SECTION( "simple msg_frame")
689 			{
690 				REQUIRE_NOTHROW(
691 					restinio::asio_ns::write( socket, restinio::asio_ns::buffer( msg_frame.data(), msg_frame.size() ) )
692 				);
693 			}
694 			SECTION( "fragmentated msg_frame")
695 			{
696 				REQUIRE_NOTHROW(
697 					fragmented_send( socket, msg_frame.data(), msg_frame.size() )
698 				);
699 			}
700 
701 			// Validation would fail, so no data in return.
702 			REQUIRE_NOTHROW(
703 				len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ) )
704 			);
705 			REQUIRE( 4 == len );
706 
707 			// TODO: какие должны быть байты?
708 			REQUIRE( 0x88 == data[ 0 ] );
709 			REQUIRE( 0x02 == data[ 1 ] );
710 			REQUIRE( (1007 >> 8) == data[ 2 ] );
711 			REQUIRE( (1007 & 0xFF) == data[ 3 ] );
712 
713 			std::vector< std::uint8_t > close_frame =
714 				{ 0x88, 0x82, 0xFF,0xFF,0xFF,0xFF, 0xFF ^ 0x03, 0xFF ^ 0xef };
715 
716 			REQUIRE_NOTHROW(
717 				restinio::asio_ns::write( socket, restinio::asio_ns::buffer( close_frame.data(), close_frame.size() ) )
718 			);
719 
720 			restinio::asio_ns::error_code ec;
721 			len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ), ec );
722 			REQUIRE( 0 == len );
723 			REQUIRE( ec );
724 			REQUIRE( restinio::asio_ns::error::eof == ec.value() );
725 		} );
726 
727 	sobj.stop_and_join();
728 
729 	REQUIRE( 1007 == g_last_close_code );
730 }
731 
732 TEST_CASE( "Connection lost" , "[ws_connection][error_close][connection_lost]" )
733 {
734 	sobj_t sobj;
735 
736 	do_with_socket(
__anon6e6555c40e02( auto & socket, auto & )737 		[&]( auto & socket, auto & /*io_context*/ ){
738 
739 			REQUIRE_NOTHROW(
740 				restinio::asio_ns::write(
741 					socket, restinio::asio_ns::buffer( upgrade_request.data(), upgrade_request.size() ) )
742 			);
743 
744 			std::array< std::uint8_t, 1024 > data;
745 
746 			std::size_t len{ 0 };
747 			REQUIRE_NOTHROW(
748 				len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ) )
749 			);
750 
751 			std::vector< std::uint8_t > msg_frame =
752 					{ 0x81, 0x85, 0xAA,0xBB,0xCC,0xDD,
753 					  0xAA ^ 'H', 0xBB ^ 'e', 0xCC ^ 'l', 0xDD ^ 'l', 0xAA ^ 'o' };
754 
755 			SECTION( "reset before msg")
756 			{
757 				std::this_thread::sleep_for( std::chrono::milliseconds( 1 ) );
758 				// Do nothing.
759 			}
760 			SECTION( "after header first byte")
761 			{
762 				REQUIRE_NOTHROW(
763 					restinio::asio_ns::write( socket, restinio::asio_ns::buffer( msg_frame.data(), 1 ) )
764 				);
765 			}
766 			SECTION( "after header second byte")
767 			{
768 				REQUIRE_NOTHROW(
769 					restinio::asio_ns::write( socket, restinio::asio_ns::buffer( msg_frame.data(), 2 ) )
770 				);
771 			}
772 			SECTION( "in the middle of mask")
773 			{
774 				REQUIRE_NOTHROW(
775 					restinio::asio_ns::write( socket, restinio::asio_ns::buffer( msg_frame.data(), 4 ) )
776 				);
777 			}
778 			SECTION( "after mask before payload")
779 			{
780 				REQUIRE_NOTHROW(
781 					restinio::asio_ns::write( socket, restinio::asio_ns::buffer( msg_frame.data(), 6 ) )
782 				);
783 			}
784 			SECTION( "in the middle of the payload")
785 			{
786 				REQUIRE_NOTHROW(
787 					restinio::asio_ns::write( socket, restinio::asio_ns::buffer( msg_frame.data(), 8 ) )
788 				);
789 			}
790 
791 			socket.close();
792 
793 		} );
794 
795 	// Give sobjectizer some time to run.
796 	std::this_thread::sleep_for( std::chrono::milliseconds( 500 ) );
797 	sobj.stop_and_join();
798 
799 
800 	REQUIRE( 1006 == g_last_close_code );
801 }
802 
803 TEST_CASE( "Invalid opcode" , "[ws_connection][error_close]" )
804 {
805 	sobj_t sobj;
806 
807 	do_with_socket(
__anon6e6555c40f02( auto & socket, auto & )808 		[&]( auto & socket, auto & /*io_context*/ ){
809 			REQUIRE_NOTHROW(
810 				restinio::asio_ns::write(
811 					socket, restinio::asio_ns::buffer( upgrade_request.data(), upgrade_request.size() ) )
812 			);
813 
814 			std::array< std::uint8_t, 1024 > data;
815 
816 			std::size_t len{ 0 };
817 			REQUIRE_NOTHROW(
818 				len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ) )
819 			);
820 
821 			std::vector< std::uint8_t > msg_frame;
822 			SECTION( "opcode 0x03" )
823 			{
824 				msg_frame.assign(
825 					{ 0x83, 0x85, 0xAA,0xBB,0xCC,0xDD,
826 					  0xAA ^ 'H', 0xBB ^ 'e', 0xCC ^ 'l', 0xDD ^ 'l', 0xAA ^ 'o'} );
827 			}
828 			SECTION( "opcode 0x04" )
829 			{
830 				msg_frame.assign(
831 					{ 0x84, 0x85, 0xAA,0xBB,0xCC,0xDD,
832 					  0xAA ^ 'H', 0xBB ^ 'e', 0xCC ^ 'l', 0xDD ^ 'l', 0xAA ^ 'o'} );
833 			}
834 			SECTION( "opcode 0x05" )
835 			{
836 				msg_frame.assign(
837 					{ 0x85, 0x85, 0xAA,0xBB,0xCC,0xDD,
838 					  0xAA ^ 'H', 0xBB ^ 'e', 0xCC ^ 'l', 0xDD ^ 'l', 0xAA ^ 'o'} );
839 			}
840 			SECTION( "opcode 0x06" )
841 			{
842 				msg_frame.assign(
843 					{ 0x86, 0x85, 0xAA,0xBB,0xCC,0xDD,
844 					  0xAA ^ 'H', 0xBB ^ 'e', 0xCC ^ 'l', 0xDD ^ 'l', 0xAA ^ 'o'} );
845 			}
846 			SECTION( "opcode 0x07" )
847 			{
848 				msg_frame.assign(
849 					{ 0x87, 0x85, 0xAA,0xBB,0xCC,0xDD,
850 					  0xAA ^ 'H', 0xBB ^ 'e', 0xCC ^ 'l', 0xDD ^ 'l', 0xAA ^ 'o'} );
851 			}
852 			SECTION( "opcode 0x0B" )
853 			{
854 				msg_frame.assign(
855 					{ 0x8B, 0x85, 0xAA,0xBB,0xCC,0xDD,
856 					  0xAA ^ 'H', 0xBB ^ 'e', 0xCC ^ 'l', 0xDD ^ 'l', 0xAA ^ 'o'} );
857 			}
858 			SECTION( "opcode 0x0C" )
859 			{
860 				msg_frame.assign(
861 					{ 0x8C, 0x85, 0xAA,0xBB,0xCC,0xDD,
862 					  0xAA ^ 'H', 0xBB ^ 'e', 0xCC ^ 'l', 0xDD ^ 'l', 0xAA ^ 'o'} );
863 			}
864 			SECTION( "opcode 0x0D" )
865 			{
866 				msg_frame.assign(
867 					{ 0x8D, 0x85, 0xAA,0xBB,0xCC,0xDD,
868 					  0xAA ^ 'H', 0xBB ^ 'e', 0xCC ^ 'l', 0xDD ^ 'l', 0xAA ^ 'o'} );
869 			}
870 			SECTION( "opcode 0x0E" )
871 			{
872 				msg_frame.assign(
873 					{ 0x8E, 0x85, 0xAA,0xBB,0xCC,0xDD,
874 					  0xAA ^ 'H', 0xBB ^ 'e', 0xCC ^ 'l', 0xDD ^ 'l', 0xAA ^ 'o'} );
875 			}
876 			SECTION( "opcode 0x0F" )
877 			{
878 				msg_frame.assign(
879 					{ 0x8F, 0x85, 0xAA,0xBB,0xCC,0xDD,
880 					  0xAA ^ 'H', 0xBB ^ 'e', 0xCC ^ 'l', 0xDD ^ 'l', 0xAA ^ 'o'} );
881 			}
882 
883 			REQUIRE_NOTHROW(
884 				restinio::asio_ns::write( socket, restinio::asio_ns::buffer( msg_frame.data(), msg_frame.size() ) )
885 			);
886 
887 			// Validation would fail, close frame in return.
888 			REQUIRE_NOTHROW(
889 				len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ) )
890 			);
891 			REQUIRE( 4 == len );
892 			REQUIRE( 0x88 == data[ 0 ] );
893 			REQUIRE( 0x02 == data[ 1 ] );
894 			REQUIRE( (1002 >> 8) == data[ 2 ] );
895 			REQUIRE( (1002 & 0xFF) == data[ 3 ] );
896 
897 			restinio::asio_ns::error_code ec;
898 			len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ), ec );
899 			REQUIRE( ec );
900 			REQUIRE( restinio::asio_ns::error::eof == ec.value() );
901 		} );
902 
903 	sobj.stop_and_join();
904 
905 	REQUIRE( 1002 == g_last_close_code );
906 }
907 
908 TEST_CASE( "Invalid payload, close on first err 1" , "[ws_connection][echo][normal_close]" )
909 {
910 	sobj_t sobj;
911 
912 	do_with_socket(
__anon6e6555c41002( auto & socket, auto & )913 		[&]( auto & socket, auto & /*io_context*/ ){
914 			REQUIRE_NOTHROW(
915 				restinio::asio_ns::write(
916 					socket, restinio::asio_ns::buffer( upgrade_request.data(), upgrade_request.size() ) )
917 			);
918 
919 			std::array< std::uint8_t, 1024 > data;
920 
921 			std::size_t len{ 0 };
922 			REQUIRE_NOTHROW(
923 				len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ) )
924 			);
925 
926 			std::vector< std::uint8_t > msg_frame =
927 					{ 0x81, 0x80 | 0x10, 0xAA,0xAA,0xAA,0xAA,
928 					  0xAA ^ '1', 0xAA ^ '2', 0xAA ^ '3', 0xAA ^ '4',
929 					  0xAA ^ '5', 0xAA ^ '6', 0xAA ^ '7', 0xAA ^ '8',
930 					  0xAA ^ '9', 0xAA ^ 'A', 0xAA ^ 'B', 0xAA ^ 'C',
931 					  0xAA ^ 'D', 0xAA ^ 'E', 0xAA ^ 'F', 0xAA ^ '0' };
932 
933 			std::size_t indx = 6;
934 			SECTION( "pos 0")
935 			{
936 				indx += 0;
937 			}
938 			SECTION( "pos 2")
939 			{
940 				indx += 2;
941 			}
942 			SECTION( "pos 4")
943 			{
944 				indx += 4;
945 			}
946 			SECTION( "pos 8")
947 			{
948 				indx += 8;
949 			}
950 			SECTION( "pos 15")
951 			{
952 				indx += 15;
953 			}
954 			msg_frame[ indx ] = 0xFF ^ 0xAA;
955 
956 			REQUIRE_NOTHROW(
957 				restinio::asio_ns::write( socket, restinio::asio_ns::buffer( msg_frame.data(), indx ) )
958 			);
959 
960 			// Now error:
961 			REQUIRE_NOTHROW(
962 				restinio::asio_ns::write( socket, restinio::asio_ns::buffer( msg_frame.data() + indx, 1 ) )
963 			);
964 
965 			REQUIRE_NOTHROW(
966 					len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ) )
967 				);
968 			REQUIRE( 4 == len );
969 			REQUIRE( 0x88 == data[ 0 ] );
970 			REQUIRE( 0x02 == data[ 1 ] );
971 			REQUIRE( 0x03 == data[ 2 ] );
972 			REQUIRE( 0xef == data[ 3 ] );
973 
974 			if( indx != msg_frame.size() )
975 			{
976 				REQUIRE_NOTHROW(
977 					restinio::asio_ns::write( socket, restinio::asio_ns::buffer( msg_frame.data() + indx + 1, msg_frame.size() - indx - 1 ) )
978 				);
979 			}
980 
981 			std::vector< std::uint8_t > close_frame =
982 				{0x88, 0x82, 0xFF,0xFF,0xFF,0xFF, 0xFF ^ 0x03, 0xFF ^ 0xef };
983 
984 			REQUIRE_NOTHROW(
985 				restinio::asio_ns::write(
986 					socket, restinio::asio_ns::buffer( close_frame.data(), close_frame.size() ) )
987 			);
988 
989 			restinio::asio_ns::error_code ec;
990 			len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ), ec );
991 			REQUIRE( ec );
992 			REQUIRE( restinio::asio_ns::error::eof == ec.value() );
993 		} );
994 
995 	sobj.stop_and_join();
996 
997 	REQUIRE( 1007 == g_last_close_code );
998 	REQUIRE( 1 == g_message_handled );
999 }
1000 
1001 TEST_CASE( "Invalid payload, close on first err 2", "[ws_connection][echo][normal_close]" )
1002 {
1003 	sobj_t sobj;
1004 
1005 	do_with_socket(
__anon6e6555c41102( auto & socket, auto & )1006 		[&]( auto & socket, auto & /*io_context*/ ){
1007 			REQUIRE_NOTHROW(
1008 				restinio::asio_ns::write(
1009 					socket, restinio::asio_ns::buffer( upgrade_request.data(), upgrade_request.size() ) )
1010 			);
1011 
1012 			std::array< std::uint8_t, 1024 > data;
1013 
1014 			std::size_t len{ 0 };
1015 			REQUIRE_NOTHROW(
1016 				len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ) )
1017 			);
1018 
1019 			std::vector< std::uint8_t > msg_frame =
1020 					{ 0x81, 0x80 | 0x10, 0xAA,0xAA,0xAA,0xAA,
1021 					  0xAA ^ '1', 0xAA ^ '2', 0xAA ^ '3', 0xAA ^ '4',
1022 					  0xAA ^ '5', 0xAA ^ '6', 0xAA ^ '7', 0xAA ^ '8',
1023 					  0xAA ^ '9', 0xAA ^ 'A', 0xAA ^ 'B', 0xAA ^ 'C',
1024 					  0xAA ^ 'D', 0xAA ^ 'E', 0xAA ^ 'F', 0xAA ^ '0' };
1025 
1026 			std::size_t indx = 6;
1027 			SECTION( "pos 0")
1028 			{
1029 				indx += 0;
1030 			}
1031 			SECTION( "pos 2")
1032 			{
1033 				indx += 2;
1034 			}
1035 			SECTION( "pos 4")
1036 			{
1037 				indx += 4;
1038 			}
1039 			SECTION( "pos 8")
1040 			{
1041 				indx += 8;
1042 			}
1043 			SECTION( "pos 15")
1044 			{
1045 				indx += 15;
1046 			}
1047 			unsigned char c = 0xFF ^ 0xAA;
1048 
1049 			REQUIRE_NOTHROW(
1050 				restinio::asio_ns::write( socket, restinio::asio_ns::buffer( msg_frame.data(), indx ) )
1051 			);
1052 
1053 			// Now error:
1054 			REQUIRE_NOTHROW(
1055 				restinio::asio_ns::write( socket, restinio::asio_ns::buffer( &c, 1 ) )
1056 			);
1057 
1058 			REQUIRE_NOTHROW(
1059 					len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ) )
1060 				);
1061 			REQUIRE( 4 == len );
1062 			REQUIRE( 0x88 == data[ 0 ] );
1063 			REQUIRE( 0x02 == data[ 1 ] );
1064 			REQUIRE( 0x03 == data[ 2 ] );
1065 			REQUIRE( 0xef == data[ 3 ] );
1066 
1067 			if( indx != msg_frame.size() )
1068 			{
1069 				REQUIRE_NOTHROW(
1070 					restinio::asio_ns::write( socket, restinio::asio_ns::buffer( msg_frame.data() + indx + 1, msg_frame.size() - indx - 1 ) )
1071 				);
1072 			}
1073 
1074 			// Send one more text-frame (valid one).
1075 			REQUIRE_NOTHROW(
1076 				restinio::asio_ns::write( socket, restinio::asio_ns::buffer( msg_frame.data(), msg_frame.size() ) )
1077 			);
1078 
1079 			std::vector< std::uint8_t > close_frame =
1080 				{0x88, 0x82, 0xFF,0xFF,0xFF,0xFF, 0xFF ^ 0x03, 0xFF ^ 0xef };
1081 
1082 			REQUIRE_NOTHROW(
1083 				restinio::asio_ns::write(
1084 					socket, restinio::asio_ns::buffer( close_frame.data(), close_frame.size() ) )
1085 			);
1086 
1087 			restinio::asio_ns::error_code ec;
1088 			len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ), ec );
1089 			REQUIRE( ec );
1090 			REQUIRE( restinio::asio_ns::error::eof == ec.value() );
1091 		} );
1092 
1093 	sobj.stop_and_join();
1094 
1095 	REQUIRE( 1007 == g_last_close_code );
1096 	REQUIRE( 1 == g_message_handled );
1097 }
1098 
1099 
1100 TEST_CASE( "Invalid payload, close on first err 3", "[ws_connection][echo][normal_close]" )
1101 {
1102 	sobj_t sobj;
1103 
1104 	do_with_socket(
__anon6e6555c41202( auto & socket, auto & )1105 		[&]( auto & socket, auto & /*io_context*/ ){
1106 			REQUIRE_NOTHROW(
1107 				restinio::asio_ns::write(
1108 					socket, restinio::asio_ns::buffer( upgrade_request.data(), upgrade_request.size() ) )
1109 			);
1110 
1111 			std::array< std::uint8_t, 1024 > data;
1112 
1113 			std::size_t len{ 0 };
1114 			REQUIRE_NOTHROW(
1115 				len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ) )
1116 			);
1117 
1118 			std::vector< std::uint8_t > msg_frame =
1119 					{ 0x81, 0x80 | 0x10, 0xAA,0xAA,0xAA,0xAA,
1120 					  0xAA ^ '1', 0xAA ^ '2', 0xAA ^ '3', 0xAA ^ '4',
1121 					  0xAA ^ '5', 0xAA ^ '6', 0xAA ^ '7', 0xAA ^ '8',
1122 					  0xAA ^ '9', 0xAA ^ 'A', 0xAA ^ 'B', 0xAA ^ 'C',
1123 					  0xAA ^ 'D', 0xAA ^ 'E', 0xAA ^ 'F', 0xAA ^ '0' };
1124 
1125 			std::size_t indx = 6;
1126 			SECTION( "pos 0")
1127 			{
1128 				indx += 0;
1129 			}
1130 			SECTION( "pos 2")
1131 			{
1132 				indx += 2;
1133 			}
1134 			SECTION( "pos 4")
1135 			{
1136 				indx += 4;
1137 			}
1138 			SECTION( "pos 8")
1139 			{
1140 				indx += 8;
1141 			}
1142 			SECTION( "pos 15")
1143 			{
1144 				indx += 15;
1145 			}
1146 			msg_frame[ indx ] = 0xFF ^ 0xAA;
1147 
1148 			REQUIRE_NOTHROW(
1149 				restinio::asio_ns::write( socket, restinio::asio_ns::buffer( msg_frame.data(), indx ) )
1150 			);
1151 
1152 			// Now error:
1153 			REQUIRE_NOTHROW(
1154 				restinio::asio_ns::write( socket, restinio::asio_ns::buffer( msg_frame.data() + indx, 1 ) )
1155 			);
1156 
1157 			REQUIRE_NOTHROW(
1158 					len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ) )
1159 				);
1160 			REQUIRE( 4 == len );
1161 			REQUIRE( 0x88 == data[ 0 ] );
1162 			REQUIRE( 0x02 == data[ 1 ] );
1163 			REQUIRE( 0x03 == data[ 2 ] );
1164 			REQUIRE( 0xef == data[ 3 ] );
1165 
1166 			if( indx != msg_frame.size() )
1167 			{
1168 				REQUIRE_NOTHROW(
1169 					restinio::asio_ns::write( socket, restinio::asio_ns::buffer( msg_frame.data() + indx + 1, msg_frame.size() - indx - 1 ) )
1170 				);
1171 			}
1172 
1173 			// Send one more text-frame (invalid one).
1174 			REQUIRE_NOTHROW(
1175 				restinio::asio_ns::write( socket, restinio::asio_ns::buffer( msg_frame.data(), msg_frame.size() ) )
1176 			);
1177 
1178 			std::vector< std::uint8_t > close_frame =
1179 				{0x88, 0x82, 0xFF,0xFF,0xFF,0xFF, 0xFF ^ 0x03, 0xFF ^ 0xef };
1180 
1181 			REQUIRE_NOTHROW(
1182 				restinio::asio_ns::write(
1183 					socket, restinio::asio_ns::buffer( close_frame.data(), close_frame.size() ) )
1184 			);
1185 
1186 			restinio::asio_ns::error_code ec;
1187 			len = socket.read_some( restinio::asio_ns::buffer( data.data(), data.size() ), ec );
1188 			REQUIRE( ec );
1189 			REQUIRE( restinio::asio_ns::error::eof == ec.value() );
1190 		} );
1191 
1192 	sobj.stop_and_join();
1193 
1194 	REQUIRE( 1007 == g_last_close_code );
1195 	REQUIRE( 1 == g_message_handled ); // close frame only.
1196 }
1197 
1198