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