LCOV - code coverage report
Current view: top level - src/core/transport/chttp2 - frame_settings.c (source / functions) Hit Total Coverage
Test: tmp.zDYK9MVh93 Lines: 103 118 87.3 %
Date: 2015-10-10 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 "src/core/debug/trace.h"
      40             : #include "src/core/transport/chttp2/frame.h"
      41             : #include "src/core/transport/chttp2_transport.h"
      42             : #include <grpc/support/log.h>
      43             : #include <grpc/support/useful.h>
      44             : 
      45             : /* HTTP/2 mandated initial connection settings */
      46             : const grpc_chttp2_setting_parameters
      47             :     grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS] = {
      48             :         {NULL, 0, 0, 0, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE},
      49             :         {"HEADER_TABLE_SIZE", 4096, 0, 0xffffffff,
      50             :          GRPC_CHTTP2_CLAMP_INVALID_VALUE},
      51             :         {"ENABLE_PUSH", 1, 0, 1, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE},
      52             :         {"MAX_CONCURRENT_STREAMS", 0xffffffffu, 0, 0xffffffffu,
      53             :          GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE},
      54             :         {"INITIAL_WINDOW_SIZE", 65535, 0, 0xffffffffu,
      55             :          GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE},
      56             :         {"MAX_FRAME_SIZE", 16384, 16384, 16777215,
      57             :          GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE},
      58             :         {"MAX_HEADER_LIST_SIZE", 0xffffffffu, 0, 0xffffffffu,
      59             :          GRPC_CHTTP2_CLAMP_INVALID_VALUE},
      60             : };
      61             : 
      62        7694 : static gpr_uint8 *fill_header(gpr_uint8 *out, gpr_uint32 length,
      63             :                               gpr_uint8 flags) {
      64        7694 :   *out++ = (gpr_uint8)(length >> 16);
      65        7694 :   *out++ = (gpr_uint8)(length >> 8);
      66        7694 :   *out++ = (gpr_uint8)(length);
      67        7694 :   *out++ = GRPC_CHTTP2_FRAME_SETTINGS;
      68        7694 :   *out++ = flags;
      69        7694 :   *out++ = 0;
      70        7694 :   *out++ = 0;
      71        7694 :   *out++ = 0;
      72        7694 :   *out++ = 0;
      73        7694 :   return out;
      74             : }
      75             : 
      76        4010 : gpr_slice grpc_chttp2_settings_create(gpr_uint32 *old, const gpr_uint32 *new,
      77             :                                       gpr_uint32 force_mask, size_t count) {
      78             :   size_t i;
      79        4010 :   gpr_uint32 n = 0;
      80             :   gpr_slice output;
      81             :   gpr_uint8 *p;
      82             : 
      83       32061 :   for (i = 0; i < count; i++) {
      84       28051 :     n += (new[i] != old[i] || (force_mask & (1u << i)) != 0);
      85             :   }
      86             : 
      87        4010 :   output = gpr_slice_malloc(9 + 6 * n);
      88        4013 :   p = fill_header(GPR_SLICE_START_PTR(output), 6 * n, 0);
      89             : 
      90       32056 :   for (i = 0; i < count; i++) {
      91       28045 :     if (new[i] != old[i] || (force_mask & (1u << i)) != 0) {
      92        8007 :       GPR_ASSERT(i);
      93        8009 :       *p++ = (gpr_uint8)(i >> 8);
      94        8009 :       *p++ = (gpr_uint8)(i);
      95        8009 :       *p++ = (gpr_uint8)(new[i] >> 24);
      96        8009 :       *p++ = (gpr_uint8)(new[i] >> 16);
      97        8009 :       *p++ = (gpr_uint8)(new[i] >> 8);
      98        8009 :       *p++ = (gpr_uint8)(new[i]);
      99        8009 :       old[i] = new[i];
     100             :     }
     101             :   }
     102             : 
     103        4011 :   GPR_ASSERT(p == GPR_SLICE_END_PTR(output));
     104             : 
     105        4011 :   return output;
     106             : }
     107             : 
     108        3680 : gpr_slice grpc_chttp2_settings_ack_create(void) {
     109        3680 :   gpr_slice output = gpr_slice_malloc(9);
     110        3681 :   fill_header(GPR_SLICE_START_PTR(output), 0, GRPC_CHTTP2_FLAG_ACK);
     111        3681 :   return output;
     112             : }
     113             : 
     114        7263 : grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame(
     115             :     grpc_chttp2_settings_parser *parser, gpr_uint32 length, gpr_uint8 flags,
     116             :     gpr_uint32 *settings) {
     117        7263 :   parser->target_settings = settings;
     118        7263 :   memcpy(parser->incoming_settings, settings,
     119             :          GRPC_CHTTP2_NUM_SETTINGS * sizeof(gpr_uint32));
     120        7263 :   parser->is_ack = 0;
     121        7263 :   parser->state = GRPC_CHTTP2_SPS_ID0;
     122        7263 :   if (flags == GRPC_CHTTP2_FLAG_ACK) {
     123        3578 :     parser->is_ack = 1;
     124        3578 :     if (length != 0) {
     125           0 :       gpr_log(GPR_ERROR, "non-empty settings ack frame received");
     126           0 :       return GRPC_CHTTP2_CONNECTION_ERROR;
     127             :     }
     128        3578 :     return GRPC_CHTTP2_PARSE_OK;
     129        3685 :   } else if (flags != 0) {
     130           0 :     gpr_log(GPR_ERROR, "invalid flags on settings frame");
     131           0 :     return GRPC_CHTTP2_CONNECTION_ERROR;
     132        3685 :   } else if (length % 6 != 0) {
     133           5 :     gpr_log(GPR_ERROR, "settings frames must be a multiple of six bytes");
     134           5 :     return GRPC_CHTTP2_CONNECTION_ERROR;
     135             :   } else {
     136        3680 :     return GRPC_CHTTP2_PARSE_OK;
     137             :   }
     138             : }
     139             : 
     140        9646 : grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
     141             :     grpc_exec_ctx *exec_ctx, void *p,
     142             :     grpc_chttp2_transport_parsing *transport_parsing,
     143             :     grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
     144        9646 :   grpc_chttp2_settings_parser *parser = p;
     145        9646 :   const gpr_uint8 *cur = GPR_SLICE_START_PTR(slice);
     146        9646 :   const gpr_uint8 *end = GPR_SLICE_END_PTR(slice);
     147             : 
     148        9646 :   if (parser->is_ack) {
     149        3578 :     return GRPC_CHTTP2_PARSE_OK;
     150             :   }
     151             : 
     152             :   for (;;) {
     153       13436 :     switch (parser->state) {
     154             :       case GRPC_CHTTP2_SPS_ID0:
     155       11269 :         if (cur == end) {
     156        3899 :           parser->state = GRPC_CHTTP2_SPS_ID0;
     157        3899 :           if (is_last) {
     158        3681 :             transport_parsing->settings_updated = 1;
     159        3681 :             memcpy(parser->target_settings, parser->incoming_settings,
     160             :                    GRPC_CHTTP2_NUM_SETTINGS * sizeof(gpr_uint32));
     161        3681 :             gpr_slice_buffer_add(&transport_parsing->qbuf,
     162             :                                  grpc_chttp2_settings_ack_create());
     163             :           }
     164        3899 :           return GRPC_CHTTP2_PARSE_OK;
     165             :         }
     166        7370 :         parser->id = (gpr_uint16)(((gpr_uint16)*cur) << 8);
     167        7370 :         cur++;
     168             :       /* fallthrough */
     169             :       case GRPC_CHTTP2_SPS_ID1:
     170        7803 :         if (cur == end) {
     171         434 :           parser->state = GRPC_CHTTP2_SPS_ID1;
     172         434 :           return GRPC_CHTTP2_PARSE_OK;
     173             :         }
     174        7369 :         parser->id = (gpr_uint16)(parser->id | (*cur));
     175        7369 :         cur++;
     176             :       /* fallthrough */
     177             :       case GRPC_CHTTP2_SPS_VAL0:
     178        7802 :         if (cur == end) {
     179         434 :           parser->state = GRPC_CHTTP2_SPS_VAL0;
     180         434 :           return GRPC_CHTTP2_PARSE_OK;
     181             :         }
     182        7368 :         parser->value = ((gpr_uint32)*cur) << 24;
     183        7368 :         cur++;
     184             :       /* fallthrough */
     185             :       case GRPC_CHTTP2_SPS_VAL1:
     186        7803 :         if (cur == end) {
     187         434 :           parser->state = GRPC_CHTTP2_SPS_VAL1;
     188         434 :           return GRPC_CHTTP2_PARSE_OK;
     189             :         }
     190        7369 :         parser->value |= ((gpr_uint32)*cur) << 16;
     191        7369 :         cur++;
     192             :       /* fallthrough */
     193             :       case GRPC_CHTTP2_SPS_VAL2:
     194        7801 :         if (cur == end) {
     195         434 :           parser->state = GRPC_CHTTP2_SPS_VAL2;
     196         434 :           return GRPC_CHTTP2_PARSE_OK;
     197             :         }
     198        7367 :         parser->value |= ((gpr_uint32)*cur) << 8;
     199        7367 :         cur++;
     200             :       /* fallthrough */
     201             :       case GRPC_CHTTP2_SPS_VAL3:
     202        7801 :         if (cur == end) {
     203         434 :           parser->state = GRPC_CHTTP2_SPS_VAL3;
     204         434 :           return GRPC_CHTTP2_PARSE_OK;
     205             :         } else {
     206        7367 :           parser->state = GRPC_CHTTP2_SPS_ID0;
     207             :         }
     208        7367 :         parser->value |= *cur;
     209        7367 :         cur++;
     210             : 
     211       14733 :         if (parser->id > 0 && parser->id < GRPC_CHTTP2_NUM_SETTINGS) {
     212        7365 :           const grpc_chttp2_setting_parameters *sp =
     213        7365 :               &grpc_chttp2_settings_parameters[parser->id];
     214        7365 :           if (parser->value < sp->min_value || parser->value > sp->max_value) {
     215           0 :             switch (sp->invalid_value_behavior) {
     216             :               case GRPC_CHTTP2_CLAMP_INVALID_VALUE:
     217           0 :                 parser->value =
     218           0 :                     GPR_CLAMP(parser->value, sp->min_value, sp->max_value);
     219           0 :                 break;
     220             :               case GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE:
     221           0 :                 gpr_log(GPR_ERROR, "invalid value %u passed for %s",
     222             :                         parser->value, sp->name);
     223           0 :                 return GRPC_CHTTP2_CONNECTION_ERROR;
     224             :             }
     225             :           }
     226       11046 :           if (parser->id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE &&
     227        3681 :               parser->incoming_settings[parser->id] != parser->value) {
     228           0 :             transport_parsing->initial_window_update =
     229           0 :                 (gpr_int64)parser->value -
     230           0 :                 parser->incoming_settings[parser->id];
     231           0 :             gpr_log(GPR_DEBUG, "adding %d for initial_window change",
     232           0 :                     (int)transport_parsing->initial_window_update);
     233             :           }
     234        7366 :           parser->incoming_settings[parser->id] = parser->value;
     235        7366 :           if (grpc_http_trace) {
     236        1302 :             gpr_log(GPR_DEBUG, "CHTTP2:%s: got setting %d = %d",
     237         868 :                     transport_parsing->is_client ? "CLI" : "SVR", parser->id,
     238             :                     parser->value);
     239             :           }
     240             :         } else {
     241           4 :           gpr_log(GPR_ERROR, "CHTTP2: Ignoring unknown setting %d (value %d)",
     242           2 :                   parser->id, parser->value);
     243             :         }
     244        7368 :         break;
     245             :     }
     246        7368 :   }
     247             : }

Generated by: LCOV version 1.10