1 /** @file
2
3 Http2Stream.h
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 "NetTimeout.h"
27
28 #include "HTTP2.h"
29 #include "ProxyTransaction.h"
30 #include "Http2DebugNames.h"
31 #include "Http2DependencyTree.h"
32 #include "tscore/History.h"
33 #include "Milestones.h"
34
35 class Http2Stream;
36 class Http2ConnectionState;
37
38 typedef Http2DependencyTree::Tree<Http2Stream *> DependencyTree;
39
40 enum class Http2StreamMilestone {
41 OPEN = 0,
42 START_DECODE_HEADERS,
43 START_TXN,
44 START_ENCODE_HEADERS,
45 START_TX_HEADERS_FRAMES,
46 START_TX_DATA_FRAMES,
47 CLOSE,
48 LAST_ENTRY,
49 };
50
51 class Http2Stream : public ProxyTransaction
52 {
53 public:
54 const int retry_delay = HRTIME_MSECONDS(10);
55 using super = ProxyTransaction; ///< Parent type.
56
Http2Stream()57 Http2Stream() {} // Just to satisfy ClassAllocator
58 Http2Stream(ProxySession *session, Http2StreamId sid, ssize_t initial_rwnd);
59 ~Http2Stream();
60
61 int main_event_handler(int event, void *edata);
62
63 void release(IOBufferReader *r) override;
64 void reenable(VIO *vio) override;
65 void transaction_done() override;
66
do_io_shutdown(ShutdownHowTo_t)67 void do_io_shutdown(ShutdownHowTo_t) override {}
68 VIO *do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) override;
69 VIO *do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *abuffer, bool owner = false) override;
70 void do_io_close(int lerrno = -1) override;
71
72 Http2ErrorCode decode_header_blocks(HpackHandle &hpack_handle, uint32_t maximum_table_size);
73 void send_request(Http2ConnectionState &cstate);
74 void initiating_close();
75 void terminate_if_possible();
76 void update_read_request(bool send_update);
77 void update_write_request(bool send_update);
78
79 void signal_read_event(int event);
80 void signal_write_event(int event);
81 void signal_write_event(bool call_update);
82
83 void restart_sending();
84 bool push_promise(URL &url, const MIMEField *accept_encoding);
85
86 // Stream level window size
87 ssize_t client_rwnd() const;
88 Http2ErrorCode increment_client_rwnd(size_t amount);
89 Http2ErrorCode decrement_client_rwnd(size_t amount);
90 ssize_t server_rwnd() const;
91 Http2ErrorCode increment_server_rwnd(size_t amount);
92 Http2ErrorCode decrement_server_rwnd(size_t amount);
93
94 /////////////////
95 // Accessors
96 void set_active_timeout(ink_hrtime timeout_in) override;
97 void set_inactivity_timeout(ink_hrtime timeout_in) override;
98 void cancel_active_timeout() override;
99 void cancel_inactivity_timeout() override;
100 bool is_active_timeout_expired(ink_hrtime now);
101 bool is_inactive_timeout_expired(ink_hrtime now);
102
103 bool is_first_transaction() const override;
104 void increment_client_transactions_stat() override;
105 void decrement_client_transactions_stat() override;
106 int get_transaction_id() const override;
107 int get_transaction_priority_weight() const override;
108 int get_transaction_priority_dependence() const override;
109
110 void clear_io_events();
111
112 bool is_client_state_writeable() const;
113 bool is_closed() const;
114 IOBufferReader *response_get_data_reader() const;
115
116 bool has_request_body(int64_t content_length, bool is_chunked_set) const override;
117
118 void mark_milestone(Http2StreamMilestone type);
119
120 void increment_data_length(uint64_t length);
121 bool payload_length_is_valid() const;
122 bool is_write_vio_done() const;
123 void update_sent_count(unsigned num_bytes);
124 Http2StreamId get_id() const;
125 Http2StreamState get_state() const;
126 bool change_state(uint8_t type, uint8_t flags);
127 void update_initial_rwnd(Http2WindowSize new_size);
128 bool has_trailing_header() const;
129 void set_request_headers(HTTPHdr &h2_headers);
130 MIOBuffer *read_vio_writer() const;
131 int64_t read_vio_read_avail();
132
133 //////////////////
134 // Variables
135 uint8_t *header_blocks = nullptr;
136 uint32_t header_blocks_length = 0; // total length of header blocks (not include Padding or other fields)
137
138 bool recv_end_stream = false;
139 bool send_end_stream = false;
140
141 bool sent_request_header = false;
142 bool response_header_done = false;
143 bool request_sent = false;
144 bool is_first_transaction_flag = false;
145
146 HTTPHdr response_header;
147 Http2DependencyTree::Node *priority_node = nullptr;
148
149 private:
150 bool response_is_data_available() const;
151 Event *send_tracked_event(Event *event, int send_event, VIO *vio);
152 void send_response_body(bool call_update);
153 void _clear_timers();
154
155 /**
156 * Check if this thread is the right thread to process events for this
157 * continuation.
158 * Return true if the caller can continue event processing.
159 */
160 bool _switch_thread_if_not_on_right_thread(int event, void *edata);
161
162 NetTimeout _timeout{};
163 HTTPParser http_parser;
164 EThread *_thread = nullptr;
165 Http2StreamId _id;
166 Http2StreamState _state = Http2StreamState::HTTP2_STREAM_STATE_IDLE;
167 int64_t _http_sm_id = -1;
168
169 HTTPHdr _req_header;
170 MIOBuffer _request_buffer = CLIENT_CONNECTION_FIRST_READ_BUFFER_SIZE_INDEX;
171 int64_t read_vio_nbytes;
172 VIO read_vio;
173 VIO write_vio;
174
175 History<HISTORY_DEFAULT_SIZE> _history;
176 Milestones<Http2StreamMilestone, static_cast<size_t>(Http2StreamMilestone::LAST_ENTRY)> _milestones;
177
178 bool trailing_header = false;
179 bool has_body = false;
180
181 // A brief discussion of similar flags and state variables: _state, closed, terminate_stream
182 //
183 // _state tracks the HTTP2 state of the stream. This field completely coincides with the H2 spec.
184 //
185 // closed is a flag that gets set when the framework indicates that the stream should be shutdown. This flag
186 // is set from either do_io_close, which indicates that the HttpSM is starting the close, or initiating_close,
187 // which indicates that the HTTP2 infrastructure is starting the close (e.g. due to the HTTP2 session shutting down
188 // or a end of stream frame being received. The closed flag does not indicate that it is safe to delete the stream
189 // immediately. Perhaps the closed flag could be folded into the _state field.
190 //
191 // terminate_stream flag gets set from the transaction_done() method. This means that the HttpSM has shutdown. Now
192 // we can delete the stream object. To ensure that the session and transaction close hooks are executed in the correct order
193 // we need to enforce that the stream is not deleted until after the state machine has shutdown. The reentrancy_count is
194 // associated with the terminate_stream flag. We need to make sure that we don't delete the stream object while we have stream
195 // methods on the stack. The reentrancy count is incremented as we enter the stream event handler. As we leave the event
196 // handler we decrement the reentrancy count, and check to see if the teriminate_stream flag and destroy the object if that is the
197 // case.
198 // The same pattern is used with HttpSM for object clean up.
199 //
200 bool closed = false;
201 int reentrancy_count = 0;
202 bool terminate_stream = false;
203
204 uint64_t data_length = 0;
205 uint64_t bytes_sent = 0;
206
207 ssize_t _client_rwnd = 0;
208 ssize_t _server_rwnd = 0;
209
210 std::vector<size_t> _recent_rwnd_increment = {SIZE_MAX, SIZE_MAX, SIZE_MAX, SIZE_MAX, SIZE_MAX};
211 int _recent_rwnd_increment_index = 0;
212
213 Event *cross_thread_event = nullptr;
214 Event *buffer_full_write_event = nullptr;
215
216 Event *read_event = nullptr;
217 Event *write_event = nullptr;
218 Event *_read_vio_event = nullptr;
219 Event *_write_vio_event = nullptr;
220 };
221
222 extern ClassAllocator<Http2Stream, true> http2StreamAllocator;
223
224 ////////////////////////////////////////////////////
225 // INLINE
226
227 inline void
mark_milestone(Http2StreamMilestone type)228 Http2Stream::mark_milestone(Http2StreamMilestone type)
229 {
230 this->_milestones.mark(type);
231 }
232
233 inline bool
is_write_vio_done()234 Http2Stream::is_write_vio_done() const
235 {
236 return this->write_vio.ntodo() == 0;
237 }
238
239 inline void
update_sent_count(unsigned num_bytes)240 Http2Stream::update_sent_count(unsigned num_bytes)
241 {
242 bytes_sent += num_bytes;
243 this->write_vio.ndone += num_bytes;
244 }
245
246 inline Http2StreamId
get_id()247 Http2Stream::get_id() const
248 {
249 return _id;
250 }
251
252 inline int
get_transaction_id()253 Http2Stream::get_transaction_id() const
254 {
255 return _id;
256 }
257
258 inline Http2StreamState
get_state()259 Http2Stream::get_state() const
260 {
261 return _state;
262 }
263
264 inline void
update_initial_rwnd(Http2WindowSize new_size)265 Http2Stream::update_initial_rwnd(Http2WindowSize new_size)
266 {
267 this->_client_rwnd = new_size;
268 }
269
270 inline bool
has_trailing_header()271 Http2Stream::has_trailing_header() const
272 {
273 return trailing_header;
274 }
275
276 inline void
set_request_headers(HTTPHdr & h2_headers)277 Http2Stream::set_request_headers(HTTPHdr &h2_headers)
278 {
279 _req_header.copy(&h2_headers);
280 }
281
282 // Check entire DATA payload length if content-length: header is exist
283 inline void
increment_data_length(uint64_t length)284 Http2Stream::increment_data_length(uint64_t length)
285 {
286 data_length += length;
287 }
288
289 inline bool
payload_length_is_valid()290 Http2Stream::payload_length_is_valid() const
291 {
292 uint32_t content_length = _req_header.get_content_length();
293 return content_length == 0 || content_length == data_length;
294 }
295
296 inline bool
is_client_state_writeable()297 Http2Stream::is_client_state_writeable() const
298 {
299 return _state == Http2StreamState::HTTP2_STREAM_STATE_OPEN || _state == Http2StreamState::HTTP2_STREAM_STATE_HALF_CLOSED_REMOTE ||
300 _state == Http2StreamState::HTTP2_STREAM_STATE_RESERVED_LOCAL;
301 }
302
303 inline bool
is_closed()304 Http2Stream::is_closed() const
305 {
306 return closed;
307 }
308
309 inline bool
is_first_transaction()310 Http2Stream::is_first_transaction() const
311 {
312 return is_first_transaction_flag;
313 }
314
315 inline MIOBuffer *
read_vio_writer()316 Http2Stream::read_vio_writer() const
317 {
318 return this->read_vio.get_writer();
319 }
320
321 inline void
_clear_timers()322 Http2Stream::_clear_timers()
323 {
324 _timeout.cancel_active_timeout();
325 _timeout.cancel_inactive_timeout();
326 }
327