blob: 5ca31d6bc728d1eb20faaa765e6b7baef3c9b36d [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
Craig Tiller06059952015-02-18 08:34:56 -08003 * Copyright 2015, 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
34#include "src/core/transport/chttp2/stream_encoder.h"
35
36#include <assert.h>
37#include <string.h>
38
39#include <grpc/support/log.h>
40#include <grpc/support/useful.h>
ctiller33023c42014-12-12 16:28:33 -080041#include "src/core/transport/chttp2/bin_encoder.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080042#include "src/core/transport/chttp2/hpack_table.h"
43#include "src/core/transport/chttp2/timeout_encoding.h"
44#include "src/core/transport/chttp2/varint.h"
45
Craig Tiller76f5d462015-04-17 14:58:12 -070046#define HASH_FRAGMENT_1(x) ((x)&255)
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080047#define HASH_FRAGMENT_2(x) ((x >> 8) & 255)
48#define HASH_FRAGMENT_3(x) ((x >> 16) & 255)
49#define HASH_FRAGMENT_4(x) ((x >> 24) & 255)
50
51/* if the probability of this item being seen again is < 1/x then don't add
52 it to the table */
53#define ONE_ON_ADD_PROBABILITY 128
54/* don't consider adding anything bigger than this to the hpack table */
55#define MAX_DECODER_SPACE_USAGE 512
56
57/* what kind of frame our we encoding? */
58typedef enum { HEADER, DATA, NONE } frame_type;
59
60typedef struct {
61 frame_type cur_frame_type;
62 /* number of bytes in 'output' when we started the frame - used to calculate
63 frame length */
64 size_t output_length_at_start_of_frame;
65 /* index (in output) of the header for the current frame */
66 size_t header_idx;
67 /* was the last frame emitted a header? (if yes, we'll need a CONTINUATION */
68 gpr_uint8 last_was_header;
69 /* output stream id */
70 gpr_uint32 stream_id;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080071 gpr_slice_buffer *output;
72} framer_state;
73
74/* fills p (which is expected to be 9 bytes long) with a data frame header */
75static void fill_header(gpr_uint8 *p, gpr_uint8 type, gpr_uint32 id,
76 gpr_uint32 len, gpr_uint8 flags) {
77 *p++ = len >> 16;
78 *p++ = len >> 8;
79 *p++ = len;
80 *p++ = type;
81 *p++ = flags;
82 *p++ = id >> 24;
83 *p++ = id >> 16;
84 *p++ = id >> 8;
85 *p++ = id;
86}
87
88/* finish a frame - fill in the previously reserved header */
89static void finish_frame(framer_state *st, int is_header_boundary,
90 int is_last_in_stream) {
91 gpr_uint8 type = 0xff;
92 switch (st->cur_frame_type) {
93 case HEADER:
94 type = st->last_was_header ? GRPC_CHTTP2_FRAME_CONTINUATION
95 : GRPC_CHTTP2_FRAME_HEADER;
96 st->last_was_header = 1;
97 break;
98 case DATA:
99 type = GRPC_CHTTP2_FRAME_DATA;
100 st->last_was_header = 0;
101 is_header_boundary = 0;
102 break;
103 case NONE:
104 return;
105 }
106 fill_header(GPR_SLICE_START_PTR(st->output->slices[st->header_idx]), type,
107 st->stream_id,
108 st->output->length - st->output_length_at_start_of_frame,
109 (is_last_in_stream ? GRPC_CHTTP2_DATA_FLAG_END_STREAM : 0) |
110 (is_header_boundary ? GRPC_CHTTP2_DATA_FLAG_END_HEADERS : 0));
111 st->cur_frame_type = NONE;
112}
113
114/* begin a new frame: reserve off header space, remember how many bytes we'd
115 output before beginning */
116static void begin_frame(framer_state *st, frame_type type) {
117 GPR_ASSERT(type != NONE);
118 GPR_ASSERT(st->cur_frame_type == NONE);
119 st->cur_frame_type = type;
120 st->header_idx =
121 gpr_slice_buffer_add_indexed(st->output, gpr_slice_malloc(9));
122 st->output_length_at_start_of_frame = st->output->length;
123}
124
125/* make sure that the current frame is of the type desired, and has sufficient
126 space to add at least about_to_add bytes -- finishes the current frame if
127 needed */
128static void ensure_frame_type(framer_state *st, frame_type type,
129 int need_bytes) {
130 if (st->cur_frame_type == type &&
131 st->output->length - st->output_length_at_start_of_frame + need_bytes <=
132 GRPC_CHTTP2_MAX_PAYLOAD_LENGTH) {
133 return;
134 }
135 finish_frame(st, type != HEADER, 0);
136 begin_frame(st, type);
137}
138
139/* increment a filter count, halve all counts if one element reaches max */
140static void inc_filter(gpr_uint8 idx, gpr_uint32 *sum, gpr_uint8 *elems) {
141 elems[idx]++;
142 if (elems[idx] < 255) {
143 (*sum)++;
144 } else {
145 int i;
146 *sum = 0;
147 for (i = 0; i < GRPC_CHTTP2_HPACKC_NUM_FILTERS; i++) {
148 elems[i] /= 2;
149 (*sum) += elems[i];
150 }
151 }
152}
153
154static void add_header_data(framer_state *st, gpr_slice slice) {
155 size_t len = GPR_SLICE_LENGTH(slice);
156 size_t remaining;
157 if (len == 0) return;
158 ensure_frame_type(st, HEADER, 1);
159 remaining = GRPC_CHTTP2_MAX_PAYLOAD_LENGTH +
160 st->output_length_at_start_of_frame - st->output->length;
161 if (len <= remaining) {
162 gpr_slice_buffer_add(st->output, slice);
163 } else {
164 gpr_slice_buffer_add(st->output, gpr_slice_split_head(&slice, remaining));
165 add_header_data(st, slice);
166 }
167}
168
169static gpr_uint8 *add_tiny_header_data(framer_state *st, int len) {
170 ensure_frame_type(st, HEADER, len);
171 return gpr_slice_buffer_tiny_add(st->output, len);
172}
173
Craig Tillerfe0104a2015-04-14 09:19:12 -0700174/* add an element to the decoder table: returns metadata element to unref */
175static grpc_mdelem *add_elem(grpc_chttp2_hpack_compressor *c,
176 grpc_mdelem *elem) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800177 gpr_uint32 key_hash = elem->key->hash;
ctillerfb93d192014-12-15 10:40:05 -0800178 gpr_uint32 elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800179 gpr_uint32 new_index = c->tail_remote_index + c->table_elems + 1;
180 gpr_uint32 elem_size = 32 + GPR_SLICE_LENGTH(elem->key->slice) +
181 GPR_SLICE_LENGTH(elem->value->slice);
Craig Tiller3de5aaf2015-04-14 21:39:08 -0700182 grpc_mdelem *elem_to_unref;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800183
184 /* Reserve space for this element in the remote table: if this overflows
185 the current table, drop elements until it fits, matching the decompressor
186 algorithm */
187 /* TODO(ctiller): constant */
188 while (c->table_size + elem_size > 4096) {
189 c->tail_remote_index++;
190 GPR_ASSERT(c->tail_remote_index > 0);
191 GPR_ASSERT(c->table_size >=
192 c->table_elem_size[c->tail_remote_index %
193 GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS]);
194 GPR_ASSERT(c->table_elems > 0);
195 c->table_size -= c->table_elem_size[c->tail_remote_index %
196 GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS];
197 c->table_elems--;
198 }
199 GPR_ASSERT(c->table_elems < GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS);
200 c->table_elem_size[new_index % GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS] =
201 elem_size;
202 c->table_size += elem_size;
203 c->table_elems++;
204
205 /* Store this element into {entries,indices}_elem */
206 if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == elem) {
207 /* already there: update with new index */
208 c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
Craig Tillerfe0104a2015-04-14 09:19:12 -0700209 elem_to_unref = elem;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800210 } else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem) {
211 /* already there (cuckoo): update with new index */
212 c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
Craig Tillerfe0104a2015-04-14 09:19:12 -0700213 elem_to_unref = elem;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800214 } else if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == NULL) {
215 /* not there, but a free element: add */
216 c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = elem;
217 c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
Craig Tillerfe0104a2015-04-14 09:19:12 -0700218 elem_to_unref = NULL;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800219 } else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == NULL) {
220 /* not there (cuckoo), but a free element: add */
221 c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = elem;
222 c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
Craig Tillerfe0104a2015-04-14 09:19:12 -0700223 elem_to_unref = NULL;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800224 } else if (c->indices_elems[HASH_FRAGMENT_2(elem_hash)] <
225 c->indices_elems[HASH_FRAGMENT_3(elem_hash)]) {
226 /* not there: replace oldest */
Craig Tillerfe0104a2015-04-14 09:19:12 -0700227 elem_to_unref = c->entries_elems[HASH_FRAGMENT_2(elem_hash)];
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800228 c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = elem;
229 c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800230 } else {
231 /* not there: replace oldest */
Craig Tillerfe0104a2015-04-14 09:19:12 -0700232 elem_to_unref = c->entries_elems[HASH_FRAGMENT_3(elem_hash)];
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800233 c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = elem;
234 c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800235 }
236
237 /* do exactly the same for the key (so we can find by that again too) */
238
239 if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == elem->key) {
240 c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index;
241 } else if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == elem->key) {
242 c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
243 } else if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == NULL) {
244 c->entries_keys[HASH_FRAGMENT_2(key_hash)] = grpc_mdstr_ref(elem->key);
245 c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index;
246 } else if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == NULL) {
247 c->entries_keys[HASH_FRAGMENT_3(key_hash)] = grpc_mdstr_ref(elem->key);
248 c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
249 } else if (c->indices_keys[HASH_FRAGMENT_2(key_hash)] <
250 c->indices_keys[HASH_FRAGMENT_3(key_hash)]) {
251 grpc_mdstr_unref(c->entries_keys[HASH_FRAGMENT_2(key_hash)]);
252 c->entries_keys[HASH_FRAGMENT_2(key_hash)] = grpc_mdstr_ref(elem->key);
253 c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index;
254 } else {
255 grpc_mdstr_unref(c->entries_keys[HASH_FRAGMENT_3(key_hash)]);
256 c->entries_keys[HASH_FRAGMENT_3(key_hash)] = grpc_mdstr_ref(elem->key);
257 c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
258 }
259
Craig Tillerfe0104a2015-04-14 09:19:12 -0700260 return elem_to_unref;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800261}
262
263static void emit_indexed(grpc_chttp2_hpack_compressor *c, gpr_uint32 index,
264 framer_state *st) {
265 int len = GRPC_CHTTP2_VARINT_LENGTH(index, 1);
266 GRPC_CHTTP2_WRITE_VARINT(index, 1, 0x80, add_tiny_header_data(st, len), len);
267}
268
ctiller33023c42014-12-12 16:28:33 -0800269static gpr_slice get_wire_value(grpc_mdelem *elem, gpr_uint8 *huffman_prefix) {
270 if (grpc_is_binary_header((const char *)GPR_SLICE_START_PTR(elem->key->slice),
271 GPR_SLICE_LENGTH(elem->key->slice))) {
272 *huffman_prefix = 0x80;
273 return grpc_mdstr_as_base64_encoded_and_huffman_compressed(elem->value);
274 }
275 /* TODO(ctiller): opportunistically compress non-binary headers */
276 *huffman_prefix = 0x00;
277 return elem->value->slice;
278}
279
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800280static void emit_lithdr_incidx(grpc_chttp2_hpack_compressor *c,
ctiller33023c42014-12-12 16:28:33 -0800281 gpr_uint32 key_index, grpc_mdelem *elem,
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800282 framer_state *st) {
283 int len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 2);
ctiller33023c42014-12-12 16:28:33 -0800284 gpr_uint8 huffman_prefix;
285 gpr_slice value_slice = get_wire_value(elem, &huffman_prefix);
286 int len_val = GPR_SLICE_LENGTH(value_slice);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800287 int len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
288 GRPC_CHTTP2_WRITE_VARINT(key_index, 2, 0x40,
289 add_tiny_header_data(st, len_pfx), len_pfx);
290 GRPC_CHTTP2_WRITE_VARINT(len_val, 1, 0x00,
291 add_tiny_header_data(st, len_val_len), len_val_len);
ctiller33023c42014-12-12 16:28:33 -0800292 add_header_data(st, gpr_slice_ref(value_slice));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800293}
294
295static void emit_lithdr_noidx(grpc_chttp2_hpack_compressor *c,
ctiller33023c42014-12-12 16:28:33 -0800296 gpr_uint32 key_index, grpc_mdelem *elem,
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800297 framer_state *st) {
298 int len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 4);
ctiller33023c42014-12-12 16:28:33 -0800299 gpr_uint8 huffman_prefix;
300 gpr_slice value_slice = get_wire_value(elem, &huffman_prefix);
301 int len_val = GPR_SLICE_LENGTH(value_slice);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800302 int len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
303 GRPC_CHTTP2_WRITE_VARINT(key_index, 4, 0x00,
304 add_tiny_header_data(st, len_pfx), len_pfx);
305 GRPC_CHTTP2_WRITE_VARINT(len_val, 1, 0x00,
306 add_tiny_header_data(st, len_val_len), len_val_len);
ctiller33023c42014-12-12 16:28:33 -0800307 add_header_data(st, gpr_slice_ref(value_slice));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800308}
309
310static void emit_lithdr_incidx_v(grpc_chttp2_hpack_compressor *c,
ctiller33023c42014-12-12 16:28:33 -0800311 grpc_mdelem *elem, framer_state *st) {
312 int len_key = GPR_SLICE_LENGTH(elem->key->slice);
313 gpr_uint8 huffman_prefix;
314 gpr_slice value_slice = get_wire_value(elem, &huffman_prefix);
315 int len_val = GPR_SLICE_LENGTH(value_slice);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800316 int len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1);
317 int len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
318 *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);
ctiller33023c42014-12-12 16:28:33 -0800321 add_header_data(st, gpr_slice_ref(elem->key->slice));
322 GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix,
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800323 add_tiny_header_data(st, len_val_len), len_val_len);
ctiller33023c42014-12-12 16:28:33 -0800324 add_header_data(st, gpr_slice_ref(value_slice));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800325}
326
327static void emit_lithdr_noidx_v(grpc_chttp2_hpack_compressor *c,
ctiller33023c42014-12-12 16:28:33 -0800328 grpc_mdelem *elem, framer_state *st) {
329 int len_key = GPR_SLICE_LENGTH(elem->key->slice);
330 gpr_uint8 huffman_prefix;
331 gpr_slice value_slice = get_wire_value(elem, &huffman_prefix);
332 int len_val = GPR_SLICE_LENGTH(value_slice);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800333 int len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1);
334 int len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
335 *add_tiny_header_data(st, 1) = 0x00;
336 GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00,
337 add_tiny_header_data(st, len_key_len), len_key_len);
ctiller33023c42014-12-12 16:28:33 -0800338 add_header_data(st, gpr_slice_ref(elem->key->slice));
339 GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix,
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800340 add_tiny_header_data(st, len_val_len), len_val_len);
ctiller33023c42014-12-12 16:28:33 -0800341 add_header_data(st, gpr_slice_ref(value_slice));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800342}
343
344static gpr_uint32 dynidx(grpc_chttp2_hpack_compressor *c, gpr_uint32 index) {
345 return 1 + GRPC_CHTTP2_LAST_STATIC_ENTRY + c->tail_remote_index +
346 c->table_elems - index;
347}
348
Craig Tillerfe0104a2015-04-14 09:19:12 -0700349/* encode an mdelem; returns metadata element to unref */
350static grpc_mdelem *hpack_enc(grpc_chttp2_hpack_compressor *c,
351 grpc_mdelem *elem, framer_state *st) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800352 gpr_uint32 key_hash = elem->key->hash;
ctillerfb93d192014-12-15 10:40:05 -0800353 gpr_uint32 elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800354 size_t decoder_space_usage;
ctiller33023c42014-12-12 16:28:33 -0800355 gpr_uint32 indices_key;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800356 int should_add_elem;
357
358 inc_filter(HASH_FRAGMENT_1(elem_hash), &c->filter_elems_sum, c->filter_elems);
359
360 /* is this elem currently in the decoders table? */
361
362 if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == elem &&
363 c->indices_elems[HASH_FRAGMENT_2(elem_hash)] > c->tail_remote_index) {
364 /* HIT: complete element (first cuckoo hash) */
365 emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_2(elem_hash)]),
366 st);
Craig Tillerfe0104a2015-04-14 09:19:12 -0700367 return elem;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800368 }
369
370 if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem &&
371 c->indices_elems[HASH_FRAGMENT_3(elem_hash)] > c->tail_remote_index) {
372 /* HIT: complete element (second cuckoo hash) */
373 emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_3(elem_hash)]),
374 st);
Craig Tillerfe0104a2015-04-14 09:19:12 -0700375 return elem;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800376 }
377
378 /* should this elem be in the table? */
379 decoder_space_usage = 32 + GPR_SLICE_LENGTH(elem->key->slice) +
380 GPR_SLICE_LENGTH(elem->value->slice);
381 should_add_elem = decoder_space_usage < MAX_DECODER_SPACE_USAGE &&
382 c->filter_elems[HASH_FRAGMENT_1(elem_hash)] >=
383 c->filter_elems_sum / ONE_ON_ADD_PROBABILITY;
384
385 /* no hits for the elem... maybe there's a key? */
386
ctiller33023c42014-12-12 16:28:33 -0800387 indices_key = c->indices_keys[HASH_FRAGMENT_2(key_hash)];
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800388 if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == elem->key &&
ctiller33023c42014-12-12 16:28:33 -0800389 indices_key > c->tail_remote_index) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800390 /* HIT: key (first cuckoo hash) */
391 if (should_add_elem) {
ctiller33023c42014-12-12 16:28:33 -0800392 emit_lithdr_incidx(c, dynidx(c, indices_key), elem, st);
Craig Tillerfe0104a2015-04-14 09:19:12 -0700393 return add_elem(c, elem);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800394 } else {
ctiller33023c42014-12-12 16:28:33 -0800395 emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st);
Craig Tillerfe0104a2015-04-14 09:19:12 -0700396 return elem;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800397 }
Craig Tillerfe0104a2015-04-14 09:19:12 -0700398 abort();
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800399 }
400
ctiller33023c42014-12-12 16:28:33 -0800401 indices_key = c->indices_keys[HASH_FRAGMENT_3(key_hash)];
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800402 if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == elem->key &&
ctiller33023c42014-12-12 16:28:33 -0800403 indices_key > c->tail_remote_index) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800404 /* HIT: key (first cuckoo hash) */
405 if (should_add_elem) {
ctiller33023c42014-12-12 16:28:33 -0800406 emit_lithdr_incidx(c, dynidx(c, indices_key), elem, st);
Craig Tillerfe0104a2015-04-14 09:19:12 -0700407 return add_elem(c, elem);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800408 } else {
ctiller33023c42014-12-12 16:28:33 -0800409 emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st);
Craig Tillerfe0104a2015-04-14 09:19:12 -0700410 return elem;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800411 }
Craig Tillerfe0104a2015-04-14 09:19:12 -0700412 abort();
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800413 }
414
415 /* no elem, key in the table... fall back to literal emission */
416
417 if (should_add_elem) {
ctiller33023c42014-12-12 16:28:33 -0800418 emit_lithdr_incidx_v(c, elem, st);
Craig Tillerfe0104a2015-04-14 09:19:12 -0700419 return add_elem(c, elem);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800420 } else {
ctiller33023c42014-12-12 16:28:33 -0800421 emit_lithdr_noidx_v(c, elem, st);
Craig Tillerfe0104a2015-04-14 09:19:12 -0700422 return elem;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800423 }
Craig Tillerfe0104a2015-04-14 09:19:12 -0700424 abort();
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800425}
426
427#define STRLEN_LIT(x) (sizeof(x) - 1)
428#define TIMEOUT_KEY "grpc-timeout"
429
430static void deadline_enc(grpc_chttp2_hpack_compressor *c, gpr_timespec deadline,
431 framer_state *st) {
Craig Tillercce17ac2015-01-20 09:29:28 -0800432 char timeout_str[GRPC_CHTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE];
Craig Tillerfe0104a2015-04-14 09:19:12 -0700433 grpc_mdelem *mdelem;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800434 grpc_chttp2_encode_timeout(gpr_time_sub(deadline, gpr_now()), timeout_str);
Craig Tillerfe0104a2015-04-14 09:19:12 -0700435 mdelem = grpc_mdelem_from_metadata_strings(
436 c->mdctx, grpc_mdstr_ref(c->timeout_key_str),
437 grpc_mdstr_from_string(c->mdctx, timeout_str));
438 mdelem = hpack_enc(c, mdelem, st);
439 if (mdelem) grpc_mdelem_unref(mdelem);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800440}
441
442gpr_slice grpc_chttp2_data_frame_create_empty_close(gpr_uint32 id) {
443 gpr_slice slice = gpr_slice_malloc(9);
444 fill_header(GPR_SLICE_START_PTR(slice), GRPC_CHTTP2_FRAME_DATA, id, 0, 1);
445 return slice;
446}
447
448void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c,
449 grpc_mdctx *ctx) {
450 memset(c, 0, sizeof(*c));
451 c->mdctx = ctx;
452 c->timeout_key_str = grpc_mdstr_from_string(ctx, "grpc-timeout");
453}
454
455void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c) {
456 int i;
457 for (i = 0; i < GRPC_CHTTP2_HPACKC_NUM_VALUES; i++) {
458 if (c->entries_keys[i]) grpc_mdstr_unref(c->entries_keys[i]);
459 if (c->entries_elems[i]) grpc_mdelem_unref(c->entries_elems[i]);
460 }
461 grpc_mdstr_unref(c->timeout_key_str);
462}
463
ctiller00297df2015-01-12 11:23:09 -0800464gpr_uint32 grpc_chttp2_preencode(grpc_stream_op *inops, size_t *inops_count,
465 gpr_uint32 max_flow_controlled_bytes,
466 grpc_stream_op_buffer *outops) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800467 gpr_slice slice;
468 grpc_stream_op *op;
469 gpr_uint32 max_take_size;
ctiller00297df2015-01-12 11:23:09 -0800470 gpr_uint32 flow_controlled_bytes_taken = 0;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800471 gpr_uint32 curop = 0;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800472 gpr_uint8 *p;
473
ctiller00297df2015-01-12 11:23:09 -0800474 while (curop < *inops_count) {
475 GPR_ASSERT(flow_controlled_bytes_taken <= max_flow_controlled_bytes);
476 op = &inops[curop];
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800477 switch (op->type) {
478 case GRPC_NO_OP:
ctiller00297df2015-01-12 11:23:09 -0800479 /* skip */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800480 curop++;
481 break;
ctiller00297df2015-01-12 11:23:09 -0800482 case GRPC_OP_METADATA:
Craig Tiller8b282cb2015-04-17 14:57:44 -0700483 grpc_metadata_batch_assert_ok(&op->data.metadata);
484 case GRPC_OP_FLOW_CTL_CB:
ctiller00297df2015-01-12 11:23:09 -0800485 /* these just get copied as they don't impact the number of flow
486 controlled bytes */
487 grpc_sopb_append(outops, op, 1);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800488 curop++;
489 break;
490 case GRPC_OP_BEGIN_MESSAGE:
491 /* begin op: for now we just convert the op to a slice and fall
492 through - this lets us reuse the slice framing code below */
493 slice = gpr_slice_malloc(5);
494 p = GPR_SLICE_START_PTR(slice);
495 p[0] = 0;
496 p[1] = op->data.begin_message.length >> 24;
497 p[2] = op->data.begin_message.length >> 16;
498 p[3] = op->data.begin_message.length >> 8;
499 p[4] = op->data.begin_message.length;
500 op->type = GRPC_OP_SLICE;
501 op->data.slice = slice;
502 /* fallthrough */
503 case GRPC_OP_SLICE:
504 slice = op->data.slice;
505 if (!GPR_SLICE_LENGTH(slice)) {
ctiller00297df2015-01-12 11:23:09 -0800506 /* skip zero length slices */
507 gpr_slice_unref(slice);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800508 curop++;
509 break;
510 }
ctiller00297df2015-01-12 11:23:09 -0800511 max_take_size = max_flow_controlled_bytes - flow_controlled_bytes_taken;
512 if (max_take_size == 0) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800513 goto exit_loop;
514 }
ctiller00297df2015-01-12 11:23:09 -0800515 if (GPR_SLICE_LENGTH(slice) > max_take_size) {
516 slice = gpr_slice_split_head(&op->data.slice, max_take_size);
517 grpc_sopb_add_slice(outops, slice);
518 } else {
519 /* consume this op immediately */
520 grpc_sopb_append(outops, op, 1);
521 curop++;
522 }
523 flow_controlled_bytes_taken += GPR_SLICE_LENGTH(slice);
524 break;
525 }
526 }
527exit_loop:
528 *inops_count -= curop;
529 memmove(inops, inops + curop, *inops_count * sizeof(grpc_stream_op));
530
Craig Tiller8b282cb2015-04-17 14:57:44 -0700531 for (curop = 0; curop < *inops_count; curop++) {
532 if (inops[curop].type == GRPC_OP_METADATA) {
533 grpc_metadata_batch_assert_ok(&inops[curop].data.metadata);
534 }
535 }
536
ctiller00297df2015-01-12 11:23:09 -0800537 return flow_controlled_bytes_taken;
538}
539
540void grpc_chttp2_encode(grpc_stream_op *ops, size_t ops_count, int eof,
541 gpr_uint32 stream_id,
542 grpc_chttp2_hpack_compressor *compressor,
543 gpr_slice_buffer *output) {
544 framer_state st;
545 gpr_slice slice;
546 grpc_stream_op *op;
547 gpr_uint32 max_take_size;
548 gpr_uint32 curop = 0;
Craig Tillerfe0104a2015-04-14 09:19:12 -0700549 gpr_uint32 unref_op;
550 grpc_mdctx *mdctx = compressor->mdctx;
Craig Tiller9c1043e2015-04-16 16:20:38 -0700551 grpc_linked_mdelem *l;
Craig Tillerfe0104a2015-04-14 09:19:12 -0700552 int need_unref = 0;
ctiller00297df2015-01-12 11:23:09 -0800553
554 GPR_ASSERT(stream_id != 0);
555
556 st.cur_frame_type = NONE;
557 st.last_was_header = 0;
558 st.stream_id = stream_id;
559 st.output = output;
560
561 while (curop < ops_count) {
562 op = &ops[curop];
563 switch (op->type) {
564 case GRPC_NO_OP:
565 case GRPC_OP_BEGIN_MESSAGE:
566 gpr_log(
567 GPR_ERROR,
568 "These stream ops should be filtered out by grpc_chttp2_preencode");
569 abort();
570 case GRPC_OP_FLOW_CTL_CB:
571 op->data.flow_ctl_cb.cb(op->data.flow_ctl_cb.arg, GRPC_OP_OK);
572 curop++;
573 break;
574 case GRPC_OP_METADATA:
Craig Tiller9c1043e2015-04-16 16:20:38 -0700575 /* Encode a metadata batch; store the returned values, representing
Craig Tillera7271352015-04-14 10:43:37 -0700576 a metadata element that needs to be unreffed back into the metadata
577 slot. THIS MAY NOT BE THE SAME ELEMENT (if a decoder table slot got
578 updated). After this loop, we'll do a batch unref of elements. */
Craig Tiller9c1043e2015-04-16 16:20:38 -0700579 need_unref |= op->data.metadata.garbage.head != NULL;
580 grpc_metadata_batch_assert_ok(&op->data.metadata);
581 for (l = op->data.metadata.list.head; l; l = l->next) {
582 l->md = hpack_enc(compressor, l->md, &st);
583 need_unref |= l->md != NULL;
584 }
585 if (gpr_time_cmp(op->data.metadata.deadline, gpr_inf_future) != 0) {
586 deadline_enc(compressor, op->data.metadata.deadline, &st);
587 }
ctiller00297df2015-01-12 11:23:09 -0800588 ensure_frame_type(&st, HEADER, 0);
589 finish_frame(&st, 1, 0);
590 st.last_was_header = 0; /* force a new header frame */
591 curop++;
592 break;
593 case GRPC_OP_SLICE:
594 slice = op->data.slice;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800595 if (st.cur_frame_type == DATA &&
596 st.output->length - st.output_length_at_start_of_frame ==
597 GRPC_CHTTP2_MAX_PAYLOAD_LENGTH) {
598 finish_frame(&st, 0, 0);
599 }
600 ensure_frame_type(&st, DATA, 1);
ctiller00297df2015-01-12 11:23:09 -0800601 max_take_size = GRPC_CHTTP2_MAX_PAYLOAD_LENGTH +
602 st.output_length_at_start_of_frame - st.output->length;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800603 if (GPR_SLICE_LENGTH(slice) > max_take_size) {
604 slice = gpr_slice_split_head(&op->data.slice, max_take_size);
605 } else {
606 /* consume this op immediately */
607 curop++;
608 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800609 gpr_slice_buffer_add(output, slice);
610 break;
611 }
612 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800613 if (eof && st.cur_frame_type == NONE) {
614 begin_frame(&st, DATA);
615 }
ctiller00297df2015-01-12 11:23:09 -0800616 finish_frame(&st, 1, eof);
Craig Tillerfe0104a2015-04-14 09:19:12 -0700617
618 if (need_unref) {
619 grpc_mdctx_lock(mdctx);
620 for (unref_op = 0; unref_op < curop; unref_op++) {
621 op = &ops[unref_op];
622 if (op->type != GRPC_OP_METADATA) continue;
Craig Tiller9c1043e2015-04-16 16:20:38 -0700623 for (l = op->data.metadata.list.head; l; l = l->next) {
624 if (l->md) grpc_mdctx_locked_mdelem_unref(mdctx, l->md);
625 }
626 for (l = op->data.metadata.garbage.head; l; l = l->next) {
627 grpc_mdctx_locked_mdelem_unref(mdctx, l->md);
628 }
Craig Tillerfe0104a2015-04-14 09:19:12 -0700629 }
630 grpc_mdctx_unlock(mdctx);
631 }
Craig Tiller190d3602015-02-18 09:23:38 -0800632}