1 /*
2 	restinio
3 */
4 
5 /*!
6 	Sendfile.
7 */
8 
9 #include <catch2/catch.hpp>
10 
11 #include <restinio/all.hpp>
12 
13 #include <restinio/utils/at_scope_exit.hpp>
14 
15 #include <test/common/utest_logger.hpp>
16 #include <test/common/pub.hpp>
17 
18 using logger_to_use_t = restinio::null_logger_t;
19 //using logger_to_use_t = utest_logger_t;
20 
21 TEST_CASE( "sendfile offset/size representation" , "[sendfile]" )
22 {
23 	REQUIRE( 8 == sizeof( restinio::file_offset_t ) );
24 	REQUIRE( 8 == sizeof( restinio::file_size_t ) );
25 }
26 
27 TEST_CASE( "simple sendfile" , "[sendfile]" )
28 {
29 	using http_server_t =
30 		restinio::http_server_t<
31 			restinio::traits_t<
32 				restinio::asio_timer_manager_t,
33 				logger_to_use_t > >;
34 
35 	http_server_t http_server{
36 		restinio::own_io_context(),
__anoned0e0aff0102( )37 		[]( auto & settings ){
38 			settings
39 				.port( utest_default_port() )
40 				.address( "127.0.0.1" )
41 				.request_handler(
42 					[]( auto req ){
43 						if( restinio::http_method_get() == req->header().method() )
44 						{
45 							req->create_response()
46 								.append_header( "Server", "RESTinio utest server" )
47 								.append_header_date_field()
48 								.append_header( "Content-Type", "text/plain; charset=utf-8" )
49 								.set_body( restinio::sendfile( "test/sendfile/f1.dat" ) )
50 								.done();
51 							return restinio::request_accepted();
52 						}
53 
54 						return restinio::request_rejected();
55 					} );
56 		}
57 	};
58 
59 	other_work_thread_for_server_t<http_server_t> other_thread{ http_server };
60 	other_thread.run();
61 
62 	const std::string request{
63 			"GET / HTTP/1.0\r\n"
64 			"From: unit-test\r\n"
65 			"User-Agent: unit-test\r\n"
66 			"Content-Type: application/x-www-form-urlencoded\r\n"
67 			"Connection: close\r\n"
68 			"\r\n"
69 	};
70 	std::string response;
71 
72 	REQUIRE_NOTHROW( response = do_request( request ) );
73 
74 	REQUIRE_THAT(
75 		response,
76 		Catch::Matchers::EndsWith(
77 			"0123456789\n"
78 			"FILE1\n"
79 			"0123456789\n" ) );
80 
81 	other_thread.stop_and_join();
82 }
83 
84 TEST_CASE( "sendfile the same file several times" , "[sendfile][same-several-times]" )
85 {
86 	using http_server_t =
87 		restinio::http_server_t<
88 			restinio::traits_t<
89 				restinio::asio_timer_manager_t,
90 				utest_logger_t > >;
91 
92 	http_server_t http_server{
93 		restinio::own_io_context(),
__anoned0e0aff0302( )94 		[]( auto & settings ){
95 			settings
96 				.port( utest_default_port() )
97 				.address( "127.0.0.1" )
98 				.request_handler(
99 					[]( auto req ){
100 						if( restinio::http_method_get() == req->header().method() )
101 						{
102 							req->create_response()
103 								.append_header( "Server", "RESTinio utest server" )
104 								.append_header_date_field()
105 								.append_header( "Content-Type", "text/plain; charset=utf-8" )
106 								.set_body( restinio::sendfile( "test/sendfile/f1.dat" ) )
107 								.set_body( restinio::sendfile( "test/sendfile/f1.dat" ) )
108 								.set_body( restinio::sendfile( "test/sendfile/f1.dat" ) )
109 								.set_body( restinio::sendfile( "test/sendfile/f1.dat" ) )
110 								.done();
111 							return restinio::request_accepted();
112 						}
113 
114 						return restinio::request_rejected();
115 					} );
116 		}
117 	};
118 
119 	other_work_thread_for_server_t<http_server_t> other_thread{ http_server };
120 	other_thread.run();
121 
122 	const std::string request{
123 			"GET / HTTP/1.0\r\n"
124 			"From: unit-test\r\n"
125 			"User-Agent: unit-test\r\n"
126 			"Content-Type: application/x-www-form-urlencoded\r\n"
127 			"Connection: close\r\n"
128 			"\r\n"
129 	};
130 	std::string response;
131 
132 	REQUIRE_NOTHROW( response = do_request( request ) );
133 
134 	REQUIRE_THAT(
135 		response,
136 		Catch::Matchers::EndsWith(
137 			"0123456789\n"
138 			"FILE1\n"
139 			"0123456789\n" ) );
140 
141 	other_thread.stop_and_join();
142 }
143 
144 TEST_CASE( "sendfile 2 files" , "[sendfile][n-files]" )
145 {
146 	using router_t = restinio::router::express_router_t<>;
147 
148 	auto router = std::make_unique< router_t >();
149 
150 	const std::string dir{ "test/sendfile/" };
151 
152 	router->http_get(
153 		"/:f1/:f2",
__anoned0e0aff0502( auto req, auto params )154 		[ & ]( auto req, auto params ){
155 			return
156 				req->create_response()
157 					.append_header( "Server", "RESTinio Benchmark" )
158 					.append_header_date_field()
159 					.append_header( "Content-Type", "text/plain; charset=utf-8" )
160 					.append_body(
161 						restinio::sendfile(
162 							dir + restinio::cast_to< std::string >( params[ "f1" ] ) + ".dat" ) )
163 					.append_body(
164 						restinio::sendfile(
165 							dir + restinio::cast_to< std::string >( params[ "f2" ] ) + ".dat" ) )
166 					.done();
167 		} );
168 	router->http_get(
169 		"/:f1/:regularBuffer/:f2",
__anoned0e0aff0602( auto req, auto params )170 		[ & ]( auto req, auto params ){
171 			return
172 				req->create_response()
173 					.append_header( "Server", "RESTinio Benchmark" )
174 					.append_header_date_field()
175 					.append_header( "Content-Type", "text/plain; charset=utf-8" )
176 					.append_body(
177 						restinio::sendfile(
178 							dir + restinio::cast_to< std::string >( params[ "f1" ] ) + ".dat" ) )
179 					.append_body(
180 						restinio::cast_to< std::string >( params[ "regularBuffer" ] ) )
181 					.append_body(
182 						restinio::sendfile(
183 							dir + restinio::cast_to< std::string >( params[ "f2" ] ) + ".dat" ) )
184 					.done();
185 		} );
186 
187 
188 	using http_server_t =
189 		restinio::http_server_t<
190 			restinio::traits_t<
191 				restinio::asio_timer_manager_t,
192 				logger_to_use_t,
193 				router_t > >;
194 
195 	http_server_t http_server{
196 		restinio::own_io_context(),
__anoned0e0aff0702( )197 		[&]( auto & settings ){
198 			settings
199 				.port( utest_default_port() )
200 				.address( "127.0.0.1" )
201 				.request_handler( std::move( router ) );
202 		}
203 	};
204 
205 	other_work_thread_for_server_t<http_server_t> other_thread{ http_server };
206 	other_thread.run();
207 
208 	{
209 		const std::string request{
210 				"GET /f1/f2 HTTP/1.0\r\n"
211 				"From: unit-test\r\n"
212 				"User-Agent: unit-test\r\n"
213 				"Content-Type: application/x-www-form-urlencoded\r\n"
214 				"Connection: close\r\n"
215 				"\r\n"
216 		};
217 		std::string response;
218 
219 		REQUIRE_NOTHROW( response = do_request( request ) );
220 
221 		REQUIRE_THAT(
222 			response,
223 			Catch::Matchers::EndsWith(
224 				"0123456789\n"
225 				"FILE1\n"
226 				"0123456789\n"
227 				"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n" ) );
228 	}
229 
230 	{
231 		const std::string request{
232 				"GET /f2/f1 HTTP/1.0\r\n"
233 				"From: unit-test\r\n"
234 				"User-Agent: unit-test\r\n"
235 				"Content-Type: application/x-www-form-urlencoded\r\n"
236 				"Connection: close\r\n"
237 				"\r\n"
238 		};
239 		std::string response;
240 
241 		REQUIRE_NOTHROW( response = do_request( request ) );
242 
243 		REQUIRE_THAT(
244 			response,
245 			Catch::Matchers::EndsWith(
246 				"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n"
247 				"0123456789\n"
248 				"FILE1\n"
249 				"0123456789\n" ) );
250 	}
251 
252 
253 	{
254 		const std::string request{
255 				"GET /f1/REGULARBUFFER/f2 HTTP/1.0\r\n"
256 				"From: unit-test\r\n"
257 				"User-Agent: unit-test\r\n"
258 				"Content-Type: application/x-www-form-urlencoded\r\n"
259 				"Connection: close\r\n"
260 				"\r\n"
261 		};
262 		std::string response;
263 
264 		REQUIRE_NOTHROW( response = do_request( request ) );
265 
266 		REQUIRE_THAT(
267 			response,
268 			Catch::Matchers::EndsWith(
269 				"0123456789\n"
270 				"FILE1\n"
271 				"0123456789\n"
272 				"REGULARBUFFER"
273 				"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n" ) );
274 	}
275 
276 	other_thread.stop_and_join();
277 }
278 
279 TEST_CASE( "sendfile offsets_and_size" , "[sendfile][offset][size]" )
280 {
281 	using router_t = restinio::router::express_router_t<>;
282 
283 	auto router = std::make_unique< router_t >();
284 
285 	const std::string dir{ "test/sendfile/" };
286 
287 	router->http_get(
288 		R"(/:fname/:offset(\d+))",
__anoned0e0aff0802( auto req, auto params )289 		[ & ]( auto req, auto params ){
290 			auto fname = dir + restinio::cast_to< std::string >( params[ "fname" ] ) + ".dat";
291 			return
292 				req->create_response()
293 					.append_header( "Server", "RESTinio Benchmark" )
294 					.append_header_date_field()
295 					.append_header( "Content-Type", "text/plain; charset=utf-8" )
296 					.append_body(
297 						restinio::sendfile( fname )
298 							.offset_and_size( restinio::cast_to< restinio::file_offset_t >( params[ "offset" ] ) ) )
299 					.done();
300 		} );
301 
302 	router->http_get(
303 		R"(/:fname/:offset(\d+)/:size(\d+))",
__anoned0e0aff0902( auto req, auto params )304 		[ & ]( auto req, auto params ){
305 			auto fname = dir + restinio::cast_to< std::string >( params[ "fname" ] ) + ".dat";
306 			const auto offset = restinio::cast_to< restinio::file_offset_t >( params[ "offset" ] );
307 			const auto size = restinio::cast_to< restinio::file_size_t >( params[ "size" ] );
308 			return
309 				req->create_response()
310 					.append_header( "Server", "RESTinio Benchmark" )
311 					.append_header_date_field()
312 					.append_header( "Content-Type", "text/plain; charset=utf-8" )
313 					.append_body(
314 						restinio::sendfile( fname ).offset_and_size( offset, size ) )
315 					.done();
316 		} );
317 
318 	using http_server_t =
319 		restinio::http_server_t<
320 			restinio::traits_t<
321 				restinio::asio_timer_manager_t,
322 				logger_to_use_t,
323 				router_t > >;
324 
325 	http_server_t http_server{
326 		restinio::own_io_context(),
__anoned0e0aff0a02( )327 		[&]( auto & settings ){
328 			settings
329 				.port( utest_default_port() )
330 				.address( "127.0.0.1" )
331 				.request_handler( std::move( router ) );
332 		}
333 	};
334 
335 	other_work_thread_for_server_t<http_server_t> other_thread{ http_server };
336 	other_thread.run();
337 
338 	{
339 		const std::string all_file{ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n" };
340 
341 		for( std::size_t i = 0; i < all_file.size(); ++i )
342 		{
343 			const std::string request{
344 					"GET /f2/" + std::to_string( i ) + " HTTP/1.0\r\n"
345 					"From: unit-test\r\n"
346 					"User-Agent: unit-test\r\n"
347 					"Content-Type: application/x-www-form-urlencoded\r\n"
348 					"Connection: close\r\n"
349 					"\r\n"
350 			};
351 
352 			std::string response;
353 			REQUIRE_NOTHROW( response = do_request( request ) );
354 
355 			REQUIRE_THAT(
356 				response,
357 				Catch::Matchers::EndsWith(
358 					all_file.substr( i ) ) );
359 		}
360 	}
361 
362 	{
363 		const std::string single_string{ "SENDILE 012345678901234567890123456789012345678901234567890123456789\n" };
364 
365 		for( std::size_t n = 0; n < 3301; n+= 300 )
366 			for( std::size_t i = 0; i < single_string.size(); ++i )
367 			{
368 				const std::string request{
369 						"GET /f3/" +
370 							std::to_string( n * single_string.size() ) + "/" +
371 							std::to_string( i ) + " HTTP/1.0\r\n"
372 						"From: unit-test\r\n"
373 						"User-Agent: unit-test\r\n"
374 						"Content-Type: application/x-www-form-urlencoded\r\n"
375 						"Connection: close\r\n"
376 						"\r\n"
377 				};
378 
379 				std::string response;
380 				REQUIRE_NOTHROW( response = do_request( request ) );
381 
382 				REQUIRE_THAT(
383 					response,
384 					Catch::Matchers::EndsWith(
385 						single_string.substr( 0, i ) ) );
386 			}
387 	}
388 
389 	other_thread.stop_and_join();
390 }
391 
392 TEST_CASE( "sendfile chunks" , "[sendfile][chunk]" )
393 {
394 	using router_t = restinio::router::express_router_t<>;
395 
396 	auto router = std::make_unique< router_t >();
397 
398 	const std::string dir{ "test/sendfile/" };
399 
400 	router->http_get(
401 		R"(/:fname/:chunk(\d+))",
__anoned0e0aff0b02( auto req, auto params )402 		[ & ]( auto req, auto params ){
403 			auto fname = dir + restinio::cast_to< std::string >( params[ "fname" ] ) + ".dat";
404 			const auto chunk_size = restinio::cast_to< restinio::file_size_t >( params[ "chunk" ] );
405 			return
406 				req->create_response()
407 					.append_header( "Server", "RESTinio Benchmark" )
408 					.append_header_date_field()
409 					.append_header( "Content-Type", "text/plain; charset=utf-8" )
410 					.append_body(
411 						restinio::sendfile( fname ).chunk_size( chunk_size ) )
412 					.done();
413 		} );
414 
415 	using http_server_t =
416 		restinio::http_server_t<
417 			restinio::traits_t<
418 				restinio::asio_timer_manager_t,
419 				logger_to_use_t,
420 				router_t > >;
421 
422 	http_server_t http_server{
423 		restinio::own_io_context(),
__anoned0e0aff0c02( )424 		[&]( auto & settings ){
425 			settings
426 				.port( utest_default_port() )
427 				.address( "127.0.0.1" )
428 				.request_handler( std::move( router ) );
429 		}
430 	};
431 
432 	other_work_thread_for_server_t<http_server_t> other_thread{ http_server };
433 	other_thread.run();
434 
435 	{
436 		const std::string request{
437 				"GET /f1/4 HTTP/1.0\r\n"
438 				"From: unit-test\r\n"
439 				"User-Agent: unit-test\r\n"
440 				"Content-Type: application/x-www-form-urlencoded\r\n"
441 				"Connection: close\r\n"
442 				"\r\n"
443 		};
444 
445 		std::string response;
446 		REQUIRE_NOTHROW( response = do_request( request ) );
447 
448 		REQUIRE_THAT(
449 			response,
450 			Catch::Matchers::EndsWith(
451 				"0123456789\n"
452 				"FILE1\n"
453 				"0123456789\n" ) );
454 	}
455 
456 	{
457 		const std::string request{
458 				"GET /f2/5 HTTP/1.0\r\n"
459 				"From: unit-test\r\n"
460 				"User-Agent: unit-test\r\n"
461 				"Content-Type: application/x-www-form-urlencoded\r\n"
462 				"Connection: close\r\n"
463 				"\r\n"
464 		};
465 
466 		std::string response;
467 		REQUIRE_NOTHROW( response = do_request( request ) );
468 
469 		REQUIRE_THAT(
470 			response,
471 			Catch::Matchers::EndsWith(
472 				"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n" ) );
473 	}
474 
475 	{
476 		const std::string request{
477 				"GET /f1/1 HTTP/1.0\r\n"
478 				"From: unit-test\r\n"
479 				"User-Agent: unit-test\r\n"
480 				"Content-Type: application/x-www-form-urlencoded\r\n"
481 				"Connection: close\r\n"
482 				"\r\n"
483 		};
484 
485 		std::string response;
486 		REQUIRE_NOTHROW( response = do_request( request ) );
487 
488 		REQUIRE_THAT(
489 			response,
490 			Catch::Matchers::EndsWith(
491 				"0123456789\n"
492 				"FILE1\n"
493 				"0123456789\n" ) );
494 	}
495 
496 	{
497 		const std::string request{
498 				"GET /f2/1 HTTP/1.0\r\n"
499 				"From: unit-test\r\n"
500 				"User-Agent: unit-test\r\n"
501 				"Content-Type: application/x-www-form-urlencoded\r\n"
502 				"Connection: close\r\n"
503 				"\r\n"
504 		};
505 
506 		std::string response;
507 		REQUIRE_NOTHROW( response = do_request( request ) );
508 
509 		REQUIRE_THAT(
510 			response,
511 			Catch::Matchers::EndsWith(
512 				"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n" ) );
513 	}
514 
515 	other_thread.stop_and_join();
516 }
517 
518 TEST_CASE( "sendfile errors" , "[sendfile][error]" )
519 {
520 	using router_t = restinio::router::express_router_t<>;
521 
522 	auto router = std::make_unique< router_t >();
523 
524 	const std::string dir{ "test/sendfile/" };
525 
526 	router->http_get(
527 		R"(/:fname/:offset(\d+))",
__anoned0e0aff0d02( auto req, auto params )528 		[ & ]( auto req, auto params ){
529 			auto fname = dir + restinio::cast_to< std::string >( params[ "fname" ] ) + ".dat";
530 			return
531 				req->create_response()
532 					.append_header( "Server", "RESTinio Benchmark" )
533 					.append_header_date_field()
534 					.append_header( "Content-Type", "text/plain; charset=utf-8" )
535 					.append_body(
536 						restinio::sendfile( fname )
537 							.offset_and_size( restinio::cast_to< restinio::file_offset_t >( params[ "offset" ] ) ) )
538 					.done();
539 		} );
540 
541 	router->http_get(
542 		R"(/:fname/:offset(\d+)/:size(\d+))",
__anoned0e0aff0e02( auto req, auto params )543 		[ & ]( auto req, auto params ){
544 			auto fname = dir + restinio::cast_to< std::string >( params[ "fname" ] ) + ".dat";
545 			const auto offset = restinio::cast_to< restinio::file_offset_t >( params[ "offset" ] );
546 			const auto size = restinio::cast_to< restinio::file_size_t >( params[ "size" ] );
547 			return
548 				req->create_response()
549 					.append_header( "Server", "RESTinio Benchmark" )
550 					.append_header_date_field()
551 					.append_header( "Content-Type", "text/plain; charset=utf-8" )
552 					.append_body(
553 						restinio::sendfile( fname ).offset_and_size( offset, size ) )
554 					.done();
555 		} );
556 
557 	using http_server_t =
558 		restinio::http_server_t<
559 			restinio::traits_t<
560 				restinio::asio_timer_manager_t,
561 				logger_to_use_t,
562 				router_t > >;
563 
564 	http_server_t http_server{
565 		restinio::own_io_context(),
__anoned0e0aff0f02( )566 		[&]( auto & settings ){
567 			settings
568 				.port( utest_default_port() )
569 				.address( "127.0.0.1" )
570 				.request_handler( std::move( router ) );
571 		}
572 	};
573 
574 	other_work_thread_for_server_t<http_server_t> other_thread{ http_server };
575 	other_thread.run();
576 
577 	{
578 		const std::string request{
579 				"GET /nosuchfile/0 HTTP/1.0\r\n"
580 				"From: unit-test\r\n"
581 				"User-Agent: unit-test\r\n"
582 				"Content-Type: application/x-www-form-urlencoded\r\n"
583 				"Connection: close\r\n"
584 				"\r\n"
585 		};
586 
587 		std::string response;
588 		REQUIRE_THROWS( response = do_request( request ) );
589 	}
590 
591 	{
592 		const std::string request{
593 				"GET /f2/1024 HTTP/1.0\r\n"
594 				"From: unit-test\r\n"
595 				"User-Agent: unit-test\r\n"
596 				"Content-Type: application/x-www-form-urlencoded\r\n"
597 				"Connection: close\r\n"
598 				"\r\n"
599 		};
600 
601 		std::string response;
602 		REQUIRE_THROWS( response = do_request( request ) );
603 	}
604 
605 	other_thread.stop_and_join();
606 }
607 
608 TEST_CASE( "sendfile with invalid descriptor with " , "[sendfile][error][is_valid]" )
609 {
610 	{
611 		const std::string fname = "must_not_exist_file_name";
612 
613 		REQUIRE_THROWS( restinio::sendfile( fname ) );
614 	}
615 
616 	{
617 		const std::string fname = "test/sendfile/f1.dat";
__anoned0e0aff1002( restinio::sendfile_t sf )618 		auto accept_moved = []( restinio::sendfile_t sf ){ REQUIRE( sf.is_valid() ); };
619 		auto sf = restinio::sendfile( fname );
620 
621 		accept_moved( std::move( sf ) );
622 
623 		REQUIRE_FALSE( sf.is_valid() );
624 	}
625 }
626 
627 TEST_CASE( "sendfile_chunk_size_guarded_value_t " , "[chunk_size_guarded_value]" )
628 {
629 	{
630 		restinio::sendfile_chunk_size_guarded_value_t chunk( 42 );
631 		REQUIRE( chunk.value() == 42 );
632 	}
633 	{
634 		restinio::sendfile_chunk_size_guarded_value_t chunk( 0 );
635 		REQUIRE( chunk.value() == restinio::sendfile_default_chunk_size );
636 	}
637 	{
638 		restinio::sendfile_chunk_size_guarded_value_t chunk( restinio::sendfile_max_chunk_size + 10 );
639 		REQUIRE( chunk.value() == restinio::sendfile_max_chunk_size );
640 	}
641 }
642 
643 TEST_CASE( "sendfile with partially-read response" ,
644 		"[sendfile][close-during-read]" )
645 {
646 	using http_server_t =
647 		restinio::http_server_t<
648 			restinio::traits_t<
649 				restinio::asio_timer_manager_t,
650 				utest_logger_t > >;
651 
652 	http_server_t http_server{
653 		restinio::own_io_context(),
__anoned0e0aff1102( )654 		[]( auto & settings ){
655 			settings
656 				.port( utest_default_port() )
657 				.address( "127.0.0.1" )
658 				.request_handler(
659 					[]( auto req ){
660 						if( restinio::http_method_get() == req->header().method() )
661 						{
662 							req->create_response()
663 								.append_header( "Server", "RESTinio utest server" )
664 								.append_header_date_field()
665 								.append_header( "Content-Type", "text/plain; charset=utf-8" )
666 								.set_body( restinio::sendfile( "test/sendfile/f3.dat" ) )
667 								.done();
668 							return restinio::request_accepted();
669 						}
670 
671 						return restinio::request_rejected();
672 					} );
673 		}
674 	};
675 
676 	other_work_thread_for_server_t<http_server_t> other_thread{ http_server };
677 	other_thread.run();
678 
679 #if defined(SIGPIPE)
680 	auto old_sig = signal(SIGPIPE, SIG_IGN);
__anoned0e0aff1302null681 	auto sig_restorer = restinio::utils::at_scope_exit( [&old_sig] {
682 			signal(SIGPIPE, old_sig);
683 		} );
684 #endif
685 
686 	const std::string request{
687 			"GET / HTTP/1.0\r\n"
688 			"From: unit-test\r\n"
689 			"User-Agent: unit-test\r\n"
690 			"Content-Type: application/x-www-form-urlencoded\r\n"
691 			"Connection: close\r\n"
692 			"\r\n"
693 	};
694 
695 	for(unsigned int i = 0; i != 20; ++i ) {
696 		do_with_socket(
__anoned0e0aff1402( auto & socket, auto & ) 697 			[&request]( auto & socket, auto & /*io_context*/ ) {
698 				restinio::asio_ns::streambuf b;
699 				std::ostream req_stream(&b);
700 				req_stream << request;
701 				restinio::asio_ns::write( socket, b );
702 
703 				restinio::asio_ns::streambuf response_stream;
704 				restinio::asio_ns::read_until( socket, response_stream, "\r\n\r\n" );
705 				std::array<char, 10> body;
706 				restinio::asio_ns::read( socket, restinio::asio_ns::buffer(body) );
707 
708 				socket.close();
709 			} );
710 	}
711 
712 	other_thread.stop_and_join();
713 }
714 
715