LCOV - code coverage report
Current view: top level - core/transport/chttp2 - frame_settings.c (source / functions) Hit Total Coverage
Test: tmp.CaZ6RjdVn2 Lines: 119 119 100.0 %
Date: 2015-12-10 22:15:08 Functions: 5 5 100.0 %

          Line data    Source code
       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/frame_settings.h"
      35             : #include "src/core/transport/chttp2/internal.h"
      36             : 
      37             : #include <string.h>
      38             : 
      39             : #include <grpc/support/log.h>
      40             : #include <grpc/support/useful.h>
      41             : 
      42             : #include "src/core/debug/trace.h"
      43             : #include "src/core/transport/chttp2/frame.h"
      44             : #include "src/core/transport/chttp2/http2_errors.h"
      45             : #include "src/core/transport/chttp2_transport.h"
      46             : 
      47             : #define MAX_MAX_HEADER_LIST_SIZE (1024*1024*1024)
      48             : 
      49             : /* HTTP/2 mandated initial connection settings */
      50             : const grpc_chttp2_setting_parameters
      51             :     grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS] = {
      52             :         {NULL, 0, 0, 0, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE,
      53             :          GRPC_CHTTP2_PROTOCOL_ERROR},
      54             :         {"HEADER_TABLE_SIZE", 4096, 0, 0xffffffff,
      55             :          GRPC_CHTTP2_CLAMP_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR},
      56             :         {"ENABLE_PUSH", 1, 0, 1, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE,
      57             :          GRPC_CHTTP2_PROTOCOL_ERROR},
      58             :         {"MAX_CONCURRENT_STREAMS", 0xffffffffu, 0, 0xffffffffu,
      59             :          GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR},
      60             :         {"INITIAL_WINDOW_SIZE", 65535, 0, 0x7fffffffu,
      61             :          GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE,
      62             :          GRPC_CHTTP2_FLOW_CONTROL_ERROR},
      63             :         {"MAX_FRAME_SIZE", 16384, 16384, 16777215,
      64             :          GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR},
      65             :         {"MAX_HEADER_LIST_SIZE", MAX_MAX_HEADER_LIST_SIZE, 0, MAX_MAX_HEADER_LIST_SIZE,
      66             :          GRPC_CHTTP2_CLAMP_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR},
      67             : };
      68             : 
      69       11428 : static gpr_uint8 *fill_header(gpr_uint8 *out, gpr_uint32 length,
      70             :                               gpr_uint8 flags) {
      71       11592 :   *out++ = (gpr_uint8)(length >> 16);
      72       11592 :   *out++ = (gpr_uint8)(length >> 8);
      73       11592 :   *out++ = (gpr_uint8)(length);
      74       11592 :   *out++ = GRPC_CHTTP2_FRAME_SETTINGS;
      75       11592 :   *out++ = flags;
      76       11592 :   *out++ = 0;
      77       11592 :   *out++ = 0;
      78       11592 :   *out++ = 0;
      79       11592 :   *out++ = 0;
      80       11428 :   return out;
      81             : }
      82             : 
      83        6039 : gpr_slice grpc_chttp2_settings_create(gpr_uint32 *old, const gpr_uint32 *new,
      84             :                                       gpr_uint32 force_mask, size_t count) {
      85             :   size_t i;
      86        5957 :   gpr_uint32 n = 0;
      87             :   gpr_slice output;
      88             :   gpr_uint8 *p;
      89             : 
      90       48285 :   for (i = 0; i < count; i++) {
      91       42246 :     n += (new[i] != old[i] || (force_mask & (1u << i)) != 0);
      92             :   }
      93             : 
      94        6039 :   output = gpr_slice_malloc(9 + 6 * n);
      95        6039 :   p = fill_header(GPR_SLICE_START_PTR(output), 6 * n, 0);
      96             : 
      97       48279 :   for (i = 0; i < count; i++) {
      98       42240 :     if (new[i] != old[i] || (force_mask & (1u << i)) != 0) {
      99       12622 :       GPR_ASSERT(i);
     100       12626 :       *p++ = (gpr_uint8)(i >> 8);
     101       12626 :       *p++ = (gpr_uint8)(i);
     102       12626 :       *p++ = (gpr_uint8)(new[i] >> 24);
     103       12626 :       *p++ = (gpr_uint8)(new[i] >> 16);
     104       12626 :       *p++ = (gpr_uint8)(new[i] >> 8);
     105       12626 :       *p++ = (gpr_uint8)(new[i]);
     106       12626 :       old[i] = new[i];
     107             :     }
     108             :   }
     109             : 
     110        6039 :   GPR_ASSERT(p == GPR_SLICE_END_PTR(output));
     111             : 
     112        6039 :   return output;
     113             : }
     114             : 
     115        5553 : gpr_slice grpc_chttp2_settings_ack_create(void) {
     116        5553 :   gpr_slice output = gpr_slice_malloc(9);
     117        5554 :   fill_header(GPR_SLICE_START_PTR(output), 0, GRPC_CHTTP2_FLAG_ACK);
     118        5554 :   return output;
     119             : }
     120             : 
     121       10934 : grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame(
     122             :     grpc_chttp2_settings_parser *parser, gpr_uint32 length, gpr_uint8 flags,
     123             :     gpr_uint32 *settings) {
     124       10934 :   parser->target_settings = settings;
     125       10934 :   memcpy(parser->incoming_settings, settings,
     126             :          GRPC_CHTTP2_NUM_SETTINGS * sizeof(gpr_uint32));
     127       10934 :   parser->is_ack = 0;
     128       10934 :   parser->state = GRPC_CHTTP2_SPS_ID0;
     129       10934 :   if (flags == GRPC_CHTTP2_FLAG_ACK) {
     130        5373 :     parser->is_ack = 1;
     131        5373 :     if (length != 0) {
     132           1 :       gpr_log(GPR_ERROR, "non-empty settings ack frame received");
     133           1 :       return GRPC_CHTTP2_CONNECTION_ERROR;
     134             :     }
     135        5290 :     return GRPC_CHTTP2_PARSE_OK;
     136        5561 :   } else if (flags != 0) {
     137           1 :     gpr_log(GPR_ERROR, "invalid flags on settings frame");
     138           1 :     return GRPC_CHTTP2_CONNECTION_ERROR;
     139        5560 :   } else if (length % 6 != 0) {
     140           5 :     gpr_log(GPR_ERROR, "settings frames must be a multiple of six bytes");
     141           5 :     return GRPC_CHTTP2_CONNECTION_ERROR;
     142             :   } else {
     143        5473 :     return GRPC_CHTTP2_PARSE_OK;
     144             :   }
     145             : }
     146             : 
     147       15264 : grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
     148             :     grpc_exec_ctx *exec_ctx, void *p,
     149             :     grpc_chttp2_transport_parsing *transport_parsing,
     150             :     grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
     151       15100 :   grpc_chttp2_settings_parser *parser = p;
     152       15264 :   const gpr_uint8 *cur = GPR_SLICE_START_PTR(slice);
     153       15264 :   const gpr_uint8 *end = GPR_SLICE_END_PTR(slice);
     154             : 
     155       15264 :   if (parser->is_ack) {
     156        5290 :     return GRPC_CHTTP2_PARSE_OK;
     157             :   }
     158             : 
     159             :   for (;;) {
     160       21464 :     switch (parser->state) {
     161             :       case GRPC_CHTTP2_SPS_ID0:
     162       17557 :         if (cur == end) {
     163        5975 :           parser->state = GRPC_CHTTP2_SPS_ID0;
     164        5975 :           if (is_last) {
     165        5553 :             transport_parsing->settings_updated = 1;
     166        5553 :             memcpy(parser->target_settings, parser->incoming_settings,
     167             :                    GRPC_CHTTP2_NUM_SETTINGS * sizeof(gpr_uint32));
     168        5553 :             gpr_slice_buffer_add(&transport_parsing->qbuf,
     169             :                                  grpc_chttp2_settings_ack_create());
     170             :           }
     171        5894 :           return GRPC_CHTTP2_PARSE_OK;
     172             :         }
     173       11582 :         parser->id = (gpr_uint16)(((gpr_uint16)*cur) << 8);
     174       11582 :         cur++;
     175             :       /* fallthrough */
     176             :       case GRPC_CHTTP2_SPS_ID1:
     177       12363 :         if (cur == end) {
     178         782 :           parser->state = GRPC_CHTTP2_SPS_ID1;
     179         782 :           return GRPC_CHTTP2_PARSE_OK;
     180             :         }
     181       11581 :         parser->id = (gpr_uint16)(parser->id | (*cur));
     182       11581 :         cur++;
     183             :       /* fallthrough */
     184             :       case GRPC_CHTTP2_SPS_VAL0:
     185       12359 :         if (cur == end) {
     186         782 :           parser->state = GRPC_CHTTP2_SPS_VAL0;
     187         782 :           return GRPC_CHTTP2_PARSE_OK;
     188             :         }
     189       11577 :         parser->value = ((gpr_uint32)*cur) << 24;
     190       11577 :         cur++;
     191             :       /* fallthrough */
     192             :       case GRPC_CHTTP2_SPS_VAL1:
     193       12361 :         if (cur == end) {
     194         782 :           parser->state = GRPC_CHTTP2_SPS_VAL1;
     195         782 :           return GRPC_CHTTP2_PARSE_OK;
     196             :         }
     197       11579 :         parser->value |= ((gpr_uint32)*cur) << 16;
     198       11579 :         cur++;
     199             :       /* fallthrough */
     200             :       case GRPC_CHTTP2_SPS_VAL2:
     201       12360 :         if (cur == end) {
     202         782 :           parser->state = GRPC_CHTTP2_SPS_VAL2;
     203         782 :           return GRPC_CHTTP2_PARSE_OK;
     204             :         }
     205       11578 :         parser->value |= ((gpr_uint32)*cur) << 8;
     206       11578 :         cur++;
     207             :       /* fallthrough */
     208             :       case GRPC_CHTTP2_SPS_VAL3:
     209       12360 :         if (cur == end) {
     210         782 :           parser->state = GRPC_CHTTP2_SPS_VAL3;
     211         782 :           return GRPC_CHTTP2_PARSE_OK;
     212             :         } else {
     213       11578 :           parser->state = GRPC_CHTTP2_SPS_ID0;
     214             :         }
     215       11578 :         parser->value |= *cur;
     216       11578 :         cur++;
     217             : 
     218       22980 :         if (parser->id > 0 && parser->id < GRPC_CHTTP2_NUM_SETTINGS) {
     219       11410 :           const grpc_chttp2_setting_parameters *sp =
     220       11574 :               &grpc_chttp2_settings_parameters[parser->id];
     221       11574 :           if (parser->value < sp->min_value || parser->value > sp->max_value) {
     222           2 :             switch (sp->invalid_value_behavior) {
     223             :               case GRPC_CHTTP2_CLAMP_INVALID_VALUE:
     224           1 :                 parser->value =
     225           1 :                     GPR_CLAMP(parser->value, sp->min_value, sp->max_value);
     226           1 :                 break;
     227             :               case GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE:
     228           1 :                 grpc_chttp2_goaway_append(
     229             :                     transport_parsing->last_incoming_stream_id, sp->error_value,
     230             :                     gpr_slice_from_static_string("HTTP2 settings error"),
     231             :                     &transport_parsing->qbuf);
     232           1 :                 gpr_log(GPR_ERROR, "invalid value %u passed for %s",
     233             :                         parser->value, sp->name);
     234           1 :                 return GRPC_CHTTP2_CONNECTION_ERROR;
     235             :             }
     236             :           }
     237       17060 :           if (parser->id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE &&
     238        5487 :               parser->incoming_settings[parser->id] != parser->value) {
     239           1 :             transport_parsing->initial_window_update =
     240           2 :                 (gpr_int64)parser->value -
     241           1 :                 parser->incoming_settings[parser->id];
     242           1 :             gpr_log(GPR_DEBUG, "adding %d for initial_window change",
     243           1 :                     (int)transport_parsing->initial_window_update);
     244             :           }
     245       11566 :           parser->incoming_settings[parser->id] = parser->value;
     246       11566 :           if (grpc_http_trace) {
     247        1302 :             gpr_log(GPR_DEBUG, "CHTTP2:%s: got setting %d = %d",
     248         868 :                     transport_parsing->is_client ? "CLI" : "SVR", parser->id,
     249             :                     parser->value);
     250             :           }
     251             :         } else {
     252           8 :           gpr_log(GPR_ERROR, "CHTTP2: Ignoring unknown setting %d (value %d)",
     253           4 :                   parser->id, parser->value);
     254             :         }
     255       11407 :         break;
     256             :     }
     257       11408 :   }
     258             : }

Generated by: LCOV version 1.11