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