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