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