blob: f30f574d0635c9fc3e7ba445f4fc5edb789b6b1a [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
murgatroid99c3910ca2016-01-06 13:14:23 -08003 * Copyright 2015-2016, Google Inc.
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08004 * 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
Craig Tiller9d35a1f2015-11-02 14:16:12 -080034#include "src/core/transport/chttp2/hpack_encoder.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080035
36#include <assert.h>
37#include <string.h>
38
murgatroid99c3910ca2016-01-06 13:14:23 -080039/* This is here for grpc_is_binary_header
40 * TODO(murgatroid99): Remove this
41 */
42#include <grpc/grpc.h>
43
Craig Tiller027a74c2015-11-10 08:37:46 +000044#include <grpc/support/alloc.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080045#include <grpc/support/log.h>
46#include <grpc/support/useful.h>
Craig Tiller027a74c2015-11-10 08:37:46 +000047
ctiller33023c42014-12-12 16:28:33 -080048#include "src/core/transport/chttp2/bin_encoder.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080049#include "src/core/transport/chttp2/hpack_table.h"
50#include "src/core/transport/chttp2/timeout_encoding.h"
51#include "src/core/transport/chttp2/varint.h"
Craig Tillerb2b42612015-11-20 12:02:17 -080052#include "src/core/transport/static_metadata.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080053
Craig Tiller76f5d462015-04-17 14:58:12 -070054#define HASH_FRAGMENT_1(x) ((x)&255)
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080055#define HASH_FRAGMENT_2(x) ((x >> 8) & 255)
56#define HASH_FRAGMENT_3(x) ((x >> 16) & 255)
57#define HASH_FRAGMENT_4(x) ((x >> 24) & 255)
58
59/* if the probability of this item being seen again is < 1/x then don't add
60 it to the table */
61#define ONE_ON_ADD_PROBABILITY 128
62/* don't consider adding anything bigger than this to the hpack table */
63#define MAX_DECODER_SPACE_USAGE 512
64
Craig Tillera82950e2015-09-22 12:33:20 -070065typedef struct {
Craig Tiller9d35a1f2015-11-02 14:16:12 -080066 int is_first_frame;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080067 /* number of bytes in 'output' when we started the frame - used to calculate
68 frame length */
69 size_t output_length_at_start_of_frame;
70 /* index (in output) of the header for the current frame */
71 size_t header_idx;
David Garcia Quintasa14ce852015-08-20 10:36:24 -070072 /* have we seen a regular (non-colon-prefixed) header yet? */
Craig Tiller7536af02015-12-22 13:49:30 -080073 uint8_t seen_regular_header;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080074 /* output stream id */
Craig Tiller7536af02015-12-22 13:49:30 -080075 uint32_t stream_id;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080076 gpr_slice_buffer *output;
77} framer_state;
78
79/* fills p (which is expected to be 9 bytes long) with a data frame header */
Craig Tiller7536af02015-12-22 13:49:30 -080080static void fill_header(uint8_t *p, uint8_t type, uint32_t id, size_t len,
81 uint8_t flags) {
Craig Tillera82950e2015-09-22 12:33:20 -070082 GPR_ASSERT(len < 16777316);
Craig Tiller7536af02015-12-22 13:49:30 -080083 *p++ = (uint8_t)(len >> 16);
84 *p++ = (uint8_t)(len >> 8);
85 *p++ = (uint8_t)(len);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080086 *p++ = type;
87 *p++ = flags;
Craig Tiller7536af02015-12-22 13:49:30 -080088 *p++ = (uint8_t)(id >> 24);
89 *p++ = (uint8_t)(id >> 16);
90 *p++ = (uint8_t)(id >> 8);
91 *p++ = (uint8_t)(id);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080092}
93
94/* finish a frame - fill in the previously reserved header */
Craig Tillera82950e2015-09-22 12:33:20 -070095static void finish_frame(framer_state *st, int is_header_boundary,
96 int is_last_in_stream) {
Craig Tiller7536af02015-12-22 13:49:30 -080097 uint8_t type = 0xff;
Craig Tiller9d35a1f2015-11-02 14:16:12 -080098 type = st->is_first_frame ? GRPC_CHTTP2_FRAME_HEADER
99 : GRPC_CHTTP2_FRAME_CONTINUATION;
Craig Tillera82950e2015-09-22 12:33:20 -0700100 fill_header(
101 GPR_SLICE_START_PTR(st->output->slices[st->header_idx]), type,
102 st->stream_id, st->output->length - st->output_length_at_start_of_frame,
Craig Tiller7536af02015-12-22 13:49:30 -0800103 (uint8_t)((is_last_in_stream ? GRPC_CHTTP2_DATA_FLAG_END_STREAM : 0) |
104 (is_header_boundary ? GRPC_CHTTP2_DATA_FLAG_END_HEADERS : 0)));
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800105 st->is_first_frame = 0;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800106}
107
108/* begin a new frame: reserve off header space, remember how many bytes we'd
109 output before beginning */
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800110static void begin_frame(framer_state *st) {
Craig Tillera82950e2015-09-22 12:33:20 -0700111 st->header_idx =
112 gpr_slice_buffer_add_indexed(st->output, gpr_slice_malloc(9));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800113 st->output_length_at_start_of_frame = st->output->length;
114}
115
116/* make sure that the current frame is of the type desired, and has sufficient
117 space to add at least about_to_add bytes -- finishes the current frame if
118 needed */
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800119static void ensure_space(framer_state *st, size_t need_bytes) {
120 if (st->output->length - st->output_length_at_start_of_frame + need_bytes <=
121 GRPC_CHTTP2_MAX_PAYLOAD_LENGTH) {
Craig Tillera82950e2015-09-22 12:33:20 -0700122 return;
123 }
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800124 finish_frame(st, 0, 0);
125 begin_frame(st);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800126}
127
128/* increment a filter count, halve all counts if one element reaches max */
Craig Tiller7536af02015-12-22 13:49:30 -0800129static void inc_filter(uint8_t idx, uint32_t *sum, uint8_t *elems) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800130 elems[idx]++;
Craig Tillera82950e2015-09-22 12:33:20 -0700131 if (elems[idx] < 255) {
132 (*sum)++;
133 } else {
134 int i;
135 *sum = 0;
136 for (i = 0; i < GRPC_CHTTP2_HPACKC_NUM_FILTERS; i++) {
137 elems[i] /= 2;
138 (*sum) += elems[i];
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800139 }
Craig Tillera82950e2015-09-22 12:33:20 -0700140 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800141}
142
Craig Tillera82950e2015-09-22 12:33:20 -0700143static void add_header_data(framer_state *st, gpr_slice slice) {
144 size_t len = GPR_SLICE_LENGTH(slice);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800145 size_t remaining;
Craig Tillera82950e2015-09-22 12:33:20 -0700146 if (len == 0) return;
Craig Tillera82950e2015-09-22 12:33:20 -0700147 remaining = GRPC_CHTTP2_MAX_PAYLOAD_LENGTH +
148 st->output_length_at_start_of_frame - st->output->length;
149 if (len <= remaining) {
150 gpr_slice_buffer_add(st->output, slice);
151 } else {
152 gpr_slice_buffer_add(st->output, gpr_slice_split_head(&slice, remaining));
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800153 finish_frame(st, 0, 0);
154 begin_frame(st);
Craig Tillera82950e2015-09-22 12:33:20 -0700155 add_header_data(st, slice);
156 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800157}
158
Craig Tiller7536af02015-12-22 13:49:30 -0800159static uint8_t *add_tiny_header_data(framer_state *st, size_t len) {
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800160 ensure_space(st, len);
Craig Tillera82950e2015-09-22 12:33:20 -0700161 return gpr_slice_buffer_tiny_add(st->output, len);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800162}
163
Craig Tiller027a74c2015-11-10 08:37:46 +0000164static void evict_entry(grpc_chttp2_hpack_compressor *c) {
165 c->tail_remote_index++;
166 GPR_ASSERT(c->tail_remote_index > 0);
167 GPR_ASSERT(c->table_size >=
Craig Tiller3c53bb22015-11-10 14:24:36 +0000168 c->table_elem_size[c->tail_remote_index % c->cap_table_elems]);
Craig Tiller027a74c2015-11-10 08:37:46 +0000169 GPR_ASSERT(c->table_elems > 0);
Craig Tiller7536af02015-12-22 13:49:30 -0800170 c->table_size =
171 (uint16_t)(c->table_size -
172 c->table_elem_size[c->tail_remote_index % c->cap_table_elems]);
Craig Tiller027a74c2015-11-10 08:37:46 +0000173 c->table_elems--;
174}
175
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800176/* add an element to the decoder table */
177static void add_elem(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem) {
Craig Tiller7536af02015-12-22 13:49:30 -0800178 uint32_t key_hash = elem->key->hash;
179 uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash);
180 uint32_t new_index = c->tail_remote_index + c->table_elems + 1;
Craig Tillera82950e2015-09-22 12:33:20 -0700181 size_t elem_size = 32 + GPR_SLICE_LENGTH(elem->key->slice) +
182 GPR_SLICE_LENGTH(elem->value->slice);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800183
Craig Tillera82950e2015-09-22 12:33:20 -0700184 GPR_ASSERT(elem_size < 65536);
Craig Tiller6a6b36c2015-09-10 16:00:22 -0700185
Craig Tiller027a74c2015-11-10 08:37:46 +0000186 if (elem_size > c->max_table_size) {
187 while (c->table_size > 0) {
188 evict_entry(c);
189 }
190 return;
191 }
192
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800193 /* Reserve space for this element in the remote table: if this overflows
194 the current table, drop elements until it fits, matching the decompressor
195 algorithm */
Craig Tiller027a74c2015-11-10 08:37:46 +0000196 while (c->table_size + elem_size > c->max_table_size) {
197 evict_entry(c);
Craig Tillera82950e2015-09-22 12:33:20 -0700198 }
Craig Tiller027a74c2015-11-10 08:37:46 +0000199 GPR_ASSERT(c->table_elems < c->max_table_size);
Craig Tiller7536af02015-12-22 13:49:30 -0800200 c->table_elem_size[new_index % c->cap_table_elems] = (uint16_t)elem_size;
201 c->table_size = (uint16_t)(c->table_size + elem_size);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800202 c->table_elems++;
203
204 /* Store this element into {entries,indices}_elem */
Craig Tillera82950e2015-09-22 12:33:20 -0700205 if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == elem) {
206 /* already there: update with new index */
207 c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
Craig Tillera82950e2015-09-22 12:33:20 -0700208 } else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem) {
209 /* already there (cuckoo): update with new index */
210 c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
Craig Tillera82950e2015-09-22 12:33:20 -0700211 } else if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == NULL) {
212 /* not there, but a free element: add */
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800213 c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem);
Craig Tillera82950e2015-09-22 12:33:20 -0700214 c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
Craig Tillera82950e2015-09-22 12:33:20 -0700215 } else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == NULL) {
216 /* not there (cuckoo), but a free element: add */
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800217 c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem);
Craig Tillera82950e2015-09-22 12:33:20 -0700218 c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
Craig Tillera82950e2015-09-22 12:33:20 -0700219 } else if (c->indices_elems[HASH_FRAGMENT_2(elem_hash)] <
220 c->indices_elems[HASH_FRAGMENT_3(elem_hash)]) {
221 /* not there: replace oldest */
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800222 GRPC_MDELEM_UNREF(c->entries_elems[HASH_FRAGMENT_2(elem_hash)]);
223 c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem);
Craig Tillera82950e2015-09-22 12:33:20 -0700224 c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
225 } else {
226 /* not there: replace oldest */
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800227 GRPC_MDELEM_UNREF(c->entries_elems[HASH_FRAGMENT_3(elem_hash)]);
228 c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem);
Craig Tillera82950e2015-09-22 12:33:20 -0700229 c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
230 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800231
232 /* do exactly the same for the key (so we can find by that again too) */
233
Craig Tillera82950e2015-09-22 12:33:20 -0700234 if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == elem->key) {
235 c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index;
236 } else if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == elem->key) {
237 c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
238 } else if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == NULL) {
239 c->entries_keys[HASH_FRAGMENT_2(key_hash)] = GRPC_MDSTR_REF(elem->key);
240 c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index;
241 } else if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == NULL) {
242 c->entries_keys[HASH_FRAGMENT_3(key_hash)] = GRPC_MDSTR_REF(elem->key);
243 c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
244 } else if (c->indices_keys[HASH_FRAGMENT_2(key_hash)] <
245 c->indices_keys[HASH_FRAGMENT_3(key_hash)]) {
246 GRPC_MDSTR_UNREF(c->entries_keys[HASH_FRAGMENT_2(key_hash)]);
247 c->entries_keys[HASH_FRAGMENT_2(key_hash)] = GRPC_MDSTR_REF(elem->key);
248 c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index;
249 } else {
250 GRPC_MDSTR_UNREF(c->entries_keys[HASH_FRAGMENT_3(key_hash)]);
251 c->entries_keys[HASH_FRAGMENT_3(key_hash)] = GRPC_MDSTR_REF(elem->key);
252 c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
253 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800254}
255
Craig Tiller7536af02015-12-22 13:49:30 -0800256static void emit_indexed(grpc_chttp2_hpack_compressor *c, uint32_t elem_index,
Craig Tillera82950e2015-09-22 12:33:20 -0700257 framer_state *st) {
Craig Tiller7536af02015-12-22 13:49:30 -0800258 uint32_t len = GRPC_CHTTP2_VARINT_LENGTH(elem_index, 1);
Vijay Pai7b080ba2015-09-29 22:22:36 +0000259 GRPC_CHTTP2_WRITE_VARINT(elem_index, 1, 0x80, add_tiny_header_data(st, len),
Craig Tillerb7a59772015-10-01 08:01:58 -0700260 len);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800261}
262
Craig Tiller7536af02015-12-22 13:49:30 -0800263static gpr_slice get_wire_value(grpc_mdelem *elem, uint8_t *huffman_prefix) {
Craig Tillera82950e2015-09-22 12:33:20 -0700264 if (grpc_is_binary_header((const char *)GPR_SLICE_START_PTR(elem->key->slice),
265 GPR_SLICE_LENGTH(elem->key->slice))) {
266 *huffman_prefix = 0x80;
267 return grpc_mdstr_as_base64_encoded_and_huffman_compressed(elem->value);
268 }
ctiller33023c42014-12-12 16:28:33 -0800269 /* TODO(ctiller): opportunistically compress non-binary headers */
270 *huffman_prefix = 0x00;
271 return elem->value->slice;
272}
273
Craig Tillera82950e2015-09-22 12:33:20 -0700274static void emit_lithdr_incidx(grpc_chttp2_hpack_compressor *c,
Craig Tiller7536af02015-12-22 13:49:30 -0800275 uint32_t key_index, grpc_mdelem *elem,
Craig Tillera82950e2015-09-22 12:33:20 -0700276 framer_state *st) {
Craig Tiller7536af02015-12-22 13:49:30 -0800277 uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 2);
278 uint8_t huffman_prefix;
Craig Tillera82950e2015-09-22 12:33:20 -0700279 gpr_slice value_slice = get_wire_value(elem, &huffman_prefix);
280 size_t len_val = GPR_SLICE_LENGTH(value_slice);
Craig Tiller7536af02015-12-22 13:49:30 -0800281 uint32_t len_val_len;
282 GPR_ASSERT(len_val <= UINT32_MAX);
283 len_val_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)len_val, 1);
Craig Tillera82950e2015-09-22 12:33:20 -0700284 GRPC_CHTTP2_WRITE_VARINT(key_index, 2, 0x40,
285 add_tiny_header_data(st, len_pfx), len_pfx);
yang-gf8174ea2016-02-01 00:09:13 -0800286 GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, huffman_prefix,
Craig Tillera82950e2015-09-22 12:33:20 -0700287 add_tiny_header_data(st, len_val_len), len_val_len);
288 add_header_data(st, gpr_slice_ref(value_slice));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800289}
290
Craig Tillera82950e2015-09-22 12:33:20 -0700291static void emit_lithdr_noidx(grpc_chttp2_hpack_compressor *c,
Craig Tiller7536af02015-12-22 13:49:30 -0800292 uint32_t key_index, grpc_mdelem *elem,
Craig Tillera82950e2015-09-22 12:33:20 -0700293 framer_state *st) {
Craig Tiller7536af02015-12-22 13:49:30 -0800294 uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 4);
295 uint8_t huffman_prefix;
Craig Tillera82950e2015-09-22 12:33:20 -0700296 gpr_slice value_slice = get_wire_value(elem, &huffman_prefix);
297 size_t len_val = GPR_SLICE_LENGTH(value_slice);
Craig Tiller7536af02015-12-22 13:49:30 -0800298 uint32_t len_val_len;
299 GPR_ASSERT(len_val <= UINT32_MAX);
300 len_val_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)len_val, 1);
Craig Tillera82950e2015-09-22 12:33:20 -0700301 GRPC_CHTTP2_WRITE_VARINT(key_index, 4, 0x00,
302 add_tiny_header_data(st, len_pfx), len_pfx);
yang-gf8174ea2016-02-01 00:09:13 -0800303 GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, huffman_prefix,
Craig Tillera82950e2015-09-22 12:33:20 -0700304 add_tiny_header_data(st, len_val_len), len_val_len);
305 add_header_data(st, gpr_slice_ref(value_slice));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800306}
307
Craig Tillera82950e2015-09-22 12:33:20 -0700308static void emit_lithdr_incidx_v(grpc_chttp2_hpack_compressor *c,
309 grpc_mdelem *elem, framer_state *st) {
Craig Tiller7536af02015-12-22 13:49:30 -0800310 uint32_t len_key = (uint32_t)GPR_SLICE_LENGTH(elem->key->slice);
311 uint8_t huffman_prefix;
Craig Tillera82950e2015-09-22 12:33:20 -0700312 gpr_slice value_slice = get_wire_value(elem, &huffman_prefix);
Craig Tiller7536af02015-12-22 13:49:30 -0800313 uint32_t len_val = (uint32_t)GPR_SLICE_LENGTH(value_slice);
314 uint32_t len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1);
315 uint32_t len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
316 GPR_ASSERT(len_key <= UINT32_MAX);
317 GPR_ASSERT(GPR_SLICE_LENGTH(value_slice) <= UINT32_MAX);
Craig Tillera82950e2015-09-22 12:33:20 -0700318 *add_tiny_header_data(st, 1) = 0x40;
319 GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00,
320 add_tiny_header_data(st, len_key_len), len_key_len);
321 add_header_data(st, gpr_slice_ref(elem->key->slice));
322 GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix,
323 add_tiny_header_data(st, len_val_len), len_val_len);
324 add_header_data(st, gpr_slice_ref(value_slice));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800325}
326
Craig Tillera82950e2015-09-22 12:33:20 -0700327static void emit_lithdr_noidx_v(grpc_chttp2_hpack_compressor *c,
328 grpc_mdelem *elem, framer_state *st) {
Craig Tiller7536af02015-12-22 13:49:30 -0800329 uint32_t len_key = (uint32_t)GPR_SLICE_LENGTH(elem->key->slice);
330 uint8_t huffman_prefix;
Craig Tillera82950e2015-09-22 12:33:20 -0700331 gpr_slice value_slice = get_wire_value(elem, &huffman_prefix);
Craig Tiller7536af02015-12-22 13:49:30 -0800332 uint32_t len_val = (uint32_t)GPR_SLICE_LENGTH(value_slice);
333 uint32_t len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1);
334 uint32_t len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
335 GPR_ASSERT(len_key <= UINT32_MAX);
336 GPR_ASSERT(GPR_SLICE_LENGTH(value_slice) <= UINT32_MAX);
Craig Tillera82950e2015-09-22 12:33:20 -0700337 *add_tiny_header_data(st, 1) = 0x00;
338 GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00,
339 add_tiny_header_data(st, len_key_len), len_key_len);
340 add_header_data(st, gpr_slice_ref(elem->key->slice));
341 GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix,
342 add_tiny_header_data(st, len_val_len), len_val_len);
343 add_header_data(st, gpr_slice_ref(value_slice));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800344}
345
Craig Tiller3c53bb22015-11-10 14:24:36 +0000346static void emit_advertise_table_size_change(grpc_chttp2_hpack_compressor *c,
347 framer_state *st) {
Craig Tiller7536af02015-12-22 13:49:30 -0800348 uint32_t len = GRPC_CHTTP2_VARINT_LENGTH(c->max_table_size, 3);
Craig Tiller3c53bb22015-11-10 14:24:36 +0000349 GRPC_CHTTP2_WRITE_VARINT(c->max_table_size, 3, 0x20,
350 add_tiny_header_data(st, len), len);
Craig Tiller027a74c2015-11-10 08:37:46 +0000351 c->advertise_table_size_change = 0;
352}
353
Craig Tiller7536af02015-12-22 13:49:30 -0800354static uint32_t dynidx(grpc_chttp2_hpack_compressor *c, uint32_t elem_index) {
Craig Tillera82950e2015-09-22 12:33:20 -0700355 return 1 + GRPC_CHTTP2_LAST_STATIC_ENTRY + c->tail_remote_index +
Vijay Pai7b080ba2015-09-29 22:22:36 +0000356 c->table_elems - elem_index;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800357}
358
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800359/* encode an mdelem */
360static void hpack_enc(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem,
361 framer_state *st) {
Craig Tiller7536af02015-12-22 13:49:30 -0800362 uint32_t key_hash = elem->key->hash;
363 uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800364 size_t decoder_space_usage;
Craig Tiller7536af02015-12-22 13:49:30 -0800365 uint32_t indices_key;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800366 int should_add_elem;
367
Craig Tillera82950e2015-09-22 12:33:20 -0700368 GPR_ASSERT(GPR_SLICE_LENGTH(elem->key->slice) > 0);
369 if (GPR_SLICE_START_PTR(elem->key->slice)[0] != ':') { /* regular header */
370 st->seen_regular_header = 1;
Craig Tiller9d5e66a2015-12-10 14:01:13 -0800371 } else {
Craig Tiller620e9652015-12-14 12:02:50 -0800372 GPR_ASSERT(
373 st->seen_regular_header == 0 &&
374 "Reserved header (colon-prefixed) happening after regular ones.");
Craig Tillera82950e2015-09-22 12:33:20 -0700375 }
David Garcia Quintas26700862015-08-20 10:27:39 -0700376
Craig Tillera82950e2015-09-22 12:33:20 -0700377 inc_filter(HASH_FRAGMENT_1(elem_hash), &c->filter_elems_sum, c->filter_elems);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800378
379 /* is this elem currently in the decoders table? */
380
Craig Tillera82950e2015-09-22 12:33:20 -0700381 if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == elem &&
382 c->indices_elems[HASH_FRAGMENT_2(elem_hash)] > c->tail_remote_index) {
383 /* HIT: complete element (first cuckoo hash) */
384 emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_2(elem_hash)]),
385 st);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800386 return;
Craig Tillera82950e2015-09-22 12:33:20 -0700387 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800388
Craig Tillera82950e2015-09-22 12:33:20 -0700389 if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem &&
390 c->indices_elems[HASH_FRAGMENT_3(elem_hash)] > c->tail_remote_index) {
391 /* HIT: complete element (second cuckoo hash) */
392 emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_3(elem_hash)]),
393 st);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800394 return;
Craig Tillera82950e2015-09-22 12:33:20 -0700395 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800396
397 /* should this elem be in the table? */
Craig Tillera82950e2015-09-22 12:33:20 -0700398 decoder_space_usage = 32 + GPR_SLICE_LENGTH(elem->key->slice) +
399 GPR_SLICE_LENGTH(elem->value->slice);
400 should_add_elem = decoder_space_usage < MAX_DECODER_SPACE_USAGE &&
401 c->filter_elems[HASH_FRAGMENT_1(elem_hash)] >=
402 c->filter_elems_sum / ONE_ON_ADD_PROBABILITY;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800403
404 /* no hits for the elem... maybe there's a key? */
405
Craig Tillera82950e2015-09-22 12:33:20 -0700406 indices_key = c->indices_keys[HASH_FRAGMENT_2(key_hash)];
407 if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == elem->key &&
408 indices_key > c->tail_remote_index) {
409 /* HIT: key (first cuckoo hash) */
410 if (should_add_elem) {
411 emit_lithdr_incidx(c, dynidx(c, indices_key), elem, st);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800412 add_elem(c, elem);
413 return;
Craig Tillera82950e2015-09-22 12:33:20 -0700414 } else {
415 emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800416 return;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800417 }
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800418 GPR_UNREACHABLE_CODE(return );
Craig Tillera82950e2015-09-22 12:33:20 -0700419 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800420
Craig Tillera82950e2015-09-22 12:33:20 -0700421 indices_key = c->indices_keys[HASH_FRAGMENT_3(key_hash)];
422 if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == elem->key &&
423 indices_key > c->tail_remote_index) {
424 /* HIT: key (first cuckoo hash) */
425 if (should_add_elem) {
426 emit_lithdr_incidx(c, dynidx(c, indices_key), elem, st);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800427 add_elem(c, elem);
428 return;
Craig Tillera82950e2015-09-22 12:33:20 -0700429 } else {
430 emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800431 return;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800432 }
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800433 GPR_UNREACHABLE_CODE(return );
Craig Tillera82950e2015-09-22 12:33:20 -0700434 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800435
436 /* no elem, key in the table... fall back to literal emission */
437
Craig Tillera82950e2015-09-22 12:33:20 -0700438 if (should_add_elem) {
439 emit_lithdr_incidx_v(c, elem, st);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800440 add_elem(c, elem);
441 return;
Craig Tillera82950e2015-09-22 12:33:20 -0700442 } else {
443 emit_lithdr_noidx_v(c, elem, st);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800444 return;
Craig Tillera82950e2015-09-22 12:33:20 -0700445 }
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800446 GPR_UNREACHABLE_CODE(return );
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800447}
448
449#define STRLEN_LIT(x) (sizeof(x) - 1)
450#define TIMEOUT_KEY "grpc-timeout"
451
Craig Tillera82950e2015-09-22 12:33:20 -0700452static void deadline_enc(grpc_chttp2_hpack_compressor *c, gpr_timespec deadline,
453 framer_state *st) {
Craig Tillercce17ac2015-01-20 09:29:28 -0800454 char timeout_str[GRPC_CHTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE];
Craig Tillerfe0104a2015-04-14 09:19:12 -0700455 grpc_mdelem *mdelem;
Craig Tillera82950e2015-09-22 12:33:20 -0700456 grpc_chttp2_encode_timeout(
457 gpr_time_sub(deadline, gpr_now(deadline.clock_type)), timeout_str);
458 mdelem = grpc_mdelem_from_metadata_strings(
Craig Tillerb2b42612015-11-20 12:02:17 -0800459 GRPC_MDSTR_GRPC_TIMEOUT, grpc_mdstr_from_string(timeout_str));
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800460 hpack_enc(c, mdelem, st);
461 GRPC_MDELEM_UNREF(mdelem);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800462}
463
Craig Tiller7536af02015-12-22 13:49:30 -0800464static uint32_t elems_for_bytes(uint32_t bytes) { return (bytes + 31) / 32; }
Craig Tiller027a74c2015-11-10 08:37:46 +0000465
Craig Tillerb2b42612015-11-20 12:02:17 -0800466void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c) {
Craig Tillera82950e2015-09-22 12:33:20 -0700467 memset(c, 0, sizeof(*c));
Craig Tiller027a74c2015-11-10 08:37:46 +0000468 c->max_table_size = GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE;
Craig Tiller2a2a6ed2015-11-18 15:52:46 -0800469 c->cap_table_elems = elems_for_bytes(c->max_table_size);
470 c->max_table_elems = c->cap_table_elems;
Craig Tiller027a74c2015-11-10 08:37:46 +0000471 c->max_usable_size = GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE;
Craig Tiller3c53bb22015-11-10 14:24:36 +0000472 c->table_elem_size =
473 gpr_malloc(sizeof(*c->table_elem_size) * c->cap_table_elems);
474 memset(c->table_elem_size, 0,
475 sizeof(*c->table_elem_size) * c->cap_table_elems);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800476}
477
Craig Tillera82950e2015-09-22 12:33:20 -0700478void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800479 int i;
Craig Tillera82950e2015-09-22 12:33:20 -0700480 for (i = 0; i < GRPC_CHTTP2_HPACKC_NUM_VALUES; i++) {
481 if (c->entries_keys[i]) GRPC_MDSTR_UNREF(c->entries_keys[i]);
482 if (c->entries_elems[i]) GRPC_MDELEM_UNREF(c->entries_elems[i]);
483 }
Craig Tiller027a74c2015-11-10 08:37:46 +0000484 gpr_free(c->table_elem_size);
485}
486
Craig Tiller3c53bb22015-11-10 14:24:36 +0000487void grpc_chttp2_hpack_compressor_set_max_usable_size(
Craig Tiller7536af02015-12-22 13:49:30 -0800488 grpc_chttp2_hpack_compressor *c, uint32_t max_table_size) {
Craig Tiller027a74c2015-11-10 08:37:46 +0000489 c->max_usable_size = max_table_size;
Craig Tiller3c53bb22015-11-10 14:24:36 +0000490 grpc_chttp2_hpack_compressor_set_max_table_size(
491 c, GPR_MIN(c->max_table_size, max_table_size));
Craig Tiller027a74c2015-11-10 08:37:46 +0000492}
493
Craig Tiller7536af02015-12-22 13:49:30 -0800494static void rebuild_elems(grpc_chttp2_hpack_compressor *c, uint32_t new_cap) {
495 uint16_t *table_elem_size = gpr_malloc(sizeof(*table_elem_size) * new_cap);
496 uint32_t i;
Craig Tiller027a74c2015-11-10 08:37:46 +0000497
Craig Tiller2a2a6ed2015-11-18 15:52:46 -0800498 memset(table_elem_size, 0, sizeof(*table_elem_size) * new_cap);
499 GPR_ASSERT(c->table_elems <= new_cap);
500
501 for (i = 0; i < c->table_elems; i++) {
Craig Tiller7536af02015-12-22 13:49:30 -0800502 uint32_t ofs = c->tail_remote_index + i + 1;
Craig Tiller0927c702015-11-20 12:25:54 -0800503 table_elem_size[ofs % new_cap] =
504 c->table_elem_size[ofs % c->cap_table_elems];
Craig Tiller2a2a6ed2015-11-18 15:52:46 -0800505 }
506
507 c->cap_table_elems = new_cap;
508 gpr_free(c->table_elem_size);
509 c->table_elem_size = table_elem_size;
Craig Tiller027a74c2015-11-10 08:37:46 +0000510}
511
Craig Tiller3c53bb22015-11-10 14:24:36 +0000512void grpc_chttp2_hpack_compressor_set_max_table_size(
Craig Tiller7536af02015-12-22 13:49:30 -0800513 grpc_chttp2_hpack_compressor *c, uint32_t max_table_size) {
Craig Tiller027a74c2015-11-10 08:37:46 +0000514 max_table_size = GPR_MIN(max_table_size, c->max_usable_size);
515 if (max_table_size == c->max_table_size) {
516 return;
517 }
518 while (c->table_size > 0 && c->table_size > max_table_size) {
519 evict_entry(c);
520 }
521 c->max_table_size = max_table_size;
522 c->max_table_elems = elems_for_bytes(max_table_size);
523 if (c->max_table_elems > c->cap_table_elems) {
524 rebuild_elems(c, GPR_MAX(c->max_table_elems, 2 * c->cap_table_elems));
525 } else if (c->max_table_elems < c->cap_table_elems / 3) {
Craig Tiller7536af02015-12-22 13:49:30 -0800526 uint32_t new_cap = GPR_MAX(c->max_table_elems, 16);
Craig Tiller027a74c2015-11-10 08:37:46 +0000527 if (new_cap != c->cap_table_elems) {
528 rebuild_elems(c, new_cap);
529 }
530 }
531 c->advertise_table_size_change = 1;
532 gpr_log(GPR_DEBUG, "set max table size from encoder to %d", max_table_size);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800533}
534
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800535void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c,
Craig Tiller7536af02015-12-22 13:49:30 -0800536 uint32_t stream_id,
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800537 grpc_metadata_batch *metadata, int is_eof,
538 gpr_slice_buffer *outbuf) {
ctiller00297df2015-01-12 11:23:09 -0800539 framer_state st;
Craig Tiller9c1043e2015-04-16 16:20:38 -0700540 grpc_linked_mdelem *l;
Craig Tiller6a7626c2015-07-19 22:21:41 -0700541 gpr_timespec deadline;
ctiller00297df2015-01-12 11:23:09 -0800542
Craig Tillera82950e2015-09-22 12:33:20 -0700543 GPR_ASSERT(stream_id != 0);
ctiller00297df2015-01-12 11:23:09 -0800544
David Garcia Quintas26700862015-08-20 10:27:39 -0700545 st.seen_regular_header = 0;
ctiller00297df2015-01-12 11:23:09 -0800546 st.stream_id = stream_id;
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800547 st.output = outbuf;
548 st.is_first_frame = 1;
ctiller00297df2015-01-12 11:23:09 -0800549
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800550 /* Encode a metadata batch; store the returned values, representing
551 a metadata element that needs to be unreffed back into the metadata
552 slot. THIS MAY NOT BE THE SAME ELEMENT (if a decoder table slot got
553 updated). After this loop, we'll do a batch unref of elements. */
554 begin_frame(&st);
Craig Tiller027a74c2015-11-10 08:37:46 +0000555 if (c->advertise_table_size_change != 0) {
556 emit_advertise_table_size_change(c, &st);
557 }
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800558 grpc_metadata_batch_assert_ok(metadata);
559 for (l = metadata->list.head; l; l = l->next) {
560 hpack_enc(c, l->md, &st);
Craig Tillera82950e2015-09-22 12:33:20 -0700561 }
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800562 deadline = metadata->deadline;
563 if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) != 0) {
564 deadline_enc(c, deadline, &st);
Craig Tillera82950e2015-09-22 12:33:20 -0700565 }
Craig Tillerfe0104a2015-04-14 09:19:12 -0700566
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800567 finish_frame(&st, 1, is_eof);
Craig Tiller190d3602015-02-18 09:23:38 -0800568}