1 /*
2 	restinio
3 */
4 
5 #include <catch2/catch.hpp>
6 
7 #include <restinio/all.hpp>
8 
9 #include <test/common/utest_logger.hpp>
10 #include <test/common/pub.hpp>
11 
12 namespace test
13 {
14 
15 class test_extra_data_factory_t
16 {
17 	struct ctor_dtor_monitors_t
18 	{
19 		std::atomic<int> m_constructors{0};
20 		std::atomic<int> m_destructors{0};
21 	};
22 
23 	std::atomic<int> m_index_counter{0};
24 
25 	ctor_dtor_monitors_t m_ctor_dtor_monitors;
26 
27 public:
28 	class data_t
29 	{
30 		ctor_dtor_monitors_t & m_monitors;
31 
32 	public:
data_t(ctor_dtor_monitors_t & monitors,int index)33 		data_t(
34 			ctor_dtor_monitors_t & monitors,
35 			int index )
36 			:	m_monitors{ monitors }
37 			,	m_index{ index }
38 		{
39 			++m_monitors.m_constructors;
40 		}
~data_t()41 		~data_t()
42 		{
43 			++m_monitors.m_destructors;
44 		}
45 
46 		int m_index;
47 	};
48 
49 	void
make_within(restinio::extra_data_buffer_t<data_t> buffer)50 	make_within( restinio::extra_data_buffer_t<data_t> buffer ) noexcept
51 	{
52 		new(buffer.get()) data_t{ m_ctor_dtor_monitors, ++m_index_counter };
53 	}
54 
55 	RESTINIO_NODISCARD
56 	int
current_value()57 	current_value() noexcept
58 	{
59 		return m_index_counter.load( std::memory_order_acquire );
60 	}
61 
62 	RESTINIO_NODISCARD
63 	int
constructors_called()64 	constructors_called() noexcept
65 	{
66 		return m_ctor_dtor_monitors.m_constructors.load( std::memory_order_acquire );
67 	}
68 
69 	RESTINIO_NODISCARD
70 	int
destructors_called()71 	destructors_called() noexcept
72 	{
73 		return m_ctor_dtor_monitors.m_destructors.load( std::memory_order_acquire );
74 	}
75 };
76 
77 struct test_traits_t : public restinio::traits_t<
78 	restinio::asio_timer_manager_t, utest_logger_t >
79 {
80 	using extra_data_factory_t = test_extra_data_factory_t;
81 };
82 
83 } /* namespace test */
84 
85 TEST_CASE( "remote_endpoint extraction" , "[remote_endpoint]" )
86 {
87 	using namespace test;
88 
89 	using http_server_t = restinio::http_server_t< test_traits_t >;
90 
91 	std::string endpoint_value;
92 	int index_value;
93 
94 	auto extra_data_factory = std::make_shared< test_extra_data_factory_t >();
95 
96 	http_server_t http_server{
97 		restinio::own_io_context(),
__anoncb17e20c0102( )98 		[&endpoint_value, &index_value, extra_data_factory]( auto & settings ){
99 			settings
100 				.port( utest_default_port() )
101 				.address( "127.0.0.1" )
102 				.extra_data_factory( extra_data_factory )
103 				.request_handler(
104 					[&endpoint_value, &index_value]( auto req ){
105 						endpoint_value = fmt::format( "{}", req->remote_endpoint() );
106 						index_value = req->extra_data().m_index;
107 
108 						req->create_response()
109 							.append_header( "Server", "RESTinio utest server" )
110 							.append_header_date_field()
111 							.append_header( "Content-Type", "text/plain; charset=utf-8" )
112 							.set_body(
113 								restinio::const_buffer( req->header().method().c_str() ) )
114 							.done();
115 
116 						return restinio::request_accepted();
117 					} );
118 		} };
119 
120 	other_work_thread_for_server_t<http_server_t> other_thread(http_server);
121 	other_thread.run();
122 
123 	std::string response;
124 	const char * request_str =
125 		"GET / HTTP/1.1\r\n"
126 		"Host: 127.0.0.1\r\n"
127 		"User-Agent: unit-test\r\n"
128 		"Accept: */*\r\n"
129 		"Connection: close\r\n"
130 		"\r\n";
131 
132 	REQUIRE_NOTHROW( response = do_request( request_str ) );
133 
134 	REQUIRE_THAT( response, Catch::Matchers::EndsWith( "GET" ) );
135 
136 	other_thread.stop_and_join();
137 
138 	REQUIRE( !endpoint_value.empty() );
139 	REQUIRE( 0 != extra_data_factory->current_value() );
140 	REQUIRE( 1 == extra_data_factory->constructors_called() );
141 	REQUIRE( 1 == extra_data_factory->destructors_called() );
142 	REQUIRE( 1 == index_value );
143 }
144 
145