1 /** @file
2 
3   ProxySession - Base class for protocol client sessions.
4 
5   @section license License
6 
7   Licensed to the Apache Software Foundation (ASF) under one
8   or more contributor license agreements.  See the NOTICE file
9   distributed with this work for additional information
10   regarding copyright ownership.  The ASF licenses this file
11   to you under the Apache License, Version 2.0 (the
12   "License"); you may not use this file except in compliance
13   with the License.  You may obtain a copy of the License at
14 
15       http://www.apache.org/licenses/LICENSE-2.0
16 
17   Unless required by applicable law or agreed to in writing, software
18   distributed under the License is distributed on an "AS IS" BASIS,
19   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   See the License for the specific language governing permissions and
21   limitations under the License.
22  */
23 
24 #include "HttpConfig.h"
25 #include "HttpDebugNames.h"
26 #include "ProxySession.h"
27 #include "P_SSLNetVConnection.h"
28 
ProxySession()29 ProxySession::ProxySession() : VConnection(nullptr) {}
30 
ProxySession(NetVConnection * vc)31 ProxySession::ProxySession(NetVConnection *vc) : VConnection(nullptr), _vc(vc) {}
32 
~ProxySession()33 ProxySession::~ProxySession()
34 {
35   if (schedule_event) {
36     schedule_event->cancel();
37     schedule_event = nullptr;
38   }
39   this->api_hooks.clear();
40   this->mutex.clear();
41   this->acl.clear();
42   this->_ssl.reset();
43 }
44 
45 void
set_session_active()46 ProxySession::set_session_active()
47 {
48   if (!m_active) {
49     m_active = true;
50     this->increment_current_active_connections_stat();
51   }
52 }
53 
54 void
clear_session_active()55 ProxySession::clear_session_active()
56 {
57   if (m_active) {
58     m_active = false;
59     this->decrement_current_active_connections_stat();
60   }
61 }
62 
63 static const TSEvent eventmap[TS_HTTP_LAST_HOOK + 1] = {
64   TS_EVENT_HTTP_READ_REQUEST_HDR,      // TS_HTTP_READ_REQUEST_HDR_HOOK
65   TS_EVENT_HTTP_OS_DNS,                // TS_HTTP_OS_DNS_HOOK
66   TS_EVENT_HTTP_SEND_REQUEST_HDR,      // TS_HTTP_SEND_REQUEST_HDR_HOOK
67   TS_EVENT_HTTP_READ_CACHE_HDR,        // TS_HTTP_READ_CACHE_HDR_HOOK
68   TS_EVENT_HTTP_READ_RESPONSE_HDR,     // TS_HTTP_READ_RESPONSE_HDR_HOOK
69   TS_EVENT_HTTP_SEND_RESPONSE_HDR,     // TS_HTTP_SEND_RESPONSE_HDR_HOOK
70   TS_EVENT_HTTP_REQUEST_TRANSFORM,     // TS_HTTP_REQUEST_TRANSFORM_HOOK
71   TS_EVENT_HTTP_RESPONSE_TRANSFORM,    // TS_HTTP_RESPONSE_TRANSFORM_HOOK
72   TS_EVENT_HTTP_SELECT_ALT,            // TS_HTTP_SELECT_ALT_HOOK
73   TS_EVENT_HTTP_TXN_START,             // TS_HTTP_TXN_START_HOOK
74   TS_EVENT_HTTP_TXN_CLOSE,             // TS_HTTP_TXN_CLOSE_HOOK
75   TS_EVENT_HTTP_SSN_START,             // TS_HTTP_SSN_START_HOOK
76   TS_EVENT_HTTP_SSN_CLOSE,             // TS_HTTP_SSN_CLOSE_HOOK
77   TS_EVENT_HTTP_CACHE_LOOKUP_COMPLETE, // TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK
78   TS_EVENT_HTTP_PRE_REMAP,             // TS_HTTP_PRE_REMAP_HOOK
79   TS_EVENT_HTTP_POST_REMAP,            // TS_HTTP_POST_REMAP_HOOK
80   TS_EVENT_NONE,                       // TS_HTTP_RESPONSE_CLIENT_HOOK
81   TS_EVENT_NONE,                       // TS_HTTP_LAST_HOOK
82 };
83 
84 int
state_api_callout(int event,void * data)85 ProxySession::state_api_callout(int event, void *data)
86 {
87   Event *e = static_cast<Event *>(data);
88   if (e == schedule_event) {
89     schedule_event = nullptr;
90   }
91 
92   switch (event) {
93   case EVENT_NONE:
94   case EVENT_INTERVAL:
95   case TS_EVENT_HTTP_CONTINUE:
96     if (nullptr == cur_hook) {
97       /// Get the next hook to invoke from HttpHookState
98       cur_hook = hook_state.getNext();
99     }
100     if (nullptr != cur_hook) {
101       APIHook const *hook = cur_hook;
102 
103       WEAK_MUTEX_TRY_LOCK(lock, hook->m_cont->mutex, mutex->thread_holding);
104 
105       // Have a mutex but didn't get the lock, reschedule
106       if (!lock.is_locked()) {
107         SET_HANDLER(&ProxySession::state_api_callout);
108         if (!schedule_event) { // Don't bother if there is already one
109           schedule_event = mutex->thread_holding->schedule_in(this, HRTIME_MSECONDS(10));
110         }
111         return -1;
112       }
113 
114       cur_hook = nullptr; // mark current callback at dispatched.
115       hook->invoke(eventmap[hook_state.id()], this);
116 
117       return 0;
118     }
119 
120     handle_api_return(event);
121     break;
122 
123   case TS_EVENT_HTTP_ERROR:
124     this->handle_api_return(event);
125     break;
126 
127   // coverity[unterminated_default]
128   default:
129     ink_release_assert(false);
130   }
131 
132   return 0;
133 }
134 
135 int
do_api_callout(TSHttpHookID id)136 ProxySession::do_api_callout(TSHttpHookID id)
137 {
138   ink_assert(id == TS_HTTP_SSN_START_HOOK || id == TS_HTTP_SSN_CLOSE_HOOK);
139   hook_state.init(id, http_global_hooks, &api_hooks);
140   /// Verify if there is any hook to invoke
141   cur_hook = hook_state.getNext();
142   if (nullptr != cur_hook) {
143     SET_HANDLER(&ProxySession::state_api_callout);
144     return this->state_api_callout(EVENT_NONE, nullptr);
145   } else {
146     this->handle_api_return(TS_EVENT_HTTP_CONTINUE);
147   }
148   return 0;
149 }
150 
151 void
handle_api_return(int event)152 ProxySession::handle_api_return(int event)
153 {
154   TSHttpHookID hookid = hook_state.id();
155 
156   SET_HANDLER(&ProxySession::state_api_callout);
157 
158   cur_hook = nullptr;
159 
160   switch (hookid) {
161   case TS_HTTP_SSN_START_HOOK:
162     if (event == TS_EVENT_HTTP_ERROR) {
163       this->do_io_close();
164     } else {
165       this->start();
166     }
167     break;
168   case TS_HTTP_SSN_CLOSE_HOOK: {
169     free(); // You can now clean things up
170     break;
171   }
172   default:
173     Fatal("received invalid session hook %s (%d)", HttpDebugNames::get_api_hook_name(hookid), hookid);
174     break;
175   }
176 }
177 
178 bool
is_chunked_encoding_supported() const179 ProxySession::is_chunked_encoding_supported() const
180 {
181   return false;
182 }
183 
184 // Override if your session protocol cares.
185 void
set_half_close_flag(bool flag)186 ProxySession::set_half_close_flag(bool flag)
187 {
188 }
189 
190 bool
get_half_close_flag() const191 ProxySession::get_half_close_flag() const
192 {
193   return false;
194 }
195 
196 int64_t
connection_id() const197 ProxySession::connection_id() const
198 {
199   return con_id;
200 }
201 
202 bool
attach_server_session(PoolableSession * ssession,bool transaction_done)203 ProxySession::attach_server_session(PoolableSession *ssession, bool transaction_done)
204 {
205   return false;
206 }
207 
208 PoolableSession *
get_server_session() const209 ProxySession::get_server_session() const
210 {
211   return nullptr;
212 }
213 
214 void
set_active_timeout(ink_hrtime timeout_in)215 ProxySession::set_active_timeout(ink_hrtime timeout_in)
216 {
217   if (_vc) {
218     _vc->set_active_timeout(timeout_in);
219   }
220 }
221 
222 void
set_inactivity_timeout(ink_hrtime timeout_in)223 ProxySession::set_inactivity_timeout(ink_hrtime timeout_in)
224 {
225   if (_vc) {
226     _vc->set_inactivity_timeout(timeout_in);
227   }
228 }
229 
230 void
cancel_inactivity_timeout()231 ProxySession::cancel_inactivity_timeout()
232 {
233   if (_vc) {
234     _vc->cancel_inactivity_timeout();
235   }
236 }
237 
238 void
cancel_active_timeout()239 ProxySession::cancel_active_timeout()
240 {
241   if (_vc) {
242     _vc->cancel_active_timeout();
243   }
244 }
245 
246 int
populate_protocol(std::string_view * result,int size) const247 ProxySession::populate_protocol(std::string_view *result, int size) const
248 {
249   return _vc ? _vc->populate_protocol(result, size) : 0;
250 }
251 
252 const char *
protocol_contains(std::string_view tag_prefix) const253 ProxySession::protocol_contains(std::string_view tag_prefix) const
254 {
255   return _vc ? _vc->protocol_contains(tag_prefix) : nullptr;
256 }
257 
258 sockaddr const *
get_remote_addr() const259 ProxySession::get_remote_addr() const
260 {
261   return _vc ? _vc->get_remote_addr() : nullptr;
262 }
263 
264 sockaddr const *
get_local_addr()265 ProxySession::get_local_addr()
266 {
267   return _vc ? _vc->get_local_addr() : nullptr;
268 }
269 
270 void
_handle_if_ssl(NetVConnection * new_vc)271 ProxySession::_handle_if_ssl(NetVConnection *new_vc)
272 {
273   auto ssl_vc = dynamic_cast<SSLNetVConnection *>(new_vc);
274   if (ssl_vc) {
275     _ssl = std::make_unique<SSLProxySession>();
276     _ssl.get()->init(*ssl_vc);
277   }
278 }
279 
280 VIO *
do_io_read(Continuation * c,int64_t nbytes,MIOBuffer * buf)281 ProxySession::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf)
282 {
283   return _vc ? this->_vc->do_io_read(c, nbytes, buf) : nullptr;
284 }
285 
286 VIO *
do_io_write(Continuation * c,int64_t nbytes,IOBufferReader * buf,bool owner)287 ProxySession::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner)
288 {
289   return _vc ? this->_vc->do_io_write(c, nbytes, buf, owner) : nullptr;
290 }
291 
292 void
do_io_shutdown(ShutdownHowTo_t howto)293 ProxySession::do_io_shutdown(ShutdownHowTo_t howto)
294 {
295   this->_vc->do_io_shutdown(howto);
296 }
297 
298 void
reenable(VIO * vio)299 ProxySession::reenable(VIO *vio)
300 {
301   this->_vc->reenable(vio);
302 }
303 
304 bool
support_sni() const305 ProxySession::support_sni() const
306 {
307   return _vc ? _vc->support_sni() : false;
308 }
309