LCOV - code coverage report
Current view: top level - src/core/transport/chttp2 - hpack_table.c (source / functions) Hit Total Coverage
Test: tmp.zDYK9MVh93 Lines: 61 64 95.3 %
Date: 2015-10-10 Functions: 6 6 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/hpack_table.h"
      35             : 
      36             : #include <assert.h>
      37             : #include <string.h>
      38             : 
      39             : #include <grpc/support/log.h>
      40             : #include "src/core/support/murmur_hash.h"
      41             : 
      42             : static struct {
      43             :   const char *key;
      44             :   const char *value;
      45             : } static_table[] = {
      46             :     /* 0: */
      47             :     {NULL, NULL},
      48             :     /* 1: */
      49             :     {":authority", ""},
      50             :     /* 2: */
      51             :     {":method", "GET"},
      52             :     /* 3: */
      53             :     {":method", "POST"},
      54             :     /* 4: */
      55             :     {":path", "/"},
      56             :     /* 5: */
      57             :     {":path", "/index.html"},
      58             :     /* 6: */
      59             :     {":scheme", "http"},
      60             :     /* 7: */
      61             :     {":scheme", "https"},
      62             :     /* 8: */
      63             :     {":status", "200"},
      64             :     /* 9: */
      65             :     {":status", "204"},
      66             :     /* 10: */
      67             :     {":status", "206"},
      68             :     /* 11: */
      69             :     {":status", "304"},
      70             :     /* 12: */
      71             :     {":status", "400"},
      72             :     /* 13: */
      73             :     {":status", "404"},
      74             :     /* 14: */
      75             :     {":status", "500"},
      76             :     /* 15: */
      77             :     {"accept-charset", ""},
      78             :     /* 16: */
      79             :     {"accept-encoding", "gzip, deflate"},
      80             :     /* 17: */
      81             :     {"accept-language", ""},
      82             :     /* 18: */
      83             :     {"accept-ranges", ""},
      84             :     /* 19: */
      85             :     {"accept", ""},
      86             :     /* 20: */
      87             :     {"access-control-allow-origin", ""},
      88             :     /* 21: */
      89             :     {"age", ""},
      90             :     /* 22: */
      91             :     {"allow", ""},
      92             :     /* 23: */
      93             :     {"authorization", ""},
      94             :     /* 24: */
      95             :     {"cache-control", ""},
      96             :     /* 25: */
      97             :     {"content-disposition", ""},
      98             :     /* 26: */
      99             :     {"content-encoding", ""},
     100             :     /* 27: */
     101             :     {"content-language", ""},
     102             :     /* 28: */
     103             :     {"content-length", ""},
     104             :     /* 29: */
     105             :     {"content-location", ""},
     106             :     /* 30: */
     107             :     {"content-range", ""},
     108             :     /* 31: */
     109             :     {"content-type", ""},
     110             :     /* 32: */
     111             :     {"cookie", ""},
     112             :     /* 33: */
     113             :     {"date", ""},
     114             :     /* 34: */
     115             :     {"etag", ""},
     116             :     /* 35: */
     117             :     {"expect", ""},
     118             :     /* 36: */
     119             :     {"expires", ""},
     120             :     /* 37: */
     121             :     {"from", ""},
     122             :     /* 38: */
     123             :     {"host", ""},
     124             :     /* 39: */
     125             :     {"if-match", ""},
     126             :     /* 40: */
     127             :     {"if-modified-since", ""},
     128             :     /* 41: */
     129             :     {"if-none-match", ""},
     130             :     /* 42: */
     131             :     {"if-range", ""},
     132             :     /* 43: */
     133             :     {"if-unmodified-since", ""},
     134             :     /* 44: */
     135             :     {"last-modified", ""},
     136             :     /* 45: */
     137             :     {"link", ""},
     138             :     /* 46: */
     139             :     {"location", ""},
     140             :     /* 47: */
     141             :     {"max-forwards", ""},
     142             :     /* 48: */
     143             :     {"proxy-authenticate", ""},
     144             :     /* 49: */
     145             :     {"proxy-authorization", ""},
     146             :     /* 50: */
     147             :     {"range", ""},
     148             :     /* 51: */
     149             :     {"referer", ""},
     150             :     /* 52: */
     151             :     {"refresh", ""},
     152             :     /* 53: */
     153             :     {"retry-after", ""},
     154             :     /* 54: */
     155             :     {"server", ""},
     156             :     /* 55: */
     157             :     {"set-cookie", ""},
     158             :     /* 56: */
     159             :     {"strict-transport-security", ""},
     160             :     /* 57: */
     161             :     {"transfer-encoding", ""},
     162             :     /* 58: */
     163             :     {"user-agent", ""},
     164             :     /* 59: */
     165             :     {"vary", ""},
     166             :     /* 60: */
     167             :     {"via", ""},
     168             :     /* 61: */
     169             :     {"www-authenticate", ""},
     170             : };
     171             : 
     172        4031 : void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl, grpc_mdctx *mdctx) {
     173             :   size_t i;
     174             : 
     175        4031 :   memset(tbl, 0, sizeof(*tbl));
     176        4031 :   tbl->mdctx = mdctx;
     177        4031 :   tbl->max_bytes = GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE;
     178      250299 :   for (i = 1; i <= GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) {
     179      246261 :     tbl->static_ents[i - 1] = grpc_mdelem_from_strings(
     180             :         mdctx, static_table[i].key, static_table[i].value);
     181             :   }
     182        4038 : }
     183             : 
     184        4036 : void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl) {
     185             :   size_t i;
     186      250351 :   for (i = 0; i < GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) {
     187      246313 :     GRPC_MDELEM_UNREF(tbl->static_ents[i]);
     188             :   }
     189       34187 :   for (i = 0; i < tbl->num_ents; i++) {
     190       30149 :     GRPC_MDELEM_UNREF(
     191             :         tbl->ents[(tbl->first_ent + i) % GRPC_CHTTP2_MAX_TABLE_COUNT]);
     192             :   }
     193        4038 : }
     194             : 
     195    20800157 : grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
     196             :                                       gpr_uint32 tbl_index) {
     197             :   /* Static table comes first, just return an entry from it */
     198    20800157 :   if (tbl_index <= GRPC_CHTTP2_LAST_STATIC_ENTRY) {
     199         187 :     return tbl->static_ents[tbl_index - 1];
     200             :   }
     201             :   /* Otherwise, find the value in the list of valid entries */
     202    20799970 :   tbl_index -= (GRPC_CHTTP2_LAST_STATIC_ENTRY + 1);
     203    20799970 :   if (tbl_index < tbl->num_ents) {
     204    20799970 :     gpr_uint32 offset = (tbl->num_ents - 1u - tbl_index + tbl->first_ent) %
     205             :                         GRPC_CHTTP2_MAX_TABLE_COUNT;
     206    20799970 :     return tbl->ents[offset];
     207             :   }
     208             :   /* Invalid entry: return error */
     209           0 :   return NULL;
     210             : }
     211             : 
     212             : /* Evict one element from the table */
     213     1017009 : static void evict1(grpc_chttp2_hptbl *tbl) {
     214     1017009 :   grpc_mdelem *first_ent = tbl->ents[tbl->first_ent];
     215     2034018 :   size_t elem_bytes = GPR_SLICE_LENGTH(first_ent->key->slice) +
     216     1017009 :                       GPR_SLICE_LENGTH(first_ent->value->slice) +
     217             :                       GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
     218     1017009 :   GPR_ASSERT(elem_bytes <= tbl->mem_used);
     219     1017009 :   tbl->mem_used = (gpr_uint16)(tbl->mem_used - elem_bytes);
     220     1017009 :   tbl->first_ent =
     221     1017009 :       (gpr_uint16)((tbl->first_ent + 1) % GRPC_CHTTP2_MAX_TABLE_COUNT);
     222     1017009 :   tbl->num_ents--;
     223     1017009 :   GRPC_MDELEM_UNREF(first_ent);
     224     1017009 : }
     225             : 
     226     1047158 : void grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
     227             :   /* determine how many bytes of buffer this entry represents */
     228     2094316 :   size_t elem_bytes = GPR_SLICE_LENGTH(md->key->slice) +
     229     1047158 :                       GPR_SLICE_LENGTH(md->value->slice) +
     230             :                       GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
     231             : 
     232             :   /* we can't add elements bigger than the max table size */
     233     1047158 :   if (elem_bytes > tbl->max_bytes) {
     234             :     /* HPACK draft 10 section 4.4 states:
     235             :      * If the size of the new entry is less than or equal to the maximum
     236             :      * size, that entry is added to the table.  It is not an error to
     237             :      * attempt to add an entry that is larger than the maximum size; an
     238             :      * attempt to add an entry larger than the entire table causes
     239             :      * the table
     240             :      * to be emptied of all existing entries, and results in an
     241             :      * empty table.
     242             :      */
     243           0 :     while (tbl->num_ents) {
     244           0 :       evict1(tbl);
     245             :     }
     246     1047158 :     return;
     247             :   }
     248             : 
     249             :   /* evict entries to ensure no overflow */
     250     3111325 :   while (elem_bytes > (size_t)tbl->max_bytes - tbl->mem_used) {
     251     1017009 :     evict1(tbl);
     252             :   }
     253             : 
     254             :   /* copy the finalized entry in */
     255     1047158 :   tbl->ents[tbl->last_ent] = md;
     256             : 
     257             :   /* update accounting values */
     258     1047158 :   tbl->last_ent =
     259     1047158 :       (gpr_uint16)((tbl->last_ent + 1) % GRPC_CHTTP2_MAX_TABLE_COUNT);
     260     1047158 :   tbl->num_ents++;
     261     1047158 :   tbl->mem_used = (gpr_uint16)(tbl->mem_used + elem_bytes);
     262             : }
     263             : 
     264         117 : grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find(
     265             :     const grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
     266         117 :   grpc_chttp2_hptbl_find_result r = {0, 0};
     267             :   gpr_uint16 i;
     268             : 
     269             :   /* See if the string is in the static table */
     270        7089 :   for (i = 0; i < GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) {
     271        6975 :     grpc_mdelem *ent = tbl->static_ents[i];
     272        6975 :     if (md->key != ent->key) continue;
     273           8 :     r.index = (gpr_uint16)(i + 1);
     274           8 :     r.has_value = md->value == ent->value;
     275           8 :     if (r.has_value) return r;
     276             :   }
     277             : 
     278             :   /* Scan the dynamic table */
     279        5688 :   for (i = 0; i < tbl->num_ents; i++) {
     280        5681 :     gpr_uint16 idx =
     281        5681 :         (gpr_uint16)(tbl->num_ents - i + GRPC_CHTTP2_LAST_STATIC_ENTRY);
     282        5681 :     grpc_mdelem *ent =
     283        5681 :         tbl->ents[(tbl->first_ent + i) % GRPC_CHTTP2_MAX_TABLE_COUNT];
     284        5681 :     if (md->key != ent->key) continue;
     285        5563 :     r.index = idx;
     286        5563 :     r.has_value = md->value == ent->value;
     287        5563 :     if (r.has_value) return r;
     288             :   }
     289             : 
     290           7 :   return r;
     291             : }

Generated by: LCOV version 1.10