3
* Copyright 2015, Google Inc.
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions are
10
* * Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* * Redistributions in binary form must reproduce the above
13
* copyright notice, this list of conditions and the following disclaimer
14
* in the documentation and/or other materials provided with the
16
* * Neither the name of Google Inc. nor the names of its
17
* contributors may be used to endorse or promote products derived from
18
* this software without specific prior written permission.
20
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
#include "src/core/transport/chttp2/internal.h"
38
#include "src/core/transport/chttp2/http2_errors.h"
39
#include "src/core/transport/chttp2/status_conversion.h"
40
#include "src/core/transport/chttp2/timeout_encoding.h"
42
#include <grpc/support/alloc.h>
43
#include <grpc/support/log.h>
45
static int init_frame_parser(grpc_chttp2_transport_parsing *transport_parsing);
46
static int init_header_frame_parser(
47
grpc_chttp2_transport_parsing *transport_parsing, int is_continuation);
48
static int init_data_frame_parser(
49
grpc_chttp2_transport_parsing *transport_parsing);
50
static int init_rst_stream_parser(
51
grpc_chttp2_transport_parsing *transport_parsing);
52
static int init_settings_frame_parser(
53
grpc_chttp2_transport_parsing *transport_parsing);
54
static int init_window_update_frame_parser(
55
grpc_chttp2_transport_parsing *transport_parsing);
56
static int init_ping_parser(grpc_chttp2_transport_parsing *transport_parsing);
57
static int init_goaway_parser(grpc_chttp2_transport_parsing *transport_parsing);
58
static int init_skip_frame_parser(
59
grpc_chttp2_transport_parsing *transport_parsing, int is_header);
61
static int parse_frame_slice(grpc_chttp2_transport_parsing *transport_parsing,
62
gpr_slice slice, int is_last);
64
void grpc_chttp2_prepare_to_read(
65
grpc_chttp2_transport_global *transport_global,
66
grpc_chttp2_transport_parsing *transport_parsing) {
67
grpc_chttp2_stream_global *stream_global;
68
grpc_chttp2_stream_parsing *stream_parsing;
70
transport_parsing->next_stream_id = transport_global->next_stream_id;
72
/* update the parsing view of incoming window */
73
if (transport_parsing->incoming_window != transport_global->incoming_window) {
74
GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
75
"parse", transport_parsing, incoming_window,
76
(gpr_int64)transport_global->incoming_window -
77
(gpr_int64)transport_parsing->incoming_window);
78
transport_parsing->incoming_window = transport_global->incoming_window;
80
while (grpc_chttp2_list_pop_incoming_window_updated(
81
transport_global, transport_parsing, &stream_global, &stream_parsing)) {
82
stream_parsing->id = stream_global->id;
83
if (stream_parsing->incoming_window != stream_global->incoming_window) {
84
GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
85
"parse", transport_parsing, stream_parsing, incoming_window,
86
(gpr_int64)stream_global->incoming_window -
87
(gpr_int64)stream_parsing->incoming_window);
88
stream_parsing->incoming_window = stream_global->incoming_window;
93
void grpc_chttp2_publish_reads(
94
grpc_chttp2_transport_global *transport_global,
95
grpc_chttp2_transport_parsing *transport_parsing) {
96
grpc_chttp2_stream_global *stream_global;
97
grpc_chttp2_stream_parsing *stream_parsing;
99
/* transport_parsing->last_incoming_stream_id is used as
100
last-grpc_chttp2_stream-id when
101
sending GOAWAY frame.
102
https://tools.ietf.org/html/draft-ietf-httpbis-http2-17#section-6.8
103
says that last-grpc_chttp2_stream-id is peer-initiated grpc_chttp2_stream
105
since we don't have server pushed streams, client should send
106
GOAWAY last-grpc_chttp2_stream-id=0 in this case. */
107
if (!transport_parsing->is_client) {
108
transport_global->last_incoming_stream_id =
109
transport_parsing->incoming_stream_id;
112
/* copy parsing qbuf to global qbuf */
113
gpr_slice_buffer_move_into(&transport_parsing->qbuf, &transport_global->qbuf);
115
/* update global settings */
116
if (transport_parsing->settings_updated) {
117
memcpy(transport_global->settings[GRPC_PEER_SETTINGS],
118
transport_parsing->settings, sizeof(transport_parsing->settings));
119
transport_parsing->settings_updated = 0;
122
/* update settings based on ack if received */
123
if (transport_parsing->settings_ack_received) {
124
memcpy(transport_global->settings[GRPC_ACKED_SETTINGS],
125
transport_global->settings[GRPC_SENT_SETTINGS],
126
GRPC_CHTTP2_NUM_SETTINGS * sizeof(gpr_uint32));
127
transport_parsing->settings_ack_received = 0;
130
/* move goaway to the global state if we received one (it will be
132
if (transport_parsing->goaway_received) {
133
grpc_chttp2_add_incoming_goaway(transport_global,
134
transport_parsing->goaway_error,
135
transport_parsing->goaway_text);
136
transport_parsing->goaway_text = gpr_empty_slice();
137
transport_parsing->goaway_received = 0;
140
/* propagate flow control tokens to global state */
141
if (transport_parsing->outgoing_window_update) {
142
GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
143
"parsed", transport_global, outgoing_window,
144
transport_parsing->outgoing_window_update);
145
GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
146
"parsed", transport_parsing, outgoing_window_update,
147
-(gpr_int64)transport_parsing->outgoing_window_update);
148
transport_global->outgoing_window +=
149
transport_parsing->outgoing_window_update;
150
transport_parsing->outgoing_window_update = 0;
153
if (transport_parsing->incoming_window_delta) {
154
GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
155
"parsed", transport_global, incoming_window,
156
-(gpr_int64)transport_parsing->incoming_window_delta);
157
GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
158
"parsed", transport_parsing, incoming_window_delta,
159
-(gpr_int64)transport_parsing->incoming_window_delta);
160
transport_global->incoming_window -=
161
transport_parsing->incoming_window_delta;
162
transport_parsing->incoming_window_delta = 0;
165
/* for each stream that saw an update, fixup global state */
166
while (grpc_chttp2_list_pop_parsing_seen_stream(
167
transport_global, transport_parsing, &stream_global, &stream_parsing)) {
168
/* update incoming flow control window */
169
if (stream_parsing->incoming_window_delta) {
170
GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
171
"parsed", transport_parsing, stream_global, incoming_window,
172
-(gpr_int64)stream_parsing->incoming_window_delta);
173
GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
174
"parsed", transport_parsing, stream_parsing, incoming_window_delta,
175
-(gpr_int64)stream_parsing->incoming_window_delta);
176
stream_global->incoming_window -= stream_parsing->incoming_window_delta;
177
stream_parsing->incoming_window_delta = 0;
178
grpc_chttp2_list_add_writable_window_update_stream(transport_global,
182
/* update outgoing flow control window */
183
if (stream_parsing->outgoing_window_update) {
184
int was_zero = stream_global->outgoing_window <= 0;
186
GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("parsed", transport_parsing,
187
stream_global, outgoing_window,
188
stream_parsing->outgoing_window_update);
189
GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
190
"parsed", transport_parsing, stream_parsing, outgoing_window_update,
191
-(gpr_int64)stream_parsing->outgoing_window_update);
192
stream_global->outgoing_window += stream_parsing->outgoing_window_update;
193
stream_parsing->outgoing_window_update = 0;
194
is_zero = stream_global->outgoing_window <= 0;
195
if (was_zero && !is_zero) {
196
grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
200
/* updating closed status */
201
if (stream_parsing->received_close) {
202
stream_global->read_closed = 1;
203
grpc_chttp2_list_add_read_write_state_changed(transport_global,
206
if (stream_parsing->saw_rst_stream) {
207
stream_global->cancelled = 1;
208
stream_global->cancelled_status = grpc_chttp2_http2_error_to_grpc_status(stream_parsing->rst_stream_reason);
209
if (stream_parsing->rst_stream_reason == GRPC_CHTTP2_NO_ERROR) {
210
stream_global->published_cancelled = 1;
212
grpc_chttp2_list_add_read_write_state_changed(transport_global,
216
/* publish incoming stream ops */
217
if (stream_parsing->data_parser.incoming_sopb.nops > 0) {
218
grpc_incoming_metadata_buffer_move_to_referencing_sopb(
219
&stream_parsing->incoming_metadata, &stream_global->incoming_metadata,
220
&stream_parsing->data_parser.incoming_sopb);
221
grpc_sopb_move_to(&stream_parsing->data_parser.incoming_sopb,
222
&stream_global->incoming_sopb);
223
grpc_chttp2_list_add_read_write_state_changed(transport_global,
229
int grpc_chttp2_perform_read(grpc_chttp2_transport_parsing *transport_parsing,
231
gpr_uint8 *beg = GPR_SLICE_START_PTR(slice);
232
gpr_uint8 *end = GPR_SLICE_END_PTR(slice);
233
gpr_uint8 *cur = beg;
235
if (cur == end) return 1;
237
switch (transport_parsing->deframe_state) {
238
case GRPC_DTS_CLIENT_PREFIX_0:
239
case GRPC_DTS_CLIENT_PREFIX_1:
240
case GRPC_DTS_CLIENT_PREFIX_2:
241
case GRPC_DTS_CLIENT_PREFIX_3:
242
case GRPC_DTS_CLIENT_PREFIX_4:
243
case GRPC_DTS_CLIENT_PREFIX_5:
244
case GRPC_DTS_CLIENT_PREFIX_6:
245
case GRPC_DTS_CLIENT_PREFIX_7:
246
case GRPC_DTS_CLIENT_PREFIX_8:
247
case GRPC_DTS_CLIENT_PREFIX_9:
248
case GRPC_DTS_CLIENT_PREFIX_10:
249
case GRPC_DTS_CLIENT_PREFIX_11:
250
case GRPC_DTS_CLIENT_PREFIX_12:
251
case GRPC_DTS_CLIENT_PREFIX_13:
252
case GRPC_DTS_CLIENT_PREFIX_14:
253
case GRPC_DTS_CLIENT_PREFIX_15:
254
case GRPC_DTS_CLIENT_PREFIX_16:
255
case GRPC_DTS_CLIENT_PREFIX_17:
256
case GRPC_DTS_CLIENT_PREFIX_18:
257
case GRPC_DTS_CLIENT_PREFIX_19:
258
case GRPC_DTS_CLIENT_PREFIX_20:
259
case GRPC_DTS_CLIENT_PREFIX_21:
260
case GRPC_DTS_CLIENT_PREFIX_22:
261
case GRPC_DTS_CLIENT_PREFIX_23:
262
while (cur != end && transport_parsing->deframe_state != GRPC_DTS_FH_0) {
263
if (*cur != GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing
266
"Connect string mismatch: expected '%c' (%d) got '%c' (%d) "
268
GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing
270
(int)(gpr_uint8)GRPC_CHTTP2_CLIENT_CONNECT_STRING
271
[transport_parsing->deframe_state],
272
*cur, (int)*cur, transport_parsing->deframe_state);
276
++transport_parsing->deframe_state;
284
GPR_ASSERT(cur < end);
285
transport_parsing->incoming_frame_size = ((gpr_uint32)*cur) << 16;
287
transport_parsing->deframe_state = GRPC_DTS_FH_1;
292
GPR_ASSERT(cur < end);
293
transport_parsing->incoming_frame_size |= ((gpr_uint32)*cur) << 8;
295
transport_parsing->deframe_state = GRPC_DTS_FH_2;
300
GPR_ASSERT(cur < end);
301
transport_parsing->incoming_frame_size |= *cur;
303
transport_parsing->deframe_state = GRPC_DTS_FH_3;
308
GPR_ASSERT(cur < end);
309
transport_parsing->incoming_frame_type = *cur;
311
transport_parsing->deframe_state = GRPC_DTS_FH_4;
316
GPR_ASSERT(cur < end);
317
transport_parsing->incoming_frame_flags = *cur;
319
transport_parsing->deframe_state = GRPC_DTS_FH_5;
324
GPR_ASSERT(cur < end);
325
transport_parsing->incoming_stream_id = (((gpr_uint32)*cur) & 0x7f) << 24;
327
transport_parsing->deframe_state = GRPC_DTS_FH_6;
332
GPR_ASSERT(cur < end);
333
transport_parsing->incoming_stream_id |= ((gpr_uint32)*cur) << 16;
335
transport_parsing->deframe_state = GRPC_DTS_FH_7;
340
GPR_ASSERT(cur < end);
341
transport_parsing->incoming_stream_id |= ((gpr_uint32)*cur) << 8;
343
transport_parsing->deframe_state = GRPC_DTS_FH_8;
348
GPR_ASSERT(cur < end);
349
transport_parsing->incoming_stream_id |= ((gpr_uint32)*cur);
350
transport_parsing->deframe_state = GRPC_DTS_FRAME;
351
if (!init_frame_parser(transport_parsing)) {
354
if (transport_parsing->incoming_stream_id) {
355
transport_parsing->last_incoming_stream_id =
356
transport_parsing->incoming_stream_id;
358
if (transport_parsing->incoming_frame_size == 0) {
359
if (!parse_frame_slice(transport_parsing, gpr_empty_slice(), 1)) {
362
transport_parsing->incoming_stream = NULL;
364
transport_parsing->deframe_state = GRPC_DTS_FH_0;
367
goto dts_fh_0; /* loop */
374
GPR_ASSERT(cur < end);
375
if ((gpr_uint32)(end - cur) == transport_parsing->incoming_frame_size) {
376
if (!parse_frame_slice(
378
gpr_slice_sub_no_ref(slice, cur - beg, end - beg), 1)) {
381
transport_parsing->deframe_state = GRPC_DTS_FH_0;
382
transport_parsing->incoming_stream = NULL;
384
} else if ((gpr_uint32)(end - cur) >
385
transport_parsing->incoming_frame_size) {
386
if (!parse_frame_slice(
388
gpr_slice_sub_no_ref(
390
cur + transport_parsing->incoming_frame_size - beg),
394
cur += transport_parsing->incoming_frame_size;
395
transport_parsing->incoming_stream = NULL;
396
goto dts_fh_0; /* loop */
398
if (!parse_frame_slice(
400
gpr_slice_sub_no_ref(slice, cur - beg, end - beg), 0)) {
403
transport_parsing->incoming_frame_size -= (end - cur);
406
gpr_log(GPR_ERROR, "should never reach here");
410
gpr_log(GPR_ERROR, "should never reach here");
416
static int init_frame_parser(grpc_chttp2_transport_parsing *transport_parsing) {
417
if (transport_parsing->expect_continuation_stream_id != 0) {
418
if (transport_parsing->incoming_frame_type !=
419
GRPC_CHTTP2_FRAME_CONTINUATION) {
420
gpr_log(GPR_ERROR, "Expected CONTINUATION frame, got frame type %02x",
421
transport_parsing->incoming_frame_type);
424
if (transport_parsing->expect_continuation_stream_id !=
425
transport_parsing->incoming_stream_id) {
427
"Expected CONTINUATION frame for grpc_chttp2_stream %08x, got "
428
"grpc_chttp2_stream %08x",
429
transport_parsing->expect_continuation_stream_id,
430
transport_parsing->incoming_stream_id);
433
return init_header_frame_parser(transport_parsing, 1);
435
switch (transport_parsing->incoming_frame_type) {
436
case GRPC_CHTTP2_FRAME_DATA:
437
return init_data_frame_parser(transport_parsing);
438
case GRPC_CHTTP2_FRAME_HEADER:
439
return init_header_frame_parser(transport_parsing, 0);
440
case GRPC_CHTTP2_FRAME_CONTINUATION:
441
gpr_log(GPR_ERROR, "Unexpected CONTINUATION frame");
443
case GRPC_CHTTP2_FRAME_RST_STREAM:
444
return init_rst_stream_parser(transport_parsing);
445
case GRPC_CHTTP2_FRAME_SETTINGS:
446
return init_settings_frame_parser(transport_parsing);
447
case GRPC_CHTTP2_FRAME_WINDOW_UPDATE:
448
return init_window_update_frame_parser(transport_parsing);
449
case GRPC_CHTTP2_FRAME_PING:
450
return init_ping_parser(transport_parsing);
451
case GRPC_CHTTP2_FRAME_GOAWAY:
452
return init_goaway_parser(transport_parsing);
454
gpr_log(GPR_ERROR, "Unknown frame type %02x",
455
transport_parsing->incoming_frame_type);
456
return init_skip_frame_parser(transport_parsing, 0);
460
static grpc_chttp2_parse_error skip_parser(
461
void *parser, grpc_chttp2_transport_parsing *transport_parsing,
462
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
463
return GRPC_CHTTP2_PARSE_OK;
466
static void skip_header(void *tp, grpc_mdelem *md) { GRPC_MDELEM_UNREF(md); }
468
static int init_skip_frame_parser(
469
grpc_chttp2_transport_parsing *transport_parsing, int is_header) {
471
int is_eoh = transport_parsing->expect_continuation_stream_id != 0;
472
transport_parsing->parser = grpc_chttp2_header_parser_parse;
473
transport_parsing->parser_data = &transport_parsing->hpack_parser;
474
transport_parsing->hpack_parser.on_header = skip_header;
475
transport_parsing->hpack_parser.on_header_user_data = NULL;
476
transport_parsing->hpack_parser.is_boundary = is_eoh;
477
transport_parsing->hpack_parser.is_eof =
478
is_eoh ? transport_parsing->header_eof : 0;
480
transport_parsing->parser = skip_parser;
485
void grpc_chttp2_parsing_become_skip_parser(
486
grpc_chttp2_transport_parsing *transport_parsing) {
487
init_skip_frame_parser(
489
transport_parsing->parser == grpc_chttp2_header_parser_parse);
492
static grpc_chttp2_parse_error update_incoming_window(
493
grpc_chttp2_transport_parsing *transport_parsing,
494
grpc_chttp2_stream_parsing *stream_parsing) {
495
if (transport_parsing->incoming_frame_size >
496
transport_parsing->incoming_window) {
497
gpr_log(GPR_ERROR, "frame of size %d overflows incoming window of %d",
498
transport_parsing->incoming_frame_size,
499
transport_parsing->incoming_window);
500
return GRPC_CHTTP2_CONNECTION_ERROR;
503
if (transport_parsing->incoming_frame_size >
504
stream_parsing->incoming_window) {
505
gpr_log(GPR_ERROR, "frame of size %d overflows incoming window of %d",
506
transport_parsing->incoming_frame_size,
507
stream_parsing->incoming_window);
508
return GRPC_CHTTP2_CONNECTION_ERROR;
511
GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
512
"data", transport_parsing, incoming_window,
513
-(gpr_int64)transport_parsing->incoming_frame_size);
514
GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT("data", transport_parsing,
515
incoming_window_delta,
516
transport_parsing->incoming_frame_size);
517
GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
518
"data", transport_parsing, stream_parsing, incoming_window,
519
-(gpr_int64)transport_parsing->incoming_frame_size);
520
GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("data", transport_parsing, stream_parsing,
521
incoming_window_delta,
522
transport_parsing->incoming_frame_size);
524
transport_parsing->incoming_window -= transport_parsing->incoming_frame_size;
525
transport_parsing->incoming_window_delta +=
526
transport_parsing->incoming_frame_size;
527
stream_parsing->incoming_window -= transport_parsing->incoming_frame_size;
528
stream_parsing->incoming_window_delta +=
529
transport_parsing->incoming_frame_size;
530
grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing);
532
return GRPC_CHTTP2_PARSE_OK;
535
static int init_data_frame_parser(
536
grpc_chttp2_transport_parsing *transport_parsing) {
537
grpc_chttp2_stream_parsing *stream_parsing =
538
grpc_chttp2_parsing_lookup_stream(transport_parsing,
539
transport_parsing->incoming_stream_id);
540
grpc_chttp2_parse_error err = GRPC_CHTTP2_PARSE_OK;
541
if (!stream_parsing || stream_parsing->received_close)
542
return init_skip_frame_parser(transport_parsing, 0);
543
if (err == GRPC_CHTTP2_PARSE_OK) {
544
err = update_incoming_window(transport_parsing, stream_parsing);
546
if (err == GRPC_CHTTP2_PARSE_OK) {
547
err = grpc_chttp2_data_parser_begin_frame(
548
&stream_parsing->data_parser, transport_parsing->incoming_frame_flags);
551
case GRPC_CHTTP2_PARSE_OK:
552
transport_parsing->incoming_stream = stream_parsing;
553
transport_parsing->parser = grpc_chttp2_data_parser_parse;
554
transport_parsing->parser_data = &stream_parsing->data_parser;
556
case GRPC_CHTTP2_STREAM_ERROR:
557
stream_parsing->received_close = 1;
558
stream_parsing->saw_rst_stream = 1;
559
stream_parsing->rst_stream_reason = GRPC_CHTTP2_PROTOCOL_ERROR;
560
gpr_slice_buffer_add(
561
&transport_parsing->qbuf,
562
grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id,
563
GRPC_CHTTP2_PROTOCOL_ERROR));
564
return init_skip_frame_parser(transport_parsing, 0);
565
case GRPC_CHTTP2_CONNECTION_ERROR:
568
gpr_log(GPR_ERROR, "should never reach here");
573
static void free_timeout(void *p) { gpr_free(p); }
575
static void on_header(void *tp, grpc_mdelem *md) {
576
grpc_chttp2_transport_parsing *transport_parsing = tp;
577
grpc_chttp2_stream_parsing *stream_parsing =
578
transport_parsing->incoming_stream;
580
GPR_ASSERT(stream_parsing);
582
GRPC_CHTTP2_IF_TRACING(gpr_log(
583
GPR_INFO, "HTTP:%d:HDR: %s: %s", stream_parsing->id,
584
transport_parsing->is_client ? "CLI" : "SVR",
585
grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value)));
587
if (md->key == transport_parsing->str_grpc_timeout) {
588
gpr_timespec *cached_timeout = grpc_mdelem_get_user_data(md, free_timeout);
589
if (!cached_timeout) {
590
/* not already parsed: parse it now, and store the result away */
591
cached_timeout = gpr_malloc(sizeof(gpr_timespec));
592
if (!grpc_chttp2_decode_timeout(grpc_mdstr_as_c_string(md->value),
594
gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'",
595
grpc_mdstr_as_c_string(md->value));
596
*cached_timeout = gpr_inf_future;
598
grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
600
grpc_chttp2_incoming_metadata_buffer_set_deadline(
601
&stream_parsing->incoming_metadata,
602
gpr_time_add(gpr_now(), *cached_timeout));
603
GRPC_MDELEM_UNREF(md);
605
grpc_chttp2_incoming_metadata_buffer_add(&stream_parsing->incoming_metadata,
609
grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing);
612
static int init_header_frame_parser(
613
grpc_chttp2_transport_parsing *transport_parsing, int is_continuation) {
614
int is_eoh = (transport_parsing->incoming_frame_flags &
615
GRPC_CHTTP2_DATA_FLAG_END_HEADERS) != 0;
617
grpc_chttp2_stream_parsing *stream_parsing;
620
transport_parsing->expect_continuation_stream_id = 0;
622
transport_parsing->expect_continuation_stream_id =
623
transport_parsing->incoming_stream_id;
626
if (!is_continuation) {
627
transport_parsing->header_eof = (transport_parsing->incoming_frame_flags &
628
GRPC_CHTTP2_DATA_FLAG_END_STREAM) != 0;
631
/* could be a new grpc_chttp2_stream or an existing grpc_chttp2_stream */
632
stream_parsing = grpc_chttp2_parsing_lookup_stream(
633
transport_parsing, transport_parsing->incoming_stream_id);
634
if (stream_parsing == NULL) {
635
if (is_continuation) {
637
"grpc_chttp2_stream disbanded before CONTINUATION received");
638
return init_skip_frame_parser(transport_parsing, 1);
640
if (transport_parsing->is_client) {
641
if ((transport_parsing->incoming_stream_id & 1) &&
642
transport_parsing->incoming_stream_id <
643
transport_parsing->next_stream_id) {
644
/* this is an old (probably cancelled) grpc_chttp2_stream */
647
"ignoring new grpc_chttp2_stream creation on client");
649
return init_skip_frame_parser(transport_parsing, 1);
650
} else if (transport_parsing->last_incoming_stream_id >
651
transport_parsing->incoming_stream_id) {
653
"ignoring out of order new grpc_chttp2_stream request on server; "
654
"last grpc_chttp2_stream "
655
"id=%d, new grpc_chttp2_stream id=%d",
656
transport_parsing->last_incoming_stream_id,
657
transport_parsing->incoming_stream_id);
658
return init_skip_frame_parser(transport_parsing, 1);
659
} else if ((transport_parsing->incoming_stream_id & 1) == 0) {
661
"ignoring grpc_chttp2_stream with non-client generated index %d",
662
transport_parsing->incoming_stream_id);
663
return init_skip_frame_parser(transport_parsing, 1);
665
stream_parsing = transport_parsing->incoming_stream =
666
grpc_chttp2_parsing_accept_stream(
667
transport_parsing, transport_parsing->incoming_stream_id);
668
if (stream_parsing == NULL) {
669
gpr_log(GPR_ERROR, "grpc_chttp2_stream not accepted");
670
return init_skip_frame_parser(transport_parsing, 1);
674
transport_parsing->incoming_stream = stream_parsing;
676
GPR_ASSERT(stream_parsing != NULL && (via_accept == 0 || via_accept == 1));
677
if (stream_parsing->received_close) {
678
gpr_log(GPR_ERROR, "skipping already closed grpc_chttp2_stream header");
679
transport_parsing->incoming_stream = NULL;
680
return init_skip_frame_parser(transport_parsing, 1);
682
transport_parsing->parser = grpc_chttp2_header_parser_parse;
683
transport_parsing->parser_data = &transport_parsing->hpack_parser;
684
transport_parsing->hpack_parser.on_header = on_header;
685
transport_parsing->hpack_parser.on_header_user_data = transport_parsing;
686
transport_parsing->hpack_parser.is_boundary = is_eoh;
687
transport_parsing->hpack_parser.is_eof =
688
is_eoh ? transport_parsing->header_eof : 0;
689
if (!is_continuation && (transport_parsing->incoming_frame_flags &
690
GRPC_CHTTP2_FLAG_HAS_PRIORITY)) {
691
grpc_chttp2_hpack_parser_set_has_priority(&transport_parsing->hpack_parser);
696
static int init_window_update_frame_parser(
697
grpc_chttp2_transport_parsing *transport_parsing) {
698
int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_window_update_parser_begin_frame(
699
&transport_parsing->simple.window_update,
700
transport_parsing->incoming_frame_size,
701
transport_parsing->incoming_frame_flags);
702
if (transport_parsing->incoming_stream_id) {
703
transport_parsing->incoming_stream = grpc_chttp2_parsing_lookup_stream(
704
transport_parsing, transport_parsing->incoming_stream_id);
706
transport_parsing->parser = grpc_chttp2_window_update_parser_parse;
707
transport_parsing->parser_data = &transport_parsing->simple.window_update;
711
static int init_ping_parser(grpc_chttp2_transport_parsing *transport_parsing) {
712
int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_ping_parser_begin_frame(
713
&transport_parsing->simple.ping,
714
transport_parsing->incoming_frame_size,
715
transport_parsing->incoming_frame_flags);
716
transport_parsing->parser = grpc_chttp2_ping_parser_parse;
717
transport_parsing->parser_data = &transport_parsing->simple.ping;
721
static int init_rst_stream_parser(
722
grpc_chttp2_transport_parsing *transport_parsing) {
723
int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_rst_stream_parser_begin_frame(
724
&transport_parsing->simple.rst_stream,
725
transport_parsing->incoming_frame_size,
726
transport_parsing->incoming_frame_flags);
727
transport_parsing->incoming_stream = grpc_chttp2_parsing_lookup_stream(
728
transport_parsing, transport_parsing->incoming_stream_id);
729
if (!transport_parsing->incoming_stream) {
730
return init_skip_frame_parser(transport_parsing, 0);
732
transport_parsing->parser = grpc_chttp2_rst_stream_parser_parse;
733
transport_parsing->parser_data = &transport_parsing->simple.rst_stream;
737
static int init_goaway_parser(
738
grpc_chttp2_transport_parsing *transport_parsing) {
739
int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_goaway_parser_begin_frame(
740
&transport_parsing->goaway_parser,
741
transport_parsing->incoming_frame_size,
742
transport_parsing->incoming_frame_flags);
743
transport_parsing->parser = grpc_chttp2_goaway_parser_parse;
744
transport_parsing->parser_data = &transport_parsing->goaway_parser;
748
static int init_settings_frame_parser(
749
grpc_chttp2_transport_parsing *transport_parsing) {
752
if (transport_parsing->incoming_stream_id != 0) {
753
gpr_log(GPR_ERROR, "settings frame received for grpc_chttp2_stream %d",
754
transport_parsing->incoming_stream_id);
758
ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_settings_parser_begin_frame(
759
&transport_parsing->simple.settings,
760
transport_parsing->incoming_frame_size,
761
transport_parsing->incoming_frame_flags,
762
transport_parsing->settings);
766
if (transport_parsing->incoming_frame_flags & GRPC_CHTTP2_FLAG_ACK) {
767
transport_parsing->settings_ack_received = 1;
769
transport_parsing->parser = grpc_chttp2_settings_parser_parse;
770
transport_parsing->parser_data = &transport_parsing->simple.settings;
775
static int is_window_update_legal(gpr_int64 window_update, gpr_int64 window) {
776
return window + window_update < MAX_WINDOW;
780
static int parse_frame_slice(grpc_chttp2_transport_parsing *transport_parsing,
781
gpr_slice slice, int is_last) {
782
grpc_chttp2_stream_parsing *stream_parsing =
783
transport_parsing->incoming_stream;
784
switch (transport_parsing->parser(transport_parsing->parser_data,
785
transport_parsing, stream_parsing, slice,
787
case GRPC_CHTTP2_PARSE_OK:
788
if (stream_parsing) {
789
grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
793
case GRPC_CHTTP2_STREAM_ERROR:
794
grpc_chttp2_parsing_become_skip_parser(transport_parsing);
795
if (stream_parsing) {
796
stream_parsing->saw_rst_stream = 1;
797
stream_parsing->rst_stream_reason = GRPC_CHTTP2_PROTOCOL_ERROR;
798
gpr_slice_buffer_add(
799
&transport_parsing->qbuf,
800
grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id,
801
GRPC_CHTTP2_PROTOCOL_ERROR));
804
case GRPC_CHTTP2_CONNECTION_ERROR:
807
gpr_log(GPR_ERROR, "should never reach here");