xref: /trafficserver/proxy/http2/Http2Stream.h (revision 9ab53fe9)
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 
57   Http2Stream(Http2StreamId sid = 0, ssize_t initial_rwnd = Http2::initial_window_size);
58 
59   void init(Http2StreamId sid, ssize_t initial_rwnd);
60 
61   int main_event_handler(int event, void *edata);
62 
63   void destroy() override;
64   void release(IOBufferReader *r) override;
65   void reenable(VIO *vio) override;
66   void transaction_done() override;
67 
do_io_shutdown(ShutdownHowTo_t)68   void do_io_shutdown(ShutdownHowTo_t) override {}
69   VIO *do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) override;
70   VIO *do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *abuffer, bool owner = false) override;
71   void do_io_close(int lerrno = -1) override;
72 
73   Http2ErrorCode decode_header_blocks(HpackHandle &hpack_handle, uint32_t maximum_table_size);
74   void send_request(Http2ConnectionState &cstate);
75   void initiating_close();
76   void terminate_if_possible();
77   void update_read_request(bool send_update);
78   void update_write_request(bool send_update);
79 
80   void signal_read_event(int event);
81   void signal_write_event(int event);
82   void signal_write_event(bool call_update);
83 
84   void restart_sending();
85   bool push_promise(URL &url, const MIMEField *accept_encoding);
86 
87   // Stream level window size
88   ssize_t client_rwnd() const;
89   Http2ErrorCode increment_client_rwnd(size_t amount);
90   Http2ErrorCode decrement_client_rwnd(size_t amount);
91   ssize_t server_rwnd() const;
92   Http2ErrorCode increment_server_rwnd(size_t amount);
93   Http2ErrorCode decrement_server_rwnd(size_t amount);
94 
95   /////////////////
96   // Accessors
97   void set_active_timeout(ink_hrtime timeout_in) override;
98   void set_inactivity_timeout(ink_hrtime timeout_in) override;
99   void cancel_active_timeout();
100   void cancel_inactivity_timeout() override;
101   bool is_active_timeout_expired(ink_hrtime now);
102   bool is_inactive_timeout_expired(ink_hrtime now);
103 
104   bool allow_half_open() const override;
105   bool is_first_transaction() const override;
106   void increment_client_transactions_stat() override;
107   void decrement_client_transactions_stat() override;
108   int get_transaction_id() const override;
109   int get_transaction_priority_weight() const override;
110   int get_transaction_priority_dependence() const override;
111 
112   void clear_io_events();
113 
114   bool is_client_state_writeable() const;
115   bool is_closed() const;
116   IOBufferReader *response_get_data_reader() const;
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 
154   /**
155    * Check if this thread is the right thread to process events for this
156    * continuation.
157    * Return true if the caller can continue event processing.
158    */
159   bool _switch_thread_if_not_on_right_thread(int event, void *edata);
160 
161   NetTimeout _timeout{};
162   HTTPParser http_parser;
163   EThread *_thread = nullptr;
164   Http2StreamId _id;
165   Http2StreamState _state = Http2StreamState::HTTP2_STREAM_STATE_IDLE;
166   int64_t _http_sm_id     = -1;
167 
168   HTTPHdr _req_header;
169   MIOBuffer _request_buffer = CLIENT_CONNECTION_FIRST_READ_BUFFER_SIZE_INDEX;
170   int64_t read_vio_nbytes;
171   VIO read_vio;
172   VIO write_vio;
173 
174   History<HISTORY_DEFAULT_SIZE> _history;
175   Milestones<Http2StreamMilestone, static_cast<size_t>(Http2StreamMilestone::LAST_ENTRY)> _milestones;
176 
177   bool trailing_header = false;
178 
179   // A brief discussion of similar flags and state variables:  _state, closed, terminate_stream
180   //
181   // _state tracks the HTTP2 state of the stream.  This field completely coincides with the H2 spec.
182   //
183   // closed is a flag that gets set when the framework indicates that the stream should be shutdown.  This flag
184   // is set from either do_io_close, which indicates that the HttpSM is starting the close, or initiating_close,
185   // which indicates that the HTTP2 infrastructure is starting the close (e.g. due to the HTTP2 session shutting down
186   // or a end of stream frame being received.  The closed flag does not indicate that it is safe to delete the stream
187   // immediately. Perhaps the closed flag could be folded into the _state field.
188   //
189   // terminate_stream flag gets set from the transaction_done() method.  This means that the HttpSM has shutdown.  Now
190   // we can delete the stream object.  To ensure that the session and transaction close hooks are executed in the correct order
191   // we need to enforce that the stream is not deleted until after the state machine has shutdown.  The reentrancy_count is
192   // associated with the terminate_stream flag.  We need to make sure that we don't delete the stream object while we have stream
193   // methods on the stack.  The reentrancy count is incremented as we enter the stream event handler.  As we leave the event
194   // handler we decrement the reentrancy count, and check to see if the teriminate_stream flag and destroy the object if that is the
195   // case.
196   // The same pattern is used with HttpSM for object clean up.
197   //
198   bool closed           = false;
199   int reentrancy_count  = 0;
200   bool terminate_stream = false;
201 
202   uint64_t data_length = 0;
203   uint64_t bytes_sent  = 0;
204 
205   ssize_t _client_rwnd = 0;
206   ssize_t _server_rwnd = 0;
207 
208   std::vector<size_t> _recent_rwnd_increment = {SIZE_MAX, SIZE_MAX, SIZE_MAX, SIZE_MAX, SIZE_MAX};
209   int _recent_rwnd_increment_index           = 0;
210 
211   Event *cross_thread_event      = nullptr;
212   Event *buffer_full_write_event = nullptr;
213 
214   Event *read_event       = nullptr;
215   Event *write_event      = nullptr;
216   Event *_read_vio_event  = nullptr;
217   Event *_write_vio_event = nullptr;
218 };
219 
220 extern ClassAllocator<Http2Stream> http2StreamAllocator;
221 
222 ////////////////////////////////////////////////////
223 // INLINE
224 
225 inline void
mark_milestone(Http2StreamMilestone type)226 Http2Stream::mark_milestone(Http2StreamMilestone type)
227 {
228   this->_milestones.mark(type);
229 }
230 
231 inline bool
is_write_vio_done() const232 Http2Stream::is_write_vio_done() const
233 {
234   return this->write_vio.ntodo() == 0;
235 }
236 
237 inline void
update_sent_count(unsigned num_bytes)238 Http2Stream::update_sent_count(unsigned num_bytes)
239 {
240   bytes_sent += num_bytes;
241   this->write_vio.ndone += num_bytes;
242 }
243 
244 inline Http2StreamId
get_id() const245 Http2Stream::get_id() const
246 {
247   return _id;
248 }
249 
250 inline int
get_transaction_id() const251 Http2Stream::get_transaction_id() const
252 {
253   return _id;
254 }
255 
256 inline Http2StreamState
get_state() const257 Http2Stream::get_state() const
258 {
259   return _state;
260 }
261 
262 inline void
update_initial_rwnd(Http2WindowSize new_size)263 Http2Stream::update_initial_rwnd(Http2WindowSize new_size)
264 {
265   this->_client_rwnd = new_size;
266 }
267 
268 inline bool
has_trailing_header() const269 Http2Stream::has_trailing_header() const
270 {
271   return trailing_header;
272 }
273 
274 inline void
set_request_headers(HTTPHdr & h2_headers)275 Http2Stream::set_request_headers(HTTPHdr &h2_headers)
276 {
277   _req_header.copy(&h2_headers);
278 }
279 
280 // Check entire DATA payload length if content-length: header is exist
281 inline void
increment_data_length(uint64_t length)282 Http2Stream::increment_data_length(uint64_t length)
283 {
284   data_length += length;
285 }
286 
287 inline bool
payload_length_is_valid() const288 Http2Stream::payload_length_is_valid() const
289 {
290   uint32_t content_length = _req_header.get_content_length();
291   return content_length == 0 || content_length == data_length;
292 }
293 
294 inline bool
allow_half_open() const295 Http2Stream::allow_half_open() const
296 {
297   return false;
298 }
299 
300 inline bool
is_client_state_writeable() const301 Http2Stream::is_client_state_writeable() const
302 {
303   return _state == Http2StreamState::HTTP2_STREAM_STATE_OPEN || _state == Http2StreamState::HTTP2_STREAM_STATE_HALF_CLOSED_REMOTE ||
304          _state == Http2StreamState::HTTP2_STREAM_STATE_RESERVED_LOCAL;
305 }
306 
307 inline bool
is_closed() const308 Http2Stream::is_closed() const
309 {
310   return closed;
311 }
312 
313 inline bool
is_first_transaction() const314 Http2Stream::is_first_transaction() const
315 {
316   return is_first_transaction_flag;
317 }
318 
319 inline MIOBuffer *
read_vio_writer() const320 Http2Stream::read_vio_writer() const
321 {
322   return this->read_vio.get_writer();
323 }
324