mirror of
https://gitea.invidious.io/iv-org/litespeed-quic.git
synced 2024-08-15 00:53:43 +00:00
Latest changes:
- Switch to using ls-hpack 1.1 - [BUGFIX] Do not ignore stream resets after receiving FIN
This commit is contained in:
parent
bf6b47adbf
commit
bea6482295
22 changed files with 1691 additions and 12978 deletions
|
@ -1,3 +1,8 @@
|
||||||
|
2018-05-02
|
||||||
|
|
||||||
|
- Switch to using ls-hpack 1.1
|
||||||
|
- [BUGFIX] Do not ignore stream resets after receiving FIN
|
||||||
|
|
||||||
2018-04-27
|
2018-04-27
|
||||||
|
|
||||||
- HPACK: do not allow header block to end with table size update.
|
- HPACK: do not allow header block to end with table size update.
|
||||||
|
|
|
@ -47,16 +47,15 @@ SET(lsquic_STAT_SRCS
|
||||||
lsquic_str.c
|
lsquic_str.c
|
||||||
lsquic_arr.c
|
lsquic_arr.c
|
||||||
lsquic_hash.c
|
lsquic_hash.c
|
||||||
lsquic_hpack_common.c
|
|
||||||
lsquic_hpack_dec.c
|
|
||||||
lsquic_hpack_enc.c
|
|
||||||
lsquic_xxhash.c
|
lsquic_xxhash.c
|
||||||
lsquic_buf.c
|
lsquic_buf.c
|
||||||
lsquic_min_heap.c
|
lsquic_min_heap.c
|
||||||
|
lshpack.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DXXH_HEADER_NAME=\\\"lsquic_xxhash.h\\\"")
|
||||||
|
|
||||||
add_library(lsquic STATIC ${lsquic_STAT_SRCS} )
|
add_library(lsquic STATIC ${lsquic_STAT_SRCS} )
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
163
src/liblsquic/lshpack.h
Normal file
163
src/liblsquic/lshpack.h
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
/* Copyright (c) 2017 - 2018 LiteSpeed Technologies Inc. See LICENSE. */
|
||||||
|
/*
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2018 LiteSpeed Technologies Inc
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LITESPEED_HPACK_H
|
||||||
|
#define LITESPEED_HPACK_H 1
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strings up to 65535 characters in length are supported.
|
||||||
|
*/
|
||||||
|
typedef uint16_t lshpack_strlen_t;
|
||||||
|
|
||||||
|
/** Maximum length is defined for convenience */
|
||||||
|
#define LSHPACK_MAX_STRLEN UINT16_MAX
|
||||||
|
|
||||||
|
struct lshpack_enc;
|
||||||
|
struct lshpack_dec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialization routine allocates memory. -1 is returned if memory
|
||||||
|
* could not be allocated. 0 is returned on success.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
lshpack_enc_init (struct lshpack_enc *);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean up HPACK encoder, freeing all allocated memory.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
lshpack_enc_cleanup (struct lshpack_enc *);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Encode one name/value pair
|
||||||
|
*
|
||||||
|
* @param[in,out] henc - A pointer to a valid HPACK API struct
|
||||||
|
* @param[out] dst - A pointer to destination buffer
|
||||||
|
* @param[out] dst_end - A pointer to end of destination buffer
|
||||||
|
* @param[in] name - A pointer to the item name
|
||||||
|
* @param[in] name_len - The item name's length
|
||||||
|
* @param[in] value - A pointer to the item value
|
||||||
|
* @param[in] value_len - The item value's length
|
||||||
|
* @param[in] indexed_type - 0, Add, 1,: without, 2: never
|
||||||
|
*
|
||||||
|
* @return The (possibly advanced) dst pointer. If the destination
|
||||||
|
* pointer was not advanced, an error must have occurred.
|
||||||
|
*/
|
||||||
|
unsigned char *
|
||||||
|
lshpack_enc_encode (struct lshpack_enc *henc, unsigned char *dst,
|
||||||
|
unsigned char *dst_end, const char *name, lshpack_strlen_t name_len,
|
||||||
|
const char *value, lshpack_strlen_t value_len, int indexed_type);
|
||||||
|
|
||||||
|
void
|
||||||
|
lshpack_enc_set_max_capacity (struct lshpack_enc *, unsigned);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize HPACK decoder structure.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
lshpack_dec_init (struct lshpack_dec *);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean up HPACK decoder structure, freeing all allocated memory.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
lshpack_dec_cleanup (struct lshpack_dec *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns 0 on success, a negative value on failure.
|
||||||
|
*
|
||||||
|
* If 0 is returned, `src' is advanced. Calling with a zero-length input
|
||||||
|
* buffer results in an error.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
lshpack_dec_decode (struct lshpack_dec *dec,
|
||||||
|
const unsigned char **src, const unsigned char *src_end,
|
||||||
|
char *dst, char *const dst_end, lshpack_strlen_t *name_len,
|
||||||
|
lshpack_strlen_t *val_len);
|
||||||
|
|
||||||
|
void
|
||||||
|
lshpack_dec_set_max_capacity (struct lshpack_dec *, unsigned);
|
||||||
|
|
||||||
|
/* Some internals follow. Struct definitions are exposed to save a malloc.
|
||||||
|
* These structures are not very complicated.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/queue.h>
|
||||||
|
|
||||||
|
struct lshpack_enc_table_entry;
|
||||||
|
|
||||||
|
STAILQ_HEAD(lshpack_enc_head, lshpack_enc_table_entry);
|
||||||
|
struct lshpack_double_enc_head;
|
||||||
|
|
||||||
|
struct lshpack_enc
|
||||||
|
{
|
||||||
|
unsigned hpe_cur_capacity;
|
||||||
|
unsigned hpe_max_capacity;
|
||||||
|
|
||||||
|
/* Each new dynamic table entry gets the next number. It is used to
|
||||||
|
* calculate the entry's position in the decoder table without having
|
||||||
|
* to maintain an actual array.
|
||||||
|
*/
|
||||||
|
unsigned hpe_next_id;
|
||||||
|
|
||||||
|
/* Dynamic table entries (struct enc_table_entry) live in two hash
|
||||||
|
* tables: name/value hash table and name hash table. These tables
|
||||||
|
* are the same size.
|
||||||
|
*/
|
||||||
|
unsigned hpe_nelem;
|
||||||
|
unsigned hpe_nbits;
|
||||||
|
struct lshpack_enc_head
|
||||||
|
hpe_all_entries;
|
||||||
|
struct lshpack_double_enc_head
|
||||||
|
*hpe_buckets;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lshpack_arr
|
||||||
|
{
|
||||||
|
unsigned nalloc,
|
||||||
|
nelem,
|
||||||
|
off;
|
||||||
|
uintptr_t *els;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lshpack_dec
|
||||||
|
{
|
||||||
|
unsigned hpd_max_capacity; /* Maximum set by caller */
|
||||||
|
unsigned hpd_cur_max_capacity; /* Adjusted at runtime */
|
||||||
|
unsigned hpd_cur_capacity;
|
||||||
|
struct lshpack_arr hpd_dyn_table;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -14,8 +14,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/queue.h>
|
#include <sys/queue.h>
|
||||||
|
|
||||||
#include "lsquic_arr.h"
|
#include "lshpack.h"
|
||||||
#include "lsquic_hpack_dec.h"
|
|
||||||
#include "lsquic.h"
|
#include "lsquic.h"
|
||||||
#include "lsquic_mm.h"
|
#include "lsquic_mm.h"
|
||||||
#include "lsquic_frame_common.h"
|
#include "lsquic_frame_common.h"
|
||||||
|
@ -123,7 +122,7 @@ struct reader_state
|
||||||
struct lsquic_frame_reader
|
struct lsquic_frame_reader
|
||||||
{
|
{
|
||||||
struct lsquic_mm *fr_mm;
|
struct lsquic_mm *fr_mm;
|
||||||
struct lsquic_hdec *fr_hdec;
|
struct lshpack_dec *fr_hdec;
|
||||||
struct lsquic_stream *fr_stream;
|
struct lsquic_stream *fr_stream;
|
||||||
fr_stream_read_f fr_read;
|
fr_stream_read_f fr_read;
|
||||||
const struct frame_reader_callbacks
|
const struct frame_reader_callbacks
|
||||||
|
@ -189,7 +188,7 @@ lsquic_frame_reader_new (enum frame_reader_flags flags,
|
||||||
unsigned max_headers_sz,
|
unsigned max_headers_sz,
|
||||||
struct lsquic_mm *mm,
|
struct lsquic_mm *mm,
|
||||||
struct lsquic_stream *stream, fr_stream_read_f read,
|
struct lsquic_stream *stream, fr_stream_read_f read,
|
||||||
struct lsquic_hdec *hdec,
|
struct lshpack_dec *hdec,
|
||||||
const struct frame_reader_callbacks *cb,
|
const struct frame_reader_callbacks *cb,
|
||||||
void *frame_reader_cb_ctx)
|
void *frame_reader_cb_ctx)
|
||||||
{
|
{
|
||||||
|
@ -516,7 +515,7 @@ struct header_writer_ctx
|
||||||
} hwc_flags;
|
} hwc_flags;
|
||||||
enum pseudo_header pseh_mask;
|
enum pseudo_header pseh_mask;
|
||||||
char *pseh_bufs[N_PSEH];
|
char *pseh_bufs[N_PSEH];
|
||||||
hpack_strlen_t name_len,
|
lshpack_strlen_t name_len,
|
||||||
val_len;
|
val_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -935,7 +934,7 @@ decode_and_pass_payload (struct lsquic_frame_reader *fr)
|
||||||
|
|
||||||
while (comp < end)
|
while (comp < end)
|
||||||
{
|
{
|
||||||
s = lsquic_hdec_decode(fr->fr_hdec, &comp, end,
|
s = lshpack_dec_decode(fr->fr_hdec, &comp, end,
|
||||||
hwc.buf, hwc.buf + 16 * 1024,
|
hwc.buf, hwc.buf + 16 * 1024,
|
||||||
&hwc.name_len, &hwc.val_len);
|
&hwc.name_len, &hwc.val_len);
|
||||||
if (s == 0)
|
if (s == 0)
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#include <vc_compat.h>
|
#include <vc_compat.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct lsquic_hdec;
|
struct lshpack_dec;
|
||||||
struct lsquic_mm;
|
struct lsquic_mm;
|
||||||
struct lsquic_stream;
|
struct lsquic_stream;
|
||||||
struct lsquic_frame_reader;
|
struct lsquic_frame_reader;
|
||||||
|
@ -110,7 +110,7 @@ typedef ssize_t (*fr_stream_read_f)(struct lsquic_stream *, void *, size_t);
|
||||||
struct lsquic_frame_reader *
|
struct lsquic_frame_reader *
|
||||||
lsquic_frame_reader_new (enum frame_reader_flags, unsigned max_headers_sz,
|
lsquic_frame_reader_new (enum frame_reader_flags, unsigned max_headers_sz,
|
||||||
struct lsquic_mm *, struct lsquic_stream *,
|
struct lsquic_mm *, struct lsquic_stream *,
|
||||||
fr_stream_read_f, struct lsquic_hdec *,
|
fr_stream_read_f, struct lshpack_dec *,
|
||||||
const struct frame_reader_callbacks *,
|
const struct frame_reader_callbacks *,
|
||||||
void *fr_cb_ctx);
|
void *fr_cb_ctx);
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/queue.h>
|
#include <sys/queue.h>
|
||||||
|
|
||||||
#include "lsquic_arr.h"
|
#include "lshpack.h"
|
||||||
#include "lsquic_hpack_enc.h"
|
|
||||||
#include "lsquic_mm.h"
|
#include "lsquic_mm.h"
|
||||||
#include "lsquic.h"
|
#include "lsquic.h"
|
||||||
|
|
||||||
|
@ -67,7 +66,7 @@ struct lsquic_frame_writer
|
||||||
struct lsquic_stream *fw_stream;
|
struct lsquic_stream *fw_stream;
|
||||||
fw_write_f fw_write;
|
fw_write_f fw_write;
|
||||||
struct lsquic_mm *fw_mm;
|
struct lsquic_mm *fw_mm;
|
||||||
struct lsquic_henc *fw_henc;
|
struct lshpack_enc *fw_henc;
|
||||||
struct frame_buf_head fw_frabs;
|
struct frame_buf_head fw_frabs;
|
||||||
unsigned fw_max_frame_sz;
|
unsigned fw_max_frame_sz;
|
||||||
uint32_t fw_max_header_list_sz; /* 0 means unlimited */
|
uint32_t fw_max_header_list_sz; /* 0 means unlimited */
|
||||||
|
@ -88,7 +87,7 @@ struct lsquic_frame_writer
|
||||||
|
|
||||||
struct lsquic_frame_writer *
|
struct lsquic_frame_writer *
|
||||||
lsquic_frame_writer_new (struct lsquic_mm *mm, struct lsquic_stream *stream,
|
lsquic_frame_writer_new (struct lsquic_mm *mm, struct lsquic_stream *stream,
|
||||||
unsigned max_frame_sz, struct lsquic_henc *henc, fw_write_f write,
|
unsigned max_frame_sz, struct lshpack_enc *henc, fw_write_f write,
|
||||||
int is_server)
|
int is_server)
|
||||||
{
|
{
|
||||||
struct lsquic_frame_writer *fw;
|
struct lsquic_frame_writer *fw;
|
||||||
|
@ -394,8 +393,8 @@ have_oversize_strings (const struct lsquic_http_headers *headers)
|
||||||
int i, have;
|
int i, have;
|
||||||
for (i = 0, have = 0; i < headers->count; ++i)
|
for (i = 0, have = 0; i < headers->count; ++i)
|
||||||
{
|
{
|
||||||
have |= headers->headers[i].name.iov_len > HPACK_MAX_STRLEN;
|
have |= headers->headers[i].name.iov_len > LSHPACK_MAX_STRLEN;
|
||||||
have |= headers->headers[i].value.iov_len > HPACK_MAX_STRLEN;
|
have |= headers->headers[i].value.iov_len > LSHPACK_MAX_STRLEN;
|
||||||
}
|
}
|
||||||
return have;
|
return have;
|
||||||
}
|
}
|
||||||
|
@ -452,7 +451,7 @@ write_headers (struct lsquic_frame_writer *fw,
|
||||||
|
|
||||||
for (i = 0; i < headers->count; ++i)
|
for (i = 0; i < headers->count; ++i)
|
||||||
{
|
{
|
||||||
end = lsquic_henc_encode(fw->fw_henc, buf, buf + buf_sz,
|
end = lshpack_enc_encode(fw->fw_henc, buf, buf + buf_sz,
|
||||||
headers->headers[i].name.iov_base, headers->headers[i].name.iov_len,
|
headers->headers[i].name.iov_base, headers->headers[i].name.iov_len,
|
||||||
headers->headers[i].value.iov_base, headers->headers[i].value.iov_len, 0);
|
headers->headers[i].value.iov_base, headers->headers[i].value.iov_len, 0);
|
||||||
if (end > buf)
|
if (end > buf)
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
struct iovec;
|
struct iovec;
|
||||||
struct lsquic_henc;
|
struct lshpack_enc;
|
||||||
struct lsquic_mm;
|
struct lsquic_mm;
|
||||||
struct lsquic_frame_writer;
|
struct lsquic_frame_writer;
|
||||||
struct lsquic_stream;
|
struct lsquic_stream;
|
||||||
|
@ -21,7 +21,7 @@ typedef ssize_t (*fw_write_f)(struct lsquic_stream *, const void *, size_t);
|
||||||
|
|
||||||
struct lsquic_frame_writer *
|
struct lsquic_frame_writer *
|
||||||
lsquic_frame_writer_new (struct lsquic_mm *, struct lsquic_stream *,
|
lsquic_frame_writer_new (struct lsquic_mm *, struct lsquic_stream *,
|
||||||
unsigned max_frame_sz, struct lsquic_henc *,
|
unsigned max_frame_sz, struct lshpack_enc *,
|
||||||
fw_write_f, int is_server);
|
fw_write_f, int is_server);
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -17,9 +17,7 @@
|
||||||
#include "lsquic_frame_common.h"
|
#include "lsquic_frame_common.h"
|
||||||
#include "lsquic_frame_reader.h"
|
#include "lsquic_frame_reader.h"
|
||||||
#include "lsquic_frame_writer.h"
|
#include "lsquic_frame_writer.h"
|
||||||
#include "lsquic_arr.h"
|
#include "lshpack.h"
|
||||||
#include "lsquic_hpack_enc.h"
|
|
||||||
#include "lsquic_hpack_dec.h"
|
|
||||||
#include "lsquic.h"
|
#include "lsquic.h"
|
||||||
|
|
||||||
#include "lsquic_headers_stream.h"
|
#include "lsquic_headers_stream.h"
|
||||||
|
@ -44,8 +42,8 @@ struct headers_stream
|
||||||
*hs_settings;
|
*hs_settings;
|
||||||
void *hs_cb_ctx;
|
void *hs_cb_ctx;
|
||||||
struct lsquic_mm *hs_mm;
|
struct lsquic_mm *hs_mm;
|
||||||
struct lsquic_henc hs_henc;
|
struct lshpack_enc hs_henc;
|
||||||
struct lsquic_hdec hs_hdec;
|
struct lshpack_dec hs_hdec;
|
||||||
enum {
|
enum {
|
||||||
HS_IS_SERVER = (1 << 0),
|
HS_IS_SERVER = (1 << 0),
|
||||||
HS_HENC_INITED = (1 << 1),
|
HS_HENC_INITED = (1 << 1),
|
||||||
|
@ -77,8 +75,8 @@ static lsquic_stream_ctx_t *
|
||||||
headers_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream)
|
headers_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream)
|
||||||
{
|
{
|
||||||
struct headers_stream *hs = stream_if_ctx;
|
struct headers_stream *hs = stream_if_ctx;
|
||||||
lsquic_hdec_init(&hs->hs_hdec);
|
lshpack_dec_init(&hs->hs_hdec);
|
||||||
if (0 != lsquic_henc_init(&hs->hs_henc))
|
if (0 != lshpack_enc_init(&hs->hs_henc))
|
||||||
{
|
{
|
||||||
LSQ_WARN("could not initialize HPACK encoder: %s", strerror(errno));
|
LSQ_WARN("could not initialize HPACK encoder: %s", strerror(errno));
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -223,8 +221,8 @@ lsquic_headers_stream_destroy (struct headers_stream *hs)
|
||||||
if (hs->hs_fw)
|
if (hs->hs_fw)
|
||||||
lsquic_frame_writer_destroy(hs->hs_fw);
|
lsquic_frame_writer_destroy(hs->hs_fw);
|
||||||
if (hs->hs_flags & HS_HENC_INITED)
|
if (hs->hs_flags & HS_HENC_INITED)
|
||||||
lsquic_henc_cleanup(&hs->hs_henc);
|
lshpack_enc_cleanup(&hs->hs_henc);
|
||||||
lsquic_hdec_cleanup(&hs->hs_hdec);
|
lshpack_dec_cleanup(&hs->hs_hdec);
|
||||||
free(hs);
|
free(hs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,7 +317,7 @@ headers_on_settings (void *ctx, uint16_t setting_id, uint32_t setting_value)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LSQ_INFO("update hpack table size to %u", setting_value);
|
LSQ_INFO("update hpack table size to %u", setting_value);
|
||||||
lsquic_henc_set_max_capacity(&hs->hs_henc, setting_value);
|
lshpack_enc_set_max_capacity(&hs->hs_henc, setting_value);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SETTINGS_MAX_HEADER_LIST_SIZE:
|
case SETTINGS_MAX_HEADER_LIST_SIZE:
|
||||||
|
@ -391,13 +389,7 @@ lsquic_headers_stream_mem_used (const struct headers_stream *hs)
|
||||||
size = sizeof(*hs);
|
size = sizeof(*hs);
|
||||||
size += lsquic_frame_reader_mem_used(hs->hs_fr);
|
size += lsquic_frame_reader_mem_used(hs->hs_fr);
|
||||||
size += lsquic_frame_writer_mem_used(hs->hs_fw);
|
size += lsquic_frame_writer_mem_used(hs->hs_fw);
|
||||||
size -= sizeof(hs->hs_hdec);
|
/* XXX: get rid of this mem_used business as we no longer use it? */
|
||||||
size += lsquic_hdec_mem_used(&hs->hs_hdec);
|
|
||||||
if (hs->hs_flags & HS_HENC_INITED)
|
|
||||||
{
|
|
||||||
size -= sizeof(hs->hs_henc);
|
|
||||||
size += lsquic_henc_mem_used(&hs->hs_henc);
|
|
||||||
}
|
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
/* Copyright (c) 2017 - 2018 LiteSpeed Technologies Inc. See LICENSE. */
|
|
||||||
#ifndef LSQUIC_HPACK_COMMON_H
|
|
||||||
#define LSQUIC_HPACK_COMMON_H
|
|
||||||
|
|
||||||
#include "lsquic_hpack_types.h"
|
|
||||||
|
|
||||||
#define HPACK_STATIC_TABLE_SIZE 61
|
|
||||||
#define INITIAL_DYNAMIC_TABLE_SIZE 4096
|
|
||||||
|
|
||||||
/* RFC 7541, Section 4.1:
|
|
||||||
*
|
|
||||||
* " The size of the dynamic table is the sum of the size of its entries.
|
|
||||||
* "
|
|
||||||
* " The size of an entry is the sum of its name's length in octets (as
|
|
||||||
* " defined in Section 5.2), its value's length in octets, and 32.
|
|
||||||
*/
|
|
||||||
#define DYNAMIC_ENTRY_OVERHEAD 32
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef hpack_hdr_tbl_t
|
|
||||||
* @brief A struct for the static table (name - value)
|
|
||||||
*/
|
|
||||||
typedef struct hpack_hdr_tbl_s
|
|
||||||
{
|
|
||||||
const char *name;
|
|
||||||
hpack_strlen_t name_len;
|
|
||||||
const char *val;
|
|
||||||
hpack_strlen_t val_len;
|
|
||||||
} hpack_hdr_tbl_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef hpack_huff_encode_t
|
|
||||||
* @brief Huffman encode struct
|
|
||||||
*/
|
|
||||||
typedef struct hpack_huff_encode_s
|
|
||||||
{
|
|
||||||
uint32_t code;
|
|
||||||
int bits;
|
|
||||||
} hpack_huff_encode_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef hpack_huff_decode_t
|
|
||||||
* @brief Huffman decode struct
|
|
||||||
*/
|
|
||||||
typedef struct hpack_huff_decode_s
|
|
||||||
{
|
|
||||||
uint8_t state;
|
|
||||||
uint8_t flags;
|
|
||||||
uint8_t sym;
|
|
||||||
} hpack_huff_decode_t;
|
|
||||||
|
|
||||||
|
|
||||||
extern const hpack_huff_decode_t lsquic_hpack_huff_decode_tables[256][16];
|
|
||||||
extern const hpack_huff_encode_t lsquic_hpack_huff_encode_tables[257];
|
|
||||||
extern const hpack_hdr_tbl_t lsquic_hpack_stx_tab[HPACK_STATIC_TABLE_SIZE];
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,446 +0,0 @@
|
||||||
/* Copyright (c) 2017 - 2018 LiteSpeed Technologies Inc. See LICENSE. */
|
|
||||||
/*
|
|
||||||
* lsquic_hdec.c - HPACK decoder
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#ifdef WIN32
|
|
||||||
#include <vc_compat.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "lsquic_arr.h"
|
|
||||||
#include "lsquic_hpack_common.h"
|
|
||||||
#include "lsquic_hpack_dec.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* Dynamic table entry: */
|
|
||||||
struct dec_table_entry
|
|
||||||
{
|
|
||||||
uint16_t dte_name_len;
|
|
||||||
uint16_t dte_val_len;
|
|
||||||
char dte_buf[0]; /* Contains both name and value */
|
|
||||||
};
|
|
||||||
|
|
||||||
#define DTE_NAME(dte) ((dte)->dte_buf)
|
|
||||||
#define DTE_VALUE(dte) (&(dte)->dte_buf[(dte)->dte_name_len])
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
HPACK_HUFFMAN_FLAG_ACCEPTED = 0x01,
|
|
||||||
HPACK_HUFFMAN_FLAG_SYM = 0x02,
|
|
||||||
HPACK_HUFFMAN_FLAG_FAIL = 0x04,
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct hpack_huff_decode_status_s
|
|
||||||
{
|
|
||||||
uint8_t state;
|
|
||||||
uint8_t eos;
|
|
||||||
} hpack_huff_decode_status_t;
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
lsquic_hdec_init (struct lsquic_hdec *dec)
|
|
||||||
{
|
|
||||||
memset(dec, 0, sizeof(*dec));
|
|
||||||
dec->hpd_max_capacity = INITIAL_DYNAMIC_TABLE_SIZE;
|
|
||||||
dec->hpd_cur_max_capacity = INITIAL_DYNAMIC_TABLE_SIZE;
|
|
||||||
lsquic_arr_init(&dec->hpd_dyn_table);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
lsquic_hdec_cleanup (struct lsquic_hdec *dec)
|
|
||||||
{
|
|
||||||
uintptr_t val;
|
|
||||||
|
|
||||||
while (lsquic_arr_count(&dec->hpd_dyn_table) > 0)
|
|
||||||
{
|
|
||||||
val = lsquic_arr_pop(&dec->hpd_dyn_table);
|
|
||||||
free((struct dec_table_entry *) val);
|
|
||||||
}
|
|
||||||
lsquic_arr_cleanup(&dec->hpd_dyn_table);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//https://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#section-5.1
|
|
||||||
#ifdef NDEBUG
|
|
||||||
static
|
|
||||||
#endif
|
|
||||||
int
|
|
||||||
lsquic_hdec_dec_int (const unsigned char **src, const unsigned char *src_end,
|
|
||||||
uint8_t prefix_bits, uint32_t *value)
|
|
||||||
{
|
|
||||||
uint32_t B, M;
|
|
||||||
uint8_t prefix_max = (1 << prefix_bits) - 1;
|
|
||||||
|
|
||||||
*value = (*(*src)++ & prefix_max);
|
|
||||||
|
|
||||||
if (*value < prefix_max)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* To optimize the loop for the normal case, the overflow is checked
|
|
||||||
* outside the loop. The decoder is limited to 28-bit integer values,
|
|
||||||
* which is far above limitations imposed by the APIs (16-bit integers).
|
|
||||||
*/
|
|
||||||
M = 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if ((*src) >= src_end)
|
|
||||||
return -1;
|
|
||||||
B = *(*src)++;
|
|
||||||
*value = *value + ((B & 0x7f) << M);
|
|
||||||
M += 7;
|
|
||||||
}
|
|
||||||
while (B & 0x80);
|
|
||||||
|
|
||||||
return -(M > sizeof(*value) * 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
hdec_drop_oldest_entry (struct lsquic_hdec *dec)
|
|
||||||
{
|
|
||||||
struct dec_table_entry *entry;
|
|
||||||
entry = (void *) lsquic_arr_shift(&dec->hpd_dyn_table);
|
|
||||||
dec->hpd_cur_capacity -= DYNAMIC_ENTRY_OVERHEAD + entry->dte_name_len
|
|
||||||
+ entry->dte_val_len;
|
|
||||||
free(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
hdec_remove_overflow_entries (struct lsquic_hdec *dec)
|
|
||||||
{
|
|
||||||
while (dec->hpd_cur_capacity > dec->hpd_cur_max_capacity)
|
|
||||||
hdec_drop_oldest_entry(dec);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
hdec_update_max_capacity (struct lsquic_hdec *dec, uint32_t new_capacity)
|
|
||||||
{
|
|
||||||
dec->hpd_cur_max_capacity = new_capacity;
|
|
||||||
hdec_remove_overflow_entries(dec);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
lsquic_hdec_set_max_capacity (struct lsquic_hdec *dec, unsigned max_capacity)
|
|
||||||
{
|
|
||||||
dec->hpd_max_capacity = max_capacity;
|
|
||||||
hdec_update_max_capacity(dec, max_capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static unsigned char *
|
|
||||||
hdec_huff_dec4bits (uint8_t src_4bits, unsigned char *dst,
|
|
||||||
hpack_huff_decode_status_t *status)
|
|
||||||
{
|
|
||||||
const hpack_huff_decode_t cur_dec_code =
|
|
||||||
lsquic_hpack_huff_decode_tables[status->state][src_4bits];
|
|
||||||
if (cur_dec_code.flags & HPACK_HUFFMAN_FLAG_FAIL) {
|
|
||||||
return NULL; //failed
|
|
||||||
}
|
|
||||||
if (cur_dec_code.flags & HPACK_HUFFMAN_FLAG_SYM)
|
|
||||||
{
|
|
||||||
*dst = cur_dec_code.sym;
|
|
||||||
dst++;
|
|
||||||
}
|
|
||||||
|
|
||||||
status->state = cur_dec_code.state;
|
|
||||||
status->eos = ((cur_dec_code.flags & HPACK_HUFFMAN_FLAG_ACCEPTED) != 0);
|
|
||||||
return dst;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
hdec_huff_decode (const unsigned char *src, int src_len,
|
|
||||||
unsigned char *dst, int dst_len)
|
|
||||||
{
|
|
||||||
const unsigned char *p_src = src;
|
|
||||||
const unsigned char *src_end = src + src_len;
|
|
||||||
unsigned char *p_dst = dst;
|
|
||||||
unsigned char *dst_end = dst + dst_len;
|
|
||||||
hpack_huff_decode_status_t status = { 0, 1 };
|
|
||||||
|
|
||||||
while (p_src != src_end)
|
|
||||||
{
|
|
||||||
if (p_dst == dst_end)
|
|
||||||
return -2;
|
|
||||||
if ((p_dst = hdec_huff_dec4bits(*p_src >> 4, p_dst, &status))
|
|
||||||
== NULL)
|
|
||||||
return -1;
|
|
||||||
if (p_dst == dst_end)
|
|
||||||
return -2;
|
|
||||||
if ((p_dst = hdec_huff_dec4bits(*p_src & 0xf, p_dst, &status))
|
|
||||||
== NULL)
|
|
||||||
return -1;
|
|
||||||
++p_src;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!status.eos)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return p_dst - dst;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//reutrn the length in the dst, also update the src
|
|
||||||
#ifdef NDEBUG
|
|
||||||
static
|
|
||||||
#endif
|
|
||||||
int
|
|
||||||
hdec_dec_str (unsigned char *dst, size_t dst_len, const unsigned char **src,
|
|
||||||
const unsigned char *src_end)
|
|
||||||
{
|
|
||||||
if ((*src) == src_end)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
int is_huffman = (*(*src) & 0x80);
|
|
||||||
uint32_t len;
|
|
||||||
if (0 != lsquic_hdec_dec_int(src, src_end, 7, &len))
|
|
||||||
return -2; //wrong int
|
|
||||||
|
|
||||||
int ret = 0;
|
|
||||||
if ((uint32_t)(src_end - (*src)) < len) {
|
|
||||||
return -2; //wrong int
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_huffman)
|
|
||||||
{
|
|
||||||
ret = hdec_huff_decode(*src, len, dst, dst_len);
|
|
||||||
if (ret < 0)
|
|
||||||
return -3; //Wrong code
|
|
||||||
|
|
||||||
(*src) += len;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (dst_len < (size_t)(src_end - (*src)))
|
|
||||||
ret = -3; //dst not enough space
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(dst, (*src), len);
|
|
||||||
(*src) += len;
|
|
||||||
ret = len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* hpd_dyn_table is a dynamic array. New entries are pushed onto it,
|
|
||||||
* while old entries are shifted from it.
|
|
||||||
*/
|
|
||||||
static struct dec_table_entry *
|
|
||||||
hdec_get_table_entry (struct lsquic_hdec *dec, uint32_t index)
|
|
||||||
{
|
|
||||||
uintptr_t val;
|
|
||||||
|
|
||||||
index -= HPACK_STATIC_TABLE_SIZE;
|
|
||||||
if (index == 0 || index > lsquic_arr_count(&dec->hpd_dyn_table))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
index = lsquic_arr_count(&dec->hpd_dyn_table) - index;
|
|
||||||
val = lsquic_arr_get(&dec->hpd_dyn_table, index);
|
|
||||||
return (struct dec_table_entry *) val;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef NDEBUG
|
|
||||||
static
|
|
||||||
#endif
|
|
||||||
int
|
|
||||||
lsquic_hdec_push_entry (struct lsquic_hdec *dec, const char *name,
|
|
||||||
uint16_t name_len, const char *val, uint16_t val_len)
|
|
||||||
{
|
|
||||||
struct dec_table_entry *entry;
|
|
||||||
size_t size;
|
|
||||||
|
|
||||||
size = sizeof(*entry) + name_len + val_len;
|
|
||||||
entry = malloc(size);
|
|
||||||
if (!entry)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (0 != lsquic_arr_push(&dec->hpd_dyn_table, (uintptr_t) entry))
|
|
||||||
{
|
|
||||||
free(entry);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
dec->hpd_cur_capacity += DYNAMIC_ENTRY_OVERHEAD + name_len + val_len;
|
|
||||||
entry->dte_name_len = name_len;
|
|
||||||
entry->dte_val_len = val_len;
|
|
||||||
memcpy(DTE_NAME(entry), name, name_len);
|
|
||||||
memcpy(DTE_VALUE(entry), val, val_len);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
lsquic_hdec_decode (struct lsquic_hdec *dec,
|
|
||||||
const unsigned char **src, const unsigned char *src_end,
|
|
||||||
char *dst, char *const dst_end, uint16_t *name_len, uint16_t *val_len)
|
|
||||||
{
|
|
||||||
struct dec_table_entry *entry;
|
|
||||||
uint32_t index, new_capacity;
|
|
||||||
int indexed_type, len;
|
|
||||||
|
|
||||||
if ((*src) == src_end)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
while ((*(*src) & 0xe0) == 0x20) //001 xxxxx
|
|
||||||
{
|
|
||||||
if (0 != lsquic_hdec_dec_int(src, src_end, 5, &new_capacity))
|
|
||||||
return -1;
|
|
||||||
if (new_capacity > dec->hpd_max_capacity)
|
|
||||||
return -1;
|
|
||||||
hdec_update_max_capacity(dec, new_capacity);
|
|
||||||
if (*src == src_end)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* lsquic_hdec_dec_int() sets `index' and advances `src'. If we do not call
|
|
||||||
* it, we set `index' and advance `src' ourselves:
|
|
||||||
*/
|
|
||||||
if (*(*src) & 0x80) //1 xxxxxxx
|
|
||||||
{
|
|
||||||
if (0 != lsquic_hdec_dec_int(src, src_end, 7, &index))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
indexed_type = 3; //need to parse value
|
|
||||||
}
|
|
||||||
else if (*(*src) > 0x40) //01 xxxxxx
|
|
||||||
{
|
|
||||||
if (0 != lsquic_hdec_dec_int(src, src_end, 6, &index))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
indexed_type = 0;
|
|
||||||
}
|
|
||||||
else if (*(*src) == 0x40) //custmized //0100 0000
|
|
||||||
{
|
|
||||||
indexed_type = 0;
|
|
||||||
index = 0;
|
|
||||||
++(*src);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Never indexed
|
|
||||||
else if (*(*src) == 0x10) //00010000
|
|
||||||
{
|
|
||||||
indexed_type = 2;
|
|
||||||
index = 0;
|
|
||||||
++(*src);
|
|
||||||
}
|
|
||||||
else if ((*(*src) & 0xf0) == 0x10) //0001 xxxx
|
|
||||||
{
|
|
||||||
if (0 != lsquic_hdec_dec_int(src, src_end, 4, &index))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
indexed_type = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
//without indexed
|
|
||||||
else if (*(*src) == 0x00) //0000 0000
|
|
||||||
{
|
|
||||||
indexed_type = 1;
|
|
||||||
index = 0;
|
|
||||||
++(*src);
|
|
||||||
}
|
|
||||||
else // 0000 xxxx
|
|
||||||
{
|
|
||||||
if (0 != lsquic_hdec_dec_int(src, src_end, 4, &index))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
indexed_type = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *const name = dst;
|
|
||||||
if (index > 0)
|
|
||||||
{
|
|
||||||
if (index <= HPACK_STATIC_TABLE_SIZE) //static table
|
|
||||||
{
|
|
||||||
if (lsquic_hpack_stx_tab[index - 1].name_len > dst_end - dst)
|
|
||||||
return -1;
|
|
||||||
*name_len = lsquic_hpack_stx_tab[index - 1].name_len;
|
|
||||||
memcpy(name, lsquic_hpack_stx_tab[index - 1].name, *name_len);
|
|
||||||
if (indexed_type == 3)
|
|
||||||
{
|
|
||||||
if (lsquic_hpack_stx_tab[index - 1].name_len +
|
|
||||||
lsquic_hpack_stx_tab[index - 1].val_len > dst_end - dst)
|
|
||||||
return -1;
|
|
||||||
*val_len = lsquic_hpack_stx_tab[index - 1].val_len;
|
|
||||||
memcpy(name + *name_len, lsquic_hpack_stx_tab[index - 1].val, *val_len);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry = hdec_get_table_entry(dec, index);
|
|
||||||
if (entry == NULL)
|
|
||||||
return -1;
|
|
||||||
if (entry->dte_name_len > dst_end - dst)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
*name_len = entry->dte_name_len;
|
|
||||||
memcpy(name, DTE_NAME(entry), *name_len);
|
|
||||||
if (indexed_type == 3)
|
|
||||||
{
|
|
||||||
if (entry->dte_name_len + entry->dte_val_len > dst_end - dst)
|
|
||||||
return -1;
|
|
||||||
*val_len = entry->dte_val_len;
|
|
||||||
memcpy(name + *name_len, DTE_VALUE(entry), *val_len);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
len = hdec_dec_str((unsigned char *)name, dst_end - dst, src, src_end);
|
|
||||||
if (len < 0)
|
|
||||||
return len; //error
|
|
||||||
if (len > UINT16_MAX)
|
|
||||||
return -2;
|
|
||||||
*name_len = len;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = hdec_dec_str((unsigned char *)name + *name_len,
|
|
||||||
dst_end - dst - *name_len, src, src_end);
|
|
||||||
if (len < 0)
|
|
||||||
return len; //error
|
|
||||||
if (len > UINT16_MAX)
|
|
||||||
return -2;
|
|
||||||
*val_len = len;
|
|
||||||
|
|
||||||
if (indexed_type == 0)
|
|
||||||
{
|
|
||||||
if (0 != lsquic_hdec_push_entry(dec, name, *name_len,
|
|
||||||
name + *name_len, *val_len))
|
|
||||||
return -1; //error
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
size_t
|
|
||||||
lsquic_hdec_mem_used (const struct lsquic_hdec *dec)
|
|
||||||
{
|
|
||||||
const struct dec_table_entry *entry;
|
|
||||||
size_t size;
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
size = sizeof(*dec);
|
|
||||||
for (i = 0; i < lsquic_arr_count(&dec->hpd_dyn_table); ++i)
|
|
||||||
{
|
|
||||||
entry = (void *) lsquic_arr_get(&dec->hpd_dyn_table, i);
|
|
||||||
size += sizeof(*entry) + entry->dte_val_len + entry->dte_name_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
size -= sizeof(dec->hpd_dyn_table);
|
|
||||||
size += lsquic_arr_mem_used(&dec->hpd_dyn_table);
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
/* Copyright (c) 2017 - 2018 LiteSpeed Technologies Inc. See LICENSE. */
|
|
||||||
/*
|
|
||||||
* lsquic_hdec.h - HPACK decoder
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LSQUIC_HPACK_DEC_H
|
|
||||||
#define LSQUIC_HPACK_DEC_H
|
|
||||||
|
|
||||||
#include "lsquic_hpack_types.h"
|
|
||||||
|
|
||||||
struct lsquic_hdec
|
|
||||||
{
|
|
||||||
unsigned hpd_max_capacity; /* Maximum set by caller */
|
|
||||||
unsigned hpd_cur_max_capacity; /* Adjusted at runtime */
|
|
||||||
unsigned hpd_cur_capacity;
|
|
||||||
struct lsquic_arr hpd_dyn_table;
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
|
||||||
lsquic_hdec_init (struct lsquic_hdec *);
|
|
||||||
|
|
||||||
void
|
|
||||||
lsquic_hdec_cleanup (struct lsquic_hdec *);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns 0 on success, a negative value on failure.
|
|
||||||
*
|
|
||||||
* If 0 is returned, `src' is advanced. Calling with a zero-length input
|
|
||||||
* buffer results in an error.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
lsquic_hdec_decode (struct lsquic_hdec *dec,
|
|
||||||
const unsigned char **src, const unsigned char *src_end,
|
|
||||||
char *dst, char *const dst_end, hpack_strlen_t *name_len,
|
|
||||||
hpack_strlen_t *val_len);
|
|
||||||
|
|
||||||
void
|
|
||||||
lsquic_hdec_set_max_capacity (struct lsquic_hdec *, unsigned);
|
|
||||||
|
|
||||||
size_t
|
|
||||||
lsquic_hdec_mem_used (const struct lsquic_hdec *);
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
int
|
|
||||||
lsquic_hdec_dec_int (const unsigned char **src, const unsigned char *src_end,
|
|
||||||
uint8_t prefix_bits, uint32_t *value);
|
|
||||||
int
|
|
||||||
lsquic_hdec_push_entry (struct lsquic_hdec *dec, const char *name,
|
|
||||||
hpack_strlen_t name_len, const char *val,
|
|
||||||
hpack_strlen_t val_len);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,878 +0,0 @@
|
||||||
/* Copyright (c) 2017 - 2018 LiteSpeed Technologies Inc. See LICENSE. */
|
|
||||||
/*
|
|
||||||
* lsquic_hpack_enc.c - HPACK encoder
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/queue.h>
|
|
||||||
#ifdef WIN32
|
|
||||||
#include <vc_compat.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "lsquic_hpack_common.h"
|
|
||||||
#include "lsquic_hpack_enc.h"
|
|
||||||
#include "lsquic_xxhash.h"
|
|
||||||
|
|
||||||
struct double_enc_head
|
|
||||||
{
|
|
||||||
struct enc_head by_name;
|
|
||||||
struct enc_head by_nameval;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct enc_table_entry
|
|
||||||
{
|
|
||||||
/* An entry always lives on all three lists */
|
|
||||||
STAILQ_ENTRY(enc_table_entry) ete_next_nameval,
|
|
||||||
ete_next_name,
|
|
||||||
ete_next_all;
|
|
||||||
unsigned ete_id;
|
|
||||||
unsigned ete_nameval_hash;
|
|
||||||
unsigned ete_name_hash;
|
|
||||||
hpack_strlen_t ete_name_len;
|
|
||||||
hpack_strlen_t ete_val_len;
|
|
||||||
char ete_buf[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
#define ETE_NAME(ete) ((ete)->ete_buf)
|
|
||||||
#define ETE_VALUE(ete) (&(ete)->ete_buf[(ete)->ete_name_len])
|
|
||||||
|
|
||||||
|
|
||||||
#define N_BUCKETS(n_bits) (1U << (n_bits))
|
|
||||||
#define BUCKNO(n_bits, hash) ((hash) & (N_BUCKETS(n_bits) - 1))
|
|
||||||
|
|
||||||
int
|
|
||||||
lsquic_henc_init (struct lsquic_henc *enc)
|
|
||||||
{
|
|
||||||
struct double_enc_head *buckets;
|
|
||||||
unsigned nbits = 2;
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
buckets = malloc(sizeof(buckets[0]) * N_BUCKETS(nbits));
|
|
||||||
if (!buckets)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
for (i = 0; i < N_BUCKETS(nbits); ++i)
|
|
||||||
{
|
|
||||||
STAILQ_INIT(&buckets[i].by_name);
|
|
||||||
STAILQ_INIT(&buckets[i].by_nameval);
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(enc, 0, sizeof(*enc));
|
|
||||||
STAILQ_INIT(&enc->hpe_all_entries);
|
|
||||||
enc->hpe_max_capacity = INITIAL_DYNAMIC_TABLE_SIZE;
|
|
||||||
enc->hpe_buckets = buckets;
|
|
||||||
/* The initial value of the entry ID is completely arbitrary. As long as
|
|
||||||
* there are fewer than 2^32 dynamic table entries, the math to calculate
|
|
||||||
* the entry ID works. To prove to ourselves that the wraparound works
|
|
||||||
* and to have the unit tests cover it, we initialize the next ID so that
|
|
||||||
* it is just about to wrap around.
|
|
||||||
*/
|
|
||||||
enc->hpe_next_id = ~0 - 3;
|
|
||||||
enc->hpe_nbits = nbits;
|
|
||||||
enc->hpe_nelem = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
lsquic_henc_cleanup (struct lsquic_henc *enc)
|
|
||||||
{
|
|
||||||
struct enc_table_entry *entry, *next;
|
|
||||||
for (entry = STAILQ_FIRST(&enc->hpe_all_entries); entry; entry = next)
|
|
||||||
{
|
|
||||||
next = STAILQ_NEXT(entry, ete_next_all);
|
|
||||||
free(entry);
|
|
||||||
}
|
|
||||||
free(enc->hpe_buckets);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//not find return 0, otherwise return the index
|
|
||||||
#ifdef NDEBUG
|
|
||||||
static
|
|
||||||
#endif
|
|
||||||
unsigned
|
|
||||||
lsquic_henc_get_stx_tab_id (const char *name, hpack_strlen_t name_len,
|
|
||||||
const char *val, hpack_strlen_t val_len, int *val_matched)
|
|
||||||
{
|
|
||||||
if (name_len < 3)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
*val_matched = 0;
|
|
||||||
|
|
||||||
//check value first
|
|
||||||
int i = -1;
|
|
||||||
switch (*val)
|
|
||||||
{
|
|
||||||
case 'G':
|
|
||||||
i = 1;
|
|
||||||
break;
|
|
||||||
case 'P':
|
|
||||||
i = 2;
|
|
||||||
break;
|
|
||||||
case '/':
|
|
||||||
if (val_len == 1)
|
|
||||||
i = 3;
|
|
||||||
else if (val_len == 11)
|
|
||||||
i = 4;
|
|
||||||
break;
|
|
||||||
case 'h':
|
|
||||||
if (val_len == 4)
|
|
||||||
i = 5;
|
|
||||||
else if (val_len == 5)
|
|
||||||
i = 6;
|
|
||||||
break;
|
|
||||||
case '2':
|
|
||||||
if (val_len == 3)
|
|
||||||
{
|
|
||||||
switch (*(val + 2))
|
|
||||||
{
|
|
||||||
case '0':
|
|
||||||
i = 7;
|
|
||||||
break;
|
|
||||||
case '4':
|
|
||||||
i = 8;
|
|
||||||
break;
|
|
||||||
case '6':
|
|
||||||
i = 9;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '3':
|
|
||||||
i = 10;
|
|
||||||
break;
|
|
||||||
case '4':
|
|
||||||
if (val_len == 3)
|
|
||||||
{
|
|
||||||
switch (*(val + 2))
|
|
||||||
{
|
|
||||||
case '0':
|
|
||||||
i = 11;
|
|
||||||
break;
|
|
||||||
case '4':
|
|
||||||
i = 12;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '5':
|
|
||||||
i = 13;
|
|
||||||
break;
|
|
||||||
case 'g':
|
|
||||||
i = 15;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i > 0 && lsquic_hpack_stx_tab[i].val_len == val_len
|
|
||||||
&& lsquic_hpack_stx_tab[i].name_len == name_len
|
|
||||||
&& memcmp(val, lsquic_hpack_stx_tab[i].val, val_len) == 0
|
|
||||||
&& memcmp(name, lsquic_hpack_stx_tab[i].name, name_len) == 0)
|
|
||||||
{
|
|
||||||
*val_matched = 1;
|
|
||||||
return i + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//macth name only checking
|
|
||||||
i = -1;
|
|
||||||
switch (*name)
|
|
||||||
{
|
|
||||||
case ':':
|
|
||||||
switch (*(name + 1))
|
|
||||||
{
|
|
||||||
case 'a':
|
|
||||||
i = 0;
|
|
||||||
break;
|
|
||||||
case 'm':
|
|
||||||
i = 1;
|
|
||||||
break;
|
|
||||||
case 'p':
|
|
||||||
i = 3;
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
if (*(name + 2) == 'c') //:scheme
|
|
||||||
i = 5;
|
|
||||||
else
|
|
||||||
i = 7;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'a':
|
|
||||||
switch (name_len)
|
|
||||||
{
|
|
||||||
case 3:
|
|
||||||
i = 20; //age
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
i = 21; //allow
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
i = 18; //accept
|
|
||||||
break;
|
|
||||||
case 13:
|
|
||||||
if (*(name + 1) == 'u')
|
|
||||||
i = 22; //authorization
|
|
||||||
else
|
|
||||||
i = 17; //accept-ranges
|
|
||||||
break;
|
|
||||||
case 14:
|
|
||||||
i = 14; //accept-charset
|
|
||||||
break;
|
|
||||||
case 15:
|
|
||||||
if (*(name + 7) == 'l')
|
|
||||||
i = 16; //accept-language,
|
|
||||||
else
|
|
||||||
i = 15;// accept-encoding
|
|
||||||
break;
|
|
||||||
case 27:
|
|
||||||
i = 19;//access-control-allow-origin
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'c':
|
|
||||||
switch (name_len)
|
|
||||||
{
|
|
||||||
case 6:
|
|
||||||
i = 31; //cookie
|
|
||||||
break;
|
|
||||||
case 12:
|
|
||||||
i = 30; //content-type
|
|
||||||
break;
|
|
||||||
case 13:
|
|
||||||
if (*(name + 1) == 'a')
|
|
||||||
i = 23; //cache-control
|
|
||||||
else
|
|
||||||
i = 29; //content-range
|
|
||||||
break;
|
|
||||||
case 14:
|
|
||||||
i = 27; //content-length
|
|
||||||
break;
|
|
||||||
case 16:
|
|
||||||
switch (*(name + 9))
|
|
||||||
{
|
|
||||||
case 'n':
|
|
||||||
i = 25 ;//content-encoding
|
|
||||||
break;
|
|
||||||
case 'a':
|
|
||||||
i = 26; //content-language
|
|
||||||
break;
|
|
||||||
case 'o':
|
|
||||||
i = 28; //content-location
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 19:
|
|
||||||
i = 24; //content-disposition
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'd':
|
|
||||||
i = 32 ;//date
|
|
||||||
break;
|
|
||||||
case 'e':
|
|
||||||
switch (name_len)
|
|
||||||
{
|
|
||||||
case 4:
|
|
||||||
i = 33; //etag
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
i = 34;
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
i = 35;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
i = 36; //from
|
|
||||||
break;
|
|
||||||
case 'h':
|
|
||||||
i = 37; //host
|
|
||||||
break;
|
|
||||||
case 'i':
|
|
||||||
switch (name_len)
|
|
||||||
{
|
|
||||||
case 8:
|
|
||||||
if (*(name + 3) == 'm')
|
|
||||||
i = 38; //if-match
|
|
||||||
else
|
|
||||||
i = 41; //if-range
|
|
||||||
break;
|
|
||||||
case 13:
|
|
||||||
i = 40; //if-none-match
|
|
||||||
break;
|
|
||||||
case 17:
|
|
||||||
i = 39; //if-modified-since
|
|
||||||
break;
|
|
||||||
case 19:
|
|
||||||
i = 42; //if-unmodified-since
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'l':
|
|
||||||
switch (name_len)
|
|
||||||
{
|
|
||||||
case 4:
|
|
||||||
i = 44; //link
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
i = 45; //location
|
|
||||||
break;
|
|
||||||
case 13:
|
|
||||||
i = 43; //last-modified
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'm':
|
|
||||||
i = 46; //max-forwards
|
|
||||||
break;
|
|
||||||
case 'p':
|
|
||||||
if (name_len == 18)
|
|
||||||
i = 47; //proxy-authenticate
|
|
||||||
else
|
|
||||||
i = 48; //proxy-authorization
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
if (name_len >= 5)
|
|
||||||
{
|
|
||||||
switch (*(name + 4))
|
|
||||||
{
|
|
||||||
case 'e':
|
|
||||||
if (name_len == 5)
|
|
||||||
i = 49; //range
|
|
||||||
else
|
|
||||||
i = 51; //refresh
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
i = 50; //referer
|
|
||||||
break;
|
|
||||||
case 'y':
|
|
||||||
i = 52; //retry-after
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
switch (name_len)
|
|
||||||
{
|
|
||||||
case 6:
|
|
||||||
i = 53; //server
|
|
||||||
break;
|
|
||||||
case 10:
|
|
||||||
i = 54; //set-cookie
|
|
||||||
break;
|
|
||||||
case 25:
|
|
||||||
i = 55; //strict-transport-security
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
i = 56;//transfer-encoding
|
|
||||||
break;
|
|
||||||
case 'u':
|
|
||||||
i = 57; //user-agent
|
|
||||||
break;
|
|
||||||
case 'v':
|
|
||||||
if (name_len == 4)
|
|
||||||
i = 58;
|
|
||||||
else
|
|
||||||
i = 59;
|
|
||||||
break;
|
|
||||||
case 'w':
|
|
||||||
i = 60;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i >= 0
|
|
||||||
&& lsquic_hpack_stx_tab[i].name_len == name_len
|
|
||||||
&& memcmp(name, lsquic_hpack_stx_tab[i].name, name_len) == 0)
|
|
||||||
return i + 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Given a dynamic entry, return its table ID */
|
|
||||||
static unsigned
|
|
||||||
henc_calc_table_id (const struct lsquic_henc *enc,
|
|
||||||
const struct enc_table_entry *entry)
|
|
||||||
{
|
|
||||||
return HPACK_STATIC_TABLE_SIZE
|
|
||||||
+ (enc->hpe_next_id - entry->ete_id)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static unsigned
|
|
||||||
henc_find_table_id (struct lsquic_henc *enc, const char *name,
|
|
||||||
hpack_strlen_t name_len, const char *value, hpack_strlen_t value_len,
|
|
||||||
int *val_matched)
|
|
||||||
{
|
|
||||||
struct enc_table_entry *entry;
|
|
||||||
unsigned name_hash, nameval_hash, buckno, static_table_id;
|
|
||||||
XXH32_state_t hash_state;
|
|
||||||
|
|
||||||
/* First, look for a match in the static table: */
|
|
||||||
static_table_id = lsquic_henc_get_stx_tab_id(name, name_len, value,
|
|
||||||
value_len, val_matched);
|
|
||||||
if (static_table_id > 0 && *val_matched)
|
|
||||||
return static_table_id;
|
|
||||||
|
|
||||||
/* Search by name and value: */
|
|
||||||
XXH32_reset(&hash_state, (uintptr_t) enc);
|
|
||||||
XXH32_update(&hash_state, &name_len, sizeof(name_len));
|
|
||||||
XXH32_update(&hash_state, name, name_len);
|
|
||||||
name_hash = XXH32_digest(&hash_state);
|
|
||||||
XXH32_update(&hash_state, &value_len, sizeof(value_len));
|
|
||||||
XXH32_update(&hash_state, value, value_len);
|
|
||||||
nameval_hash = XXH32_digest(&hash_state);
|
|
||||||
buckno = BUCKNO(enc->hpe_nbits, nameval_hash);
|
|
||||||
STAILQ_FOREACH(entry, &enc->hpe_buckets[buckno].by_nameval, ete_next_nameval)
|
|
||||||
if (nameval_hash == entry->ete_nameval_hash &&
|
|
||||||
name_len == entry->ete_name_len &&
|
|
||||||
value_len == entry->ete_val_len &&
|
|
||||||
0 == memcmp(name, ETE_NAME(entry), name_len) &&
|
|
||||||
0 == memcmp(value, ETE_VALUE(entry), value_len))
|
|
||||||
{
|
|
||||||
*val_matched = 1;
|
|
||||||
return henc_calc_table_id(enc, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Name/value match is not found, but if the caller found a matching
|
|
||||||
* static table entry, no need to continue to search:
|
|
||||||
*/
|
|
||||||
if (static_table_id > 0)
|
|
||||||
return static_table_id;
|
|
||||||
|
|
||||||
/* Search by name only: */
|
|
||||||
buckno = BUCKNO(enc->hpe_nbits, name_hash);
|
|
||||||
STAILQ_FOREACH(entry, &enc->hpe_buckets[buckno].by_name, ete_next_name)
|
|
||||||
if (name_hash == entry->ete_name_hash &&
|
|
||||||
name_len == entry->ete_name_len &&
|
|
||||||
0 == memcmp(name, ETE_NAME(entry), name_len))
|
|
||||||
{
|
|
||||||
*val_matched = 0;
|
|
||||||
return henc_calc_table_id(enc, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////https://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#section-5.1
|
|
||||||
static unsigned char *
|
|
||||||
henc_enc_int (unsigned char *dst, unsigned char *const end, uint32_t value,
|
|
||||||
uint8_t prefix_bits)
|
|
||||||
{
|
|
||||||
unsigned char *const dst_orig = dst;
|
|
||||||
|
|
||||||
/* This function assumes that at least one byte is available */
|
|
||||||
assert(dst < end);
|
|
||||||
if (value < (uint32_t)(1 << prefix_bits) - 1)
|
|
||||||
*dst++ |= value;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*dst++ |= (1 << prefix_bits) - 1;
|
|
||||||
value -= (1 << prefix_bits) - 1;
|
|
||||||
while (value >= 128)
|
|
||||||
{
|
|
||||||
if (dst < end)
|
|
||||||
{
|
|
||||||
*dst++ = (0x80 | value);
|
|
||||||
value >>= 7;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return dst_orig;
|
|
||||||
}
|
|
||||||
if (dst < end)
|
|
||||||
*dst++ = value;
|
|
||||||
else
|
|
||||||
return dst_orig;
|
|
||||||
}
|
|
||||||
return dst;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef NDEBUG
|
|
||||||
static
|
|
||||||
#endif
|
|
||||||
int
|
|
||||||
henc_huffman_enc (const unsigned char *src, const unsigned char *const src_end,
|
|
||||||
unsigned char *dst, int dst_len)
|
|
||||||
{
|
|
||||||
const unsigned char *p_src = src;
|
|
||||||
unsigned char *p_dst = dst;
|
|
||||||
unsigned char *dst_end = p_dst + dst_len;
|
|
||||||
uint64_t bits = 0;
|
|
||||||
int bits_left = 40;
|
|
||||||
hpack_huff_encode_t cur_enc_code;
|
|
||||||
|
|
||||||
assert(dst_len > 0);
|
|
||||||
|
|
||||||
while (p_src != src_end)
|
|
||||||
{
|
|
||||||
cur_enc_code = lsquic_hpack_huff_encode_tables[(int) *p_src++];
|
|
||||||
assert(bits_left >= cur_enc_code.bits); // (possible negative shift, undefined behavior)
|
|
||||||
bits |= (uint64_t)cur_enc_code.code << (bits_left - cur_enc_code.bits);
|
|
||||||
bits_left -= cur_enc_code.bits;
|
|
||||||
while (bits_left <= 32)
|
|
||||||
{
|
|
||||||
*p_dst++ = bits >> 32;
|
|
||||||
bits <<= 8;
|
|
||||||
bits_left += 8;
|
|
||||||
if (p_dst == dst_end)
|
|
||||||
return -1; //dst does not have enough space
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bits_left != 40)
|
|
||||||
{
|
|
||||||
assert(bits_left < 40 && bits_left > 0);
|
|
||||||
bits |= ((uint64_t)1 << bits_left) - 1;
|
|
||||||
*p_dst++ = bits >> 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
return p_dst - dst;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef NDEBUG
|
|
||||||
static
|
|
||||||
#endif
|
|
||||||
int
|
|
||||||
lsquic_henc_enc_str (unsigned char *const dst, size_t dst_len,
|
|
||||||
const unsigned char *str, hpack_strlen_t str_len)
|
|
||||||
{
|
|
||||||
unsigned char size_buf[4];
|
|
||||||
unsigned char *p;
|
|
||||||
unsigned size_len;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (dst_len > 1)
|
|
||||||
/* We guess that the string size fits into a single byte -- meaning
|
|
||||||
* compressed string of size 126 and smaller -- which is the normal
|
|
||||||
* case. Thus, we immediately write compressed string to the output
|
|
||||||
* buffer. If our guess is not correct, we fix it later.
|
|
||||||
*/
|
|
||||||
rc = henc_huffman_enc(str, str + str_len, dst + 1, dst_len - 1);
|
|
||||||
else if (dst_len == 1)
|
|
||||||
/* Here, the call can only succeed if the string to encode is empty. */
|
|
||||||
rc = 0;
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if need huffman encoding or not
|
|
||||||
* Comment: (size_t)rc <= str_len = means if same length, still use Huffman
|
|
||||||
* ^
|
|
||||||
*/
|
|
||||||
if (rc > 0 && (size_t)rc <= str_len)
|
|
||||||
{
|
|
||||||
if (rc < 127)
|
|
||||||
{
|
|
||||||
*dst = 0x80 | rc;
|
|
||||||
return 1 + rc;
|
|
||||||
}
|
|
||||||
size_buf[0] = 0x80;
|
|
||||||
str_len = rc;
|
|
||||||
str = dst + 1;
|
|
||||||
}
|
|
||||||
else if (str_len <= dst_len - 1)
|
|
||||||
{
|
|
||||||
if (str_len < 127)
|
|
||||||
{
|
|
||||||
*dst = str_len;
|
|
||||||
memcpy(dst + 1, str, str_len);
|
|
||||||
return 1 + str_len;
|
|
||||||
}
|
|
||||||
size_buf[0] = 0x00;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* The guess of one-byte size was incorrect. Perform necessary
|
|
||||||
* adjustments.
|
|
||||||
*/
|
|
||||||
p = henc_enc_int(size_buf, size_buf + sizeof(size_buf), str_len, 7);
|
|
||||||
if (p == size_buf)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
size_len = p - size_buf;
|
|
||||||
assert(size_len > 1);
|
|
||||||
|
|
||||||
/* Check if there is enough room in the output buffer for both
|
|
||||||
* encoded size and the string.
|
|
||||||
*/
|
|
||||||
if (size_len + str_len > dst_len)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
memmove(dst + size_len, str, str_len);
|
|
||||||
memcpy(dst, size_buf, size_len);
|
|
||||||
return size_len + str_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
henc_drop_oldest_entry (struct lsquic_henc *enc)
|
|
||||||
{
|
|
||||||
struct enc_table_entry *entry;
|
|
||||||
unsigned buckno;
|
|
||||||
|
|
||||||
entry = STAILQ_FIRST(&enc->hpe_all_entries);
|
|
||||||
assert(entry);
|
|
||||||
STAILQ_REMOVE_HEAD(&enc->hpe_all_entries, ete_next_all);
|
|
||||||
buckno = BUCKNO(enc->hpe_nbits, entry->ete_nameval_hash);
|
|
||||||
assert(entry == STAILQ_FIRST(&enc->hpe_buckets[buckno].by_nameval));
|
|
||||||
STAILQ_REMOVE_HEAD(&enc->hpe_buckets[buckno].by_nameval, ete_next_nameval);
|
|
||||||
buckno = BUCKNO(enc->hpe_nbits, entry->ete_name_hash);
|
|
||||||
assert(entry == STAILQ_FIRST(&enc->hpe_buckets[buckno].by_name));
|
|
||||||
STAILQ_REMOVE_HEAD(&enc->hpe_buckets[buckno].by_name, ete_next_name);
|
|
||||||
|
|
||||||
enc->hpe_cur_capacity -= DYNAMIC_ENTRY_OVERHEAD + entry->ete_name_len
|
|
||||||
+ entry->ete_val_len;
|
|
||||||
--enc->hpe_nelem;
|
|
||||||
free(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
henc_remove_overflow_entries (struct lsquic_henc *enc)
|
|
||||||
{
|
|
||||||
while (enc->hpe_cur_capacity > enc->hpe_max_capacity)
|
|
||||||
henc_drop_oldest_entry(enc);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
henc_grow_tables (struct lsquic_henc *enc)
|
|
||||||
{
|
|
||||||
struct double_enc_head *new_buckets, *new[2];
|
|
||||||
struct enc_table_entry *entry;
|
|
||||||
unsigned n, old_nbits;
|
|
||||||
int idx;
|
|
||||||
|
|
||||||
old_nbits = enc->hpe_nbits;
|
|
||||||
new_buckets = malloc(sizeof(enc->hpe_buckets[0])
|
|
||||||
* N_BUCKETS(old_nbits + 1));
|
|
||||||
if (!new_buckets)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
for (n = 0; n < N_BUCKETS(old_nbits); ++n)
|
|
||||||
{
|
|
||||||
new[0] = &new_buckets[n];
|
|
||||||
new[1] = &new_buckets[n + N_BUCKETS(old_nbits)];
|
|
||||||
STAILQ_INIT(&new[0]->by_name);
|
|
||||||
STAILQ_INIT(&new[1]->by_name);
|
|
||||||
STAILQ_INIT(&new[0]->by_nameval);
|
|
||||||
STAILQ_INIT(&new[1]->by_nameval);
|
|
||||||
while ((entry = STAILQ_FIRST(&enc->hpe_buckets[n].by_name)))
|
|
||||||
{
|
|
||||||
STAILQ_REMOVE_HEAD(&enc->hpe_buckets[n].by_name, ete_next_name);
|
|
||||||
idx = (BUCKNO(old_nbits + 1, entry->ete_name_hash) >> old_nbits) & 1;
|
|
||||||
STAILQ_INSERT_TAIL(&new[idx]->by_name, entry, ete_next_name);
|
|
||||||
}
|
|
||||||
while ((entry = STAILQ_FIRST(&enc->hpe_buckets[n].by_nameval)))
|
|
||||||
{
|
|
||||||
STAILQ_REMOVE_HEAD(&enc->hpe_buckets[n].by_nameval, ete_next_nameval);
|
|
||||||
idx = (BUCKNO(old_nbits + 1, entry->ete_nameval_hash) >> old_nbits) & 1;
|
|
||||||
STAILQ_INSERT_TAIL(&new[idx]->by_nameval, entry, ete_next_nameval);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(enc->hpe_buckets);
|
|
||||||
enc->hpe_nbits = old_nbits + 1;
|
|
||||||
enc->hpe_buckets = new_buckets;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef NDEBUG
|
|
||||||
static
|
|
||||||
#endif
|
|
||||||
int
|
|
||||||
lsquic_henc_push_entry (struct lsquic_henc *enc, const char *name,
|
|
||||||
hpack_strlen_t name_len, const char *value,
|
|
||||||
hpack_strlen_t value_len)
|
|
||||||
{
|
|
||||||
unsigned name_hash, nameval_hash, buckno;
|
|
||||||
struct enc_table_entry *entry;
|
|
||||||
XXH32_state_t hash_state;
|
|
||||||
size_t size;
|
|
||||||
|
|
||||||
if (enc->hpe_nelem >= N_BUCKETS(enc->hpe_nbits) / 2 &&
|
|
||||||
0 != henc_grow_tables(enc))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
size = sizeof(*entry) + name_len + value_len;
|
|
||||||
entry = malloc(size);
|
|
||||||
if (!entry)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
XXH32_reset(&hash_state, (uintptr_t) enc);
|
|
||||||
XXH32_update(&hash_state, &name_len, sizeof(name_len));
|
|
||||||
XXH32_update(&hash_state, name, name_len);
|
|
||||||
name_hash = XXH32_digest(&hash_state);
|
|
||||||
XXH32_update(&hash_state, &value_len, sizeof(value_len));
|
|
||||||
XXH32_update(&hash_state, value, value_len);
|
|
||||||
nameval_hash = XXH32_digest(&hash_state);
|
|
||||||
|
|
||||||
entry->ete_name_hash = name_hash;
|
|
||||||
entry->ete_nameval_hash = nameval_hash;
|
|
||||||
entry->ete_name_len = name_len;
|
|
||||||
entry->ete_val_len = value_len;
|
|
||||||
entry->ete_id = enc->hpe_next_id++;
|
|
||||||
memcpy(ETE_NAME(entry), name, name_len);
|
|
||||||
memcpy(ETE_VALUE(entry), value, value_len);
|
|
||||||
|
|
||||||
STAILQ_INSERT_TAIL(&enc->hpe_all_entries, entry, ete_next_all);
|
|
||||||
buckno = BUCKNO(enc->hpe_nbits, nameval_hash);
|
|
||||||
STAILQ_INSERT_TAIL(&enc->hpe_buckets[buckno].by_nameval, entry, ete_next_nameval);
|
|
||||||
buckno = BUCKNO(enc->hpe_nbits, name_hash);
|
|
||||||
STAILQ_INSERT_TAIL(&enc->hpe_buckets[buckno].by_name, entry, ete_next_name);
|
|
||||||
|
|
||||||
enc->hpe_cur_capacity += DYNAMIC_ENTRY_OVERHEAD + name_len + value_len;
|
|
||||||
++enc->hpe_nelem;
|
|
||||||
henc_remove_overflow_entries(enc);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
unsigned char *
|
|
||||||
lsquic_henc_encode (struct lsquic_henc *enc, unsigned char *dst,
|
|
||||||
unsigned char *dst_end, const char *name, hpack_strlen_t name_len,
|
|
||||||
const char *value, hpack_strlen_t value_len, int indexed_type)
|
|
||||||
{
|
|
||||||
//indexed_type: 0, Add, 1,: without, 2: never
|
|
||||||
static const char indexed_prefix_number[] = {0x40, 0x00, 0x10};
|
|
||||||
unsigned char *const dst_org = dst;
|
|
||||||
int val_matched, rc;
|
|
||||||
unsigned table_id;
|
|
||||||
|
|
||||||
assert(indexed_type >= 0 && indexed_type <= 2);
|
|
||||||
|
|
||||||
if (dst_end <= dst)
|
|
||||||
return dst_org;
|
|
||||||
|
|
||||||
table_id = henc_find_table_id(enc, name, name_len, value, value_len,
|
|
||||||
&val_matched);
|
|
||||||
if (table_id > 0)
|
|
||||||
{
|
|
||||||
if (val_matched)
|
|
||||||
{
|
|
||||||
*dst = 0x80;
|
|
||||||
dst = henc_enc_int(dst, dst_end, table_id, 7);
|
|
||||||
/* No need to check return value: we pass it up as-is because
|
|
||||||
* the behavior is the same.
|
|
||||||
*/
|
|
||||||
return dst;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*dst = indexed_prefix_number[indexed_type];
|
|
||||||
dst = henc_enc_int(dst, dst_end, table_id, ((indexed_type == 0) ? 6 : 4));
|
|
||||||
if (dst == dst_org)
|
|
||||||
return dst_org;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*dst++ = indexed_prefix_number[indexed_type];
|
|
||||||
rc = lsquic_henc_enc_str(dst, dst_end - dst, (const unsigned char *)name, name_len);
|
|
||||||
if (rc < 0)
|
|
||||||
return dst_org; //Failed to enc this header, return unchanged ptr.
|
|
||||||
dst += rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = lsquic_henc_enc_str(dst, dst_end - dst, (const unsigned char *)value, value_len);
|
|
||||||
if (rc < 0)
|
|
||||||
return dst_org; //Failed to enc this header, return unchanged ptr.
|
|
||||||
dst += rc;
|
|
||||||
|
|
||||||
if (indexed_type == 0)
|
|
||||||
{
|
|
||||||
rc = lsquic_henc_push_entry(enc, name, name_len, value, value_len);
|
|
||||||
if (rc != 0)
|
|
||||||
return dst_org; //Failed to enc this header, return unchanged ptr.
|
|
||||||
}
|
|
||||||
|
|
||||||
return dst;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
lsquic_henc_set_max_capacity (struct lsquic_henc *enc, unsigned max_capacity)
|
|
||||||
{
|
|
||||||
enc->hpe_max_capacity = max_capacity;
|
|
||||||
henc_remove_overflow_entries(enc);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
void
|
|
||||||
lsquic_henc_iter_reset (struct lsquic_henc *enc)
|
|
||||||
{
|
|
||||||
enc->hpe_iter = STAILQ_FIRST(&enc->hpe_all_entries);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Returns 0 if entry is found */
|
|
||||||
int
|
|
||||||
lsquic_henc_iter_next (struct lsquic_henc *enc,
|
|
||||||
struct enc_dyn_table_entry *retval)
|
|
||||||
{
|
|
||||||
const struct enc_table_entry *entry;
|
|
||||||
|
|
||||||
entry = enc->hpe_iter;
|
|
||||||
if (!entry)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
enc->hpe_iter = STAILQ_NEXT(entry, ete_next_all);
|
|
||||||
|
|
||||||
retval->name = ETE_NAME(entry);
|
|
||||||
retval->value = ETE_VALUE(entry);
|
|
||||||
retval->name_len = entry->ete_name_len;
|
|
||||||
retval->value_len = entry->ete_val_len;
|
|
||||||
retval->entry_id = henc_calc_table_id(enc, entry);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
size_t
|
|
||||||
lsquic_henc_mem_used (const struct lsquic_henc *enc)
|
|
||||||
{
|
|
||||||
const struct enc_table_entry *entry;
|
|
||||||
size_t size;
|
|
||||||
|
|
||||||
size = sizeof(*enc);
|
|
||||||
|
|
||||||
STAILQ_FOREACH(entry, &enc->hpe_all_entries, ete_next_all)
|
|
||||||
size += sizeof(*entry) + entry->ete_name_len + entry->ete_val_len;
|
|
||||||
|
|
||||||
size += N_BUCKETS(enc->hpe_nbits) * sizeof(enc->hpe_buckets[0]);
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
|
@ -1,107 +0,0 @@
|
||||||
/* Copyright (c) 2017 - 2018 LiteSpeed Technologies Inc. See LICENSE. */
|
|
||||||
/*
|
|
||||||
* lsquic_hpack_enc.h - HPACK encoder
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LSQUIC_HPACK_ENC_H
|
|
||||||
#define LSQUIC_HPACK_ENC_H 1
|
|
||||||
|
|
||||||
#include "lsquic_hpack_types.h"
|
|
||||||
|
|
||||||
struct enc_table_entry;
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
struct enc_dyn_table_entry
|
|
||||||
{
|
|
||||||
const char *name, /* Not NUL-terminated */
|
|
||||||
*value; /* Not NUL-terminated */
|
|
||||||
unsigned name_len,
|
|
||||||
value_len;
|
|
||||||
unsigned entry_id;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
STAILQ_HEAD(enc_head, enc_table_entry);
|
|
||||||
struct double_enc_head;
|
|
||||||
|
|
||||||
struct lsquic_henc
|
|
||||||
{
|
|
||||||
unsigned hpe_cur_capacity;
|
|
||||||
unsigned hpe_max_capacity;
|
|
||||||
|
|
||||||
/* Each new dynamic table entry gets the next number. It is used to
|
|
||||||
* calculate the entry's position in the decoder table without having
|
|
||||||
* to maintain an actual array.
|
|
||||||
*/
|
|
||||||
unsigned hpe_next_id;
|
|
||||||
|
|
||||||
/* Dynamic table entries (struct enc_table_entry) live in two hash
|
|
||||||
* tables: name/value hash table and name hash table. These tables
|
|
||||||
* are the same size.
|
|
||||||
*/
|
|
||||||
unsigned hpe_nelem;
|
|
||||||
unsigned hpe_nbits;
|
|
||||||
struct enc_head hpe_all_entries;
|
|
||||||
struct double_enc_head
|
|
||||||
*hpe_buckets;
|
|
||||||
#ifndef NDEBUG
|
|
||||||
const struct enc_table_entry
|
|
||||||
*hpe_iter;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* Initialization routine allocates memory. -1 is returned if memory
|
|
||||||
* could not be allocated. 0 is returned on success.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
lsquic_henc_init (struct lsquic_henc *);
|
|
||||||
|
|
||||||
void
|
|
||||||
lsquic_henc_cleanup (struct lsquic_henc *);
|
|
||||||
|
|
||||||
/** @lsquic_hpack_encode
|
|
||||||
* @brief HPACK encode one name/value item
|
|
||||||
* @param[in,out] henc - A pointer to a valid HPACK API struct
|
|
||||||
* @param[out] dst - A pointer to destination buffer
|
|
||||||
* @param[out] dst_end - A pointer to end of destination buffer
|
|
||||||
* @param[in] name - A pointer to the item name
|
|
||||||
* @param[in] name_len - The item name's length
|
|
||||||
* @param[in] value - A pointer to the item value
|
|
||||||
* @param[in] value_len - The item value's length
|
|
||||||
* @param[in] indexed_type - 0, Add, 1,: without, 2: never
|
|
||||||
* @return The (possibly advanced) dst pointer
|
|
||||||
*/
|
|
||||||
unsigned char *
|
|
||||||
lsquic_henc_encode (struct lsquic_henc *henc, unsigned char *dst,
|
|
||||||
unsigned char *dst_end, const char *name, hpack_strlen_t name_len,
|
|
||||||
const char *value, hpack_strlen_t value_len, int indexed_type);
|
|
||||||
|
|
||||||
void
|
|
||||||
lsquic_henc_set_max_capacity (struct lsquic_henc *, unsigned);
|
|
||||||
|
|
||||||
size_t
|
|
||||||
lsquic_henc_mem_used (const struct lsquic_henc *);
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
unsigned
|
|
||||||
lsquic_henc_get_stx_tab_id (const char *name, hpack_strlen_t name_len,
|
|
||||||
const char *val, hpack_strlen_t val_len, int *val_matched);
|
|
||||||
|
|
||||||
int
|
|
||||||
lsquic_henc_push_entry (struct lsquic_henc *enc, const char *name,
|
|
||||||
hpack_strlen_t name_len, const char *value, hpack_strlen_t value_len);
|
|
||||||
|
|
||||||
int
|
|
||||||
lsquic_henc_enc_str (unsigned char *const dst, size_t dst_len,
|
|
||||||
const unsigned char *str, hpack_strlen_t str_len);
|
|
||||||
|
|
||||||
void
|
|
||||||
lsquic_henc_iter_reset (struct lsquic_henc *enc);
|
|
||||||
|
|
||||||
/* Returns 0 if entry is found */
|
|
||||||
int
|
|
||||||
lsquic_henc_iter_next (struct lsquic_henc *enc, struct enc_dyn_table_entry *);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,10 +0,0 @@
|
||||||
/* Copyright (c) 2017 - 2018 LiteSpeed Technologies Inc. See LICENSE. */
|
|
||||||
#ifndef LSQUIC_HPACK_TYPES_H
|
|
||||||
#define LSQUIC_HPACK_TYPES_H 1
|
|
||||||
|
|
||||||
typedef uint16_t hpack_strlen_t;
|
|
||||||
|
|
||||||
#define HPACK_MAX_STRLEN (((1 << (sizeof(hpack_strlen_t) * 8 - 1)) | \
|
|
||||||
(((1 << (sizeof(hpack_strlen_t) * 8 - 1)) - 1))))
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -586,16 +586,6 @@ lsquic_stream_rst_in (lsquic_stream_t *stream, uint64_t offset,
|
||||||
*/
|
*/
|
||||||
stream->stream_flags |= STREAM_RST_RECVD;
|
stream->stream_flags |= STREAM_RST_RECVD;
|
||||||
|
|
||||||
if ((stream->stream_flags & STREAM_FIN_RECVD) &&
|
|
||||||
/* Pushed streams have fake STREAM_FIN_RECVD set, thus
|
|
||||||
* we need a special check:
|
|
||||||
*/
|
|
||||||
!lsquic_stream_is_pushed(stream))
|
|
||||||
{
|
|
||||||
LSQ_DEBUG("ignore RST_STREAM frame after FIN is received");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lsquic_sfcw_get_max_recv_off(&stream->fc) > offset)
|
if (lsquic_sfcw_get_max_recv_off(&stream->fc) > offset)
|
||||||
{
|
{
|
||||||
LSQ_INFO("stream %u: RST_STREAM invalid: its offset 0x%"PRIX64" is "
|
LSQ_INFO("stream %u: RST_STREAM invalid: its offset 0x%"PRIX64" is "
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
include_directories( BEFORE ../../ssl/include )
|
include_directories( BEFORE ../../ssl/include )
|
||||||
include_directories( ../../include )
|
include_directories( ../../include )
|
||||||
include_directories( ../../src/liblsquic )
|
include_directories( ../../src/liblsquic )
|
||||||
|
include_directories( ../../src/liblsquic/ls-hpack/include )
|
||||||
|
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
|
||||||
|
@ -210,10 +211,6 @@ IF (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||||
add_test(frame_rw test_frame_rw)
|
add_test(frame_rw test_frame_rw)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
add_executable(test_hpack test_hpack.c)
|
|
||||||
target_link_libraries(test_hpack lsquic m ${FIULIB})
|
|
||||||
add_test(hpack test_hpack)
|
|
||||||
|
|
||||||
add_executable(test_hkdf test_hkdf.c)
|
add_executable(test_hkdf test_hkdf.c)
|
||||||
target_link_libraries(test_hkdf lsquic pthread libssl.a libcrypto.a m ${FIULIB})
|
target_link_libraries(test_hkdf lsquic pthread libssl.a libcrypto.a m ${FIULIB})
|
||||||
add_test(hkdf test_hkdf)
|
add_test(hkdf test_hkdf)
|
||||||
|
@ -443,10 +440,6 @@ add_executable(test_frame_chop test_frame_chop.c ../../wincompat/getopt.c ../../
|
||||||
target_link_libraries(test_frame_chop lsquic ${LIBS_LIST})
|
target_link_libraries(test_frame_chop lsquic ${LIBS_LIST})
|
||||||
add_test(frame_chop test_frame_chop)
|
add_test(frame_chop test_frame_chop)
|
||||||
|
|
||||||
add_executable(test_hpack test_hpack.c)
|
|
||||||
target_link_libraries(test_hpack lsquic ${MIN_LIBS_LIST})
|
|
||||||
add_test(hpack test_hpack)
|
|
||||||
|
|
||||||
add_executable(test_hkdf test_hkdf.c)
|
add_executable(test_hkdf test_hkdf.c)
|
||||||
target_link_libraries(test_hkdf lsquic ${LIBS_LIST})
|
target_link_libraries(test_hkdf lsquic ${LIBS_LIST})
|
||||||
add_test(hkdf test_hkdf)
|
add_test(hkdf test_hkdf)
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include <sys/queue.h>
|
#include <sys/queue.h>
|
||||||
|
|
||||||
#include "lsquic.h"
|
#include "lsquic.h"
|
||||||
#include "lsquic_hpack_enc.h"
|
#include "lshpack.h"
|
||||||
#include "lsquic_logger.h"
|
#include "lsquic_logger.h"
|
||||||
#include "lsquic_mm.h"
|
#include "lsquic_mm.h"
|
||||||
#include "lsquic_frame_common.h"
|
#include "lsquic_frame_common.h"
|
||||||
|
@ -95,11 +95,11 @@ test_chop (unsigned max_write_sz)
|
||||||
struct lsquic_frame_writer *fw;
|
struct lsquic_frame_writer *fw;
|
||||||
struct lsquic_stream *stream;
|
struct lsquic_stream *stream;
|
||||||
struct lsquic_mm mm;
|
struct lsquic_mm mm;
|
||||||
struct lsquic_henc henc;
|
struct lshpack_enc henc;
|
||||||
int s;
|
int s;
|
||||||
|
|
||||||
lsquic_mm_init(&mm);
|
lsquic_mm_init(&mm);
|
||||||
lsquic_henc_init(&henc);
|
lshpack_enc_init(&henc);
|
||||||
stream = stream_new(max_write_sz);
|
stream = stream_new(max_write_sz);
|
||||||
|
|
||||||
fw = lsquic_frame_writer_new(&mm, stream, 0, &henc, stream_write, 0);
|
fw = lsquic_frame_writer_new(&mm, stream, 0, &henc, stream_write, 0);
|
||||||
|
@ -161,7 +161,7 @@ test_chop (unsigned max_write_sz)
|
||||||
|
|
||||||
lsquic_frame_writer_destroy(fw);
|
lsquic_frame_writer_destroy(fw);
|
||||||
stream_destroy(stream);
|
stream_destroy(stream);
|
||||||
lsquic_henc_cleanup(&henc);
|
lshpack_enc_cleanup(&henc);
|
||||||
lsquic_mm_cleanup(&mm);
|
lsquic_mm_cleanup(&mm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,7 @@
|
||||||
|
|
||||||
#include "lsquic.h"
|
#include "lsquic.h"
|
||||||
#include "lsquic_frame_common.h"
|
#include "lsquic_frame_common.h"
|
||||||
#include "lsquic_arr.h"
|
#include "lshpack.h"
|
||||||
#include "lsquic_hpack_dec.h"
|
|
||||||
#include "lsquic_mm.h"
|
#include "lsquic_mm.h"
|
||||||
#include "lsquic_logger.h"
|
#include "lsquic_logger.h"
|
||||||
|
|
||||||
|
@ -1063,12 +1062,12 @@ test_one_frt (const struct frame_reader_test *frt)
|
||||||
{
|
{
|
||||||
struct lsquic_frame_reader *fr;
|
struct lsquic_frame_reader *fr;
|
||||||
unsigned short exp_off;
|
unsigned short exp_off;
|
||||||
struct lsquic_hdec hdec;
|
struct lshpack_dec hdec;
|
||||||
struct lsquic_mm mm;
|
struct lsquic_mm mm;
|
||||||
int s;
|
int s;
|
||||||
|
|
||||||
lsquic_mm_init(&mm);
|
lsquic_mm_init(&mm);
|
||||||
lsquic_hdec_init(&hdec);
|
lshpack_dec_init(&hdec);
|
||||||
memset(&input, 0, sizeof(input));
|
memset(&input, 0, sizeof(input));
|
||||||
memcpy(input.in_buf, frt->frt_buf, frt->frt_bufsz);
|
memcpy(input.in_buf, frt->frt_buf, frt->frt_bufsz);
|
||||||
input.in_sz = frt->frt_bufsz;
|
input.in_sz = frt->frt_bufsz;
|
||||||
|
@ -1105,7 +1104,7 @@ test_one_frt (const struct frame_reader_test *frt)
|
||||||
lsquic_frame_reader_destroy(fr);
|
lsquic_frame_reader_destroy(fr);
|
||||||
}
|
}
|
||||||
while (input.in_max_sz < input.in_max_req_sz);
|
while (input.in_max_sz < input.in_max_req_sz);
|
||||||
lsquic_hdec_cleanup(&hdec);
|
lshpack_dec_cleanup(&hdec);
|
||||||
lsquic_mm_cleanup(&mm);
|
lsquic_mm_cleanup(&mm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,9 +21,7 @@
|
||||||
#include <sys/queue.h>
|
#include <sys/queue.h>
|
||||||
|
|
||||||
#include "lsquic.h"
|
#include "lsquic.h"
|
||||||
#include "lsquic_arr.h"
|
#include "lshpack.h"
|
||||||
#include "lsquic_hpack_enc.h"
|
|
||||||
#include "lsquic_hpack_dec.h"
|
|
||||||
#include "lsquic_logger.h"
|
#include "lsquic_logger.h"
|
||||||
#include "lsquic_mm.h"
|
#include "lsquic_mm.h"
|
||||||
#include "lsquic_frame_common.h"
|
#include "lsquic_frame_common.h"
|
||||||
|
@ -186,13 +184,13 @@ test_rw (unsigned max_frame_sz)
|
||||||
struct lsquic_stream *stream;
|
struct lsquic_stream *stream;
|
||||||
struct uncompressed_headers *uh;
|
struct uncompressed_headers *uh;
|
||||||
struct lsquic_mm mm;
|
struct lsquic_mm mm;
|
||||||
struct lsquic_henc henc;
|
struct lshpack_enc henc;
|
||||||
struct lsquic_hdec hdec;
|
struct lshpack_dec hdec;
|
||||||
int s;
|
int s;
|
||||||
|
|
||||||
lsquic_mm_init(&mm);
|
lsquic_mm_init(&mm);
|
||||||
lsquic_henc_init(&henc);
|
lshpack_enc_init(&henc);
|
||||||
lsquic_hdec_init(&hdec);
|
lshpack_dec_init(&hdec);
|
||||||
stream = stream_new();
|
stream = stream_new();
|
||||||
stream->sm_max_sz = 1;
|
stream->sm_max_sz = 1;
|
||||||
|
|
||||||
|
@ -236,8 +234,8 @@ test_rw (unsigned max_frame_sz)
|
||||||
|
|
||||||
lsquic_frame_writer_destroy(fw);
|
lsquic_frame_writer_destroy(fw);
|
||||||
stream_destroy(stream);
|
stream_destroy(stream);
|
||||||
lsquic_henc_cleanup(&henc);
|
lshpack_enc_cleanup(&henc);
|
||||||
lsquic_hdec_cleanup(&hdec);
|
lshpack_dec_cleanup(&hdec);
|
||||||
lsquic_mm_cleanup(&mm);
|
lsquic_mm_cleanup(&mm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#include <sys/queue.h>
|
#include <sys/queue.h>
|
||||||
|
|
||||||
#include "lsquic.h"
|
#include "lsquic.h"
|
||||||
#include "lsquic_hpack_enc.h"
|
#include "lshpack.h"
|
||||||
#include "lsquic_mm.h"
|
#include "lsquic_mm.h"
|
||||||
#include "lsquic_frame_common.h"
|
#include "lsquic_frame_common.h"
|
||||||
#include "lsquic_frame_writer.h"
|
#include "lsquic_frame_writer.h"
|
||||||
|
@ -54,12 +54,12 @@ output_write (struct lsquic_stream *stream, const void *buf, size_t sz)
|
||||||
static void
|
static void
|
||||||
test_max_frame_size (void)
|
test_max_frame_size (void)
|
||||||
{
|
{
|
||||||
struct lsquic_henc henc;
|
struct lshpack_enc henc;
|
||||||
struct lsquic_mm mm;
|
struct lsquic_mm mm;
|
||||||
struct lsquic_frame_writer *fw;
|
struct lsquic_frame_writer *fw;
|
||||||
unsigned max_size;
|
unsigned max_size;
|
||||||
|
|
||||||
lsquic_henc_init(&henc);
|
lshpack_enc_init(&henc);
|
||||||
lsquic_mm_init(&mm);
|
lsquic_mm_init(&mm);
|
||||||
|
|
||||||
for (max_size = 1; max_size < 6 /* one settings frame */; ++max_size)
|
for (max_size = 1; max_size < 6 /* one settings frame */; ++max_size)
|
||||||
|
@ -73,7 +73,7 @@ test_max_frame_size (void)
|
||||||
assert(fw);
|
assert(fw);
|
||||||
|
|
||||||
lsquic_frame_writer_destroy(fw);
|
lsquic_frame_writer_destroy(fw);
|
||||||
lsquic_henc_cleanup(&henc);
|
lshpack_enc_cleanup(&henc);
|
||||||
lsquic_mm_cleanup(&mm);
|
lsquic_mm_cleanup(&mm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,12 +81,12 @@ test_max_frame_size (void)
|
||||||
static void
|
static void
|
||||||
test_one_header (void)
|
test_one_header (void)
|
||||||
{
|
{
|
||||||
struct lsquic_henc henc;
|
struct lshpack_enc henc;
|
||||||
struct lsquic_frame_writer *fw;
|
struct lsquic_frame_writer *fw;
|
||||||
int s;
|
int s;
|
||||||
struct lsquic_mm mm;
|
struct lsquic_mm mm;
|
||||||
|
|
||||||
lsquic_henc_init(&henc);
|
lshpack_enc_init(&henc);
|
||||||
lsquic_mm_init(&mm);
|
lsquic_mm_init(&mm);
|
||||||
fw = lsquic_frame_writer_new(&mm, NULL, 0x200, &henc, output_write, 0);
|
fw = lsquic_frame_writer_new(&mm, NULL, 0x200, &henc, output_write, 0);
|
||||||
reset_output(0);
|
reset_output(0);
|
||||||
|
@ -131,7 +131,7 @@ test_one_header (void)
|
||||||
sizeof(struct http_prio_frame), "\x48\x82\x64\x02", 4));
|
sizeof(struct http_prio_frame), "\x48\x82\x64\x02", 4));
|
||||||
|
|
||||||
lsquic_frame_writer_destroy(fw);
|
lsquic_frame_writer_destroy(fw);
|
||||||
lsquic_henc_cleanup(&henc);
|
lshpack_enc_cleanup(&henc);
|
||||||
lsquic_mm_cleanup(&mm);
|
lsquic_mm_cleanup(&mm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,14 +139,14 @@ test_one_header (void)
|
||||||
static void
|
static void
|
||||||
test_oversize_header (void)
|
test_oversize_header (void)
|
||||||
{
|
{
|
||||||
struct lsquic_henc henc;
|
struct lshpack_enc henc;
|
||||||
struct lsquic_frame_writer *fw;
|
struct lsquic_frame_writer *fw;
|
||||||
int s;
|
int s;
|
||||||
struct lsquic_mm mm;
|
struct lsquic_mm mm;
|
||||||
const size_t big_len = 100 * 1000;
|
const size_t big_len = 100 * 1000;
|
||||||
char *value;
|
char *value;
|
||||||
|
|
||||||
lsquic_henc_init(&henc);
|
lshpack_enc_init(&henc);
|
||||||
lsquic_mm_init(&mm);
|
lsquic_mm_init(&mm);
|
||||||
fw = lsquic_frame_writer_new(&mm, NULL, 0x200, &henc, output_write, 0);
|
fw = lsquic_frame_writer_new(&mm, NULL, 0x200, &henc, output_write, 0);
|
||||||
reset_output(0);
|
reset_output(0);
|
||||||
|
@ -170,7 +170,7 @@ test_oversize_header (void)
|
||||||
assert(-1 == s);
|
assert(-1 == s);
|
||||||
|
|
||||||
lsquic_frame_writer_destroy(fw);
|
lsquic_frame_writer_destroy(fw);
|
||||||
lsquic_henc_cleanup(&henc);
|
lshpack_enc_cleanup(&henc);
|
||||||
lsquic_mm_cleanup(&mm);
|
lsquic_mm_cleanup(&mm);
|
||||||
free(value);
|
free(value);
|
||||||
}
|
}
|
||||||
|
@ -180,11 +180,11 @@ static void
|
||||||
test_continuations (void)
|
test_continuations (void)
|
||||||
{
|
{
|
||||||
struct lsquic_frame_writer *fw;
|
struct lsquic_frame_writer *fw;
|
||||||
struct lsquic_henc henc;
|
struct lshpack_enc henc;
|
||||||
int s;
|
int s;
|
||||||
struct lsquic_mm mm;
|
struct lsquic_mm mm;
|
||||||
|
|
||||||
lsquic_henc_init(&henc);
|
lshpack_enc_init(&henc);
|
||||||
lsquic_mm_init(&mm);
|
lsquic_mm_init(&mm);
|
||||||
fw = lsquic_frame_writer_new(&mm, NULL, 6, &henc, output_write, 0);
|
fw = lsquic_frame_writer_new(&mm, NULL, 6, &henc, output_write, 0);
|
||||||
reset_output(0);
|
reset_output(0);
|
||||||
|
@ -258,7 +258,7 @@ perl tools/henc.pl :status 302 x-some-header some-value | hexdump -C
|
||||||
assert(0 == memcmp(output.buf + 60, expected_buf + 60, 14));
|
assert(0 == memcmp(output.buf + 60, expected_buf + 60, 14));
|
||||||
|
|
||||||
lsquic_frame_writer_destroy(fw);
|
lsquic_frame_writer_destroy(fw);
|
||||||
lsquic_henc_cleanup(&henc);
|
lshpack_enc_cleanup(&henc);
|
||||||
lsquic_mm_cleanup(&mm);
|
lsquic_mm_cleanup(&mm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,10 +426,10 @@ test_errors (void)
|
||||||
{
|
{
|
||||||
struct lsquic_frame_writer *fw;
|
struct lsquic_frame_writer *fw;
|
||||||
struct lsquic_mm mm;
|
struct lsquic_mm mm;
|
||||||
struct lsquic_henc henc;
|
struct lshpack_enc henc;
|
||||||
int s;
|
int s;
|
||||||
|
|
||||||
lsquic_henc_init(&henc);
|
lshpack_enc_init(&henc);
|
||||||
lsquic_mm_init(&mm);
|
lsquic_mm_init(&mm);
|
||||||
fw = lsquic_frame_writer_new(&mm, NULL, 0x200, &henc, output_write, 1);
|
fw = lsquic_frame_writer_new(&mm, NULL, 0x200, &henc, output_write, 1);
|
||||||
reset_output(0);
|
reset_output(0);
|
||||||
|
@ -466,7 +466,7 @@ test_errors (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
lsquic_frame_writer_destroy(fw);
|
lsquic_frame_writer_destroy(fw);
|
||||||
lsquic_henc_cleanup(&henc);
|
lshpack_enc_cleanup(&henc);
|
||||||
lsquic_mm_cleanup(&mm);
|
lsquic_mm_cleanup(&mm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,12 +474,12 @@ test_errors (void)
|
||||||
static void
|
static void
|
||||||
test_push_promise (void)
|
test_push_promise (void)
|
||||||
{
|
{
|
||||||
struct lsquic_henc henc;
|
struct lshpack_enc henc;
|
||||||
struct lsquic_frame_writer *fw;
|
struct lsquic_frame_writer *fw;
|
||||||
int s;
|
int s;
|
||||||
struct lsquic_mm mm;
|
struct lsquic_mm mm;
|
||||||
|
|
||||||
lsquic_henc_init(&henc);
|
lshpack_enc_init(&henc);
|
||||||
lsquic_mm_init(&mm);
|
lsquic_mm_init(&mm);
|
||||||
fw = lsquic_frame_writer_new(&mm, NULL, 0x200, &henc, output_write, 1);
|
fw = lsquic_frame_writer_new(&mm, NULL, 0x200, &henc, output_write, 1);
|
||||||
reset_output(0);
|
reset_output(0);
|
||||||
|
@ -543,7 +543,7 @@ perl tools/hpack.pl :method GET :path /index.html :authority www.example.com :sc
|
||||||
sizeof(exp_headers)));
|
sizeof(exp_headers)));
|
||||||
|
|
||||||
lsquic_frame_writer_destroy(fw);
|
lsquic_frame_writer_destroy(fw);
|
||||||
lsquic_henc_cleanup(&henc);
|
lshpack_enc_cleanup(&henc);
|
||||||
lsquic_mm_cleanup(&mm);
|
lsquic_mm_cleanup(&mm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue