1 /*!
2  * @file
3  * @brief Implementation of connect_method_handler.
4  */
5 
6 #include <arataga/acl_handler/handlers/http/basics.hpp>
7 #include <arataga/acl_handler/handlers/http/factories.hpp>
8 #include <arataga/acl_handler/handlers/http/helpers.hpp>
9 #include <arataga/acl_handler/handlers/http/responses.hpp>
10 
11 #include <arataga/acl_handler/handler_factories.hpp>
12 
13 namespace arataga::acl_handler
14 {
15 
16 namespace handlers::http
17 {
18 
19 //
20 // connect_method_handler_t
21 //
22 /*!
23  * @brief Connection-handler that services CONNECT method.
24  */
25 class connect_method_handler_t final : public handler_with_out_connection_t
26 {
27 	//! The first chunk of the incoming connection.
28 	/*!
29 	 * Has to be passed to data_transfer_handler.
30 	 *
31 	 * @since v.0.5.0
32 	 */
33 	first_chunk_for_next_handler_t m_first_chunk_data;
34 
35 	//! Description of the target host.
36 	/*!
37 	 * It's necessary for logging purposes.
38 	 */
39 	const std::string m_connection_target;
40 
41 	//! Traffic limiter for the user.
42 	traffic_limiter_unique_ptr_t m_traffic_limiter;
43 
44 	//! Buffer for positive response to the user.
45 	/*!
46 	 * After the sending of the response a data-transfer handler will
47 	 * be used for the connection.
48 	 */
49 	out_string_view_buffer_t m_positive_response;
50 
51 	//! Timepoint when this object was created.
52 	/*!
53 	 * Used for controlling the timeout of sending the response.
54 	 */
55 	std::chrono::steady_clock::time_point m_created_at;
56 
57 public:
connect_method_handler_t(handler_context_holder_t ctx,handler_context_t::connection_id_t id,asio::ip::tcp::socket in_connection,http_handling_state_unique_ptr_t http_state,request_info_t request_info,traffic_limiter_unique_ptr_t traffic_limiter,asio::ip::tcp::socket out_connection)58 	connect_method_handler_t(
59 		handler_context_holder_t ctx,
60 		handler_context_t::connection_id_t id,
61 		asio::ip::tcp::socket in_connection,
62 		http_handling_state_unique_ptr_t http_state,
63 		request_info_t request_info,
64 		traffic_limiter_unique_ptr_t traffic_limiter,
65 		asio::ip::tcp::socket out_connection )
66 		:	handler_with_out_connection_t{
67 				std::move(ctx),
68 				id,
69 				std::move(in_connection),
70 				std::move(out_connection)
71 			}
72 		,	m_first_chunk_data{
73 				http_state->giveaway_first_chunk_for_next_handler()
74 			}
75 		,	m_connection_target{
76 				fmt::format( "{}:{}",
77 					request_info.m_target_host,
78 					request_info.m_target_port )
79 			}
80 		,	m_traffic_limiter{ std::move(traffic_limiter) }
81 		,	m_positive_response{ response_ok_for_connect_method }
82 		,	m_created_at{ std::chrono::steady_clock::now() }
83 	{
84 	}
85 
86 protected:
87 	void
on_start_impl(delete_protector_t delete_protector)88 	on_start_impl( delete_protector_t delete_protector ) override
89 	{
90 		wrap_action_and_handle_exceptions(
91 			delete_protector,
92 			[this]( delete_protector_t, can_throw_t can_throw ) {
93 				::arataga::logging::wrap_logging(
94 						proxy_logging_mode,
95 						spdlog::level::info,
96 						[this, can_throw]( auto level )
97 						{
98 							log_message_for_connection(
99 									can_throw,
100 									level,
101 									"serving-request=CONNECT " + m_connection_target );
102 						} );
103 
104 				// Have to send positive response to the user.
105 				write_whole( can_throw,
106 						m_connection,
107 						m_positive_response,
108 						[this]( delete_protector_t delete_protector,
109 							can_throw_t can_throw )
110 						{
111 							// The response is sent. Now we can switch
112 							// to data-transfer-handler.
113 							replace_handler(
114 									delete_protector,
115 									can_throw,
116 									[this]( can_throw_t )
117 									{
118 										return make_data_transfer_handler(
119 												std::move(m_ctx),
120 												m_id,
121 												std::move(m_connection),
122 												std::move(m_first_chunk_data),
123 												std::move(m_out_connection),
124 												std::move(m_traffic_limiter) );
125 									} );
126 						} );
127 			} );
128 	}
129 
130 	void
on_timer_impl(delete_protector_t delete_protector)131 	on_timer_impl( delete_protector_t delete_protector ) override
132 	{
133 		wrap_action_and_handle_exceptions(
134 			delete_protector,
135 			[this]( delete_protector_t delete_protector, can_throw_t can_throw )
136 			{
137 				// Will use idle_connection_timeout as the timeout duration.
138 				const auto now = std::chrono::steady_clock::now();
139 				if( m_created_at +
140 						context().config().idle_connection_timeout() < now )
141 				{
142 					return log_and_remove_connection(
143 							delete_protector,
144 							can_throw,
145 							remove_reason_t::no_activity_for_too_long,
146 							spdlog::level::warn,
147 							"timeout writing positive response to CONNECT method" );
148 				}
149 			} );
150 	}
151 
152 public:
153 	arataga::utils::string_literal_t
name() const154 	name() const noexcept override
155 	{
156 		using namespace arataga::utils::string_literals;
157 		return "http-connect-method-handler"_static_str;
158 	}
159 };
160 
161 //
162 // make_connect_method_handler
163 //
164 [[nodiscard]]
165 connection_handler_shptr_t
make_connect_method_handler(handler_context_holder_t ctx,handler_context_t::connection_id_t id,asio::ip::tcp::socket in_connection,http_handling_state_unique_ptr_t http_state,request_info_t request_info,traffic_limiter_unique_ptr_t traffic_limiter,asio::ip::tcp::socket out_connection)166 make_connect_method_handler(
167 	handler_context_holder_t ctx,
168 	handler_context_t::connection_id_t id,
169 	asio::ip::tcp::socket in_connection,
170 	http_handling_state_unique_ptr_t http_state,
171 	request_info_t request_info,
172 	traffic_limiter_unique_ptr_t traffic_limiter,
173 	asio::ip::tcp::socket out_connection )
174 {
175 	return std::make_shared< connect_method_handler_t >(
176 			std::move(ctx),
177 			id,
178 			std::move(in_connection),
179 			std::move(http_state),
180 			std::move(request_info),
181 			std::move(traffic_limiter),
182 			std::move(out_connection) );
183 }
184 
185 } /* namespace arataga::acl_handler */
186 
187 } /* namespace handlers::http */
188 
189