1 /** @file
2 
3   Http2ClientSession.
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 "HTTP2.h"
27 #include "Plugin.h"
28 #include "ProxySession.h"
29 #include "Http2ConnectionState.h"
30 #include "Http2Frame.h"
31 #include <string_view>
32 #include "tscore/ink_inet.h"
33 #include "tscore/History.h"
34 #include "Milestones.h"
35 
36 // Name                       Edata                 Description
37 // HTTP2_SESSION_EVENT_INIT   Http2ClientSession *  HTTP/2 session is born
38 // HTTP2_SESSION_EVENT_FINI   Http2ClientSession *  HTTP/2 session is ended
39 // HTTP2_SESSION_EVENT_RECV   Http2Frame *          Received a frame
40 // HTTP2_SESSION_EVENT_XMIT   Http2Frame *          Send this frame
41 
42 #define HTTP2_SESSION_EVENT_INIT (HTTP2_SESSION_EVENTS_START + 1)
43 #define HTTP2_SESSION_EVENT_FINI (HTTP2_SESSION_EVENTS_START + 2)
44 #define HTTP2_SESSION_EVENT_RECV (HTTP2_SESSION_EVENTS_START + 3)
45 #define HTTP2_SESSION_EVENT_XMIT (HTTP2_SESSION_EVENTS_START + 4)
46 #define HTTP2_SESSION_EVENT_SHUTDOWN_INIT (HTTP2_SESSION_EVENTS_START + 5)
47 #define HTTP2_SESSION_EVENT_SHUTDOWN_CONT (HTTP2_SESSION_EVENTS_START + 6)
48 #define HTTP2_SESSION_EVENT_REENABLE (HTTP2_SESSION_EVENTS_START + 7)
49 
50 enum class Http2SessionCod : int {
51   NOT_PROVIDED,
52   HIGH_ERROR_RATE,
53 };
54 
55 enum class Http2SsnMilestone {
56   OPEN = 0,
57   CLOSE,
58   LAST_ENTRY,
59 };
60 
61 size_t const HTTP2_HEADER_BUFFER_SIZE_INDEX = CLIENT_CONNECTION_FIRST_READ_BUFFER_SIZE_INDEX;
62 
63 // To support Upgrade: h2c
64 struct Http2UpgradeContext {
Http2UpgradeContextHttp2UpgradeContext65   Http2UpgradeContext() {}
~Http2UpgradeContextHttp2UpgradeContext66   ~Http2UpgradeContext()
67   {
68     if (req_header) {
69       req_header->clear();
70       delete req_header;
71     }
72   }
73 
74   // Modified request header
75   HTTPHdr *req_header = nullptr;
76 
77   // Decoded HTTP2-Settings Header Field
78   Http2ConnectionSettings client_settings;
79 };
80 
81 class Http2ClientSession : public ProxySession
82 {
83 public:
84   using super          = ProxySession; ///< Parent type.
85   using SessionHandler = int (Http2ClientSession::*)(int, void *);
86 
87   Http2ClientSession();
88 
89   /////////////////////
90   // Methods
91 
92   // Implement VConnection interface
93   void do_io_close(int lerrno = -1) override;
94 
95   // Implement ProxySession interface
96   void new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBufferReader *reader) override;
97   void start() override;
98   void destroy() override;
99   void release(ProxyTransaction *trans) override;
100   void free() override;
101 
102   // more methods
103   void write_reenable();
104   int64_t xmit(const Http2TxFrame &frame);
105 
106   ////////////////////
107   // Accessors
108   sockaddr const *get_client_addr() override;
109   sockaddr const *get_local_addr() override;
110   int get_transact_count() const override;
111   const char *get_protocol_string() const override;
112   int populate_protocol(std::string_view *result, int size) const override;
113   const char *protocol_contains(std::string_view prefix) const override;
114   void increment_current_active_client_connections_stat() override;
115   void decrement_current_active_client_connections_stat() override;
116 
117   void set_upgrade_context(HTTPHdr *h);
118   const Http2UpgradeContext &get_upgrade_context() const;
119   void set_dying_event(int event);
120   int get_dying_event() const;
121   bool ready_to_free() const;
122   bool is_recursing() const;
123   void set_half_close_local_flag(bool flag);
124   bool get_half_close_local_flag() const;
125   bool is_url_pushed(const char *url, int url_len);
126   void add_url_to_pushed_table(const char *url, int url_len);
127   int64_t write_buffer_size();
128 
129   // Record history from Http2ConnectionState
130   void remember(const SourceLocation &location, int event, int reentrant = NO_REENTRANT);
131 
132   int64_t write_avail();
133 
134   // noncopyable
135   Http2ClientSession(Http2ClientSession &) = delete;
136   Http2ClientSession &operator=(const Http2ClientSession &) = delete;
137 
138   ///////////////////
139   // Variables
140   Http2ConnectionState connection_state;
141 
142 private:
143   int main_event_handler(int, void *);
144 
145   int state_read_connection_preface(int, void *);
146   int state_start_frame_read(int, void *);
147   int do_start_frame_read(Http2ErrorCode &ret_error);
148   int state_complete_frame_read(int, void *);
149   int do_complete_frame_read();
150   // state_start_frame_read and state_complete_frame_read are set up as
151   // event handler.  Both feed into state_process_frame_read which may iterate
152   // if there are multiple frames ready on the wire
153   int state_process_frame_read(int event, VIO *vio, bool inside_frame);
154 
155   bool _should_do_something_else();
156 
157   int64_t total_write_len        = 0;
158   SessionHandler session_handler = nullptr;
159   MIOBuffer *read_buffer         = nullptr;
160   IOBufferReader *_reader        = nullptr;
161   MIOBuffer *write_buffer        = nullptr;
162   IOBufferReader *sm_writer      = nullptr;
163   Http2FrameHeader current_hdr   = {0, 0, 0, 0};
164 
165   IpEndpoint cached_client_addr;
166   IpEndpoint cached_local_addr;
167 
168   History<HISTORY_DEFAULT_SIZE> _history;
169   Milestones<Http2SsnMilestone, static_cast<size_t>(Http2SsnMilestone::LAST_ENTRY)> _milestones;
170 
171   // For Upgrade: h2c
172   Http2UpgradeContext upgrade_context;
173 
174   VIO *write_vio                 = nullptr;
175   int dying_event                = 0;
176   bool kill_me                   = false;
177   Http2SessionCod cause_of_death = Http2SessionCod::NOT_PROVIDED;
178   bool half_close_local          = false;
179   int recursion                  = 0;
180 
181   std::unordered_set<std::string> *_h2_pushed_urls = nullptr;
182 
183   Event *_reenable_event = nullptr;
184   int _n_frame_read      = 0;
185 
186   int64_t read_from_early_data   = 0;
187   bool cur_frame_from_early_data = false;
188 };
189 
190 extern ClassAllocator<Http2ClientSession> http2ClientSessionAllocator;
191 
192 ///////////////////////////////////////////////
193 // INLINE
194 
195 inline const Http2UpgradeContext &
get_upgrade_context() const196 Http2ClientSession::get_upgrade_context() const
197 {
198   return upgrade_context;
199 }
200 
201 inline bool
ready_to_free() const202 Http2ClientSession::ready_to_free() const
203 {
204   return kill_me;
205 }
206 
207 inline void
set_dying_event(int event)208 Http2ClientSession::set_dying_event(int event)
209 {
210   dying_event = event;
211 }
212 
213 inline int
get_dying_event() const214 Http2ClientSession::get_dying_event() const
215 {
216   return dying_event;
217 }
218 
219 inline bool
is_recursing() const220 Http2ClientSession::is_recursing() const
221 {
222   return recursion > 0;
223 }
224 
225 inline bool
get_half_close_local_flag() const226 Http2ClientSession::get_half_close_local_flag() const
227 {
228   return half_close_local;
229 }
230 
231 inline bool
is_url_pushed(const char * url,int url_len)232 Http2ClientSession::is_url_pushed(const char *url, int url_len)
233 {
234   if (_h2_pushed_urls == nullptr) {
235     return false;
236   }
237 
238   return _h2_pushed_urls->find(url) != _h2_pushed_urls->end();
239 }
240 
241 inline int64_t
write_buffer_size()242 Http2ClientSession::write_buffer_size()
243 {
244   return write_buffer->max_read_avail();
245 }
246