mirror of
https://gitee.com/openharmony/third_party_nghttp2
synced 2024-11-26 17:40:25 +00:00
c10a55588b
This commit implements RFC 9218 extensible prioritization scheme. It is enabled when a local endpoint submits SETTINGS_NO_RFC7540_PRIORITIES = 1. This commit only handles priority signal in HTTP request header field. Priority header field in PUSH_PROMISE is not supported. HTTP messaging must be enabled to take advantage of this prioritization scheme because HTTP fields are not parsed if HTTP messaging is disabled.
441 lines
14 KiB
C
441 lines
14 KiB
C
/*
|
|
* nghttp2 - HTTP/2 C Library
|
|
*
|
|
* Copyright (c) 2013 Tatsuhiro Tsujikawa
|
|
*
|
|
* 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 NGHTTP2_HD_H
|
|
#define NGHTTP2_HD_H
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif /* HAVE_CONFIG_H */
|
|
|
|
#include <nghttp2/nghttp2.h>
|
|
|
|
#include "nghttp2_hd_huffman.h"
|
|
#include "nghttp2_buf.h"
|
|
#include "nghttp2_mem.h"
|
|
#include "nghttp2_rcbuf.h"
|
|
|
|
#define NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE NGHTTP2_DEFAULT_HEADER_TABLE_SIZE
|
|
#define NGHTTP2_HD_ENTRY_OVERHEAD 32
|
|
|
|
/* The maximum length of one name/value pair. This is the sum of the
|
|
length of name and value. This is not specified by the spec. We
|
|
just chose the arbitrary size */
|
|
#define NGHTTP2_HD_MAX_NV 65536
|
|
|
|
/* Default size of maximum table buffer size for encoder. Even if
|
|
remote decoder notifies larger buffer size for its decoding,
|
|
encoder only uses the memory up to this value. */
|
|
#define NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE (1 << 12)
|
|
|
|
/* Exported for unit test */
|
|
#define NGHTTP2_STATIC_TABLE_LENGTH 61
|
|
|
|
/* Generated by genlibtokenlookup.py */
|
|
typedef enum {
|
|
NGHTTP2_TOKEN__AUTHORITY = 0,
|
|
NGHTTP2_TOKEN__METHOD = 1,
|
|
NGHTTP2_TOKEN__PATH = 3,
|
|
NGHTTP2_TOKEN__SCHEME = 5,
|
|
NGHTTP2_TOKEN__STATUS = 7,
|
|
NGHTTP2_TOKEN_ACCEPT_CHARSET = 14,
|
|
NGHTTP2_TOKEN_ACCEPT_ENCODING = 15,
|
|
NGHTTP2_TOKEN_ACCEPT_LANGUAGE = 16,
|
|
NGHTTP2_TOKEN_ACCEPT_RANGES = 17,
|
|
NGHTTP2_TOKEN_ACCEPT = 18,
|
|
NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN = 19,
|
|
NGHTTP2_TOKEN_AGE = 20,
|
|
NGHTTP2_TOKEN_ALLOW = 21,
|
|
NGHTTP2_TOKEN_AUTHORIZATION = 22,
|
|
NGHTTP2_TOKEN_CACHE_CONTROL = 23,
|
|
NGHTTP2_TOKEN_CONTENT_DISPOSITION = 24,
|
|
NGHTTP2_TOKEN_CONTENT_ENCODING = 25,
|
|
NGHTTP2_TOKEN_CONTENT_LANGUAGE = 26,
|
|
NGHTTP2_TOKEN_CONTENT_LENGTH = 27,
|
|
NGHTTP2_TOKEN_CONTENT_LOCATION = 28,
|
|
NGHTTP2_TOKEN_CONTENT_RANGE = 29,
|
|
NGHTTP2_TOKEN_CONTENT_TYPE = 30,
|
|
NGHTTP2_TOKEN_COOKIE = 31,
|
|
NGHTTP2_TOKEN_DATE = 32,
|
|
NGHTTP2_TOKEN_ETAG = 33,
|
|
NGHTTP2_TOKEN_EXPECT = 34,
|
|
NGHTTP2_TOKEN_EXPIRES = 35,
|
|
NGHTTP2_TOKEN_FROM = 36,
|
|
NGHTTP2_TOKEN_HOST = 37,
|
|
NGHTTP2_TOKEN_IF_MATCH = 38,
|
|
NGHTTP2_TOKEN_IF_MODIFIED_SINCE = 39,
|
|
NGHTTP2_TOKEN_IF_NONE_MATCH = 40,
|
|
NGHTTP2_TOKEN_IF_RANGE = 41,
|
|
NGHTTP2_TOKEN_IF_UNMODIFIED_SINCE = 42,
|
|
NGHTTP2_TOKEN_LAST_MODIFIED = 43,
|
|
NGHTTP2_TOKEN_LINK = 44,
|
|
NGHTTP2_TOKEN_LOCATION = 45,
|
|
NGHTTP2_TOKEN_MAX_FORWARDS = 46,
|
|
NGHTTP2_TOKEN_PROXY_AUTHENTICATE = 47,
|
|
NGHTTP2_TOKEN_PROXY_AUTHORIZATION = 48,
|
|
NGHTTP2_TOKEN_RANGE = 49,
|
|
NGHTTP2_TOKEN_REFERER = 50,
|
|
NGHTTP2_TOKEN_REFRESH = 51,
|
|
NGHTTP2_TOKEN_RETRY_AFTER = 52,
|
|
NGHTTP2_TOKEN_SERVER = 53,
|
|
NGHTTP2_TOKEN_SET_COOKIE = 54,
|
|
NGHTTP2_TOKEN_STRICT_TRANSPORT_SECURITY = 55,
|
|
NGHTTP2_TOKEN_TRANSFER_ENCODING = 56,
|
|
NGHTTP2_TOKEN_USER_AGENT = 57,
|
|
NGHTTP2_TOKEN_VARY = 58,
|
|
NGHTTP2_TOKEN_VIA = 59,
|
|
NGHTTP2_TOKEN_WWW_AUTHENTICATE = 60,
|
|
NGHTTP2_TOKEN_TE,
|
|
NGHTTP2_TOKEN_CONNECTION,
|
|
NGHTTP2_TOKEN_KEEP_ALIVE,
|
|
NGHTTP2_TOKEN_PROXY_CONNECTION,
|
|
NGHTTP2_TOKEN_UPGRADE,
|
|
NGHTTP2_TOKEN__PROTOCOL,
|
|
NGHTTP2_TOKEN_PRIORITY,
|
|
} nghttp2_token;
|
|
|
|
struct nghttp2_hd_entry;
|
|
typedef struct nghttp2_hd_entry nghttp2_hd_entry;
|
|
|
|
typedef struct {
|
|
/* The buffer containing header field name. NULL-termination is
|
|
guaranteed. */
|
|
nghttp2_rcbuf *name;
|
|
/* The buffer containing header field value. NULL-termination is
|
|
guaranteed. */
|
|
nghttp2_rcbuf *value;
|
|
/* nghttp2_token value for name. It could be -1 if we have no token
|
|
for that header field name. */
|
|
int32_t token;
|
|
/* Bitwise OR of one or more of nghttp2_nv_flag. */
|
|
uint8_t flags;
|
|
} nghttp2_hd_nv;
|
|
|
|
struct nghttp2_hd_entry {
|
|
/* The header field name/value pair */
|
|
nghttp2_hd_nv nv;
|
|
/* This is solely for nghttp2_hd_{deflate,inflate}_get_table_entry
|
|
APIs to keep backward compatibility. */
|
|
nghttp2_nv cnv;
|
|
/* The next entry which shares same bucket in hash table. */
|
|
nghttp2_hd_entry *next;
|
|
/* The sequence number. We will increment it by one whenever we
|
|
store nghttp2_hd_entry to dynamic header table. */
|
|
uint32_t seq;
|
|
/* The hash value for header name (nv.name). */
|
|
uint32_t hash;
|
|
};
|
|
|
|
/* The entry used for static header table. */
|
|
typedef struct {
|
|
nghttp2_rcbuf name;
|
|
nghttp2_rcbuf value;
|
|
nghttp2_nv cnv;
|
|
int32_t token;
|
|
uint32_t hash;
|
|
} nghttp2_hd_static_entry;
|
|
|
|
typedef struct {
|
|
nghttp2_hd_entry **buffer;
|
|
size_t mask;
|
|
size_t first;
|
|
size_t len;
|
|
} nghttp2_hd_ringbuf;
|
|
|
|
typedef enum {
|
|
NGHTTP2_HD_OPCODE_NONE,
|
|
NGHTTP2_HD_OPCODE_INDEXED,
|
|
NGHTTP2_HD_OPCODE_NEWNAME,
|
|
NGHTTP2_HD_OPCODE_INDNAME
|
|
} nghttp2_hd_opcode;
|
|
|
|
typedef enum {
|
|
NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE,
|
|
NGHTTP2_HD_STATE_INFLATE_START,
|
|
NGHTTP2_HD_STATE_OPCODE,
|
|
NGHTTP2_HD_STATE_READ_TABLE_SIZE,
|
|
NGHTTP2_HD_STATE_READ_INDEX,
|
|
NGHTTP2_HD_STATE_NEWNAME_CHECK_NAMELEN,
|
|
NGHTTP2_HD_STATE_NEWNAME_READ_NAMELEN,
|
|
NGHTTP2_HD_STATE_NEWNAME_READ_NAMEHUFF,
|
|
NGHTTP2_HD_STATE_NEWNAME_READ_NAME,
|
|
NGHTTP2_HD_STATE_CHECK_VALUELEN,
|
|
NGHTTP2_HD_STATE_READ_VALUELEN,
|
|
NGHTTP2_HD_STATE_READ_VALUEHUFF,
|
|
NGHTTP2_HD_STATE_READ_VALUE
|
|
} nghttp2_hd_inflate_state;
|
|
|
|
typedef enum {
|
|
NGHTTP2_HD_WITH_INDEXING,
|
|
NGHTTP2_HD_WITHOUT_INDEXING,
|
|
NGHTTP2_HD_NEVER_INDEXING
|
|
} nghttp2_hd_indexing_mode;
|
|
|
|
typedef struct {
|
|
/* dynamic header table */
|
|
nghttp2_hd_ringbuf hd_table;
|
|
/* Memory allocator */
|
|
nghttp2_mem *mem;
|
|
/* Abstract buffer size of hd_table as described in the spec. This
|
|
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 effective header table size. */
|
|
size_t hd_table_bufsize_max;
|
|
/* Next sequence number for nghttp2_hd_entry */
|
|
uint32_t next_seq;
|
|
/* If inflate/deflate error occurred, this value is set to 1 and
|
|
further invocation of inflate/deflate will fail with
|
|
NGHTTP2_ERR_HEADER_COMP. */
|
|
uint8_t bad;
|
|
} nghttp2_hd_context;
|
|
|
|
#define HD_MAP_SIZE 128
|
|
|
|
typedef struct {
|
|
nghttp2_hd_entry *table[HD_MAP_SIZE];
|
|
} nghttp2_hd_map;
|
|
|
|
struct nghttp2_hd_deflater {
|
|
nghttp2_hd_context ctx;
|
|
nghttp2_hd_map map;
|
|
/* The upper limit of the header table size the deflater accepts. */
|
|
size_t deflate_hd_table_bufsize_max;
|
|
/* Minimum header table size notified in the next context update */
|
|
size_t min_hd_table_bufsize_max;
|
|
/* If nonzero, send header table size using encoding context update
|
|
in the next deflate process */
|
|
uint8_t notify_table_size_change;
|
|
};
|
|
|
|
struct nghttp2_hd_inflater {
|
|
nghttp2_hd_context ctx;
|
|
/* Stores current state of huffman decoding */
|
|
nghttp2_hd_huff_decode_context huff_decode_ctx;
|
|
/* header buffer */
|
|
nghttp2_buf namebuf, valuebuf;
|
|
nghttp2_rcbuf *namercbuf, *valuercbuf;
|
|
/* Pointer to the name/value pair which are used in the current
|
|
header emission. */
|
|
nghttp2_rcbuf *nv_name_keep, *nv_value_keep;
|
|
/* The number of bytes to read */
|
|
size_t left;
|
|
/* The index in indexed repr or indexed name */
|
|
size_t 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;
|
|
/* Minimum header table size set by nghttp2_hd_inflate_change_table_size */
|
|
size_t min_hd_table_bufsize_max;
|
|
/* The number of next shift to decode integer */
|
|
size_t shift;
|
|
nghttp2_hd_opcode opcode;
|
|
nghttp2_hd_inflate_state state;
|
|
/* nonzero if string is huffman encoded */
|
|
uint8_t huffman_encoded;
|
|
/* nonzero if deflater requires that current entry is indexed */
|
|
uint8_t index_required;
|
|
/* nonzero if deflater requires that current entry must not be
|
|
indexed */
|
|
uint8_t no_index;
|
|
};
|
|
|
|
/*
|
|
* Initializes the |ent| members. The reference counts of nv->name
|
|
* and nv->value are increased by one for each.
|
|
*/
|
|
void nghttp2_hd_entry_init(nghttp2_hd_entry *ent, nghttp2_hd_nv *nv);
|
|
|
|
/*
|
|
* This function decreases the reference counts of nv->name and
|
|
* nv->value.
|
|
*/
|
|
void nghttp2_hd_entry_free(nghttp2_hd_entry *ent);
|
|
|
|
/*
|
|
* Initializes |deflater| for deflating name/values pairs.
|
|
*
|
|
* The encoder only uses up to
|
|
* NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE bytes for header table
|
|
* even if the larger value is specified later in
|
|
* nghttp2_hd_change_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_deflate_init(nghttp2_hd_deflater *deflater, nghttp2_mem *mem);
|
|
|
|
/*
|
|
* Initializes |deflater| for deflating name/values pairs.
|
|
*
|
|
* The encoder only uses up to |max_deflate_dynamic_table_size| bytes
|
|
* for header table even if the larger value is specified later in
|
|
* nghttp2_hd_change_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_deflate_init2(nghttp2_hd_deflater *deflater,
|
|
size_t max_deflate_dynamic_table_size,
|
|
nghttp2_mem *mem);
|
|
|
|
/*
|
|
* Deallocates any resources allocated for |deflater|.
|
|
*/
|
|
void nghttp2_hd_deflate_free(nghttp2_hd_deflater *deflater);
|
|
|
|
/*
|
|
* Deflates the |nva|, which has the |nvlen| name/value pairs, into
|
|
* the |bufs|.
|
|
*
|
|
* This function expands |bufs| as necessary to store the result. If
|
|
* buffers is full and the process still requires more space, this
|
|
* function fails and returns NGHTTP2_ERR_HEADER_COMP.
|
|
*
|
|
* After this function returns, it is safe to delete the |nva|.
|
|
*
|
|
* This function returns 0 if it succeeds, or one of the following
|
|
* negative error codes:
|
|
*
|
|
* NGHTTP2_ERR_NOMEM
|
|
* Out of memory.
|
|
* NGHTTP2_ERR_HEADER_COMP
|
|
* Deflation process has failed.
|
|
* NGHTTP2_ERR_BUFFER_ERROR
|
|
* Out of buffer space.
|
|
*/
|
|
int nghttp2_hd_deflate_hd_bufs(nghttp2_hd_deflater *deflater,
|
|
nghttp2_bufs *bufs, const nghttp2_nv *nva,
|
|
size_t nvlen);
|
|
|
|
/*
|
|
* Initializes |inflater| for inflating name/values pairs.
|
|
*
|
|
* This function returns 0 if it succeeds, or one of the following
|
|
* negative error codes:
|
|
*
|
|
* :enum:`NGHTTP2_ERR_NOMEM`
|
|
* Out of memory.
|
|
*/
|
|
int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, nghttp2_mem *mem);
|
|
|
|
/*
|
|
* Deallocates any resources allocated for |inflater|.
|
|
*/
|
|
void nghttp2_hd_inflate_free(nghttp2_hd_inflater *inflater);
|
|
|
|
/*
|
|
* Similar to nghttp2_hd_inflate_hd(), but this takes nghttp2_hd_nv
|
|
* instead of nghttp2_nv as output parameter |nv_out|. Other than
|
|
* that return values and semantics are the same as
|
|
* nghttp2_hd_inflate_hd().
|
|
*/
|
|
ssize_t nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
|
|
nghttp2_hd_nv *nv_out, int *inflate_flags,
|
|
const uint8_t *in, size_t inlen, int in_final);
|
|
|
|
/* For unittesting purpose */
|
|
int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t index,
|
|
nghttp2_nv *nv, int indexing_mode);
|
|
|
|
/* For unittesting purpose */
|
|
int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv,
|
|
int indexing_mode);
|
|
|
|
/* For unittesting purpose */
|
|
int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size);
|
|
|
|
/* For unittesting purpose */
|
|
nghttp2_hd_nv nghttp2_hd_table_get(nghttp2_hd_context *context, size_t index);
|
|
|
|
/* For unittesting purpose */
|
|
ssize_t nghttp2_hd_decode_length(uint32_t *res, size_t *shift_ptr, int *fin,
|
|
uint32_t initial, size_t shift, uint8_t *in,
|
|
uint8_t *last, size_t prefix);
|
|
|
|
/* Huffman encoding/decoding functions */
|
|
|
|
/*
|
|
* 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);
|
|
|
|
/*
|
|
* Encodes the given data |src| with length |srclen| to the |bufs|.
|
|
* This function expands extra buffers in |bufs| if necessary.
|
|
*
|
|
* This function returns 0 if it succeeds, or one of the following
|
|
* negative error codes:
|
|
*
|
|
* NGHTTP2_ERR_NOMEM
|
|
* Out of memory.
|
|
* NGHTTP2_ERR_BUFFER_ERROR
|
|
* Out of buffer space.
|
|
*/
|
|
int nghttp2_hd_huff_encode(nghttp2_bufs *bufs, const uint8_t *src,
|
|
size_t srclen);
|
|
|
|
void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx);
|
|
|
|
/*
|
|
* Decodes the given data |src| with length |srclen|. The |ctx| must
|
|
* be initialized by nghttp2_hd_huff_decode_context_init(). The result
|
|
* will be written to |buf|. This function assumes that |buf| has the
|
|
* enough room to store the decoded byte string.
|
|
*
|
|
* The caller must set the |fin| to nonzero if the given input is the
|
|
* final block.
|
|
*
|
|
* This function returns the number of read bytes from the |in|.
|
|
*
|
|
* If this function fails, it returns one of the following negative
|
|
* return codes:
|
|
*
|
|
* NGHTTP2_ERR_NOMEM
|
|
* Out of memory.
|
|
* NGHTTP2_ERR_HEADER_COMP
|
|
* Decoding process has failed.
|
|
*/
|
|
ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
|
|
nghttp2_buf *buf, const uint8_t *src,
|
|
size_t srclen, int fin);
|
|
|
|
/*
|
|
* nghttp2_hd_huff_decode_failure_state returns nonzero if |ctx|
|
|
* indicates that huffman decoding context is in failure state.
|
|
*/
|
|
int nghttp2_hd_huff_decode_failure_state(nghttp2_hd_huff_decode_context *ctx);
|
|
|
|
#endif /* NGHTTP2_HD_H */
|