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 class Http2ClientSession : public ProxySession
64 {
65 public:
66   using super          = ProxySession; ///< Parent type.
67   using SessionHandler = int (Http2ClientSession::*)(int, void *);
68 
69   Http2ClientSession();
70 
71   /////////////////////
72   // Methods
73 
74   // Implement VConnection interface
75   void do_io_close(int lerrno = -1) override;
76 
77   // Implement ProxySession interface
78   void new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBufferReader *reader) override;
79   void start() override;
80   void destroy() override;
81   void release(ProxyTransaction *trans) override;
82   void free() override;
83 
84   // more methods
85   void write_reenable();
86   int64_t xmit(const Http2TxFrame &frame, bool flush = true);
87   void flush();
88 
89   ////////////////////
90   // Accessors
91   sockaddr const *get_remote_addr() const override;
92   sockaddr const *get_local_addr() override;
93   int get_transact_count() const override;
94   const char *get_protocol_string() const override;
95   int populate_protocol(std::string_view *result, int size) const override;
96   const char *protocol_contains(std::string_view prefix) const override;
97   void increment_current_active_connections_stat() override;
98   void decrement_current_active_connections_stat() override;
99 
100   void set_upgrade_context(HTTPHdr *h);
101   void set_dying_event(int event);
102   int get_dying_event() const;
103   bool ready_to_free() const;
104   bool is_recursing() const;
105   void set_half_close_local_flag(bool flag);
106   bool get_half_close_local_flag() const;
107   bool is_url_pushed(const char *url, int url_len);
108   void add_url_to_pushed_table(const char *url, int url_len);
109   int64_t write_buffer_size();
110 
111   // Record history from Http2ConnectionState
112   void remember(const SourceLocation &location, int event, int reentrant = NO_REENTRANT);
113 
114   int64_t write_avail();
115 
116   // noncopyable
117   Http2ClientSession(Http2ClientSession &) = delete;
118   Http2ClientSession &operator=(const Http2ClientSession &) = delete;
119 
120   ///////////////////
121   // Variables
122   Http2ConnectionState connection_state;
123 
124 private:
125   int main_event_handler(int, void *);
126 
127   int state_read_connection_preface(int, void *);
128   int state_start_frame_read(int, void *);
129   int do_start_frame_read(Http2ErrorCode &ret_error);
130   int state_complete_frame_read(int, void *);
131   int do_complete_frame_read();
132   // state_start_frame_read and state_complete_frame_read are set up as
133   // event handler.  Both feed into state_process_frame_read which may iterate
134   // if there are multiple frames ready on the wire
135   int state_process_frame_read(int event, VIO *vio, bool inside_frame);
136 
137   bool _should_do_something_else();
138 
139   ////////
140   // Variables
141   SessionHandler session_handler = nullptr;
142 
143   MIOBuffer *read_buffer              = nullptr;
144   IOBufferReader *_read_buffer_reader = nullptr;
145 
146   VIO *write_vio                       = nullptr;
147   MIOBuffer *write_buffer              = nullptr;
148   IOBufferReader *_write_buffer_reader = nullptr;
149 
150   Http2FrameHeader current_hdr        = {0, 0, 0, 0};
151   uint32_t _write_size_threshold      = 0;
152   uint32_t _write_time_threshold      = 100;
153   ink_hrtime _write_buffer_last_flush = 0;
154 
155   IpEndpoint cached_client_addr;
156   IpEndpoint cached_local_addr;
157 
158   History<HISTORY_DEFAULT_SIZE> _history;
159   Milestones<Http2SsnMilestone, static_cast<size_t>(Http2SsnMilestone::LAST_ENTRY)> _milestones;
160 
161   int dying_event                = 0;
162   bool kill_me                   = false;
163   Http2SessionCod cause_of_death = Http2SessionCod::NOT_PROVIDED;
164   bool half_close_local          = false;
165   int recursion                  = 0;
166 
167   std::unordered_set<std::string> *_h2_pushed_urls = nullptr;
168 
169   Event *_reenable_event = nullptr;
170   int _n_frame_read      = 0;
171 
172   uint32_t _pending_sending_data_size = 0;
173 
174   int64_t read_from_early_data   = 0;
175   bool cur_frame_from_early_data = false;
176 };
177 
178 extern ClassAllocator<Http2ClientSession, true> http2ClientSessionAllocator;
179 
180 ///////////////////////////////////////////////
181 // INLINE
182 
183 inline bool
ready_to_free()184 Http2ClientSession::ready_to_free() const
185 {
186   return kill_me;
187 }
188 
189 inline void
set_dying_event(int event)190 Http2ClientSession::set_dying_event(int event)
191 {
192   dying_event = event;
193 }
194 
195 inline int
get_dying_event()196 Http2ClientSession::get_dying_event() const
197 {
198   return dying_event;
199 }
200 
201 inline bool
is_recursing()202 Http2ClientSession::is_recursing() const
203 {
204   return recursion > 0;
205 }
206 
207 inline bool
get_half_close_local_flag()208 Http2ClientSession::get_half_close_local_flag() const
209 {
210   return half_close_local;
211 }
212 
213 inline bool
is_url_pushed(const char * url,int url_len)214 Http2ClientSession::is_url_pushed(const char *url, int url_len)
215 {
216   if (_h2_pushed_urls == nullptr) {
217     return false;
218   }
219 
220   return _h2_pushed_urls->find(url) != _h2_pushed_urls->end();
221 }
222 
223 inline int64_t
write_buffer_size()224 Http2ClientSession::write_buffer_size()
225 {
226   return write_buffer->max_read_avail();
227 }
228