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