1 /*
2 * Copyright (c) 2014,2015 DeNA Co., Ltd.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 * IN THE SOFTWARE.
21 */
22 #ifndef h2o__http2__internal_h
23 #define h2o__http2__internal_h
24
25 #include <assert.h>
26 #include <stdint.h>
27 #include "khash.h"
28 #include "h2o/cache.h"
29 #include "h2o/http2_casper.h"
30 #include "h2o/http2_scheduler.h"
31
32 typedef struct st_h2o_http2_conn_t h2o_http2_conn_t;
33 typedef struct st_h2o_http2_stream_t h2o_http2_stream_t;
34
35 typedef enum enum_h2o_http2_stream_state_t {
36 /**
37 * stream in idle state (but registered; i.e. priority stream)
38 */
39 H2O_HTTP2_STREAM_STATE_IDLE,
40 /**
41 * receiving headers
42 */
43 H2O_HTTP2_STREAM_STATE_RECV_HEADERS,
44 /**
45 * receiving body (or trailers), waiting for the arrival of END_STREAM
46 */
47 H2O_HTTP2_STREAM_STATE_RECV_BODY,
48 /**
49 * received request but haven't been assigned a handler
50 */
51 H2O_HTTP2_STREAM_STATE_REQ_PENDING,
52 /**
53 * waiting for receiving response headers from the handler
54 */
55 H2O_HTTP2_STREAM_STATE_SEND_HEADERS,
56 /**
57 * sending body
58 */
59 H2O_HTTP2_STREAM_STATE_SEND_BODY,
60 /**
61 * received EOS from handler but still is sending body to client
62 */
63 H2O_HTTP2_STREAM_STATE_SEND_BODY_IS_FINAL,
64 /**
65 * closed
66 */
67 H2O_HTTP2_STREAM_STATE_END_STREAM
68 } h2o_http2_stream_state_t;
69
70 typedef struct st_h2o_http2_conn_num_streams_t {
71 uint32_t open;
72 uint32_t half_closed;
73 uint32_t send_body;
74 } h2o_http2_conn_num_streams_t;
75
76 struct st_h2o_http2_stream_t {
77 /**
78 * stream-id
79 */
80 uint32_t stream_id;
81 /**
82 * scheduler (entries below scheduler are not maintained after the stream is closed, see ...)
83 */
84 h2o_http2_scheduler_openref_t _scheduler;
85 /**
86 * link-list of streams govered by connection.c
87 */
88 h2o_linklist_t _link;
89 /**
90 * the final ostream
91 */
92 h2o_ostream_t _ostr_final;
93 h2o_http2_stream_state_t state;
94 h2o_http2_window_t output_window;
95 struct {
96 h2o_http2_window_t window;
97 size_t bytes_unnotified;
98 } input_window;
99 h2o_http2_priority_t received_priority;
100 H2O_VECTOR(h2o_sendvec_t) _data;
101 size_t _data_off; /* offset within _data.entries[0] */
102 /**
103 * points to http2_conn_t::num_streams::* in which the stream is counted
104 */
105 h2o_http2_conn_num_streams_t *_num_streams_slot;
106 h2o_cache_digests_t *cache_digests;
107 union {
108 struct {
109 uint32_t parent_stream_id;
110 unsigned promise_sent : 1;
111 } push;
112 struct {
113 unsigned casper_is_ready : 1;
114 } pull;
115 };
116 unsigned blocked_by_server : 1;
117 /**
118 * state of the ostream, only used in push mode
119 */
120 h2o_send_state_t send_state;
121 /**
122 * request body (not available when `buf` is NULL
123 */
124 struct {
125 h2o_buffer_t *buf;
126 enum en_h2o_req_body_state_t {
127 H2O_HTTP2_REQ_BODY_NONE,
128 H2O_HTTP2_REQ_BODY_OPEN_BEFORE_FIRST_FRAME,
129 H2O_HTTP2_REQ_BODY_OPEN,
130 H2O_HTTP2_REQ_BODY_CLOSE_QUEUED,
131 H2O_HTTP2_REQ_BODY_CLOSE_DELIVERED
132 } state;
133 /**
134 * if the response body is streaming or was streamed, including tunnels
135 */
136 unsigned streamed : 1;
137 } req_body;
138 /**
139 * the request object; placed at last since it is large and has it's own ctor
140 */
141 h2o_req_t req;
142 };
143
144 KHASH_MAP_INIT_INT64(h2o_http2_stream_t, h2o_http2_stream_t *)
145
146 typedef enum enum_h2o_http2_conn_state_t {
147 H2O_HTTP2_CONN_STATE_OPEN, /* accepting new connections */
148 H2O_HTTP2_CONN_STATE_HALF_CLOSED, /* no more accepting new streams */
149 H2O_HTTP2_CONN_STATE_IS_CLOSING /* nothing should be sent */
150 } h2o_http2_conn_state_t;
151
152 struct st_h2o_http2_conn_t {
153 h2o_conn_t super;
154 h2o_socket_t *sock;
155 /* settings */
156 h2o_http2_settings_t peer_settings;
157 /* streams */
158 khash_t(h2o_http2_stream_t) * streams;
159 struct {
160 uint32_t max_open;
161 uint32_t max_processed;
162 } pull_stream_ids;
163 struct {
164 uint32_t max_open;
165 } push_stream_ids;
166 struct {
167 h2o_http2_conn_num_streams_t priority;
168 h2o_http2_conn_num_streams_t pull;
169 h2o_http2_conn_num_streams_t push;
170 uint32_t blocked_by_server;
171 /**
172 * number of streams that have the flag with the same name being set
173 */
174 uint32_t _req_streaming_in_progress;
175 /**
176 * number of CONNECT tunnels inflight (this is a proper subset of `_req_streaming_in_progress`)
177 */
178 uint32_t tunnel;
179 } num_streams;
180 /* internal */
181 h2o_http2_scheduler_node_t scheduler;
182 h2o_http2_conn_state_t state;
183 int is_chromium_dependency_tree; /* indicates whether the client-generated dependency tree is from Chromium
184 * Dependency tree from Chromium satisfies the following properties:
185 * 1) Every stream has the exclusive bit set
186 * 2) On a dependency tree, child's weight is lower than or equal to parent's
187 */
188
189 h2o_linklist_t _conns; /* linklist to h2o_context_t::http2._conns */
190 ssize_t (*_read_expect)(h2o_http2_conn_t *conn, const uint8_t *src, size_t len, const char **err_desc);
191 h2o_buffer_t *_http1_req_input; /* contains data referred to by original request via HTTP/1.1 */
192 h2o_hpack_header_table_t _input_header_table;
193 h2o_http2_window_t _input_window;
194 h2o_hpack_header_table_t _output_header_table;
195 h2o_linklist_t _pending_reqs; /* list of h2o_http2_stream_t that contain pending requests */
196 h2o_timer_t _timeout_entry;
197 h2o_buffer_t *_headers_unparsed; /* for temporary storing HEADERS|CONTINUATION frames without END_HEADERS flag set */
198 struct {
199 h2o_buffer_t *buf;
200 h2o_buffer_t *buf_in_flight;
201 h2o_linklist_t streams_to_proceed;
202 h2o_timer_t timeout_entry;
203 h2o_http2_window_t window;
204 } _write;
205 h2o_cache_t *push_memo;
206 h2o_http2_casper_t *casper;
207 struct {
208 h2o_linklist_t blocked_streams;
209 } early_data;
210 h2o_iovec_t *http2_origin_frame;
211 /**
212 * Ring buffer of closed streams. `next_slot` points to the next write position. The stored object is shrinked to only contain
213 * stream_id and _scheduler.
214 */
215 struct {
216 #define HTTP2_CLOSED_STREAM_PRIORITIES 10
217 h2o_http2_stream_t *streams[HTTP2_CLOSED_STREAM_PRIORITIES];
218 size_t next_slot;
219 } _recently_closed_streams;
220 struct {
221 struct timeval settings_sent_at;
222 struct timeval settings_acked_at;
223 } timestamps;
224 };
225
226 /* connection */
227 void h2o_http2_conn_register_stream(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream);
228 void h2o_http2_conn_unregister_stream(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream);
229 static h2o_http2_stream_t *h2o_http2_conn_get_stream(h2o_http2_conn_t *conn, uint32_t stream_id);
230 void h2o_http2_conn_push_path(h2o_http2_conn_t *conn, h2o_iovec_t path, h2o_http2_stream_t *src_stream);
231 void h2o_http2_conn_request_write(h2o_http2_conn_t *conn);
232 void h2o_http2_conn_register_for_proceed_callback(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream);
233 static ssize_t h2o_http2_conn_get_buffer_window(h2o_http2_conn_t *conn);
234 static void h2o_http2_conn_init_casper(h2o_http2_conn_t *conn, unsigned capacity_bits);
235 void h2o_http2_conn_register_for_replay(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream);
236 void h2o_http2_conn_preserve_stream_scheduler(h2o_http2_conn_t *conn, h2o_http2_stream_t *src);
237
238 /* stream */
239 static int h2o_http2_stream_is_push(uint32_t stream_id);
240 h2o_http2_stream_t *h2o_http2_stream_open(h2o_http2_conn_t *conn, uint32_t stream_id, h2o_req_t *src_req,
241 const h2o_http2_priority_t *received_priority);
242 static void h2o_http2_stream_update_open_slot(h2o_http2_stream_t *stream, h2o_http2_conn_num_streams_t *slot);
243 static void h2o_http2_stream_set_blocked_by_server(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream, unsigned on);
244 static void h2o_http2_stream_set_state(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream, h2o_http2_stream_state_t new_state);
245 static void h2o_http2_stream_prepare_for_request(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream);
246 void h2o_http2_stream_close(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream);
247 void h2o_http2_stream_reset(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream);
248 void h2o_http2_stream_send_pending_data(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream);
249 static int h2o_http2_stream_has_pending_data(h2o_http2_stream_t *stream);
250 void h2o_http2_stream_proceed(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream);
251 static void h2o_http2_stream_send_push_promise(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream);
252 h2o_http2_debug_state_t *h2o_http2_get_debug_state(h2o_req_t *req, int hpack_enabled);
253
254 /* inline definitions */
255
h2o_http2_conn_get_stream(h2o_http2_conn_t * conn,uint32_t stream_id)256 inline h2o_http2_stream_t *h2o_http2_conn_get_stream(h2o_http2_conn_t *conn, uint32_t stream_id)
257 {
258 khiter_t iter = kh_get(h2o_http2_stream_t, conn->streams, stream_id);
259 if (iter != kh_end(conn->streams))
260 return kh_val(conn->streams, iter);
261 return NULL;
262 }
263
h2o_http2_stream_is_push(uint32_t stream_id)264 inline int h2o_http2_stream_is_push(uint32_t stream_id)
265 {
266 return stream_id % 2 == 0;
267 }
268
h2o_http2_conn_get_buffer_window(h2o_http2_conn_t * conn)269 inline ssize_t h2o_http2_conn_get_buffer_window(h2o_http2_conn_t *conn)
270 {
271 ssize_t ret, winsz;
272 size_t capacity, cwnd_left;
273
274 capacity = conn->_write.buf->capacity;
275 if ((cwnd_left = h2o_socket_prepare_for_latency_optimized_write(
276 conn->sock, &conn->super.ctx->globalconf->http2.latency_optimization)) < capacity) {
277 capacity = cwnd_left;
278 if (capacity < conn->_write.buf->size)
279 return 0;
280 }
281
282 ret = capacity - conn->_write.buf->size;
283 if (ret < H2O_HTTP2_FRAME_HEADER_SIZE)
284 return 0;
285 ret -= H2O_HTTP2_FRAME_HEADER_SIZE;
286 winsz = h2o_http2_window_get_avail(&conn->_write.window);
287 if (winsz < ret)
288 ret = winsz;
289 return ret;
290 }
291
h2o_http2_conn_init_casper(h2o_http2_conn_t * conn,unsigned capacity_bits)292 inline void h2o_http2_conn_init_casper(h2o_http2_conn_t *conn, unsigned capacity_bits)
293 {
294 assert(conn->casper == NULL);
295 conn->casper = h2o_http2_casper_create(capacity_bits, 6);
296 }
297
h2o_http2_stream_update_open_slot(h2o_http2_stream_t * stream,h2o_http2_conn_num_streams_t * slot)298 inline void h2o_http2_stream_update_open_slot(h2o_http2_stream_t *stream, h2o_http2_conn_num_streams_t *slot)
299 {
300 --stream->_num_streams_slot->open;
301 ++slot->open;
302 stream->_num_streams_slot = slot;
303 }
304
h2o_http2_stream_set_blocked_by_server(h2o_http2_conn_t * conn,h2o_http2_stream_t * stream,unsigned on)305 inline void h2o_http2_stream_set_blocked_by_server(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream, unsigned on)
306 {
307 if (on) {
308 assert(!stream->blocked_by_server);
309 stream->blocked_by_server = 1;
310 ++conn->num_streams.blocked_by_server;
311 } else {
312 assert(stream->blocked_by_server);
313 stream->blocked_by_server = 0;
314 --conn->num_streams.blocked_by_server;
315 }
316 }
317
h2o_http2_stream_set_state(h2o_http2_conn_t * conn,h2o_http2_stream_t * stream,h2o_http2_stream_state_t new_state)318 inline void h2o_http2_stream_set_state(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream, h2o_http2_stream_state_t new_state)
319 {
320 switch (new_state) {
321 case H2O_HTTP2_STREAM_STATE_IDLE:
322 assert(!"FIXME");
323 break;
324 case H2O_HTTP2_STREAM_STATE_RECV_HEADERS:
325 assert(stream->state == H2O_HTTP2_STREAM_STATE_IDLE);
326 if (h2o_http2_stream_is_push(stream->stream_id))
327 h2o_http2_stream_update_open_slot(stream, &conn->num_streams.push);
328 else
329 h2o_http2_stream_update_open_slot(stream, &conn->num_streams.pull);
330 stream->state = new_state;
331 stream->req.timestamps.request_begin_at = h2o_gettimeofday(conn->super.ctx->loop);
332 break;
333 case H2O_HTTP2_STREAM_STATE_RECV_BODY:
334 stream->state = new_state;
335 stream->req.timestamps.request_body_begin_at = h2o_gettimeofday(conn->super.ctx->loop);
336 break;
337 case H2O_HTTP2_STREAM_STATE_REQ_PENDING:
338 stream->state = new_state;
339 break;
340 case H2O_HTTP2_STREAM_STATE_SEND_HEADERS:
341 assert(stream->state == H2O_HTTP2_STREAM_STATE_REQ_PENDING);
342 ++stream->_num_streams_slot->half_closed;
343 stream->state = new_state;
344 break;
345 case H2O_HTTP2_STREAM_STATE_SEND_BODY:
346 assert(stream->state == H2O_HTTP2_STREAM_STATE_SEND_HEADERS);
347 stream->state = new_state;
348 ++stream->_num_streams_slot->send_body;
349 break;
350 case H2O_HTTP2_STREAM_STATE_SEND_BODY_IS_FINAL:
351 assert(stream->state == H2O_HTTP2_STREAM_STATE_SEND_BODY);
352 stream->state = new_state;
353 break;
354 case H2O_HTTP2_STREAM_STATE_END_STREAM:
355 switch (stream->state) {
356 case H2O_HTTP2_STREAM_STATE_IDLE:
357 case H2O_HTTP2_STREAM_STATE_RECV_BODY:
358 case H2O_HTTP2_STREAM_STATE_RECV_HEADERS:
359 break;
360 case H2O_HTTP2_STREAM_STATE_REQ_PENDING:
361 break;
362 case H2O_HTTP2_STREAM_STATE_SEND_HEADERS:
363 --stream->_num_streams_slot->half_closed;
364 break;
365 case H2O_HTTP2_STREAM_STATE_SEND_BODY:
366 case H2O_HTTP2_STREAM_STATE_SEND_BODY_IS_FINAL:
367 --stream->_num_streams_slot->half_closed;
368 --stream->_num_streams_slot->send_body;
369 break;
370 case H2O_HTTP2_STREAM_STATE_END_STREAM:
371 assert(!"FIXME");
372 break;
373 }
374 stream->state = new_state;
375 stream->req.timestamps.response_end_at = h2o_gettimeofday(conn->super.ctx->loop);
376 --stream->_num_streams_slot->open;
377 stream->_num_streams_slot = NULL;
378 if (stream->blocked_by_server)
379 h2o_http2_stream_set_blocked_by_server(conn, stream, 0);
380 break;
381 }
382 }
383
h2o_http2_stream_prepare_for_request(h2o_http2_conn_t * conn,h2o_http2_stream_t * stream)384 inline void h2o_http2_stream_prepare_for_request(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream)
385 {
386 assert(conn->state != H2O_HTTP2_CONN_STATE_IS_CLOSING);
387 assert(h2o_http2_scheduler_is_open(&stream->_scheduler));
388
389 /* adjust max-open */
390 uint32_t *max_open = NULL;
391 if (h2o_http2_stream_is_push(stream->stream_id)) {
392 max_open = &conn->push_stream_ids.max_open;
393 } else if (conn->state == H2O_HTTP2_CONN_STATE_OPEN) {
394 max_open = &conn->pull_stream_ids.max_open;
395 }
396 if (max_open != NULL && *max_open < stream->stream_id)
397 *max_open = stream->stream_id;
398
399 h2o_http2_stream_set_state(conn, stream, H2O_HTTP2_STREAM_STATE_RECV_HEADERS);
400 h2o_http2_window_init(&stream->output_window, conn->peer_settings.initial_window_size);
401 }
402
h2o_http2_stream_has_pending_data(h2o_http2_stream_t * stream)403 inline int h2o_http2_stream_has_pending_data(h2o_http2_stream_t *stream)
404 {
405 return stream->_data.size != 0;
406 }
407
h2o_http2_stream_send_push_promise(h2o_http2_conn_t * conn,h2o_http2_stream_t * stream)408 inline void h2o_http2_stream_send_push_promise(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream)
409 {
410 assert(!stream->push.promise_sent);
411 h2o_hpack_flatten_push_promise(&conn->_write.buf, &conn->_output_header_table, conn->peer_settings.header_table_size,
412 stream->stream_id, conn->peer_settings.max_frame_size, stream->req.input.scheme,
413 stream->req.input.authority, stream->req.input.method, stream->req.input.path,
414 stream->req.headers.entries, stream->req.headers.size, stream->push.parent_stream_id);
415 stream->push.promise_sent = 1;
416 }
417
418 #endif
419