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 #pragma once
25
26 #include "tscore/ink_platform.h"
27 #include "tscore/ink_resolver.h"
28 #include "tscore/TSSystemState.h"
29 #include <string_view>
30 #include <memory>
31 #include "P_Net.h"
32 #include "InkAPIInternal.h"
33 #include "http/HttpSessionAccept.h"
34 #include "IPAllow.h"
35 #include "private/SSLProxySession.h"
36
37 // Emit a debug message conditional on whether this particular client session
38 // has debugging enabled. This should only be called from within a client session
39 // member function.
40 #define SsnDebug(ssn, tag, ...) SpecificDebug((ssn)->debug(), tag, __VA_ARGS__)
41
42 class ProxyTransaction;
43 class PoolableSession;
44
45 enum class ProxyErrorClass {
46 NONE,
47 SSN,
48 TXN,
49 };
50
51 struct ProxyError {
ProxyErrorProxyError52 ProxyError() {}
ProxyErrorProxyError53 ProxyError(ProxyErrorClass cl, uint32_t co) : cls(cl), code(co) {}
54 size_t
strProxyError55 str(char *buf, size_t buf_len) const
56 {
57 size_t len = 0;
58
59 if (this->cls == ProxyErrorClass::NONE) {
60 buf[0] = '-';
61 return 1;
62 }
63
64 buf[0] = (this->cls == ProxyErrorClass::SSN) ? 'S' : 'T';
65 ++len;
66
67 len += snprintf(buf + len, buf_len - len, "%" PRIx32, this->code);
68
69 return len;
70 }
71
72 ProxyErrorClass cls = ProxyErrorClass::NONE;
73 uint32_t code = 0;
74 };
75
76 /// Abstract class for HttpSM to interface with any session
77 class ProxySession : public VConnection, public PluginUserArgs<TS_USER_ARGS_SSN>
78 {
79 public:
80 ProxySession();
81 ProxySession(NetVConnection *vc);
82 virtual ~ProxySession();
83
84 // noncopyable
85 ProxySession(ProxySession &) = delete;
86 ProxySession &operator=(const ProxySession &) = delete;
87
88 static int64_t next_connection_id();
89
90 // Virtual Methods
91 virtual void new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBufferReader *reader) = 0;
92 virtual void start() = 0;
93 virtual bool attach_server_session(PoolableSession *ssession, bool transaction_done = true);
94
95 virtual void release(ProxyTransaction *trans) = 0;
96
97 virtual void destroy() = 0;
98 virtual void free() = 0;
99
100 virtual void increment_current_active_connections_stat() = 0;
101 virtual void decrement_current_active_connections_stat() = 0;
102
103 // Virtual Accessors
104 virtual int get_transact_count() const = 0;
105 virtual const char *get_protocol_string() const = 0;
106
107 virtual void hook_add(TSHttpHookID id, INKContInternal *cont);
108
109 virtual bool is_chunked_encoding_supported() const;
110
111 virtual void set_half_close_flag(bool flag);
112 virtual bool get_half_close_flag() const;
113
114 virtual PoolableSession *get_server_session() const;
115
116 // Replicate NetVConnection API
117 virtual sockaddr const *get_remote_addr() const;
118 virtual sockaddr const *get_local_addr();
119
120 virtual void set_active_timeout(ink_hrtime timeout_in);
121 virtual void set_inactivity_timeout(ink_hrtime timeout_in);
122 virtual void cancel_inactivity_timeout();
123 virtual void cancel_active_timeout();
124
125 virtual int populate_protocol(std::string_view *result, int size) const;
126 virtual const char *protocol_contains(std::string_view tag_prefix) const;
127
128 // Non-Virtual Methods
129 NetVConnection *get_netvc() const;
130 int do_api_callout(TSHttpHookID id);
131
132 void set_debug(bool flag);
133 bool debug() const;
134
135 void set_session_active();
136 void clear_session_active();
137 bool is_active() const;
138 bool is_draining() const;
139 bool is_client_closed() const;
140
141 int64_t connection_id() const;
142 TSHttpHookID get_hookid() const;
143 bool has_hooks() const;
144
145 virtual bool support_sni() const;
146
147 APIHook *hook_get(TSHttpHookID id) const;
148 HttpAPIHooks const *feature_hooks() const;
149
150 // Returns null pointer if session does not use a TLS connection.
151 SSLProxySession const *ssl() const;
152
153 // Implement VConnection interface
154 VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = nullptr) override;
155 VIO *do_io_write(Continuation *c = nullptr, int64_t nbytes = INT64_MAX, IOBufferReader *buf = 0, bool owner = false) override;
156 void do_io_shutdown(ShutdownHowTo_t howto) override;
157 void reenable(VIO *vio) override;
158
159 ////////////////////
160 // Members
161
162 IpAllow::ACL acl; ///< IpAllow based method ACL.
163
164 HttpSessionAccept::Options const *accept_options; ///< connection info // L7R TODO: set in constructor
165
166 protected:
167 // Hook dispatching state
168 HttpHookState hook_state;
169
170 // XXX Consider using a bitwise flags variable for the following flags, so
171 // that we can make the best use of internal alignment padding.
172
173 // Session specific debug flag.
174 bool debug_on = false;
175 bool in_destroy = false;
176
177 int64_t con_id = 0;
178 Event *schedule_event = nullptr;
179
180 // This function should be called in all overrides of new_connection() where
181 // the new_vc may be an SSLNetVConnection object.
182 void _handle_if_ssl(NetVConnection *new_vc);
183
184 NetVConnection *_vc = nullptr; // The netvc associated with the concrete session class
185
186 private:
187 void handle_api_return(int event);
188 int state_api_callout(int event, void *edata);
189
190 APIHook const *cur_hook = nullptr;
191 HttpAPIHooks api_hooks;
192
193 // for DI. An active connection is one that a request has
194 // been successfully parsed (PARSE_DONE) and it remains to
195 // be active until the transaction goes through or the client
196 // aborts.
197 bool m_active = false;
198
199 std::unique_ptr<SSLProxySession> _ssl;
200 static inline int64_t next_cs_id = 0;
201 };
202
203 ///////////////////
204 // INLINE
205
206 inline int64_t
next_connection_id()207 ProxySession::next_connection_id()
208 {
209 return ink_atomic_increment(&next_cs_id, 1);
210 }
211
212 inline void
set_debug(bool flag)213 ProxySession::set_debug(bool flag)
214 {
215 debug_on = flag;
216 }
217
218 // Return whether debugging is enabled for this session.
219 inline bool
debug()220 ProxySession::debug() const
221 {
222 return this->debug_on;
223 }
224
225 inline bool
is_active()226 ProxySession::is_active() const
227 {
228 return m_active;
229 }
230
231 inline bool
is_draining()232 ProxySession::is_draining() const
233 {
234 return TSSystemState::is_draining();
235 }
236
237 inline bool
is_client_closed()238 ProxySession::is_client_closed() const
239 {
240 return get_netvc() == nullptr;
241 }
242
243 inline TSHttpHookID
get_hookid()244 ProxySession::get_hookid() const
245 {
246 return hook_state.id();
247 }
248
249 inline void
hook_add(TSHttpHookID id,INKContInternal * cont)250 ProxySession::hook_add(TSHttpHookID id, INKContInternal *cont)
251 {
252 this->api_hooks.append(id, cont);
253 }
254
255 inline APIHook *
hook_get(TSHttpHookID id)256 ProxySession::hook_get(TSHttpHookID id) const
257 {
258 return this->api_hooks.get(id);
259 }
260
261 inline HttpAPIHooks const *
feature_hooks()262 ProxySession::feature_hooks() const
263 {
264 return &api_hooks;
265 }
266
267 inline bool
has_hooks()268 ProxySession::has_hooks() const
269 {
270 return this->api_hooks.has_hooks() || http_global_hooks->has_hooks();
271 }
272
273 inline SSLProxySession const *
ssl()274 ProxySession::ssl() const
275 {
276 return _ssl.get();
277 }
278
279 inline NetVConnection *
get_netvc()280 ProxySession::get_netvc() const
281 {
282 return _vc;
283 }
284