• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * nghttp2 - HTTP/2 C Library
3  *
4  * Copyright (c) 2012 Tatsuhiro Tsujikawa
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 #ifndef SHRPX_HTTP2_SESSION_H
26 #define SHRPX_HTTP2_SESSION_H
27 
28 #include "shrpx.h"
29 
30 #include <unordered_set>
31 #include <memory>
32 
33 #include <openssl/ssl.h>
34 
35 #include <ev.h>
36 
37 #include <nghttp2/nghttp2.h>
38 
39 #include "llhttp.h"
40 
41 #include "shrpx_connection.h"
42 #include "buffer.h"
43 #include "template.h"
44 
45 using namespace nghttp2;
46 
47 namespace shrpx {
48 
49 class Http2DownstreamConnection;
50 class Worker;
51 class Downstream;
52 struct DownstreamAddrGroup;
53 struct DownstreamAddr;
54 struct DNSQuery;
55 
56 struct StreamData {
57   StreamData *dlnext, *dlprev;
58   Http2DownstreamConnection *dconn;
59 };
60 
61 enum class FreelistZone {
62   // Http2Session object is not linked in any freelist.
63   NONE,
64   // Http2Session object is linked in address scope
65   // http2_extra_freelist.
66   EXTRA,
67   // Http2Session object is about to be deleted, and it does not
68   // belong to any linked list.
69   GONE
70 };
71 
72 enum class Http2SessionState {
73   // Disconnected
74   DISCONNECTED,
75   // Connecting proxy and making CONNECT request
76   PROXY_CONNECTING,
77   // Tunnel is established with proxy
78   PROXY_CONNECTED,
79   // Establishing tunnel is failed
80   PROXY_FAILED,
81   // Connecting to downstream and/or performing SSL/TLS handshake
82   CONNECTING,
83   // Connected to downstream
84   CONNECTED,
85   // Connection is started to fail
86   CONNECT_FAILING,
87   // Resolving host name
88   RESOLVING_NAME,
89 };
90 
91 enum class ConnectionCheck {
92   // Connection checking is not required
93   NONE,
94   // Connection checking is required
95   REQUIRED,
96   // Connection checking has been started
97   STARTED,
98 };
99 
100 class Http2Session {
101 public:
102   Http2Session(struct ev_loop *loop, SSL_CTX *ssl_ctx, Worker *worker,
103                const std::shared_ptr<DownstreamAddrGroup> &group,
104                DownstreamAddr *addr);
105   ~Http2Session();
106 
107   // If hard is true, all pending requests are abandoned and
108   // associated ClientHandlers will be deleted.
109   int disconnect(bool hard = false);
110   int initiate_connection();
111   int resolve_name();
112 
113   void add_downstream_connection(Http2DownstreamConnection *dconn);
114   void remove_downstream_connection(Http2DownstreamConnection *dconn);
115 
116   void remove_stream_data(StreamData *sd);
117 
118   int submit_request(Http2DownstreamConnection *dconn, const nghttp2_nv *nva,
119                      size_t nvlen, const nghttp2_data_provider *data_prd);
120 
121   int submit_rst_stream(int32_t stream_id, uint32_t error_code);
122 
123   int terminate_session(uint32_t error_code);
124 
125   nghttp2_session *get_session() const;
126 
127   int resume_data(Http2DownstreamConnection *dconn);
128 
129   int connection_made();
130 
131   int do_read();
132   int do_write();
133 
134   int on_read(const uint8_t *data, size_t datalen);
135   int on_write();
136 
137   int connected();
138   int read_clear();
139   int write_clear();
140   int tls_handshake();
141   int read_tls();
142   int write_tls();
143   // This is a special write function which just stop write event
144   // watcher.
145   int write_void();
146 
147   int downstream_read_proxy(const uint8_t *data, size_t datalen);
148   int downstream_connect_proxy();
149 
150   int downstream_read(const uint8_t *data, size_t datalen);
151   int downstream_write();
152 
153   int noop();
154   int read_noop(const uint8_t *data, size_t datalen);
155   int write_noop();
156 
157   void signal_write();
158 
159   struct ev_loop *get_loop() const;
160 
161   ev_io *get_wev();
162 
163   Http2SessionState get_state() const;
164   void set_state(Http2SessionState state);
165 
166   void start_settings_timer();
167   void stop_settings_timer();
168 
169   SSL *get_ssl() const;
170 
171   int consume(int32_t stream_id, size_t len);
172 
173   // Returns true if request can be issued on downstream connection.
174   bool can_push_request(const Downstream *downstream) const;
175   // Initiates the connection checking if downstream connection has
176   // been established and connection checking is required.
177   void start_checking_connection();
178   // Resets connection check timer to timeout |t|.  After timeout, we
179   // require connection checking.  If connection checking is already
180   // enabled, this timeout is for PING ACK timeout.
181   void reset_connection_check_timer(ev_tstamp t);
182   void reset_connection_check_timer_if_not_checking();
183   // Signals that connection is alive.  Internally
184   // reset_connection_check_timer() is called.
185   void connection_alive();
186   // Change connection check state.
187   void set_connection_check_state(ConnectionCheck state);
188   ConnectionCheck get_connection_check_state() const;
189 
190   bool should_hard_fail() const;
191 
192   void submit_pending_requests();
193 
194   DownstreamAddr *get_addr() const;
195 
196   const std::shared_ptr<DownstreamAddrGroup> &get_downstream_addr_group() const;
197 
198   int handle_downstream_push_promise(Downstream *downstream,
199                                      int32_t promised_stream_id);
200   int handle_downstream_push_promise_complete(Downstream *downstream,
201                                               Downstream *promised_downstream);
202 
203   // Returns number of downstream connections, including pushed
204   // streams.
205   size_t get_num_dconns() const;
206 
207   // Adds to group scope http2_avail_freelist.
208   void add_to_avail_freelist();
209   // Adds to address scope http2_extra_freelist.
210   void add_to_extra_freelist();
211 
212   // Removes this object from any freelist.  If this object is not
213   // linked from any freelist, this function does nothing.
214   void remove_from_freelist();
215 
216   // Removes this object form any freelist, and marks this object as
217   // not schedulable.
218   void exclude_from_scheduling();
219 
220   // Returns true if the maximum concurrency is reached.  In other
221   // words, the number of currently participated streams in this
222   // session is equal or greater than the max concurrent streams limit
223   // advertised by server.  If |extra| is nonzero, it is added to the
224   // number of current concurrent streams when comparing against
225   // server initiated concurrency limit.
226   bool max_concurrency_reached(size_t extra = 0) const;
227 
228   DefaultMemchunks *get_request_buf();
229 
230   void on_timeout();
231 
232   // This is called periodically using ev_prepare watcher, and if
233   // group_ is retired (backend has been replaced), send GOAWAY to
234   // shutdown the connection.
235   void check_retire();
236 
237   // Returns address used to connect to backend.  Could be nullptr.
238   const Address *get_raddr() const;
239 
240   // This is called when SETTINGS frame without ACK flag set is
241   // received.
242   void on_settings_received(const nghttp2_frame *frame);
243 
244   bool get_allow_connect_proto() const;
245 
246   using ReadBuf = Buffer<8_k>;
247 
248   Http2Session *dlnext, *dlprev;
249 
250 private:
251   Connection conn_;
252   DefaultMemchunks wb_;
253   ev_timer settings_timer_;
254   // This timer has 2 purpose: when it first timeout, set
255   // connection_check_state_ = ConnectionCheck::REQUIRED.  After
256   // connection check has started, this timer is started again and
257   // traps PING ACK timeout.
258   ev_timer connchk_timer_;
259   // timer to initiate connection.  usually, this fires immediately.
260   ev_timer initiate_connection_timer_;
261   ev_prepare prep_;
262   DList<Http2DownstreamConnection> dconns_;
263   DList<StreamData> streams_;
264   std::function<int(Http2Session &)> read_, write_;
265   std::function<int(Http2Session &, const uint8_t *, size_t)> on_read_;
266   std::function<int(Http2Session &)> on_write_;
267   // Used to parse the response from HTTP proxy
268   std::unique_ptr<llhttp_t> proxy_htp_;
269   Worker *worker_;
270   // NULL if no TLS is configured
271   SSL_CTX *ssl_ctx_;
272   std::shared_ptr<DownstreamAddrGroup> group_;
273   // Address of remote endpoint
274   DownstreamAddr *addr_;
275   nghttp2_session *session_;
276   // Actual remote address used to contact backend.  This is initially
277   // nullptr, and may point to either &addr_->addr,
278   // resolved_addr_.get(), or HTTP proxy's address structure.
279   const Address *raddr_;
280   // Resolved IP address if dns parameter is used
281   std::unique_ptr<Address> resolved_addr_;
282   std::unique_ptr<DNSQuery> dns_query_;
283   Http2SessionState state_;
284   ConnectionCheck connection_check_state_;
285   FreelistZone freelist_zone_;
286   // true if SETTINGS without ACK is received from peer.
287   bool settings_recved_;
288   // true if peer enables RFC 8441 CONNECT protocol.
289   bool allow_connect_proto_;
290 };
291 
292 nghttp2_session_callbacks *create_http2_downstream_callbacks();
293 
294 } // namespace shrpx
295 
296 #endif // SHRPX_HTTP2_SESSION_H
297