mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-11 16:29:36 +00:00
MEDIUM: hpack: make it possible to encode any static header name
We used to have a series of well-known header fields that were looked up, but most of them were not. The current model couldn't scale with the addition of the new headers or pseudo-headers required to process requests, resulting in their encoding being hard-coded in the caller. This patch implements a quick lookup which retrieves any header from the static table. A binary stream is made of header names prefixed by lengths and indexes. These header names are sorted by length, then by frequency, then by direction (preference for response), then by name, the the lowest index of each is stored only in case of multiple entries. A parallel length index table provides the index of the first header for a given string. This allows to focus on the first few values matching the same length. Everything was made to limit the cache footprint. Interestingly, the lookup ends up being slightly faster than the previous one, while covering the 54 distinct headers instead of only 10. A test with a curl request and a basic response showed that the request size has dropped from 85 to 56 bytes and that the response size has dropped from 197 to 170 bytes, thus we can now shave roughly 25-30 bytes per message.
This commit is contained in:
parent
841bc7d471
commit
2c3139489c
156
src/hpack-enc.c
156
src/hpack-enc.c
@ -36,6 +36,110 @@
|
||||
|
||||
#include <types/global.h>
|
||||
|
||||
/*
|
||||
* HPACK encoding: these tables were generated using gen-enc.c
|
||||
*/
|
||||
|
||||
/* encoding of stream of compressed headers. This stream is composed of series
|
||||
* of <len:8b> <index:8b> <name:<len>*8b>.
|
||||
*/
|
||||
const char hpack_enc_stream[666] = {
|
||||
/* 0: */ 0x03, 0x15, 0x61, 0x67, 0x65, 0x03, 0x3c, 0x76,
|
||||
/* 8: */ 0x69, 0x61, 0x04, 0x21, 0x64, 0x61, 0x74, 0x65,
|
||||
/* 16: */ 0x04, 0x26, 0x68, 0x6f, 0x73, 0x74, 0x04, 0x22,
|
||||
/* 24: */ 0x65, 0x74, 0x61, 0x67, 0x04, 0x25, 0x66, 0x72,
|
||||
/* 32: */ 0x6f, 0x6d, 0x04, 0x2d, 0x6c, 0x69, 0x6e, 0x6b,
|
||||
/* 40: */ 0x04, 0x3b, 0x76, 0x61, 0x72, 0x79, 0x05, 0x04,
|
||||
/* 48: */ 0x3a, 0x70, 0x61, 0x74, 0x68, 0x05, 0x16, 0x61,
|
||||
/* 56: */ 0x6c, 0x6c, 0x6f, 0x77, 0x05, 0x32, 0x72, 0x61,
|
||||
/* 64: */ 0x6e, 0x67, 0x65, 0x06, 0x13, 0x61, 0x63, 0x63,
|
||||
/* 72: */ 0x65, 0x70, 0x74, 0x06, 0x36, 0x73, 0x65, 0x72,
|
||||
/* 80: */ 0x76, 0x65, 0x72, 0x06, 0x20, 0x63, 0x6f, 0x6f,
|
||||
/* 88: */ 0x6b, 0x69, 0x65, 0x06, 0x23, 0x65, 0x78, 0x70,
|
||||
/* 96: */ 0x65, 0x63, 0x74, 0x07, 0x33, 0x72, 0x65, 0x66,
|
||||
/* 104: */ 0x65, 0x72, 0x65, 0x72, 0x07, 0x24, 0x65, 0x78,
|
||||
/* 112: */ 0x70, 0x69, 0x72, 0x65, 0x73, 0x07, 0x02, 0x3a,
|
||||
/* 120: */ 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x07, 0x06,
|
||||
/* 128: */ 0x3a, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x07,
|
||||
/* 136: */ 0x08, 0x3a, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
|
||||
/* 144: */ 0x07, 0x34, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73,
|
||||
/* 152: */ 0x68, 0x08, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x74,
|
||||
/* 160: */ 0x69, 0x6f, 0x6e, 0x08, 0x27, 0x69, 0x66, 0x2d,
|
||||
/* 168: */ 0x6d, 0x61, 0x74, 0x63, 0x68, 0x08, 0x2a, 0x69,
|
||||
/* 176: */ 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x0a,
|
||||
/* 184: */ 0x3a, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x61, 0x67,
|
||||
/* 192: */ 0x65, 0x6e, 0x74, 0x0a, 0x37, 0x73, 0x65, 0x74,
|
||||
/* 200: */ 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x0a,
|
||||
/* 208: */ 0x01, 0x3a, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72,
|
||||
/* 216: */ 0x69, 0x74, 0x79, 0x0b, 0x35, 0x72, 0x65, 0x74,
|
||||
/* 224: */ 0x72, 0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72,
|
||||
/* 232: */ 0x0c, 0x1f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,
|
||||
/* 240: */ 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x0c, 0x2f,
|
||||
/* 248: */ 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72, 0x77,
|
||||
/* 256: */ 0x61, 0x72, 0x64, 0x73, 0x0d, 0x18, 0x63, 0x61,
|
||||
/* 264: */ 0x63, 0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74,
|
||||
/* 272: */ 0x72, 0x6f, 0x6c, 0x0d, 0x2c, 0x6c, 0x61, 0x73,
|
||||
/* 280: */ 0x74, 0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69,
|
||||
/* 288: */ 0x65, 0x64, 0x0d, 0x12, 0x61, 0x63, 0x63, 0x65,
|
||||
/* 296: */ 0x70, 0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65,
|
||||
/* 304: */ 0x73, 0x0d, 0x29, 0x69, 0x66, 0x2d, 0x6e, 0x6f,
|
||||
/* 312: */ 0x6e, 0x65, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68,
|
||||
/* 320: */ 0x0d, 0x17, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72,
|
||||
/* 328: */ 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0d,
|
||||
/* 336: */ 0x1e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,
|
||||
/* 344: */ 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x0e, 0x1c,
|
||||
/* 352: */ 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d,
|
||||
/* 360: */ 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x0e, 0x0f,
|
||||
/* 368: */ 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x63,
|
||||
/* 376: */ 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x0f, 0x10,
|
||||
/* 384: */ 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x65,
|
||||
/* 392: */ 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x0f,
|
||||
/* 400: */ 0x11, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d,
|
||||
/* 408: */ 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65,
|
||||
/* 416: */ 0x10, 0x1a, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,
|
||||
/* 424: */ 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69,
|
||||
/* 432: */ 0x6e, 0x67, 0x10, 0x1b, 0x63, 0x6f, 0x6e, 0x74,
|
||||
/* 440: */ 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x61, 0x6e, 0x67,
|
||||
/* 448: */ 0x75, 0x61, 0x67, 0x65, 0x10, 0x1d, 0x63, 0x6f,
|
||||
/* 456: */ 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f,
|
||||
/* 464: */ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0x3d,
|
||||
/* 472: */ 0x77, 0x77, 0x77, 0x2d, 0x61, 0x75, 0x74, 0x68,
|
||||
/* 480: */ 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65,
|
||||
/* 488: */ 0x11, 0x39, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66,
|
||||
/* 496: */ 0x65, 0x72, 0x2d, 0x65, 0x6e, 0x63, 0x6f, 0x64,
|
||||
/* 504: */ 0x69, 0x6e, 0x67, 0x11, 0x28, 0x69, 0x66, 0x2d,
|
||||
/* 512: */ 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64,
|
||||
/* 520: */ 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x12, 0x30,
|
||||
/* 528: */ 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61, 0x75,
|
||||
/* 536: */ 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61,
|
||||
/* 544: */ 0x74, 0x65, 0x13, 0x19, 0x63, 0x6f, 0x6e, 0x74,
|
||||
/* 552: */ 0x65, 0x6e, 0x74, 0x2d, 0x64, 0x69, 0x73, 0x70,
|
||||
/* 560: */ 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x13,
|
||||
/* 568: */ 0x2b, 0x69, 0x66, 0x2d, 0x75, 0x6e, 0x6d, 0x6f,
|
||||
/* 576: */ 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73,
|
||||
/* 584: */ 0x69, 0x6e, 0x63, 0x65, 0x13, 0x31, 0x70, 0x72,
|
||||
/* 592: */ 0x6f, 0x78, 0x79, 0x2d, 0x61, 0x75, 0x74, 0x68,
|
||||
/* 600: */ 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f,
|
||||
/* 608: */ 0x6e, 0x19, 0x38, 0x73, 0x74, 0x72, 0x69, 0x63,
|
||||
/* 616: */ 0x74, 0x2d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70,
|
||||
/* 624: */ 0x6f, 0x72, 0x74, 0x2d, 0x73, 0x65, 0x63, 0x75,
|
||||
/* 632: */ 0x72, 0x69, 0x74, 0x79, 0x1b, 0x14, 0x61, 0x63,
|
||||
/* 640: */ 0x63, 0x65, 0x73, 0x73, 0x2d, 0x63, 0x6f, 0x6e,
|
||||
/* 648: */ 0x74, 0x72, 0x6f, 0x6c, 0x2d, 0x61, 0x6c, 0x6c,
|
||||
/* 656: */ 0x6f, 0x77, 0x2d, 0x6f, 0x72, 0x69, 0x67, 0x69,
|
||||
/* 664: */ 0x6e, 0x00,
|
||||
};
|
||||
|
||||
/* This points to the first position in table hpack_enc_stream[] of a header
|
||||
* of the same length.
|
||||
*/
|
||||
const signed short hpack_pos_len[32] = {
|
||||
/* 0: */ -1, -1, -1, 0, 10, 46, 67, 99,
|
||||
/* 8: */ 153, -1, 183, 219, 232, 260, 350, 382,
|
||||
/* 16: */ 416, 488, 526, 546, -1, -1, -1, -1,
|
||||
/* 24: */ -1, 609, -1, 636, -1, -1, -1, -1,
|
||||
};
|
||||
|
||||
/* returns the number of bytes required to encode the string length <len>. The
|
||||
* number of usable bits is an integral multiple of 7 plus 6 for the last byte.
|
||||
* The maximum number of bytes returned is 4 (2097279 max length). Larger values
|
||||
@ -86,35 +190,36 @@ int hpack_encode_header(struct buffer *out, const struct ist n,
|
||||
{
|
||||
int len = out->data;
|
||||
int size = out->size;
|
||||
int pos;
|
||||
|
||||
if (len >= size)
|
||||
return 0;
|
||||
|
||||
/* check a few very common response header fields to encode them using
|
||||
* the static header table. The tests are sorted by size to help the
|
||||
* compiler factor out the common sizes.
|
||||
*/
|
||||
if (isteq(n, ist("date")))
|
||||
out->area[len++] = 0x61; // literal with indexing -- name="date" (idx 33)
|
||||
else if (isteq(n, ist("etag")))
|
||||
out->area[len++] = 0x62; // literal with indexing -- name="etag" (idx 34)
|
||||
else if (isteq(n, ist(":path")))
|
||||
out->area[len++] = 0x44; // literal with indexing -- name=":path" (idx 4)
|
||||
else if (isteq(n, ist("server")))
|
||||
out->area[len++] = 0x76; // literal with indexing -- name="server" (idx 54)
|
||||
else if (isteq(n, ist("location")))
|
||||
out->area[len++] = 0x6e; // literal with indexing -- name="location" (idx 46)
|
||||
else if (isteq(n, ist("content-type")))
|
||||
out->area[len++] = 0x5f; // literal with indexing -- name="content-type" (idx 31)
|
||||
else if (isteq(n, ist("last-modified")))
|
||||
out->area[len++] = 0x6c; // literal with indexing -- name="last-modified" (idx 44)
|
||||
else if (isteq(n, ist("accept-ranges")))
|
||||
out->area[len++] = 0x52; // literal with indexing -- name="accept-ranges" (idx 18)
|
||||
else if (isteq(n, ist("cache-control")))
|
||||
out->area[len++] = 0x58; // literal with indexing -- name="cache-control" (idx 24)
|
||||
else if (isteq(n, ist("content-length")))
|
||||
out->area[len++] = 0x5c; // literal with indexing -- name="content-length" (idx 28)
|
||||
else if (likely(n.len < 127 && len + 1 + n.len <= size)) {
|
||||
/* look for the header field <n> in the static table */
|
||||
if (n.len >= sizeof(hpack_pos_len) / sizeof(hpack_pos_len[0]))
|
||||
goto make_literal;
|
||||
|
||||
pos = hpack_pos_len[n.len];
|
||||
if (pos >= 0) {
|
||||
/* At least one header field of this length exist */
|
||||
do {
|
||||
char idx;
|
||||
|
||||
pos++;
|
||||
idx = hpack_enc_stream[pos++];
|
||||
pos += n.len;
|
||||
if (isteq(ist2(&hpack_enc_stream[pos - n.len], n.len), n)) {
|
||||
/* emit literal with indexing (7541#6.2.1) :
|
||||
* [ 0 | 1 | Index (6+) ]
|
||||
*/
|
||||
out->area[len++] = idx | 0x40;
|
||||
goto emit_value;
|
||||
}
|
||||
} while ((unsigned char)hpack_enc_stream[pos] == n.len);
|
||||
}
|
||||
|
||||
make_literal:
|
||||
if (likely(n.len < 127 && len + 1 + n.len <= size)) {
|
||||
out->area[len++] = 0x00; /* literal without indexing -- new name */
|
||||
out->area[len++] = n.len; /* single-byte length encoding */
|
||||
ist2bin(out->area + len, n);
|
||||
@ -131,6 +236,7 @@ int hpack_encode_header(struct buffer *out, const struct ist n,
|
||||
return 0;
|
||||
}
|
||||
|
||||
emit_value:
|
||||
/* copy literal header field value */
|
||||
if (!len_to_bytes(v.len) || len + len_to_bytes(v.len) + v.len > size) {
|
||||
/* header value too large for the buffer */
|
||||
|
Loading…
Reference in New Issue
Block a user