~ubuntu-branches/ubuntu/wily/grpc/wily

« back to all changes in this revision

Viewing changes to src/core/transport/chttp2/parsing.c

  • Committer: Package Import Robot
  • Author(s): Andrew Pollock
  • Date: 2015-05-07 13:28:11 UTC
  • Revision ID: package-import@ubuntu.com-20150507132811-ybm4hfq73tnvvd2e
Tags: upstream-0.10.0
ImportĀ upstreamĀ versionĀ 0.10.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *
 
3
 * Copyright 2015, Google Inc.
 
4
 * All rights reserved.
 
5
 *
 
6
 * Redistribution and use in source and binary forms, with or without
 
7
 * modification, are permitted provided that the following conditions are
 
8
 * met:
 
9
 *
 
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
 
15
 * distribution.
 
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.
 
19
 *
 
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.
 
31
 *
 
32
 */
 
33
 
 
34
#include "src/core/transport/chttp2/internal.h"
 
35
 
 
36
#include <string.h>
 
37
 
 
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"
 
41
 
 
42
#include <grpc/support/alloc.h>
 
43
#include <grpc/support/log.h>
 
44
 
 
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);
 
60
 
 
61
static int parse_frame_slice(grpc_chttp2_transport_parsing *transport_parsing,
 
62
                             gpr_slice slice, int is_last);
 
63
 
 
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;
 
69
 
 
70
  transport_parsing->next_stream_id = transport_global->next_stream_id;
 
71
 
 
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;
 
79
  }
 
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;
 
89
    }
 
90
  }
 
91
}
 
92
 
 
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;
 
98
 
 
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
 
104
     ID.  So,
 
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;
 
110
  }
 
111
 
 
112
  /* copy parsing qbuf to global qbuf */
 
113
  gpr_slice_buffer_move_into(&transport_parsing->qbuf, &transport_global->qbuf);
 
114
 
 
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;
 
120
  }
 
121
 
 
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;
 
128
  }
 
129
 
 
130
  /* move goaway to the global state if we received one (it will be
 
131
     published later */
 
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;
 
138
  }
 
139
 
 
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;
 
151
  }
 
152
 
 
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;
 
163
  }
 
164
 
 
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,
 
179
                                                         stream_global);
 
180
    }
 
181
 
 
182
    /* update outgoing flow control window */
 
183
    if (stream_parsing->outgoing_window_update) {
 
184
      int was_zero = stream_global->outgoing_window <= 0;
 
185
      int is_zero;
 
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);
 
197
      }
 
198
    }
 
199
 
 
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,
 
204
                                                    stream_global);
 
205
    }
 
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;
 
211
      }
 
212
      grpc_chttp2_list_add_read_write_state_changed(transport_global,
 
213
                                                    stream_global);
 
214
    }
 
215
 
 
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,
 
224
                                                    stream_global);
 
225
    }
 
226
  }
 
227
}
 
228
 
 
229
int grpc_chttp2_perform_read(grpc_chttp2_transport_parsing *transport_parsing,
 
230
                             gpr_slice slice) {
 
231
  gpr_uint8 *beg = GPR_SLICE_START_PTR(slice);
 
232
  gpr_uint8 *end = GPR_SLICE_END_PTR(slice);
 
233
  gpr_uint8 *cur = beg;
 
234
 
 
235
  if (cur == end) return 1;
 
236
 
 
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
 
264
                                                          ->deframe_state]) {
 
265
          gpr_log(GPR_INFO,
 
266
                  "Connect string mismatch: expected '%c' (%d) got '%c' (%d) "
 
267
                  "at byte %d",
 
268
                  GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing
 
269
                                                        ->deframe_state],
 
270
                  (int)(gpr_uint8)GRPC_CHTTP2_CLIENT_CONNECT_STRING
 
271
                      [transport_parsing->deframe_state],
 
272
                  *cur, (int)*cur, transport_parsing->deframe_state);
 
273
          return 0;
 
274
        }
 
275
        ++cur;
 
276
        ++transport_parsing->deframe_state;
 
277
      }
 
278
      if (cur == end) {
 
279
        return 1;
 
280
      }
 
281
    /* fallthrough */
 
282
    dts_fh_0:
 
283
    case GRPC_DTS_FH_0:
 
284
      GPR_ASSERT(cur < end);
 
285
      transport_parsing->incoming_frame_size = ((gpr_uint32)*cur) << 16;
 
286
      if (++cur == end) {
 
287
        transport_parsing->deframe_state = GRPC_DTS_FH_1;
 
288
        return 1;
 
289
      }
 
290
    /* fallthrough */
 
291
    case GRPC_DTS_FH_1:
 
292
      GPR_ASSERT(cur < end);
 
293
      transport_parsing->incoming_frame_size |= ((gpr_uint32)*cur) << 8;
 
294
      if (++cur == end) {
 
295
        transport_parsing->deframe_state = GRPC_DTS_FH_2;
 
296
        return 1;
 
297
      }
 
298
    /* fallthrough */
 
299
    case GRPC_DTS_FH_2:
 
300
      GPR_ASSERT(cur < end);
 
301
      transport_parsing->incoming_frame_size |= *cur;
 
302
      if (++cur == end) {
 
303
        transport_parsing->deframe_state = GRPC_DTS_FH_3;
 
304
        return 1;
 
305
      }
 
306
    /* fallthrough */
 
307
    case GRPC_DTS_FH_3:
 
308
      GPR_ASSERT(cur < end);
 
309
      transport_parsing->incoming_frame_type = *cur;
 
310
      if (++cur == end) {
 
311
        transport_parsing->deframe_state = GRPC_DTS_FH_4;
 
312
        return 1;
 
313
      }
 
314
    /* fallthrough */
 
315
    case GRPC_DTS_FH_4:
 
316
      GPR_ASSERT(cur < end);
 
317
      transport_parsing->incoming_frame_flags = *cur;
 
318
      if (++cur == end) {
 
319
        transport_parsing->deframe_state = GRPC_DTS_FH_5;
 
320
        return 1;
 
321
      }
 
322
    /* fallthrough */
 
323
    case GRPC_DTS_FH_5:
 
324
      GPR_ASSERT(cur < end);
 
325
      transport_parsing->incoming_stream_id = (((gpr_uint32)*cur) & 0x7f) << 24;
 
326
      if (++cur == end) {
 
327
        transport_parsing->deframe_state = GRPC_DTS_FH_6;
 
328
        return 1;
 
329
      }
 
330
    /* fallthrough */
 
331
    case GRPC_DTS_FH_6:
 
332
      GPR_ASSERT(cur < end);
 
333
      transport_parsing->incoming_stream_id |= ((gpr_uint32)*cur) << 16;
 
334
      if (++cur == end) {
 
335
        transport_parsing->deframe_state = GRPC_DTS_FH_7;
 
336
        return 1;
 
337
      }
 
338
    /* fallthrough */
 
339
    case GRPC_DTS_FH_7:
 
340
      GPR_ASSERT(cur < end);
 
341
      transport_parsing->incoming_stream_id |= ((gpr_uint32)*cur) << 8;
 
342
      if (++cur == end) {
 
343
        transport_parsing->deframe_state = GRPC_DTS_FH_8;
 
344
        return 1;
 
345
      }
 
346
    /* fallthrough */
 
347
    case 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)) {
 
352
        return 0;
 
353
      }
 
354
      if (transport_parsing->incoming_stream_id) {
 
355
        transport_parsing->last_incoming_stream_id =
 
356
            transport_parsing->incoming_stream_id;
 
357
      }
 
358
      if (transport_parsing->incoming_frame_size == 0) {
 
359
        if (!parse_frame_slice(transport_parsing, gpr_empty_slice(), 1)) {
 
360
          return 0;
 
361
        }
 
362
        transport_parsing->incoming_stream = NULL;
 
363
        if (++cur == end) {
 
364
          transport_parsing->deframe_state = GRPC_DTS_FH_0;
 
365
          return 1;
 
366
        }
 
367
        goto dts_fh_0; /* loop */
 
368
      }
 
369
      if (++cur == end) {
 
370
        return 1;
 
371
      }
 
372
    /* fallthrough */
 
373
    case GRPC_DTS_FRAME:
 
374
      GPR_ASSERT(cur < end);
 
375
      if ((gpr_uint32)(end - cur) == transport_parsing->incoming_frame_size) {
 
376
        if (!parse_frame_slice(
 
377
                transport_parsing,
 
378
                gpr_slice_sub_no_ref(slice, cur - beg, end - beg), 1)) {
 
379
          return 0;
 
380
        }
 
381
        transport_parsing->deframe_state = GRPC_DTS_FH_0;
 
382
        transport_parsing->incoming_stream = NULL;
 
383
        return 1;
 
384
      } else if ((gpr_uint32)(end - cur) >
 
385
                 transport_parsing->incoming_frame_size) {
 
386
        if (!parse_frame_slice(
 
387
                transport_parsing,
 
388
                gpr_slice_sub_no_ref(
 
389
                    slice, cur - beg,
 
390
                    cur + transport_parsing->incoming_frame_size - beg),
 
391
                1)) {
 
392
          return 0;
 
393
        }
 
394
        cur += transport_parsing->incoming_frame_size;
 
395
        transport_parsing->incoming_stream = NULL;
 
396
        goto dts_fh_0; /* loop */
 
397
      } else {
 
398
        if (!parse_frame_slice(
 
399
                transport_parsing,
 
400
                gpr_slice_sub_no_ref(slice, cur - beg, end - beg), 0)) {
 
401
          return 0;
 
402
        }
 
403
        transport_parsing->incoming_frame_size -= (end - cur);
 
404
        return 1;
 
405
      }
 
406
      gpr_log(GPR_ERROR, "should never reach here");
 
407
      abort();
 
408
  }
 
409
 
 
410
  gpr_log(GPR_ERROR, "should never reach here");
 
411
  abort();
 
412
 
 
413
  return 0;
 
414
}
 
415
 
 
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);
 
422
      return 0;
 
423
    }
 
424
    if (transport_parsing->expect_continuation_stream_id !=
 
425
        transport_parsing->incoming_stream_id) {
 
426
      gpr_log(GPR_ERROR,
 
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);
 
431
      return 0;
 
432
    }
 
433
    return init_header_frame_parser(transport_parsing, 1);
 
434
  }
 
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");
 
442
      return 0;
 
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);
 
453
    default:
 
454
      gpr_log(GPR_ERROR, "Unknown frame type %02x",
 
455
              transport_parsing->incoming_frame_type);
 
456
      return init_skip_frame_parser(transport_parsing, 0);
 
457
  }
 
458
}
 
459
 
 
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;
 
464
}
 
465
 
 
466
static void skip_header(void *tp, grpc_mdelem *md) { GRPC_MDELEM_UNREF(md); }
 
467
 
 
468
static int init_skip_frame_parser(
 
469
    grpc_chttp2_transport_parsing *transport_parsing, int is_header) {
 
470
  if (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;
 
479
  } else {
 
480
    transport_parsing->parser = skip_parser;
 
481
  }
 
482
  return 1;
 
483
}
 
484
 
 
485
void grpc_chttp2_parsing_become_skip_parser(
 
486
    grpc_chttp2_transport_parsing *transport_parsing) {
 
487
  init_skip_frame_parser(
 
488
      transport_parsing,
 
489
      transport_parsing->parser == grpc_chttp2_header_parser_parse);
 
490
}
 
491
 
 
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;
 
501
  }
 
502
 
 
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;
 
509
  }
 
510
 
 
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);
 
523
 
 
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);
 
531
 
 
532
  return GRPC_CHTTP2_PARSE_OK;
 
533
}
 
534
 
 
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);
 
545
  }
 
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);
 
549
  }
 
550
  switch (err) {
 
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;
 
555
      return 1;
 
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:
 
566
      return 0;
 
567
  }
 
568
  gpr_log(GPR_ERROR, "should never reach here");
 
569
  abort();
 
570
  return 0;
 
571
}
 
572
 
 
573
static void free_timeout(void *p) { gpr_free(p); }
 
574
 
 
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;
 
579
 
 
580
  GPR_ASSERT(stream_parsing);
 
581
 
 
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)));
 
586
 
 
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),
 
593
                                      cached_timeout)) {
 
594
        gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'",
 
595
                grpc_mdstr_as_c_string(md->value));
 
596
        *cached_timeout = gpr_inf_future;
 
597
      }
 
598
      grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
 
599
    }
 
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);
 
604
  } else {
 
605
    grpc_chttp2_incoming_metadata_buffer_add(&stream_parsing->incoming_metadata,
 
606
                                             md);
 
607
  }
 
608
 
 
609
  grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing);
 
610
}
 
611
 
 
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;
 
616
  int via_accept = 0;
 
617
  grpc_chttp2_stream_parsing *stream_parsing;
 
618
 
 
619
  if (is_eoh) {
 
620
    transport_parsing->expect_continuation_stream_id = 0;
 
621
  } else {
 
622
    transport_parsing->expect_continuation_stream_id =
 
623
        transport_parsing->incoming_stream_id;
 
624
  }
 
625
 
 
626
  if (!is_continuation) {
 
627
    transport_parsing->header_eof = (transport_parsing->incoming_frame_flags &
 
628
                                     GRPC_CHTTP2_DATA_FLAG_END_STREAM) != 0;
 
629
  }
 
630
 
 
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) {
 
636
      gpr_log(GPR_ERROR,
 
637
              "grpc_chttp2_stream disbanded before CONTINUATION received");
 
638
      return init_skip_frame_parser(transport_parsing, 1);
 
639
    }
 
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 */
 
645
      } else {
 
646
        gpr_log(GPR_ERROR,
 
647
                "ignoring new grpc_chttp2_stream creation on client");
 
648
      }
 
649
      return init_skip_frame_parser(transport_parsing, 1);
 
650
    } else if (transport_parsing->last_incoming_stream_id >
 
651
               transport_parsing->incoming_stream_id) {
 
652
      gpr_log(GPR_ERROR,
 
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) {
 
660
      gpr_log(GPR_ERROR,
 
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);
 
664
    }
 
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);
 
671
    }
 
672
    via_accept = 1;
 
673
  } else {
 
674
    transport_parsing->incoming_stream = stream_parsing;
 
675
  }
 
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);
 
681
  }
 
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);
 
692
  }
 
693
  return 1;
 
694
}
 
695
 
 
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);
 
705
  }
 
706
  transport_parsing->parser = grpc_chttp2_window_update_parser_parse;
 
707
  transport_parsing->parser_data = &transport_parsing->simple.window_update;
 
708
  return ok;
 
709
}
 
710
 
 
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;
 
718
  return ok;
 
719
}
 
720
 
 
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);
 
731
  }
 
732
  transport_parsing->parser = grpc_chttp2_rst_stream_parser_parse;
 
733
  transport_parsing->parser_data = &transport_parsing->simple.rst_stream;
 
734
  return ok;
 
735
}
 
736
 
 
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;
 
745
  return ok;
 
746
}
 
747
 
 
748
static int init_settings_frame_parser(
 
749
    grpc_chttp2_transport_parsing *transport_parsing) {
 
750
  int ok;
 
751
 
 
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);
 
755
    return 0;
 
756
  }
 
757
 
 
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);
 
763
  if (!ok) {
 
764
    return 0;
 
765
  }
 
766
  if (transport_parsing->incoming_frame_flags & GRPC_CHTTP2_FLAG_ACK) {
 
767
    transport_parsing->settings_ack_received = 1;
 
768
  }
 
769
  transport_parsing->parser = grpc_chttp2_settings_parser_parse;
 
770
  transport_parsing->parser_data = &transport_parsing->simple.settings;
 
771
  return ok;
 
772
}
 
773
 
 
774
/*
 
775
static int is_window_update_legal(gpr_int64 window_update, gpr_int64 window) {
 
776
  return window + window_update < MAX_WINDOW;
 
777
}
 
778
*/
 
779
 
 
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,
 
786
                                    is_last)) {
 
787
    case GRPC_CHTTP2_PARSE_OK:
 
788
      if (stream_parsing) {
 
789
        grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
 
790
                                                 stream_parsing);
 
791
      }
 
792
      return 1;
 
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));
 
802
      }
 
803
      return 1;
 
804
    case GRPC_CHTTP2_CONNECTION_ERROR:
 
805
      return 0;
 
806
  }
 
807
  gpr_log(GPR_ERROR, "should never reach here");
 
808
  abort();
 
809
  return 0;
 
810
}