Commit 5cc24cb7 authored by Tatsuhiro Tsujikawa's avatar Tatsuhiro Tsujikawa

Merge branch 'draft-10'

parents a5353c22 27b3091a
This diff is collapsed.
......@@ -40,13 +40,13 @@ extern "C" {
*
* The protocol version identification of this library supports.
*/
#define NGHTTP2_PROTO_VERSION_ID "HTTP-draft-09/2.0"
#define NGHTTP2_PROTO_VERSION_ID "h2-10"
/**
* @macro
*
* The length of :macro:`NGHTTP2_PROTO_VERSION_ID`.
*/
#define NGHTTP2_PROTO_VERSION_ID_LEN 17
#define NGHTTP2_PROTO_VERSION_ID_LEN 5
struct nghttp2_session;
/**
......@@ -364,11 +364,11 @@ typedef enum {
/**
* The WINDOW_UPDATE frame.
*/
NGHTTP2_WINDOW_UPDATE = 9,
NGHTTP2_WINDOW_UPDATE = 8,
/**
* The CONTINUATION frame.
*/
NGHTTP2_CONTINUATION = 10
NGHTTP2_CONTINUATION = 9
} nghttp2_frame_type;
/**
......@@ -401,7 +401,19 @@ typedef enum {
/**
* The ACK flag.
*/
NGHTTP2_FLAG_ACK = 0x1
NGHTTP2_FLAG_ACK = 0x1,
/**
* The END_SEGMENT flag.
*/
NGHTTP2_FLAG_END_SEGMENT = 0x2,
/**
* The PAD_LOW flag.
*/
NGHTTP2_FLAG_PAD_LOW = 0x10,
/**
* The PAD_HIGH flag.
*/
NGHTTP2_FLAG_PAD_HIGH = 0x20
} nghttp2_flag;
/**
......@@ -420,19 +432,15 @@ typedef enum {
/**
* SETTINGS_MAX_CONCURRENT_STREAMS
*/
NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS = 4,
NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS = 3,
/**
* SETTINGS_INITIAL_WINDOW_SIZE
*/
NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE = 7,
/**
* SETTINGS_FLOW_CONTROL_OPTIONS
*/
NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS = 10,
NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE = 4,
/**
* Maximum ID of :type:`nghttp2_settings_id`.
*/
NGHTTP2_SETTINGS_MAX = 10
NGHTTP2_SETTINGS_MAX = 4
} nghttp2_settings_id;
/**
......@@ -493,7 +501,11 @@ typedef enum {
/**
* ENHANCE_YOUR_CALM
*/
NGHTTP2_ENHANCE_YOUR_CALM = 420
NGHTTP2_ENHANCE_YOUR_CALM = 11,
/**
* INADEQUATE_SECURITY
*/
NGHTTP2_INADEQUATE_SECURITY = 12
} nghttp2_error_code;
/**
......@@ -587,6 +599,11 @@ typedef struct {
*/
typedef struct {
nghttp2_frame_hd hd;
/**
* The length of the padding in this frame. This includes PAD_HIGH
* and PAD_LOW.
*/
size_t padlen;
} nghttp2_data;
/**
......@@ -630,6 +647,11 @@ typedef struct {
* The frame header.
*/
nghttp2_frame_hd hd;
/**
* The length of the padding in this frame. This includes PAD_HIGH
* and PAD_LOW.
*/
size_t padlen;
/**
* The name/value pairs.
*/
......@@ -721,6 +743,11 @@ typedef struct {
* The frame header.
*/
nghttp2_frame_hd hd;
/**
* The length of the padding in this frame. This includes PAD_HIGH
* and PAD_LOW.
*/
size_t padlen;
/**
* The name/value pairs.
*/
......@@ -1149,6 +1176,26 @@ typedef int (*nghttp2_on_header_callback)
const uint8_t *value, size_t valuelen,
void *user_data);
/**
* @functypedef
*
* Callback function invoked when the library asks application how
* much padding is required for the transmission of the |frame|. The
* application must choose the total length of payload including
* padded bytes in range [frame->hd.length, max_payloadlen],
* inclusive. Choosing number not in this range will be treated as
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. Returning
* ``frame->hd.length`` means no padding is added. Returning
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will make
* `nghttp2_session_send()` function immediately return
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
*/
typedef ssize_t (*nghttp2_select_padding_callback)
(nghttp2_session *session,
const nghttp2_frame *frame,
size_t max_payloadlen,
void *user_data);
/**
* @struct
*
......@@ -1212,6 +1259,11 @@ typedef struct {
* received.
*/
nghttp2_on_header_callback on_header_callback;
/**
* Callback function invoked when the library asks application how
* much padding is required for the transmission of the given frame.
*/
nghttp2_select_padding_callback select_padding_callback;
} nghttp2_session_callbacks;
/**
......@@ -1623,9 +1675,6 @@ size_t nghttp2_session_get_outbound_queue_size(nghttp2_session *session);
* window_size_increment with `nghttp2_submit_window_update()`, this
* function returns the number of bytes less than actually received.
*
* If flow control is disabled for that stream, this function returns
* 0.
*
* This function returns -1 if it fails.
*/
int32_t nghttp2_session_get_stream_effective_recv_data_length
......@@ -1656,9 +1705,6 @@ int32_t nghttp2_session_get_stream_effective_local_window_size
* with `nghttp2_submit_window_update()`, this function returns the
* number of bytes less than actually received.
*
* If flow control is disabled for a connection, this function returns
* 0.
*
* This function returns -1 if it fails.
*/
int32_t nghttp2_session_get_effective_recv_data_length
......@@ -2021,8 +2067,8 @@ int nghttp2_submit_rst_stream(nghttp2_session *session, uint8_t flags,
* negative error codes:
*
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
* The |iv| contains invalid value (e.g., attempting to re-enable
* flow control).
* The |iv| contains invalid value (e.g., initial window size
* strictly greater than (1 << 31) - 1.
* :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
......
This diff is collapsed.
......@@ -48,6 +48,9 @@
/* The number of bytes of frame header. */
#define NGHTTP2_FRAME_HEAD_LENGTH 8
/* The number of bytes for each SETTINGS entry */
#define NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH 5
/* Category of frames. */
typedef enum {
/* non-DATA frame */
......@@ -68,6 +71,11 @@ typedef struct {
* The data to be sent for this DATA frame.
*/
nghttp2_data_provider data_prd;
/**
* The number of bytes added as padding. This includes PAD_HIGH and
* PAD_LOW.
*/
size_t padlen;
/**
* The flag to indicate whether EOF was reached or not. Initially
* |eof| is 0. It becomes 1 after all data were read. This is used
......@@ -96,14 +104,19 @@ size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame);
* expansion occurred, memory previously pointed by |*buf_ptr| may
* change. |*buf_ptr| and |*buflen_ptr| are updated accordingly.
*
* The first byte the frame is serialized is returned in the
* |*bufoff_ptr|. Currently, it is always 2 to account for possible
* PAD_HIGH and PAD_LOW.
*
* frame->hd.length is assigned after length is determined during
* packing process. If payload length is strictly larger than
* NGHTTP2_MAX_FRAME_LENGTH, payload data is still serialized as is,
* but frame->hd.length is set to NGHTTP2_MAX_FRAME_LENGTH and
* NGHTTP2_FLAG_END_HEADERS flag is cleared from frame->hd.flags.
*
* This function returns the size of packed frame if it succeeds, or
* returns one of the following negative error codes:
* This function returns the size of packed frame (which includes
* |*bufoff_ptr| bytes) if it succeeds, or returns one of the
* following negative error codes:
*
* NGHTTP2_ERR_HEADER_COMP
* The deflate operation failed.
......@@ -114,6 +127,7 @@ size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame);
*/
ssize_t nghttp2_frame_pack_headers(uint8_t **buf_ptr,
size_t *buflen_ptr,
size_t *bufoff_ptr,
nghttp2_headers *frame,
nghttp2_hd_deflater *deflater);
......@@ -242,12 +256,20 @@ int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
* expansion occurred, memory previously pointed by |*buf_ptr| may
* change. |*buf_ptr| and |*buflen_ptr| are updated accordingly.
*
* The first byte the frame is serialized is returned in the
* |*bufoff_ptr|. Currently, it is always 2 to account for possible
* PAD_HIGH and PAD_LOW.
*
* frame->hd.length is assigned after length is determined during
* packing process. If payload length is strictly larger than
* NGHTTP2_MAX_FRAME_LENGTH, payload data is still serialized as is,
* but frame->hd.length is set to NGHTTP2_MAX_FRAME_LENGTH and
* NGHTTP2_FLAG_END_HEADERS flag is cleared from frame->hd.flags.
*
* This function returns the size of packed frame (which includes
* |*bufoff_ptr| bytes) if it succeeds, or returns one of the
* following negative error codes:
*
* This function returns the size of packed frame if it succeeds, or
* returns one of the following negative error codes:
*
......@@ -260,6 +282,7 @@ int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
*/
ssize_t nghttp2_frame_pack_push_promise(uint8_t **buf_ptr,
size_t *buflen_ptr,
size_t *bufoff_ptr,
nghttp2_push_promise *frame,
nghttp2_hd_deflater *deflater);
......@@ -418,6 +441,13 @@ void nghttp2_frame_window_update_free(nghttp2_window_update *frame);
void nghttp2_frame_data_init(nghttp2_data *frame, nghttp2_private_data *pdata);
/*
* Returns the number of padding bytes after payload. The total
* padding length is given in the |padlen|. The returned value does
* not include the PAD_HIGH and PAD_LOW.
*/
size_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen);
void nghttp2_frame_private_data_init(nghttp2_private_data *frame,
uint8_t flags,
int32_t stream_id,
......@@ -472,12 +502,87 @@ void nghttp2_nv_array_del(nghttp2_nv *nva);
/*
* Checks that the |iv|, which includes |niv| entries, does not have
* invalid values. The |flow_control_opt| is current flow control
* option value.
* invalid values.
*
* This function returns nonzero if it succeeds, or 0.
*/
int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv,
int32_t flow_control_opt);
int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv);
/*
* Add padding to the payload in the |*buf_ptr| of length
* |*buflen_ptr|. The payload length is given in |payloadlen|. The
* frame header starts at offset |*bufoff_ptr|. Therefore, the payload
* must start at offset *bufoff_ptr + NGHTTP2_FRAME_HEAD_LENGTH from
* |*buf_ptr| to account for PAD_HIGH and PAD_LOW. The padding is
* given in the |padlen|.
*
* The |*flags_ptr| is updated to include NGHTTP2_FLAG_PAD_LOW and
* NGHTTP2_FLAG_PAD_HIGH based on the padding length. The
* |*bufoff_ptr| will have the offset starting the frame header in
* |*buf_ptr|.
*
* The |*buf_ptr| and |*buflen_ptr| may be extended to include padding
* bytes.
*
* The padding specifier PAD_HIGH and PAD_LOW are located right after
* the frame header. But they may not be there depending of the length
* of the padding. To save the additional buffer copy, we allocate
* buffer size as if these 2 bytes always exist. Depending of the
* length of the padding, we move the location of frame header and
* adjust |*bufoff_ptr|. If more than or equal to 256 padding is made,
* the |*bufoff_ptr| is 0 and the content of the |*buf_ptr| looks like
* this:
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Frame header ...
* +---------------------------------------------------------------+
* . Frame header |
* +---------------+---------------+-------------------------------+
* | Pad high | Pad low | Payload ...
* +---------------+---------------+-------------------------------+
*
*
* If padding is less than 256 but strictly more than 0, the
* |*bufoff_ptr| is 1 and the |*buf_ptr| looks like this:
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Unused | Frame header ...
* +---------------+-----------------------------------------------+
* . Frame header ...
* +---------------+---------------+-------------------------------+
* . Frame Header | Pad low | Payload ...
* +---------------+---------------+-------------------------------+
*
* If no padding is added, the |*bufoff_ptr| is 2 and the |*buf_ptr|
* looks like this:
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Unused | Frame header ...
* +-------------------------------+-------------------------------+
* . Frame header ...
* +-------------------------------+-------------------------------+
* . Frame Header | Payload ...
* +-------------------------------+-------------------------------+
*
* Notice that the position of payload does not change. This way, we
* can set PAD_HIGH and PAD_LOW after payload was serialized and no
* additional copy operation is required (if the |*buf_ptr| is large
* enough to account the additional padding, of course).
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_frame_add_pad(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *bufoff_ptr, uint8_t *flags_ptr,
size_t payloadlen, size_t padlen);
#endif /* NGHTTP2_FRAME_H */
This diff is collapsed.
......@@ -22,8 +22,8 @@
* 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 NGHTTP2_HD_COMP_H
#define NGHTTP2_HD_COMP_H
#ifndef NGHTTP2_HD_H
#define NGHTTP2_HD_H
#ifdef HAVE_CONFIG_H
# include <config.h>
......@@ -48,11 +48,6 @@
encoder only uses the memory up to this value. */
#define NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE (1 << 12)
typedef enum {
NGHTTP2_HD_SIDE_REQUEST = 0,
NGHTTP2_HD_SIDE_RESPONSE = 1
} nghttp2_hd_side;
typedef enum {
NGHTTP2_HD_ROLE_DEFLATE,
NGHTTP2_HD_ROLE_INFLATE
......@@ -108,6 +103,8 @@ typedef enum {
typedef enum {
NGHTTP2_HD_STATE_OPCODE,
NGHTTP2_HD_STATE_CONTEXT_UPDATE,
NGHTTP2_HD_STATE_READ_TABLE_SIZE,
NGHTTP2_HD_STATE_READ_INDEX,
NGHTTP2_HD_STATE_NEWNAME_CHECK_NAMELEN,
NGHTTP2_HD_STATE_NEWNAME_READ_NAMELEN,
......@@ -126,30 +123,10 @@ typedef struct {
is the sum of length of name/value in hd_table +
NGHTTP2_HD_ENTRY_OVERHEAD bytes overhead per each entry. */
size_t hd_table_bufsize;
/* The header table size for decoding. If the context is initialized
as encoder, this value is advertised by remote endpoint
decoder. */
/* The effective header table size. */
size_t hd_table_bufsize_max;
/* The current effective header table size for encoding. This value
is always equal to |hd_table_bufsize| on decoder
context. |deflate_hd_table_bufsize| <= |hd_table_bufsize| must be
hold. */
size_t deflate_hd_table_bufsize;
/* The maximum effective header table for encoding. Although header
table size is bounded by |hd_table_bufsize_max|, the encoder can
use smaller buffer by not retaining the header name/values beyond
the |deflate_hd_table_bufsize_max| and not referencing those
entries. This value is always equal to |hd_table_bufsize_max| on
decoder context. */
size_t deflate_hd_table_bufsize_max;
/* The number of effective entry in |hd_table|. This value is always
equal to hd_table.len on decoder side. */
size_t deflate_hd_tablelen;
/* Role of this context; deflate or infalte */
nghttp2_hd_role role;
/* NGHTTP2_HD_SIDE_REQUEST for processing request, otherwise
response. */
nghttp2_hd_side side;
/* If inflate/deflate error occurred, this value is set to 1 and
further invocation of inflate/deflate will fail with
NGHTTP2_ERR_HEADER_COMP. */
......@@ -158,6 +135,8 @@ typedef struct {
typedef struct {
nghttp2_hd_context ctx;
/* The upper limit of the header table size the deflater accepts. */
size_t deflate_hd_table_bufsize_max;
/* Set to this nonzero to clear reference set on each deflation each
time. */
uint8_t no_refset;
......@@ -189,6 +168,9 @@ typedef struct {
/* The index of header table to toggle off the entry from reference
set at the end of decompression. */
size_t end_headers_index;
/* The maximum header table size the inflater supports. This is the
same value transmitted in SETTINGS_HEADER_TABLE_SIZE */
size_t settings_hd_table_bufsize_max;
nghttp2_hd_opcode opcode;
nghttp2_hd_inflate_state state;
/* nonzero if string is huffman encoded */
......@@ -230,8 +212,7 @@ void nghttp2_hd_entry_free(nghttp2_hd_entry *ent);
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater,
nghttp2_hd_side side);
int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater);
/*
* Initializes |deflater| for deflating name/values pairs.
......@@ -247,7 +228,6 @@ int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater,
* Out of memory.
*/
int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater,
nghttp2_hd_side side,
size_t deflate_hd_table_bufsize_max);
/*
......@@ -259,8 +239,7 @@ int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater,
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater,
nghttp2_hd_side side);
int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater);
/*
* Deallocates any resources allocated for |deflater|.
......@@ -282,10 +261,11 @@ void nghttp2_hd_deflate_set_no_refset(nghttp2_hd_deflater *deflater,
uint8_t no_refset);
/*
* Changes header table size in |context|. This may trigger eviction
* in the dynamic table.
* Changes header table size of the |deflater|. This may trigger
* eviction in the dynamic table.
*
* This function can be used for deflater and inflater.
* The |settings_hd_table_bufsize_max| should be the value received in
* SETTINGS_HEADER_TABLE_SIZE.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
......@@ -293,8 +273,25 @@ void nghttp2_hd_deflate_set_no_refset(nghttp2_hd_deflater *deflater,
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_hd_change_table_size(nghttp2_hd_context *context,
size_t hd_table_bufsize_max);
int nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater,
size_t settings_hd_table_bufsize_max);
/*
* Changes header table size in the |inflater|. This may trigger
* eviction in the dynamic table.
*
* The |settings_hd_table_bufsize_max| should be the value transmitted
* in SETTINGS_HEADER_TABLE_SIZE.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater,
size_t settings_hd_table_bufsize_max);
/*
* Deflates the |nva|, which has the |nvlen| name/value pairs, into
......@@ -379,14 +376,16 @@ int nghttp2_hd_inflate_end_headers(nghttp2_hd_inflater *inflater);
int nghttp2_hd_emit_indname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, size_t index,
const uint8_t *value, size_t valuelen,
int inc_indexing,
nghttp2_hd_side side);
int inc_indexing);
/* For unittesting purpose */
int nghttp2_hd_emit_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, nghttp2_nv *nv,
int inc_indexing,
nghttp2_hd_side side);
int inc_indexing);
/* For unittesting purpose */
int nghttp2_hd_emit_table_size(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, size_t table_size);
/* For unittesting purpose */
nghttp2_hd_entry* nghttp2_hd_table_get(nghttp2_hd_context *context,
......@@ -395,37 +394,30 @@ nghttp2_hd_entry* nghttp2_hd_table_get(nghttp2_hd_context *context,
/* Huffman encoding/decoding functions */
/*
* Counts the required bytes to encode |src| with length |len|. If
* |side| is NGHTTP2_HD_SIDE_REQUEST, the request huffman code table
* is used. Otherwise, the response code table is used.
* Counts the required bytes to encode |src| with length |len|.
*
* This function returns the number of required bytes to encode given
* data, including padding of prefix of terminal symbol code. This
* function always succeeds.
*/
size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len,
nghttp2_hd_side side);
size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len);
/*
* Encodes the given data |src| with length |srclen| to the given
* memory location pointed by |dest|, allocated at lest |destlen|
* bytes. The caller is responsible to specify |destlen| at least the
* length that nghttp2_hd_huff_encode_count() returns. If |side| is
* NGHTTP2_HD_SIDE_REQUEST, the request huffman code table is
* used. Otherwise, the response code table is used.
* length that nghttp2_hd_huff_encode_count() returns.
*
* This function returns the number of written bytes, including
* padding of prefix of terminal symbol code. This return value is
* exactly the same with the return value of
* nghttp2_hd_huff_encode_count() if it is given with the same |src|,
* |srclen|, and |side|. This function always succeeds.
* nghttp2_hd_huff_encode_count() if it is given with the same |src|
* and |srclen|. This function always succeeds.
*/
ssize_t nghttp2_hd_huff_encode(uint8_t *dest, size_t destlen,
const uint8_t *src, size_t srclen,
nghttp2_hd_side side);
const uint8_t *src, size_t srclen);
void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx,
nghttp2_hd_side side);
void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx);
/*
* Decodes the given data |src| with length |srclen|. The |ctx| must
......@@ -453,4 +445,4 @@ ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
nghttp2_buffer *dest,
const uint8_t *src, size_t srclen, int final);
#endif /* NGHTTP2_HD_COMP_H */
#endif /* NGHTTP2_HD_H */
......@@ -30,11 +30,8 @@
#include "nghttp2_hd.h"
extern const nghttp2_huff_sym req_huff_sym_table[];
extern const nghttp2_huff_decode req_huff_decode_table[][16];
extern const nghttp2_huff_sym res_huff_sym_table[];
extern const nghttp2_huff_decode res_huff_decode_table[][16];
extern const nghttp2_huff_sym huff_sym_table[];
extern const nghttp2_huff_decode huff_decode_table[][16];
/*
* Encodes huffman code |sym| into |*dest_ptr|, whose least |rembits|
......@@ -65,18 +62,11 @@ static size_t huff_encode_sym(uint8_t **dest_ptr, size_t rembits,
return rembits;
}
size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len,
nghttp2_hd_side side)
size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len)
{
size_t i;
size_t nbits = 0;
const nghttp2_huff_sym *huff_sym_table;
if(side == NGHTTP2_HD_SIDE_REQUEST) {
huff_sym_table = req_huff_sym_table;
} else {
huff_sym_table = res_huff_sym_table;
}
for(i = 0; i < len; ++i) {
nbits += huff_sym_table[src[i]].nbits;
}
......@@ -85,19 +75,12 @@ size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len,
}
ssize_t nghttp2_hd_huff_encode(uint8_t *dest, size_t destlen,
const uint8_t *src, size_t srclen,
nghttp2_hd_side side)
const uint8_t *src, size_t srclen)
{
int rembits = 8;
uint8_t *dest_first = dest;
size_t i;
const nghttp2_huff_sym *huff_sym_table;
if(side == NGHTTP2_HD_SIDE_REQUEST) {
huff_sym_table = req_huff_sym_table;
} else {
huff_sym_table = res_huff_sym_table;
}
for(i = 0; i < srclen; ++i) {
const nghttp2_huff_sym *sym = &huff_sym_table[src[i]];
if(rembits == 8) {
......@@ -114,14 +97,8 @@ ssize_t nghttp2_hd_huff_encode(uint8_t *dest, size_t destlen,
return dest - dest_first;
}
void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx,
nghttp2_hd_side side)
void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx)
{
if(side == NGHTTP2_HD_SIDE_REQUEST) {
ctx->huff_decode_table = req_huff_decode_table;
} else {
ctx->huff_decode_table = res_huff_decode_table;
}
ctx->state = 0;
ctx->accept = 1;
}
......@@ -137,7 +114,7 @@ ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
for(i = 0; i < srclen; ++i) {
uint8_t in = src[i] >> 4;
for(j = 0; j < 2; ++j) {
const nghttp2_huff_decode *t = &ctx->huff_decode_table[ctx->state][in];
const nghttp2_huff_decode *t = &huff_decode_table[ctx->state][in];
if(t->state == -1) {
return NGHTTP2_ERR_HEADER_COMP;
}
......
......@@ -52,7 +52,6 @@ typedef struct {
typedef nghttp2_huff_decode huff_decode_table_type[16];
typedef struct {
const huff_decode_table_type *huff_decode_table;
/* Current huffman decoding state. We stripped leaf nodes, so the
value range is [0..255], inclusive. */
uint8_t state;
......
This diff is collapsed.
This diff is collapsed.
......@@ -86,6 +86,9 @@ typedef enum {
NGHTTP2_IB_READ_GOAWAY_DEBUG,
NGHTTP2_IB_EXPECT_CONTINUATION,
NGHTTP2_IB_IGN_CONTINUATION,
NGHTTP2_IB_READ_PAD_CONTINUATION,
NGHTTP2_IB_IGN_PAD_CONTINUATION,
NGHTTP2_IB_READ_PAD_DATA,
NGHTTP2_IB_READ_DATA,
NGHTTP2_IB_IGN_DATA
} nghttp2_inbound_state;
......@@ -102,9 +105,9 @@ typedef struct {
size_t left;
/* How many bytes we still need to receive for current frame */
size_t payloadleft;
/* padding length for the current frame */
size_t padlen;
nghttp2_inbound_state state;
/* TODO, remove this. Error code */
int error_code;
uint8_t buf[8];
/* How many bytes have been written to |buf| */
uint8_t buflen;
......@@ -189,14 +192,6 @@ struct nghttp2_session {
/* Flags indicating GOAWAY is sent and/or recieved. The flags are
composed by bitwise OR-ing nghttp2_goaway_flag. */
uint8_t goaway_flags;
/* Non-zero indicates connection-level flow control on remote side
is in effect. This will be disabled when WINDOW_UPDATE with
END_FLOW_CONTROL bit set is received. */
uint8_t remote_flow_control;
/* Non-zero indicates connection-level flow control on local side is
in effect. This will be disabled when WINDOW_UPDATE with
END_FLOW_CONTROL bit set is sent. */
uint8_t local_flow_control;
};
/* Struct used when updating initial window size of each active
......@@ -516,9 +511,11 @@ nghttp2_stream* nghttp2_session_get_stream(nghttp2_session *session,
* Packs DATA frame |frame| in wire frame format and stores it in
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
* length. This function expands |*buf_ptr| as necessary to store
* given |frame|. It packs header in first 8 bytes. Remaining bytes
* are the DATA apyload and are filled using |frame->data_prd|. The
* length of payload is at most |datamax| bytes.
* given |frame|. It packs header in first 8 bytes starting
* |*bufoff_ptr| offset. The |*bufoff_ptr| is calculated based on
* usage of padding. Remaining bytes are the DATA apyload and are
* filled using |frame->data_prd|. The length of payload is at most
* |datamax| bytes.
*
* This function returns the size of packed frame if it succeeds, or
* one of the following negative error codes:
......@@ -534,6 +531,7 @@ nghttp2_stream* nghttp2_session_get_stream(nghttp2_session *session,
*/
ssize_t nghttp2_session_pack_data(nghttp2_session *session,
uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *bufoff_ptr,
size_t datamax,
nghttp2_private_data *frame);
......
......@@ -29,8 +29,6 @@
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
uint8_t flags, int32_t pri,
nghttp2_stream_state initial_state,
uint8_t remote_flow_control,
uint8_t local_flow_control,
int32_t remote_initial_window_size,
int32_t local_initial_window_size,
void *stream_user_data)
......@@ -44,8 +42,6 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
stream->stream_user_data = stream_user_data;
stream->deferred_data = NULL;
stream->deferred_flags = NGHTTP2_DEFERRED_NONE;
stream->remote_flow_control = remote_flow_control;
stream->local_flow_control = local_flow_control;
stream->remote_window_size = remote_initial_window_size;
stream->local_window_size = local_initial_window_size;
stream->recv_window_size = 0;
......
......@@ -117,25 +117,11 @@ typedef struct {
/* The flags for defered DATA. Bitwise OR of zero or more
nghttp2_deferred_flag values */
uint8_t deferred_flags;
/* Flag to indicate whether the remote side has flow control
enabled. If it is enabled, we have to enforces flow control to
send data to the other side. This could be disabled when
receiving SETTINGS with flow control options off or receiving
WINDOW_UPDATE with END_FLOW_CONTROL bit set. */
uint8_t remote_flow_control;
/* Flag to indicate whether the local side has flow control
enabled. If it is enabled, the received data are subject to the
flow control. This could be disabled by sending SETTINGS with
flow control options off or sending WINDOW_UPDATE with
END_FLOW_CONTROL bit set. */
uint8_t local_flow_control;
} nghttp2_stream;
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
uint8_t flags, int32_t pri,
nghttp2_stream_state initial_state,
uint8_t remote_flow_control,
uint8_t local_flow_control,
int32_t remote_initial_window_size,
int32_t local_initial_window_size,
void *stream_user_data);
......
......@@ -75,8 +75,9 @@ static int nghttp2_submit_headers_shared
rv = NGHTTP2_ERR_NOMEM;
goto fail;
}
/* TODO Implement header continuation */
flags_copy = (flags & (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_PRIORITY)) |
flags_copy =
(flags & (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_PRIORITY |
NGHTTP2_FLAG_END_SEGMENT)) |
NGHTTP2_FLAG_END_HEADERS;
nghttp2_frame_headers_init(&frame->headers, flags_copy, stream_id, pri,
......@@ -196,7 +197,6 @@ int nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags,
free(frame);
return rv;
}
/* TODO Implement header continuation */
flags_copy = NGHTTP2_FLAG_END_PUSH_PROMISE;
nghttp2_frame_push_promise_init(&frame->push_promise, flags_copy,
stream_id, -1, nva_copy, nvlen);
......@@ -219,9 +219,6 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
}
flags = 0;
if(stream_id == 0) {
if(!session->local_flow_control) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
rv = nghttp2_adjust_local_window_size(&session->local_window_size,
&session->recv_window_size,
&session->recv_reduction,
......@@ -232,9 +229,6 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
} else {
stream = nghttp2_session_get_stream(session, stream_id);
if(stream) {
if(!stream->local_flow_control) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
rv = nghttp2_adjust_local_window_size(&stream->local_window_size,
&stream->recv_window_size,
&stream->recv_reduction,
......@@ -325,14 +319,13 @@ ssize_t nghttp2_pack_settings_payload(uint8_t *buf,
const nghttp2_settings_entry *iv,
size_t niv)
{
/* Assume that current flow_control_option is 0 (which means that
flow control is enabled) */
if(!nghttp2_iv_check(iv, niv, 0)) {
if(!nghttp2_iv_check(iv, niv)) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
if(buflen < (niv * 8))
if(buflen < (niv * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH)) {
return NGHTTP2_ERR_INSUFF_BUFSIZE;
}
return nghttp2_frame_pack_settings_payload(buf, iv, niv);
}
......@@ -45,10 +45,6 @@ cdef extern from 'nghttp2_hd.h':
# This is macro
int NGHTTP2_HD_ENTRY_OVERHEAD
ctypedef enum nghttp2_hd_side:
NGHTTP2_HD_SIDE_REQUEST
NGHTTP2_HD_SIDE_RESPONSE
ctypedef enum nghttp2_hd_flags:
NGHTTP2_HD_FLAG_REFSET
......@@ -73,12 +69,9 @@ cdef extern from 'nghttp2_hd.h':
nghttp2_hd_context ctx
int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater,
nghttp2_hd_side side,
size_t deflate_hd_table_bufsize_max)
int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater,
nghttp2_hd_side side)
int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater)
void nghttp2_hd_deflate_free(nghttp2_hd_deflater *deflater)
......@@ -87,8 +80,11 @@ cdef extern from 'nghttp2_hd.h':
void nghttp2_hd_deflate_set_no_refset(nghttp2_hd_deflater *deflater,
uint8_t no_refset)
int nghttp2_hd_change_table_size(nghttp2_hd_context *context,
size_t hd_table_bufsize_max)
int nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater,
size_t hd_table_bufsize_max)
int nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater,
size_t hd_table_bufsize_max)
ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
uint8_t **buf_ptr, size_t *buflen_ptr,
......
......@@ -13,12 +13,7 @@ from binascii import a2b_hex
import nghttp2
def testsuite(testdata):
if testdata['context'] == 'request':
side = nghttp2.HD_SIDE_REQUEST
else:
side = nghttp2.HD_SIDE_RESPONSE
inflater = nghttp2.HDInflater(side)
inflater = nghttp2.HDInflater()
for casenum, item in enumerate(testdata['cases']):
if 'header_table_size' in item:
......@@ -47,7 +42,7 @@ def testsuite(testdata):
if __name__ == '__main__':
for filename in sys.argv[1:]:
sys.stderr.write('{}\n'.format(filename))
sys.stderr.write('{}: '.format(filename))
with open(filename) as f:
input = f.read()
testsuite(json.loads(input))
......@@ -14,11 +14,6 @@ from binascii import b2a_hex
import nghttp2
def testsuite(testdata, filename, outdir, table_size, deflate_table_size):
if testdata['context'] == 'request':
side = nghttp2.HD_SIDE_REQUEST
else:
side = nghttp2.HD_SIDE_RESPONSE
res = {
'draft':5, 'context': testdata['context'],
'description': '''\
......@@ -29,7 +24,7 @@ original. We make some headers not indexing at all, but this does not always \
result in less bits on the wire.'''
}
cases = []
deflater = nghttp2.HDDeflater(side, deflate_table_size)
deflater = nghttp2.HDDeflater(deflate_table_size)
deflater.change_table_size(table_size)
for casenum, item in enumerate(testdata['cases']):
outitem = {
......
......@@ -26,9 +26,6 @@ from libc.stdlib cimport malloc, free
from libc.string cimport memcpy, memset
from libc.stdint cimport uint8_t, uint16_t, uint32_t, int32_t
HD_SIDE_REQUEST = cnghttp2.NGHTTP2_HD_SIDE_REQUEST
HD_SIDE_RESPONSE = cnghttp2.NGHTTP2_HD_SIDE_RESPONSE
HD_DEFLATE_HD_TABLE_BUFSIZE_MAX = 4096
HD_ENTRY_OVERHEAD = cnghttp2.NGHTTP2_HD_ENTRY_OVERHEAD
......@@ -45,12 +42,6 @@ class HDTableEntry:
def space(self):
return self.namelen + self.valuelen + HD_ENTRY_OVERHEAD
cdef _change_table_size(cnghttp2.nghttp2_hd_context *ctx, hd_table_bufsize_max):
cdef int rv
rv = cnghttp2.nghttp2_hd_change_table_size(ctx, hd_table_bufsize_max)
if rv != 0:
raise Exception(_strerror(rv))
cdef _get_hd_table(cnghttp2.nghttp2_hd_context *ctx):
cdef int length = ctx.hd_table.len
cdef cnghttp2.nghttp2_hd_entry *entry
......@@ -65,35 +56,25 @@ cdef _get_hd_table(cnghttp2.nghttp2_hd_context *ctx):
return res
cdef _get_pybytes(uint8_t *b, uint16_t blen):
# While the |blen| is positive, the |b| could be NULL. This is
# because deflater may deallocate the byte strings its local table
# space.
if b == NULL and blen > 0:
val = None
else:
val = b[:blen]
return val
return b[:blen]
cdef class HDDeflater:
'''Performs header compression. The header compression algorithm has
to know the header set to be compressed is request headers or
response headers. It is indicated by |side| parameter in the
constructor. The constructor also takes |hd_table_bufsize_max|
parameter, which limits the usage of header table in the given
amount of bytes. This is necessary because the header compressor
and decompressor has to share the same amount of header table and
the decompressor decides that number. The compressor may not want
to use all header table size because of limited memory
availability. In that case, the |hd_table_bufsize_max| can be used
to cap the upper limit of talbe size whatever the header table
size is chosen. The default value of |hd_table_bufsize_max| is
4096 bytes.
'''Performs header compression. The constructor takes
|hd_table_bufsize_max| parameter, which limits the usage of header
table in the given amount of bytes. This is necessary because the
header compressor and decompressor has to share the same amount of
header table and the decompressor decides that number. The
compressor may not want to use all header table size because of
limited memory availability. In that case, the
|hd_table_bufsize_max| can be used to cap the upper limit of table
size whatever the header table size is chosen by the decompressor.
The default value of |hd_table_bufsize_max| is 4096 bytes.
The following example shows how to compress request header sets:
import binascii, nghttp2
deflater = nghttp2.HDDeflater(nghttp2.HD_SIDE_REQUEST)
deflater = nghttp2.HDDeflater()
res = deflater.deflate([(b'foo', b'bar'),
(b'baz', b'buz')])
print(binascii.b2a_hex(res))
......@@ -102,17 +83,13 @@ cdef class HDDeflater:
cdef cnghttp2.nghttp2_hd_deflater _deflater
def __cinit__(self, side,
def __cinit__(self,
hd_table_bufsize_max = HD_DEFLATE_HD_TABLE_BUFSIZE_MAX):
rv = cnghttp2.nghttp2_hd_deflate_init2(&self._deflater, side,
rv = cnghttp2.nghttp2_hd_deflate_init2(&self._deflater,
hd_table_bufsize_max)
if rv != 0:
raise Exception(_strerror(rv))
def __init__(self, side,
hd_table_bufsize_max = HD_DEFLATE_HD_TABLE_BUFSIZE_MAX):
super(HDDeflater, self).__init__()
def __dealloc__(self):
cnghttp2.nghttp2_hd_deflate_free(&self._deflater)
......@@ -165,7 +142,11 @@ cdef class HDDeflater:
An exception will be raised on error.
'''
_change_table_size(&self._deflater.ctx, hd_table_bufsize_max)
cdef int rv
rv = cnghttp2.nghttp2_hd_deflate_change_table_size(&self._deflater,
hd_table_bufsize_max)
if rv != 0:
raise Exception(_strerror(rv))
def get_hd_table(self,):
'''Returns copy of current dynamic header table.'''
......@@ -177,7 +158,7 @@ cdef class HDInflater:
The following example shows how to compress request header sets:
data = b'0082c5ad82bd0f000362617a0362757a'
inflater = nghttp2.HDInflater(nghttp2.HD_SIDE_REQUEST)
inflater = nghttp2.HDInflater()
hdrs = inflater.inflate(data)
print(hdrs)
......@@ -185,14 +166,11 @@ cdef class HDInflater:
cdef cnghttp2.nghttp2_hd_inflater _inflater
def __cinit__(self, side):
rv = cnghttp2.nghttp2_hd_inflate_init(&self._inflater, side)
def __cinit__(self):
rv = cnghttp2.nghttp2_hd_inflate_init(&self._inflater)
if rv != 0:
raise Exception(_strerror(rv))
def __init__(self, side):
super(HDInflater, self).__init__()
def __dealloc__(self):
cnghttp2.nghttp2_hd_inflate_free(&self._inflater)
......@@ -231,7 +209,11 @@ cdef class HDInflater:
An exception will be raised on error.
'''
_change_table_size(&self._inflater.ctx, hd_table_bufsize_max)
cdef int rv
rv = cnghttp2.nghttp2_hd_inflate_change_table_size(&self._inflater,
hd_table_bufsize_max)
if rv != 0:
raise Exception(_strerror(rv))
def get_hd_table(self):
'''Returns copy of current dynamic header table.'''
......@@ -255,5 +237,5 @@ def print_hd_table(hdtable):
print('[{}] (s={}) (r={}) {}: {}'\
.format(idx, entry.space(),
'y' if entry.ref else 'n',
'**DEALLOCATED**' if entry.name is None else entry.name.decode('utf-8'),
'**DEALLOCATED**' if entry.value is None else entry.value.decode('utf-8')))
entry.name.decode('utf-8'),
entry.value.decode('utf-8')))
......@@ -66,13 +66,13 @@ const std::string NGHTTPD_SERVER = "nghttpd nghttp2/" NGHTTP2_VERSION;
Config::Config()
: data_ptr(nullptr),
output_upper_thres(1024*1024),
padding(0),
header_table_size(-1),
port(0),
verbose(false),
daemon(false),
verify_client(false),
no_tls(false),
no_flow_control(false)
no_tls(false)
{}
Request::Request(int32_t stream_id)
......@@ -373,11 +373,6 @@ int Http2Handler::on_connect()
entry[0].value = 100;
entry[1].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
entry[1].value = 0;
if(sessions_->get_config()->no_flow_control) {
entry[niv].settings_id = NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS;
entry[niv].value = 1;
++niv;
}
if(sessions_->get_config()->header_table_size >= 0) {
entry[niv].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
entry[niv].value = sessions_->get_config()->header_table_size;
......@@ -930,6 +925,16 @@ int hd_on_frame_send_callback
}
} // namespace
namespace {
ssize_t select_padding_callback
(nghttp2_session *session, const nghttp2_frame *frame, size_t max_payload,
void *user_data)
{
auto hd = static_cast<Http2Handler*>(user_data);
return std::min(max_payload, frame->hd.length + hd->get_config()->padding);
}
} // namespace
namespace {
int on_data_chunk_recv_callback
(nghttp2_session *session, uint8_t flags, int32_t stream_id,
......@@ -976,6 +981,9 @@ void fill_callback(nghttp2_session_callbacks& callbacks, const Config *config)
callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback;
callbacks.on_header_callback = on_header_callback;
callbacks.on_begin_headers_callback = on_begin_headers_callback;
if(config->padding) {
callbacks.select_padding_callback = select_padding_callback;
}
}
} // namespace
......
......@@ -56,13 +56,13 @@ struct Config {
std::string cert_file;
void *data_ptr;
size_t output_upper_thres;
size_t padding;
ssize_t header_table_size;
uint16_t port;
bool verbose;
bool daemon;
bool verify_client;
bool no_tls;
bool no_flow_control;
Config();
};
......
......@@ -71,6 +71,7 @@ nghttpd_SOURCES = ${HELPER_OBJECTS} ${HELPER_HFILES} nghttpd.cc \
NGHTTPX_SRCS = \
util.cc util.h http2.cc http2.h timegm.c timegm.h base64.h \
app_helper.cc app_helper.h \
shrpx_config.cc shrpx_config.h \
shrpx_error.h \
shrpx_listen_handler.cc shrpx_listen_handler.h \
......
This diff is collapsed.
......@@ -86,6 +86,10 @@ void print_timer();
// variable.
void set_color_output(bool f);
// Set output file when printing HTTP2 frames. By default, stdout is
// used.
void set_output(FILE *file);
} // namespace nghttp2
#endif // APP_HELPER_H
......@@ -27,11 +27,7 @@
static void dump_val(json_t *jent, const char *key, uint8_t *val, size_t len)
{
if(val == NULL && len > 0) {
json_object_set_new(jent, key, json_string("**DEALLOCATED**"));
} else {
json_object_set_new(jent, key, json_pack("s#", val, len));
}
json_object_set_new(jent, key, json_pack("s#", val, len));
}
json_t* dump_header_table(nghttp2_hd_context *context)
......@@ -58,12 +54,6 @@ json_t* dump_header_table(nghttp2_hd_context *context)
json_object_set_new(obj, "size", json_integer(context->hd_table_bufsize));
json_object_set_new(obj, "max_size",
json_integer(context->hd_table_bufsize_max));
if(context->role == NGHTTP2_HD_ROLE_DEFLATE) {
json_object_set_new(obj, "deflate_size",
json_integer(context->deflate_hd_table_bufsize));
json_object_set_new(obj, "max_deflate_size",
json_integer(context->deflate_hd_table_bufsize_max));
}
return obj;
}
......@@ -93,13 +83,11 @@ json_t* dump_headers(const nghttp2_nv *nva, size_t nvlen)
return headers;
}
void output_json_header(int side)
void output_json_header(void)
{
printf("{\n"
" \"context\": \"%s\",\n"
" \"cases\":\n"
" [\n",
(side == NGHTTP2_HD_SIDE_REQUEST ? "request" : "response"));
" [\n");
}
void output_json_footer(void)
......
......@@ -40,7 +40,7 @@ json_t* dump_header(const uint8_t *name, size_t namelen,
json_t* dump_headers(const nghttp2_nv *nva, size_t nvlen);
void output_json_header(int side);
void output_json_header(void);
void output_json_footer(void);
......
......@@ -44,7 +44,6 @@
typedef struct {
size_t table_size;
size_t deflate_table_size;
nghttp2_hd_side side;
int http1text;
int dump_header_table;
int no_refset;
......@@ -174,11 +173,11 @@ static int deflate_hd_json(json_t *obj, nghttp2_hd_deflater *deflater, int seq)
return 0;
}
static void init_deflater(nghttp2_hd_deflater *deflater, nghttp2_hd_side side)
static void init_deflater(nghttp2_hd_deflater *deflater)
{
nghttp2_hd_deflate_init2(deflater, side, config.deflate_table_size);
nghttp2_hd_deflate_init2(deflater, config.deflate_table_size);
nghttp2_hd_deflate_set_no_refset(deflater, config.no_refset);
nghttp2_hd_change_table_size(&deflater->ctx, config.table_size);
nghttp2_hd_deflate_change_table_size(deflater, config.table_size);
}
static void deinit_deflater(nghttp2_hd_deflater *deflater)
......@@ -193,19 +192,12 @@ static int perform(void)
json_error_t error;
size_t len;
nghttp2_hd_deflater deflater;
nghttp2_hd_side side;
json = json_loadf(stdin, 0, &error);
if(json == NULL) {
fprintf(stderr, "JSON loading failed\n");
exit(EXIT_FAILURE);
}
if(strcmp("request", json_string_value(json_object_get(json, "context")))
== 0) {
side = NGHTTP2_HD_SIDE_REQUEST;
} else {
side = NGHTTP2_HD_SIDE_RESPONSE;
}
cases = json_object_get(json, "cases");
if(cases == NULL) {
fprintf(stderr, "Missing 'cases' key in root object\n");
......@@ -215,8 +207,8 @@ static int perform(void)
fprintf(stderr, "'cases' must be JSON array\n");
exit(EXIT_FAILURE);
}
init_deflater(&deflater, side);
output_json_header(side);
init_deflater(&deflater);
output_json_header();
len = json_array_size(cases);
for(i = 0; i < len; ++i) {
json_t *obj = json_array_get(cases, i);
......@@ -244,8 +236,8 @@ static int perform_from_http1text(void)
nghttp2_nv nva[256];
int seq = 0;
nghttp2_hd_deflater deflater;
init_deflater(&deflater, config.side);
output_json_header(config.side);
init_deflater(&deflater);
output_json_header();
for(;;) {
size_t nvlen = 0;
int end = 0;
......@@ -355,10 +347,6 @@ static void print_help(void)
"The output of this program can be used as input for inflatehd.\n"
"\n"
"OPTIONS:\n"
" -r, --response Use response compression context instead of\n"
" request if -t is used. For JSON input, it is\n"
" determined by inspecting \"context\" key in\n"
" root JSON object.\n"
" -t, --http1text Use HTTP/1 style header field text as input.\n"
" Each header set is delimited by single empty\n"
" line.\n"
......@@ -377,7 +365,6 @@ static void print_help(void)
}
static struct option long_options[] = {
{"response", no_argument, NULL, 'r'},
{"http1text", no_argument, NULL, 't'},
{"table-size", required_argument, NULL, 's'},
{"deflate-table-size", required_argument, NULL, 'S'},
......@@ -390,7 +377,6 @@ int main(int argc, char **argv)
{
char *end;
config.side = NGHTTP2_HD_SIDE_REQUEST;
config.table_size = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE;
config.deflate_table_size = NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE;
config.http1text = 0;
......@@ -398,15 +384,11 @@ int main(int argc, char **argv)
config.no_refset = 0;
while(1) {
int option_index = 0;
int c = getopt_long(argc, argv, "S:cdhrs:t", long_options, &option_index);
int c = getopt_long(argc, argv, "S:cdhs:t", long_options, &option_index);
if(c == -1) {
break;
}
switch(c) {
case 'r':
/* --response */
config.side = NGHTTP2_HD_SIDE_RESPONSE;
break;
case 'h':
print_help();
exit(EXIT_SUCCESS);
......
......@@ -42,7 +42,6 @@
#include "comp_helper.h"
typedef struct {
size_t table_size;
int dump_header_table;
} inflate_config;
......@@ -110,8 +109,8 @@ static int inflate_hd(json_t *obj, nghttp2_hd_inflater *inflater, int seq)
seq);
return -1;
}
rv = nghttp2_hd_change_table_size(&inflater->ctx,
json_integer_value(table_size));
rv = nghttp2_hd_inflate_change_table_size(inflater,
json_integer_value(table_size));
if(rv != 0) {
fprintf(stderr,
"nghttp2_hd_change_table_size() failed with error %s at %d\n",
......@@ -163,19 +162,12 @@ static int perform(void)
json_t *json, *cases;
json_error_t error;
size_t len;
nghttp2_hd_side side;
json = json_loadf(stdin, 0, &error);
if(json == NULL) {
fprintf(stderr, "JSON loading failed\n");
exit(EXIT_FAILURE);
}
if(strcmp("request", json_string_value(json_object_get(json, "context")))
== 0) {
side = NGHTTP2_HD_SIDE_REQUEST;
} else {
side = NGHTTP2_HD_SIDE_RESPONSE;
}
cases = json_object_get(json, "cases");
if(cases == NULL) {
fprintf(stderr, "Missing 'cases' key in root object\n");
......@@ -185,10 +177,8 @@ static int perform(void)
fprintf(stderr, "'cases' must be JSON array\n");
exit(EXIT_FAILURE);
}
nghttp2_hd_inflate_init(&inflater, side);
nghttp2_hd_change_table_size(&inflater.ctx, config.table_size);
output_json_header(side);
nghttp2_hd_inflate_init(&inflater);
output_json_header();
len = json_array_size(cases);
for(i = 0; i < len; ++i) {
json_t *obj = json_array_get(cases, i);
......@@ -241,29 +231,21 @@ static void print_help(void)
"The output of this program can be used as input for deflatehd.\n"
"\n"
"OPTIONS:\n"
" -s, --table-size=<N>\n"
" Set dynamic table size. In the HPACK\n"
" specification, this value is denoted by\n"
" SETTINGS_HEADER_TABLE_SIZE.\n"
" Default: 4096\n"
" -d, --dump-header-table\n"
" Output dynamic header table.\n");
}
static struct option long_options[] = {
{"table-size", required_argument, NULL, 's'},
{"dump-header-table", no_argument, NULL, 'd'},
{NULL, 0, NULL, 0 }
};
int main(int argc, char **argv)
{
char *end;
config.table_size = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE;
config.dump_header_table = 0;
while(1) {
int option_index = 0;
int c = getopt_long(argc, argv, "dhs:", long_options, &option_index);
int c = getopt_long(argc, argv, "dh", long_options, &option_index);
if(c == -1) {
break;
}
......@@ -271,15 +253,6 @@ int main(int argc, char **argv)
case 'h':
print_help();
exit(EXIT_SUCCESS);
case 's':
/* --table-size */
errno = 0;
config.table_size = strtoul(optarg, &end, 10);
if(errno == ERANGE || *end != '\0') {
fprintf(stderr, "-s: Bad option value\n");
exit(EXIT_FAILURE);
}
break;
case 'd':
/* --dump-header-table */
config.dump_header_table = 1;
......
......@@ -82,6 +82,7 @@ struct Config {
std::string keyfile;
std::string datafile;
size_t output_upper_thres;
size_t padding;
ssize_t peer_max_concurrent_streams;
ssize_t header_table_size;
int32_t pri;
......@@ -95,10 +96,11 @@ struct Config {
bool verbose;
bool get_assets;
bool stat;
bool no_flow_control;
bool upgrade;
bool continuation;
Config()
: output_upper_thres(1024*1024),
padding(0),
peer_max_concurrent_streams(NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS),
header_table_size(-1),
pri(NGHTTP2_PRI_DEFAULT),
......@@ -111,8 +113,8 @@ struct Config {
verbose(false),
get_assets(false),
stat(false),
no_flow_control(false),
upgrade(false)
upgrade(false),
continuation(false)
{}
};
} // namespace
......@@ -366,11 +368,6 @@ size_t populate_settings(nghttp2_settings_entry *iv)
} else {
iv[1].value = NGHTTP2_INITIAL_WINDOW_SIZE;
}
if(config.no_flow_control) {
iv[niv].settings_id = NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS;
iv[niv].value = 1;
++niv;
}
if(config.header_table_size >= 0) {
iv[niv].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
iv[niv].value = config.header_table_size;
......@@ -964,6 +961,12 @@ int submit_request
{"accept", "*/*"},
{"accept-encoding", "gzip, deflate"},
{"user-agent", "nghttp2/" NGHTTP2_VERSION}};
if(config.continuation) {
for(size_t i = 0; i < 8; ++i) {
build_headers.emplace_back("continuation-test-" + util::utos(i+1),
std::string(4096, '-'));
}
}
auto num_initial_headers = build_headers.size();
if(req->data_prd) {
build_headers.emplace_back("content-length", util::utos(req->data_length));
......@@ -1123,6 +1126,15 @@ int before_frame_send_callback
}
} // namespace
namespace {
ssize_t select_padding_callback
(nghttp2_session *session, const nghttp2_frame *frame, size_t max_payload,
void *user_data)
{
return std::min(max_payload, frame->hd.length + config.padding);
}
} // namespace
namespace {
void check_response_header(nghttp2_session *session, Request* req)
{
......@@ -1579,6 +1591,9 @@ int run(char **uris, int n)
}
callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback;
callbacks.on_header_callback = on_header_callback;
if(config.padding) {
callbacks.select_padding_callback = select_padding_callback;
}
std::string prev_scheme;
std::string prev_host;
......@@ -1642,9 +1657,9 @@ int run(char **uris, int n)
namespace {
void print_usage(std::ostream& out)
{
out << "Usage: nghttp [-Oafnsuv] [-t <SECONDS>] [-w <WINDOW_BITS>] [-W <WINDOW_BITS>]\n"
out << "Usage: nghttp [-Oansuv] [-t <SECONDS>] [-w <WINDOW_BITS>] [-W <WINDOW_BITS>]\n"
<< " [--cert=<CERT>] [--key=<KEY>] [-d <FILE>] [-m <N>]\n"
<< " [-p <PRIORITY>] [-M <N>]\n"
<< " [-p <PRIORITY>] [-M <N>] [-b <ALIGNMENT>]\n"
<< " <URI>..."
<< std::endl;
}
......@@ -1686,9 +1701,6 @@ void print_help(std::ostream& out)
<< " -m, --multiply=<N> Request each URI <N> times. By default, same\n"
<< " URI is not requested twice. This option\n"
<< " disables it too.\n"
<< " -f, --no-flow-control\n"
<< " Disables connection and stream level flow\n"
<< " controls.\n"
<< " -u, --upgrade Perform HTTP Upgrade for HTTP/2.0. This\n"
<< " option is ignored if the request URI has\n"
<< " https scheme.\n"
......@@ -1704,7 +1716,10 @@ void print_help(std::ostream& out)
<< " is large enough as it is seen as unlimited.\n"
<< " -c, --header-table-size=<N>\n"
<< " Specify decoder header table size.\n"
<< " -b, --padding=<N> Add at most <N> bytes to a frame payload as\n"
<< " padding. Specify 0 to disable padding.\n"
<< " --color Force colored log output.\n"
<< " --continuation Send large header to test CONTINUATION.\n"
<< std::endl;
}
} // namespace
......@@ -1727,18 +1742,19 @@ int main(int argc, char **argv)
{"header", required_argument, nullptr, 'H'},
{"data", required_argument, nullptr, 'd'},
{"multiply", required_argument, nullptr, 'm'},
{"no-flow-control", no_argument, nullptr, 'f'},
{"upgrade", no_argument, nullptr, 'u'},
{"pri", required_argument, nullptr, 'p'},
{"peer-max-concurrent-streams", required_argument, nullptr, 'M'},
{"header-table-size", required_argument, nullptr, 'c'},
{"padding", required_argument, nullptr, 'b'},
{"cert", required_argument, &flag, 1},
{"key", required_argument, &flag, 2},
{"color", no_argument, &flag, 3},
{"continuation", no_argument, &flag, 4},
{nullptr, 0, nullptr, 0 }
};
int option_index = 0;
int c = getopt_long(argc, argv, "M:Oac:d:fm:np:hH:vst:uw:W:", long_options,
int c = getopt_long(argc, argv, "M:Oab:c:d:m:np:hH:vst:uw:W:", long_options,
&option_index);
char *end;
if(c == -1) {
......@@ -1752,12 +1768,12 @@ int main(int argc, char **argv)
case 'O':
config.remote_name = true;
break;
case 'f':
config.no_flow_control = true;
break;
case 'h':
print_help(std::cout);
exit(EXIT_SUCCESS);
case 'b':
config.padding = strtol(optarg, nullptr, 10);
break;
case 'n':
config.null_out = true;
break;
......@@ -1869,6 +1885,10 @@ int main(int argc, char **argv)
// color option
color = true;
break;
case 4:
// continuation option
config.continuation = true;
break;
}
break;
default:
......
......@@ -75,7 +75,8 @@ int parse_push_config(Config& config, const char *optarg)
namespace {
void print_usage(std::ostream& out)
{
out << "Usage: nghttpd [-DVfhv] [-d <PATH>] [--no-tls] <PORT> [<PRIVATE_KEY> <CERT>]"
out << "Usage: nghttpd [-DVhpv] [-d <PATH>] [--no-tls] [-b <ALIGNMENT>]\n"
<< " <PORT> [<PRIVATE_KEY> <CERT>]"
<< std::endl;
}
} // namespace
......@@ -103,9 +104,6 @@ void print_help(std::ostream& out)
<< " -v, --verbose Print debug information such as reception/\n"
<< " transmission of frames and name/value pairs.\n"
<< " --no-tls Disable SSL/TLS.\n"
<< " -f, --no-flow-control\n"
<< " Disables connection and stream level flow\n"
<< " controls.\n"
<< " -c, --header-table-size=<N>\n"
<< " Specify decoder header table size.\n"
<< " --color Force colored log output.\n"
......@@ -117,6 +115,8 @@ void print_help(std::ostream& out)
<< " -p/=/foo.png -p/doc=/bar.css\n"
<< " PATH and PUSH_PATHs are relative to document\n"
<< " root. See --htdocs option.\n"
<< " -b, --padding=<N> Add at most <N> bytes to a frame payload as\n"
<< " padding. Specify 0 to disable padding.\n"
<< " -h, --help Print this help.\n"
<< std::endl;
}
......@@ -134,15 +134,15 @@ int main(int argc, char **argv)
{"help", no_argument, nullptr, 'h'},
{"verbose", no_argument, nullptr, 'v'},
{"verify-client", no_argument, nullptr, 'V'},
{"no-flow-control", no_argument, nullptr, 'f'},
{"header-table-size", required_argument, nullptr, 'c'},
{"push", required_argument, nullptr, 'p'},
{"padding", required_argument, nullptr, 'b'},
{"no-tls", no_argument, &flag, 1},
{"color", no_argument, &flag, 2},
{nullptr, 0, nullptr, 0}
};
int option_index = 0;
int c = getopt_long(argc, argv, "DVc:d:fhp:v", long_options, &option_index);
int c = getopt_long(argc, argv, "DVb:c:d:hp:v", long_options, &option_index);
char *end;
if(c == -1) {
break;
......@@ -154,12 +154,12 @@ int main(int argc, char **argv)
case 'V':
config.verify_client = true;
break;
case 'b':
config.padding = strtol(optarg, nullptr, 10);
break;
case 'd':
config.htdocs = optarg;
break;
case 'f':
config.no_flow_control = true;
break;
case 'h':
print_help(std::cout);
exit(EXIT_SUCCESS);
......
......@@ -53,6 +53,7 @@
#include "shrpx_listen_handler.h"
#include "shrpx_ssl.h"
#include "util.h"
#include "app_helper.h"
using namespace nghttp2;
......@@ -435,6 +436,8 @@ void fill_default_config()
mod_config()->http2_upstream_dump_request_header = nullptr;
mod_config()->http2_upstream_dump_response_header = nullptr;
mod_config()->http2_no_cookie_crumbling = false;
mod_config()->upstream_frame_debug = false;
mod_config()->padding = 0;
}
} // namespace
......@@ -673,6 +676,11 @@ void print_help(std::ostream& out)
<< " --backend-no-tls Disable SSL/TLS on backend connections.\n"
<< " --http2-no-cookie-crumbling\n"
<< " Don't crumble cookie header field.\n"
<< " --padding=<N> Add at most <N> bytes to a HTTP/2 frame payload\n"
<< " as padding.\n"
<< " Specify 0 to disable padding. This option is\n"
<< " meant for debugging purpose and not intended\n"
<< " to enhance protocol security.\n"
<< "\n"
<< " Mode:\n"
<< " (default mode) Accept HTTP/2.0, SPDY and HTTP/1.1 over\n"
......@@ -736,6 +744,10 @@ void print_help(std::ostream& out)
<< " an empty line.\n"
<< " This option is not thread safe and MUST NOT\n"
<< " be used with option -n=N, where N >= 2.\n"
<< " -o, --frontend-frame-debug\n"
<< " Print HTTP/2 frames in frontend to stderr.\n"
<< " This option is not thread safe and MUST NOT\n"
<< " be used with option -n=N, where N >= 2.\n"
<< " -D, --daemon Run in a background. If -D is used, the\n"
<< " current working directory is changed to '/'.\n"
<< " --pid-file=<PATH> Set path to save PID of this program.\n"
......@@ -771,6 +783,7 @@ int main(int argc, char **argv)
{"client-proxy", no_argument, nullptr, 'p'},
{"http2-proxy", no_argument, nullptr, 's'},
{"version", no_argument, nullptr, 'v'},
{"frontend-frame-debug", no_argument, nullptr, 'o'},
{"add-x-forwarded-for", no_argument, &flag, 1},
{"frontend-http2-read-timeout", required_argument, &flag, 2},
{"frontend-read-timeout", required_argument, &flag, 3},
......@@ -817,11 +830,12 @@ int main(int argc, char **argv)
{"frontend-http2-connection-window-bits", required_argument, &flag, 46},
{"backend-http2-connection-window-bits", required_argument, &flag, 47},
{"tls-proto-list", required_argument, &flag, 48},
{"padding", required_argument, &flag, 49},
{nullptr, 0, nullptr, 0 }
};
int option_index = 0;
int c = getopt_long(argc, argv, "DL:b:c:f:hkn:psv", long_options,
int c = getopt_long(argc, argv, "DL:b:c:f:hkn:opsv", long_options,
&option_index);
if(c == -1) {
break;
......@@ -851,6 +865,9 @@ int main(int argc, char **argv)
case 'n':
cmdcfgs.emplace_back(SHRPX_OPT_WORKERS, optarg);
break;
case 'o':
cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_FRAME_DEBUG, "yes");
break;
case 'p':
cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_PROXY, "yes");
break;
......@@ -1050,6 +1067,10 @@ int main(int argc, char **argv)
// --tls-proto-list
cmdcfgs.emplace_back(SHRPX_OPT_TLS_PROTO_LIST, optarg);
break;
case 49:
// --padding
cmdcfgs.emplace_back(SHRPX_OPT_PADDING, optarg);
break;
default:
break;
}
......@@ -1204,6 +1225,15 @@ int main(int argc, char **argv)
get_rate_limit(get_config()->write_burst),
nullptr);
if(get_config()->upstream_frame_debug) {
// To make it sync to logging
set_output(stderr);
if(isatty(fileno(stdout))) {
set_color_output(true);
}
reset_timer();
}
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_handler = SIG_IGN;
......
......@@ -115,6 +115,8 @@ const char SHRPX_OPT_FRONTEND_HTTP2_DUMP_REQUEST_HEADER[] =
const char SHRPX_OPT_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER[] =
"frontend-http2-dump-response-header";
const char SHRPX_OPT_HTTP2_NO_COOKIE_CRUMBLING[] = "http2-no-cookie-crumbling";
const char SHRPX_OPT_FRONTEND_FRAME_DEBUG[] = "frontend-frame-debug";
const char SHRPX_OPT_PADDING[] = "padding";
namespace {
Config *config = nullptr;
......@@ -480,6 +482,10 @@ int parse_config(const char *opt, const char *optarg)
mod_config()->http2_upstream_dump_response_header = f;
} else if(util::strieq(opt, SHRPX_OPT_HTTP2_NO_COOKIE_CRUMBLING)) {
mod_config()->http2_no_cookie_crumbling = util::strieq(optarg, "yes");
} else if(util::strieq(opt, SHRPX_OPT_FRONTEND_FRAME_DEBUG)) {
mod_config()->upstream_frame_debug = util::strieq(optarg, "yes");
} else if(util::strieq(opt, SHRPX_OPT_PADDING)) {
mod_config()->padding = strtoul(optarg, nullptr, 10);
} else if(util::strieq(opt, "conf")) {
LOG(WARNING) << "conf is ignored";
} else {
......
......@@ -102,6 +102,8 @@ extern const char SHRPX_OPT_CLIENT_CERT_FILE[];
extern const char SHRPX_OPT_FRONTEND_HTTP2_DUMP_REQUEST_HEADER[];
extern const char SHRPX_OPT_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER[];
extern const char SHRPX_OPT_HTTP2_NO_COOKIE_CRUMBLING[];
extern const char SHRPX_OPT_FRONTEND_FRAME_DEBUG[];
extern const char SHRPX_OPT_PADDING[];
union sockaddr_union {
sockaddr sa;
......@@ -179,6 +181,7 @@ struct Config {
size_t npn_list_len;
// The number of elements in tls_proto_list
size_t tls_proto_list_len;
size_t padding;
// downstream protocol; this will be determined by given options.
shrpx_proto downstream_proto;
int syslog_facility;
......@@ -213,6 +216,7 @@ struct Config {
// true if stderr refers to a terminal.
bool tty;
bool http2_no_cookie_crumbling;
bool upstream_frame_debug;
};
const Config* get_config();
......
......@@ -94,6 +94,13 @@ std::string colorizeHeaders(const char *hdrs)
return nhdrs;
}
ssize_t select_padding_callback
(nghttp2_session *session, const nghttp2_frame *frame, size_t max_payload,
void *user_data)
{
return std::min(max_payload, frame->hd.length + get_config()->padding);
}
} // namespace http
} // namespace shrpx
......@@ -29,6 +29,8 @@
#include <string>
#include <nghttp2/nghttp2.h>
namespace shrpx {
namespace http {
......@@ -40,6 +42,10 @@ std::string create_via_header_value(int major, int minor);
// Adds ANSI color codes to HTTP headers |hdrs|.
std::string colorizeHeaders(const char *hdrs);
ssize_t select_padding_callback
(nghttp2_session *session, const nghttp2_frame *frame, size_t max_payload,
void *user_data);
} // namespace http
} // namespace shrpx
......
......@@ -1193,6 +1193,9 @@ int Http2Session::on_connect()
callbacks.on_unknown_frame_recv_callback = on_unknown_frame_recv_callback;
callbacks.on_header_callback = on_header_callback;
callbacks.on_begin_headers_callback = on_begin_headers_callback;
if(get_config()->padding) {
callbacks.select_padding_callback = http::select_padding_callback;
}
nghttp2_opt_set opt_set;
opt_set.no_auto_stream_window_update = 1;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -28,7 +28,6 @@
void test_nghttp2_hd_deflate(void);
void test_nghttp2_hd_deflate_same_indexed_repr(void);
void test_nghttp2_hd_deflate_common_header_eviction(void);
void test_nghttp2_hd_deflate_deflate_buffer(void);
void test_nghttp2_hd_deflate_clear_refset(void);
void test_nghttp2_hd_inflate_indname_noinc(void);
void test_nghttp2_hd_inflate_indname_inc(void);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment