Merge branch 'draft-10'
This commit is contained in:
commit
5cc24cb7c2
256
README.rst
256
README.rst
|
@ -7,25 +7,22 @@ version 2.0.
|
|||
Development Status
|
||||
------------------
|
||||
|
||||
We started to implement HTTP-draft-09/2.0
|
||||
(http://tools.ietf.org/html/draft-ietf-httpbis-http2-09) and the
|
||||
We started to implement h2-10
|
||||
(http://tools.ietf.org/html/draft-ietf-httpbis-http2-10) and the
|
||||
header compression
|
||||
(http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-05).
|
||||
(http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-06).
|
||||
|
||||
The nghttp2 code base was forked from spdylay project.
|
||||
|
||||
========================== =================
|
||||
Features HTTP-draft-09/2.0
|
||||
========================== =================
|
||||
:authority Done
|
||||
HPACK-draft-05 Done
|
||||
SETTINGS_HEADER_TABLE_SIZE Done
|
||||
SETTINGS_ENABLE_PUSH Done
|
||||
FRAME_SIZE_ERROR Done
|
||||
SETTINGS with ACK Done
|
||||
Header Continuation Done
|
||||
ALPN Done
|
||||
========================== =================
|
||||
========================== =====
|
||||
Features h2-10
|
||||
========================== =====
|
||||
HPACK-draft-06 Done
|
||||
Strict SETTINGS validation Done
|
||||
Disallow client to push Done
|
||||
Padding Done
|
||||
END_SEGMENT
|
||||
========================== =====
|
||||
|
||||
Public Test Server
|
||||
------------------
|
||||
|
@ -150,19 +147,21 @@ with prior knowledge, HTTP Upgrade and NPN/ALPN TLS extension.
|
|||
It has verbose output mode for framing information. Here is sample
|
||||
output from ``nghttp`` client::
|
||||
|
||||
$ src/nghttp -vn https://localhost:8443
|
||||
[ 0.003] NPN select next protocol: the remote server offers:
|
||||
* HTTP-draft-09/2.0
|
||||
$ src/nghttp -nv https://localhost:8443
|
||||
[ 0.004][NPN] server offers:
|
||||
* h2-10
|
||||
* spdy/3.1
|
||||
* spdy/3
|
||||
* spdy/2
|
||||
* http/1.1
|
||||
NPN selected the protocol: HTTP-draft-09/2.0
|
||||
[ 0.005] send SETTINGS frame <length=16, flags=0x00, stream_id=0>
|
||||
The negotiated protocol: h2-10
|
||||
[ 0.006] send SETTINGS frame <length=10, flags=0x00, stream_id=0>
|
||||
(niv=2)
|
||||
[SETTINGS_MAX_CONCURRENT_STREAMS(4):100]
|
||||
[SETTINGS_INITIAL_WINDOW_SIZE(7):65535]
|
||||
[ 0.006] send HEADERS frame <length=47, flags=0x05, stream_id=1>
|
||||
[SETTINGS_MAX_CONCURRENT_STREAMS(3):100]
|
||||
[SETTINGS_INITIAL_WINDOW_SIZE(4):65535]
|
||||
[ 0.007] send HEADERS frame <length=48, flags=0x05, stream_id=1>
|
||||
; END_STREAM | END_HEADERS
|
||||
(padlen=0)
|
||||
; Open new stream
|
||||
:authority: localhost:8443
|
||||
:method: GET
|
||||
|
@ -170,91 +169,91 @@ output from ``nghttp`` client::
|
|||
:scheme: https
|
||||
accept: */*
|
||||
accept-encoding: gzip, deflate
|
||||
user-agent: nghttp2/0.1.0-DEV
|
||||
[ 0.006] recv SETTINGS frame <length=16, flags=0x00, stream_id=0>
|
||||
(niv=2)
|
||||
[SETTINGS_MAX_CONCURRENT_STREAMS(4):100]
|
||||
[SETTINGS_INITIAL_WINDOW_SIZE(7):65535]
|
||||
[ 0.006] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
|
||||
user-agent: nghttp2/0.4.0-DEV
|
||||
[ 0.007] recv SETTINGS frame <length=15, flags=0x00, stream_id=0>
|
||||
(niv=3)
|
||||
[SETTINGS_MAX_CONCURRENT_STREAMS(3):100]
|
||||
[SETTINGS_INITIAL_WINDOW_SIZE(4):65535]
|
||||
[SETTINGS_ENABLE_PUSH(2):0]
|
||||
[ 0.007] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
|
||||
; ACK
|
||||
(niv=0)
|
||||
[ 0.006] recv WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=0>
|
||||
(window_size_increment=1000000007)
|
||||
[ 0.006] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>
|
||||
[ 0.007] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>
|
||||
; ACK
|
||||
(niv=0)
|
||||
[ 0.006] recv HEADERS frame <length=132, flags=0x04, stream_id=1>
|
||||
[ 0.008] (stream_id=1) :status: 200
|
||||
[ 0.008] (stream_id=1) accept-ranges: bytes
|
||||
[ 0.008] (stream_id=1) content-encoding: gzip
|
||||
[ 0.008] (stream_id=1) content-length: 146
|
||||
[ 0.008] (stream_id=1) content-type: text/html
|
||||
[ 0.008] (stream_id=1) date: Sat, 15 Feb 2014 08:14:12 GMT
|
||||
[ 0.008] (stream_id=1) etag: "b1-4e5535a027780-gzip"
|
||||
[ 0.008] (stream_id=1) last-modified: Sun, 01 Sep 2013 14:34:22 GMT
|
||||
[ 0.008] (stream_id=1) server: Apache/2.4.6 (Debian)
|
||||
[ 0.008] (stream_id=1) vary: Accept-Encoding
|
||||
[ 0.008] (stream_id=1) via: 1.1 nghttpx
|
||||
[ 0.008] recv HEADERS frame <length=141, flags=0x04, stream_id=1>
|
||||
; END_HEADERS
|
||||
(padlen=0)
|
||||
; First response header
|
||||
:status: 200
|
||||
accept-ranges: bytes
|
||||
content-encoding: gzip
|
||||
content-length: 146
|
||||
content-type: text/html
|
||||
date: Sun, 27 Oct 2013 14:23:54 GMT
|
||||
etag: "b1-4e5535a027780-gzip"
|
||||
last-modified: Sun, 01 Sep 2013 14:34:22 GMT
|
||||
server: Apache/2.4.6 (Debian)
|
||||
vary: Accept-Encoding
|
||||
via: 1.1 nghttpx
|
||||
[ 0.006] recv DATA frame <length=146, flags=0x00, stream_id=1>
|
||||
[ 0.006] recv DATA frame <length=0, flags=0x01, stream_id=1>
|
||||
[ 0.008] recv DATA frame <length=146, flags=0x00, stream_id=1>
|
||||
[ 0.008] recv DATA frame <length=0, flags=0x01, stream_id=1>
|
||||
; END_STREAM
|
||||
[ 0.007] send GOAWAY frame <length=8, flags=0x00, stream_id=0>
|
||||
[ 0.008] send GOAWAY frame <length=8, flags=0x00, stream_id=0>
|
||||
(last_stream_id=0, error_code=NO_ERROR(0), opaque_data(0)=[])
|
||||
|
||||
The HTTP Upgrade is performed like this::
|
||||
|
||||
$ src/nghttp -vnu http://localhost:8080
|
||||
$ src/nghttp -nvu http://localhost:8080
|
||||
[ 0.000] HTTP Upgrade request
|
||||
GET / HTTP/1.1
|
||||
Host: localhost:8080
|
||||
Connection: Upgrade, HTTP2-Settings
|
||||
Upgrade: HTTP-draft-09/2.0
|
||||
HTTP2-Settings: AAAABAAAAGQAAAAHAAD__w
|
||||
Upgrade: h2-10
|
||||
HTTP2-Settings: AwAAAGQEAAD__w
|
||||
Accept: */*
|
||||
User-Agent: nghttp2/0.1.0-DEV
|
||||
User-Agent: nghttp2/0.4.0-DEV
|
||||
|
||||
|
||||
[ 0.000] HTTP Upgrade response
|
||||
[ 0.001] HTTP Upgrade response
|
||||
HTTP/1.1 101 Switching Protocols
|
||||
Connection: Upgrade
|
||||
Upgrade: HTTP-draft-09/2.0
|
||||
Upgrade: h2-10
|
||||
|
||||
|
||||
[ 0.001] HTTP Upgrade success
|
||||
[ 0.001] send SETTINGS frame <length=16, flags=0x00, stream_id=0>
|
||||
[ 0.001] send SETTINGS frame <length=10, flags=0x00, stream_id=0>
|
||||
(niv=2)
|
||||
[SETTINGS_MAX_CONCURRENT_STREAMS(4):100]
|
||||
[SETTINGS_INITIAL_WINDOW_SIZE(7):65535]
|
||||
[ 0.001] recv SETTINGS frame <length=16, flags=0x00, stream_id=0>
|
||||
(niv=2)
|
||||
[SETTINGS_MAX_CONCURRENT_STREAMS(4):100]
|
||||
[SETTINGS_INITIAL_WINDOW_SIZE(7):65535]
|
||||
[ 0.001] recv WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=0>
|
||||
(window_size_increment=1000000007)
|
||||
[ 0.001] recv HEADERS frame <length=121, flags=0x04, stream_id=1>
|
||||
[SETTINGS_MAX_CONCURRENT_STREAMS(3):100]
|
||||
[SETTINGS_INITIAL_WINDOW_SIZE(4):65535]
|
||||
[ 0.001] recv SETTINGS frame <length=15, flags=0x00, stream_id=0>
|
||||
(niv=3)
|
||||
[SETTINGS_MAX_CONCURRENT_STREAMS(3):100]
|
||||
[SETTINGS_INITIAL_WINDOW_SIZE(4):65535]
|
||||
[SETTINGS_ENABLE_PUSH(2):0]
|
||||
[ 0.001] (stream_id=1) :status: 200
|
||||
[ 0.001] (stream_id=1) accept-ranges: bytes
|
||||
[ 0.001] (stream_id=1) content-length: 177
|
||||
[ 0.001] (stream_id=1) content-type: text/html
|
||||
[ 0.001] (stream_id=1) date: Sat, 15 Feb 2014 08:16:23 GMT
|
||||
[ 0.001] (stream_id=1) etag: "b1-4e5535a027780"
|
||||
[ 0.001] (stream_id=1) last-modified: Sun, 01 Sep 2013 14:34:22 GMT
|
||||
[ 0.001] (stream_id=1) server: Apache/2.4.6 (Debian)
|
||||
[ 0.001] (stream_id=1) vary: Accept-Encoding
|
||||
[ 0.001] (stream_id=1) via: 1.1 nghttpx
|
||||
[ 0.001] recv HEADERS frame <length=132, flags=0x04, stream_id=1>
|
||||
; END_HEADERS
|
||||
(padlen=0)
|
||||
; First response header
|
||||
:status: 200
|
||||
accept-ranges: bytes
|
||||
content-length: 177
|
||||
content-type: text/html
|
||||
date: Sun, 27 Oct 2013 14:26:04 GMT
|
||||
etag: "b1-4e5535a027780"
|
||||
last-modified: Sun, 01 Sep 2013 14:34:22 GMT
|
||||
server: Apache/2.4.6 (Debian)
|
||||
vary: Accept-Encoding
|
||||
via: 1.1 nghttpx
|
||||
[ 0.001] recv DATA frame <length=177, flags=0x00, stream_id=1>
|
||||
[ 0.001] recv DATA frame <length=0, flags=0x01, stream_id=1>
|
||||
; END_STREAM
|
||||
[ 0.001] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
|
||||
[ 0.002] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
|
||||
; ACK
|
||||
(niv=0)
|
||||
[ 0.001] send GOAWAY frame <length=8, flags=0x00, stream_id=0>
|
||||
[ 0.002] send GOAWAY frame <length=8, flags=0x00, stream_id=0>
|
||||
(last_stream_id=0, error_code=NO_ERROR(0), opaque_data(0)=[])
|
||||
[ 0.001] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>
|
||||
[ 0.002] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>
|
||||
; ACK
|
||||
(niv=0)
|
||||
|
||||
|
@ -278,50 +277,53 @@ information. Here is sample output from ``nghttpd`` server::
|
|||
$ src/nghttpd --no-tls -v 8080
|
||||
IPv4: listen on port 8080
|
||||
IPv6: listen on port 8080
|
||||
[id=1] [ 1.189] send SETTINGS frame <length=8, flags=0x00, stream_id=0>
|
||||
(niv=1)
|
||||
[SETTINGS_MAX_CONCURRENT_STREAMS(4):100]
|
||||
[id=1] [ 1.191] recv SETTINGS frame <length=16, flags=0x00, stream_id=0>
|
||||
[id=1] [ 1.027] send SETTINGS frame <length=10, flags=0x00, stream_id=0>
|
||||
(niv=2)
|
||||
[SETTINGS_MAX_CONCURRENT_STREAMS(4):100]
|
||||
[SETTINGS_INITIAL_WINDOW_SIZE(7):65535]
|
||||
[id=1] [ 1.191] recv HEADERS frame <length=47, flags=0x05, stream_id=1>
|
||||
[SETTINGS_MAX_CONCURRENT_STREAMS(3):100]
|
||||
[SETTINGS_ENABLE_PUSH(2):0]
|
||||
[id=1] [ 1.027] recv SETTINGS frame <length=10, flags=0x00, stream_id=0>
|
||||
(niv=2)
|
||||
[SETTINGS_MAX_CONCURRENT_STREAMS(3):100]
|
||||
[SETTINGS_INITIAL_WINDOW_SIZE(4):65535]
|
||||
[id=1] [ 1.027] (stream_id=1) :authority: localhost:8080
|
||||
[id=1] [ 1.027] (stream_id=1) :method: GET
|
||||
[id=1] [ 1.027] (stream_id=1) :path: /
|
||||
[id=1] [ 1.027] (stream_id=1) :scheme: http
|
||||
[id=1] [ 1.027] (stream_id=1) accept: */*
|
||||
[id=1] [ 1.027] (stream_id=1) accept-encoding: gzip, deflate
|
||||
[id=1] [ 1.027] (stream_id=1) user-agent: nghttp2/0.4.0-DEV
|
||||
[id=1] [ 1.027] recv HEADERS frame <length=48, flags=0x05, stream_id=1>
|
||||
; END_STREAM | END_HEADERS
|
||||
(padlen=0)
|
||||
; Open new stream
|
||||
:authority: localhost:8080
|
||||
:method: GET
|
||||
:path: /
|
||||
:scheme: http
|
||||
accept: */*
|
||||
accept-encoding: gzip, deflate
|
||||
user-agent: nghttp2/0.1.0-DEV
|
||||
[id=1] [ 1.192] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
|
||||
[id=1] [ 1.027] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
|
||||
; ACK
|
||||
(niv=0)
|
||||
[id=1] [ 1.192] send HEADERS frame <length=70, flags=0x04, stream_id=1>
|
||||
[id=1] [ 1.027] send HEADERS frame <length=72, flags=0x04, stream_id=1>
|
||||
; END_HEADERS
|
||||
(padlen=0)
|
||||
; First response header
|
||||
:status: 404
|
||||
content-encoding: gzip
|
||||
content-type: text/html; charset=UTF-8
|
||||
date: Sun, 27 Oct 2013 14:27:53 GMT
|
||||
server: nghttpd nghttp2/0.1.0-DEV
|
||||
[id=1] [ 1.192] send DATA frame <length=117, flags=0x00, stream_id=1>
|
||||
[id=1] [ 1.192] send DATA frame <length=0, flags=0x01, stream_id=1>
|
||||
date: Sat, 15 Feb 2014 08:18:53 GMT
|
||||
server: nghttpd nghttp2/0.4.0-DEV
|
||||
[id=1] [ 1.028] send DATA frame <length=118, flags=0x00, stream_id=1>
|
||||
[id=1] [ 1.028] send DATA frame <length=0, flags=0x01, stream_id=1>
|
||||
; END_STREAM
|
||||
[id=1] [ 1.192] stream_id=1 closed
|
||||
[id=1] [ 1.192] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>
|
||||
[id=1] [ 1.028] stream_id=1 closed
|
||||
[id=1] [ 1.028] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>
|
||||
; ACK
|
||||
(niv=0)
|
||||
[id=1] [ 1.192] recv GOAWAY frame <length=8, flags=0x00, stream_id=0>
|
||||
[id=1] [ 1.028] recv GOAWAY frame <length=8, flags=0x00, stream_id=0>
|
||||
(last_stream_id=0, error_code=NO_ERROR(0), opaque_data(0)=[])
|
||||
[id=1] [ 1.192] closed
|
||||
[id=1] [ 1.028] closed
|
||||
|
||||
nghttpx - proxy
|
||||
+++++++++++++++
|
||||
|
||||
The ``nghttpx`` is a multi-threaded reverse proxy for
|
||||
HTTP-draft-09/2.0, SPDY and HTTP/1.1. It has several operation modes:
|
||||
h2-10, SPDY and HTTP/1.1. It has several operation modes:
|
||||
|
||||
================== ============================== ============== =============
|
||||
Mode option Frontend Backend Note
|
||||
|
@ -334,7 +336,7 @@ default mode HTTP/2.0, SPDY, HTTP/1.1 (TLS) HTTP/1.1 Reverse proxy
|
|||
================== ============================== ============== =============
|
||||
|
||||
The interesting mode at the moment is the default mode. It works like
|
||||
a reverse proxy and listens HTTP-draft-09/2.0, SPDY and HTTP/1.1 and
|
||||
a reverse proxy and listens h2-10, SPDY and HTTP/1.1 and
|
||||
can be deployed SSL/TLS terminator for existing web server.
|
||||
|
||||
The default mode, ``--http2-proxy`` and ``--http2-bridge`` modes use
|
||||
|
@ -440,21 +442,18 @@ deflatehd - header compressor
|
|||
The ``deflatehd`` reads JSON data or HTTP/1-style header fields from
|
||||
stdin and outputs compressed header block in JSON.
|
||||
|
||||
For the JSON input, the root JSON object must contain ``context`` key,
|
||||
which indicates which compression context is used. If it is
|
||||
``request``, request compression context is used. Otherwise, response
|
||||
compression context is used. The value of ``cases`` key contains the
|
||||
sequence of input header set. They share the same compression context
|
||||
and are processed in the order they appear. Each item in the sequence
|
||||
is a JSON object and it must have at least ``headers`` key. Its value
|
||||
is an array of a JSON object containing exactly one name/value pair.
|
||||
For the JSON input, the root JSON object must include ``cases``
|
||||
key. Its value has to include the sequence of input header set. They
|
||||
share the same compression context and are processed in the order they
|
||||
appear. Each item in the sequence is a JSON object and it must
|
||||
include ``headers`` key. Its value is an array of a JSON object ,
|
||||
which includes exactly one name/value pair.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"context": "request",
|
||||
"cases":
|
||||
[
|
||||
{
|
||||
|
@ -485,9 +484,7 @@ Example::
|
|||
:method: POST
|
||||
user-agent: nghttp2
|
||||
|
||||
The output is JSON object. It contains ``context`` key and its value
|
||||
is ``request`` if the compression context is request, otherwise
|
||||
``response``. The root JSON object also contains ``cases`` key and its
|
||||
The output is JSON object. It should include ``cases`` key and its
|
||||
value is an array of JSON object, which has at least following keys:
|
||||
|
||||
seq
|
||||
|
@ -516,7 +513,6 @@ Examples:
|
|||
.. code-block:: json
|
||||
|
||||
{
|
||||
"context": "request",
|
||||
"cases":
|
||||
[
|
||||
{
|
||||
|
@ -578,9 +574,9 @@ The output can be used as the input for ``inflatehd`` and
|
|||
``deflatehd``.
|
||||
|
||||
With ``-d`` option, the extra ``header_table`` key is added and its
|
||||
associated value contains the state of dyanmic header table after the
|
||||
corresponding header set was processed. The value contains following
|
||||
keys:
|
||||
associated value includes the state of dyanmic header table after the
|
||||
corresponding header set was processed. The value includes at least
|
||||
following keys:
|
||||
|
||||
entries
|
||||
The entry in the header table. If ``referenced`` is ``true``, it
|
||||
|
@ -616,7 +612,6 @@ Example:
|
|||
.. code-block:: json
|
||||
|
||||
{
|
||||
"context": "request",
|
||||
"cases":
|
||||
[
|
||||
{
|
||||
|
@ -772,21 +767,17 @@ inflatehd - header decompressor
|
|||
The ``inflatehd`` reads JSON data from stdin and outputs decompressed
|
||||
name/value pairs in JSON.
|
||||
|
||||
The root JSON object must contain ``context`` key, which indicates
|
||||
which compression context is used. If it is ``request``, request
|
||||
compression context is used. Otherwise, response compression context
|
||||
is used. The value of ``cases`` key contains the sequence of
|
||||
compressed header block. They share the same compression context and
|
||||
are processed in the order they appear. Each item in the sequence is a
|
||||
JSON object and it must have at least ``wire`` key. Its value is a
|
||||
string containing compressed header block in hex string.
|
||||
The root JSON object must include ``cases`` key. Its value has to
|
||||
include the sequence of compressed header block. They share the same
|
||||
compression context and are processed in the order they appear. Each
|
||||
item in the sequence is a JSON object and it must have at least
|
||||
``wire`` key. Its value is a compressed header block in hex string.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"context": "request",
|
||||
"cases":
|
||||
[
|
||||
{ "wire": "8285" },
|
||||
|
@ -794,16 +785,14 @@ Example:
|
|||
]
|
||||
}
|
||||
|
||||
The output is JSON object. It contains ``context`` key and its value
|
||||
is ``request`` if the compression context is request, otherwise
|
||||
``response``. The root JSON object also contains ``cases`` key and its
|
||||
The output is JSON object. It should include ``cases`` key and its
|
||||
value is an array of JSON object, which has at least following keys:
|
||||
|
||||
seq
|
||||
The index of header set in the input.
|
||||
|
||||
headers
|
||||
The JSON array contains decompressed name/value pairs.
|
||||
The JSON array includes decompressed name/value pairs.
|
||||
|
||||
wire
|
||||
The compressed header block in hex string.
|
||||
|
@ -817,7 +806,6 @@ Example:
|
|||
.. code-block:: json
|
||||
|
||||
{
|
||||
"context": "request",
|
||||
"cases":
|
||||
[
|
||||
{
|
||||
|
@ -872,7 +860,7 @@ The output can be used as the input for ``deflatehd`` and
|
|||
``inflatehd``.
|
||||
|
||||
With ``-d`` option, the extra ``header_table`` key is added and its
|
||||
associated value contains the state of dyanmic header table after the
|
||||
associated value includes the state of dyanmic header table after the
|
||||
corresponding header set was processed. The format is the same as
|
||||
``deflatehd``.
|
||||
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -110,7 +110,8 @@ void nghttp2_frame_settings_init(nghttp2_settings *frame, uint8_t flags,
|
|||
nghttp2_settings_entry *iv, size_t niv)
|
||||
{
|
||||
memset(frame, 0, sizeof(nghttp2_settings));
|
||||
nghttp2_frame_set_hd(&frame->hd, niv*8, NGHTTP2_SETTINGS, flags, 0);
|
||||
nghttp2_frame_set_hd(&frame->hd, niv * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH,
|
||||
NGHTTP2_SETTINGS, flags, 0);
|
||||
frame->niv = niv;
|
||||
frame->iv = iv;
|
||||
}
|
||||
|
@ -184,6 +185,7 @@ void nghttp2_frame_window_update_free(nghttp2_window_update *frame)
|
|||
void nghttp2_frame_data_init(nghttp2_data *frame, nghttp2_private_data *pdata)
|
||||
{
|
||||
frame->hd = pdata->hd;
|
||||
frame->padlen = pdata->padlen;
|
||||
/* flags may have NGHTTP2_FLAG_END_STREAM even if the sent chunk
|
||||
is not the end of the stream */
|
||||
if(!pdata->eof) {
|
||||
|
@ -191,6 +193,13 @@ void nghttp2_frame_data_init(nghttp2_data *frame, nghttp2_private_data *pdata)
|
|||
}
|
||||
}
|
||||
|
||||
size_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen)
|
||||
{
|
||||
return padlen
|
||||
- ((frame->hd.flags & NGHTTP2_FLAG_PAD_HIGH) > 0)
|
||||
- ((frame->hd.flags & NGHTTP2_FLAG_PAD_LOW) > 0);
|
||||
}
|
||||
|
||||
void nghttp2_frame_private_data_init(nghttp2_private_data *frame,
|
||||
uint8_t flags,
|
||||
int32_t stream_id,
|
||||
|
@ -205,19 +214,6 @@ void nghttp2_frame_private_data_init(nghttp2_private_data *frame,
|
|||
void nghttp2_frame_private_data_free(nghttp2_private_data *frame)
|
||||
{}
|
||||
|
||||
/*
|
||||
* Returns the offset of the name/header block in the HEADERS frame,
|
||||
* including frame header length.
|
||||
*/
|
||||
static size_t headers_nv_offset(nghttp2_headers *frame)
|
||||
{
|
||||
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
|
||||
return NGHTTP2_FRAME_HEAD_LENGTH + 4;
|
||||
} else {
|
||||
return NGHTTP2_FRAME_HEAD_LENGTH;
|
||||
}
|
||||
}
|
||||
|
||||
size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame)
|
||||
{
|
||||
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
|
||||
|
@ -229,37 +225,48 @@ 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)
|
||||
{
|
||||
ssize_t framelen;
|
||||
size_t nv_offset = headers_nv_offset(frame);
|
||||
size_t payloadoff = NGHTTP2_FRAME_HEAD_LENGTH + 2;
|
||||
size_t nv_offset =
|
||||
payloadoff + nghttp2_frame_headers_payload_nv_offset(frame);
|
||||
ssize_t rv;
|
||||
size_t payloadlen;
|
||||
|
||||
rv = nghttp2_hd_deflate_hd(deflater, buf_ptr, buflen_ptr, nv_offset,
|
||||
frame->nva, frame->nvlen);
|
||||
if(rv < 0) {
|
||||
return rv;
|
||||
}
|
||||
framelen = rv + nv_offset;
|
||||
if(NGHTTP2_FRAME_HEAD_LENGTH + NGHTTP2_MAX_FRAME_LENGTH < rv + nv_offset) {
|
||||
frame->hd.length = NGHTTP2_MAX_FRAME_LENGTH;
|
||||
frame->hd.flags &= ~NGHTTP2_FLAG_END_HEADERS;
|
||||
} else {
|
||||
frame->hd.length = framelen - NGHTTP2_FRAME_HEAD_LENGTH;
|
||||
}
|
||||
|
||||
payloadlen = nghttp2_frame_headers_payload_nv_offset(frame) + rv;
|
||||
|
||||
*bufoff_ptr = 2;
|
||||
frame->padlen = 0;
|
||||
frame->hd.length = payloadlen;
|
||||
/* If frame->nvlen == 0, *buflen_ptr may be smaller than
|
||||
nv_offset */
|
||||
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, nv_offset);
|
||||
if(rv < 0) {
|
||||
return rv;
|
||||
}
|
||||
memset(*buf_ptr, 0, nv_offset);
|
||||
memset(*buf_ptr + *bufoff_ptr, 0, NGHTTP2_FRAME_HEAD_LENGTH);
|
||||
/* pack ctrl header after length is determined */
|
||||
nghttp2_frame_pack_frame_hd(*buf_ptr, &frame->hd);
|
||||
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
|
||||
nghttp2_put_uint32be(&(*buf_ptr)[8], frame->pri);
|
||||
if(NGHTTP2_MAX_FRAME_LENGTH < payloadlen) {
|
||||
/* Needs CONTINUATION */
|
||||
nghttp2_frame_hd hd = frame->hd;
|
||||
hd.flags &= ~NGHTTP2_FLAG_END_HEADERS;
|
||||
hd.length = NGHTTP2_MAX_FRAME_LENGTH;
|
||||
nghttp2_frame_pack_frame_hd(*buf_ptr + *bufoff_ptr, &hd);
|
||||
} else {
|
||||
nghttp2_frame_pack_frame_hd(*buf_ptr + *bufoff_ptr, &frame->hd);
|
||||
}
|
||||
return framelen;
|
||||
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
|
||||
nghttp2_put_uint32be(&(*buf_ptr)[payloadoff], frame->pri);
|
||||
}
|
||||
return *bufoff_ptr + NGHTTP2_FRAME_HEAD_LENGTH + frame->hd.length;
|
||||
}
|
||||
|
||||
int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
|
||||
|
@ -267,7 +274,6 @@ int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
|
|||
size_t payloadlen)
|
||||
{
|
||||
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
|
||||
assert(payloadlen == 4);
|
||||
frame->pri = nghttp2_get_uint32(payload) & NGHTTP2_PRIORITY_MASK;
|
||||
} else {
|
||||
frame->pri = NGHTTP2_PRI_DEFAULT;
|
||||
|
@ -341,11 +347,11 @@ size_t nghttp2_frame_pack_settings_payload(uint8_t *buf,
|
|||
size_t niv)
|
||||
{
|
||||
size_t i;
|
||||
for(i = 0; i < niv; ++i, buf += 8) {
|
||||
nghttp2_put_uint32be(buf, iv[i].settings_id);
|
||||
nghttp2_put_uint32be(buf + 4, iv[i].value);
|
||||
for(i = 0; i < niv; ++i, buf += NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH) {
|
||||
buf[0] = iv[i].settings_id;
|
||||
nghttp2_put_uint32be(buf + 1, iv[i].value);
|
||||
}
|
||||
return 8 * niv;
|
||||
return NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH * niv;
|
||||
}
|
||||
|
||||
int nghttp2_frame_unpack_settings_payload(nghttp2_settings *frame,
|
||||
|
@ -366,9 +372,8 @@ int nghttp2_frame_unpack_settings_payload(nghttp2_settings *frame,
|
|||
void nghttp2_frame_unpack_settings_entry(nghttp2_settings_entry *iv,
|
||||
const uint8_t *payload)
|
||||
{
|
||||
iv->settings_id = nghttp2_get_uint32(&payload[0]) &
|
||||
NGHTTP2_SETTINGS_ID_MASK;
|
||||
iv->value = nghttp2_get_uint32(&payload[4]);
|
||||
iv->settings_id = payload[0];
|
||||
iv->value = nghttp2_get_uint32(&payload[1]);
|
||||
}
|
||||
|
||||
int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
|
||||
|
@ -377,13 +382,13 @@ int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
|
|||
size_t payloadlen)
|
||||
{
|
||||
size_t i;
|
||||
*niv_ptr = payloadlen / 8;
|
||||
*niv_ptr = payloadlen / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH;
|
||||
*iv_ptr = malloc((*niv_ptr)*sizeof(nghttp2_settings_entry));
|
||||
if(*iv_ptr == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
for(i = 0; i < *niv_ptr; ++i) {
|
||||
size_t off = i*8;
|
||||
size_t off = i * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH;
|
||||
nghttp2_frame_unpack_settings_entry(&(*iv_ptr)[i], &payload[off]);
|
||||
}
|
||||
return 0;
|
||||
|
@ -391,35 +396,45 @@ 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)
|
||||
{
|
||||
ssize_t framelen;
|
||||
size_t nv_offset = NGHTTP2_FRAME_HEAD_LENGTH + 4;
|
||||
size_t payloadoff = NGHTTP2_FRAME_HEAD_LENGTH + 2;
|
||||
size_t nv_offset = payloadoff + 4;
|
||||
ssize_t rv;
|
||||
size_t payloadlen;
|
||||
|
||||
rv = nghttp2_hd_deflate_hd(deflater, buf_ptr, buflen_ptr, nv_offset,
|
||||
frame->nva, frame->nvlen);
|
||||
if(rv < 0) {
|
||||
return rv;
|
||||
}
|
||||
framelen = rv + nv_offset;
|
||||
if(NGHTTP2_FRAME_HEAD_LENGTH + NGHTTP2_MAX_FRAME_LENGTH < rv + nv_offset) {
|
||||
frame->hd.length = NGHTTP2_MAX_FRAME_LENGTH;
|
||||
frame->hd.flags &= ~NGHTTP2_FLAG_END_HEADERS;
|
||||
} else {
|
||||
frame->hd.length = framelen - NGHTTP2_FRAME_HEAD_LENGTH;
|
||||
}
|
||||
|
||||
payloadlen = 4 + rv;
|
||||
|
||||
*bufoff_ptr = 2;
|
||||
frame->padlen = 0;
|
||||
frame->hd.length = payloadlen;
|
||||
/* If frame->nvlen == 0, *buflen_ptr may be smaller than
|
||||
nv_offset */
|
||||
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, nv_offset);
|
||||
if(rv < 0) {
|
||||
return rv;
|
||||
}
|
||||
memset(*buf_ptr, 0, nv_offset);
|
||||
memset(*buf_ptr + *bufoff_ptr, 0, NGHTTP2_FRAME_HEAD_LENGTH);
|
||||
/* pack ctrl header after length is determined */
|
||||
nghttp2_frame_pack_frame_hd(*buf_ptr, &frame->hd);
|
||||
nghttp2_put_uint32be(&(*buf_ptr)[8], frame->promised_stream_id);
|
||||
return framelen;
|
||||
if(NGHTTP2_MAX_FRAME_LENGTH < payloadlen) {
|
||||
/* Needs CONTINUATION */
|
||||
nghttp2_frame_hd hd = frame->hd;
|
||||
hd.flags &= ~NGHTTP2_FLAG_END_HEADERS;
|
||||
hd.length = NGHTTP2_MAX_FRAME_LENGTH;
|
||||
nghttp2_frame_pack_frame_hd(*buf_ptr + *bufoff_ptr, &hd);
|
||||
} else {
|
||||
nghttp2_frame_pack_frame_hd(*buf_ptr + *bufoff_ptr, &frame->hd);
|
||||
}
|
||||
nghttp2_put_uint32be(&(*buf_ptr)[payloadoff], frame->promised_stream_id);
|
||||
return *bufoff_ptr + NGHTTP2_FRAME_HEAD_LENGTH + frame->hd.length;
|
||||
}
|
||||
|
||||
int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
|
||||
|
@ -617,29 +632,67 @@ ssize_t nghttp2_nv_array_copy(nghttp2_nv **nva_ptr,
|
|||
return nvlen;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
size_t i;
|
||||
for(i = 0; i < niv; ++i) {
|
||||
switch(iv[i].settings_id) {
|
||||
case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE:
|
||||
case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS:
|
||||
break;
|
||||
case NGHTTP2_SETTINGS_ENABLE_PUSH:
|
||||
if(iv[i].value != 0 && iv[i].value != 1) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE:
|
||||
if(iv[i].value > (uint32_t)NGHTTP2_MAX_WINDOW_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS:
|
||||
if(flow_control_opt) {
|
||||
if((iv[i].value & 0x1) == 0) {
|
||||
/* Attempt to re-enabling flow-control is error */
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
flow_control_opt = iv[i].value & 0x1;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int rv;
|
||||
size_t trail_padlen = 0;
|
||||
/* extra 2 bytes for PAD_HIGH and PAD_LOW. */
|
||||
size_t trail_padoff = *bufoff_ptr + NGHTTP2_FRAME_HEAD_LENGTH + payloadlen;
|
||||
|
||||
if(padlen > 257) {
|
||||
uint8_t *p;
|
||||
*bufoff_ptr -= 2;
|
||||
trail_padlen = padlen - 2;
|
||||
*flags_ptr |= NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW;
|
||||
p = *buf_ptr + *bufoff_ptr + NGHTTP2_FRAME_HEAD_LENGTH;
|
||||
*p++ = trail_padlen >> 8;
|
||||
*p = trail_padlen & 0xff;
|
||||
} else if(padlen > 0) {
|
||||
--*bufoff_ptr;
|
||||
trail_padlen = padlen - 1;
|
||||
*flags_ptr |= NGHTTP2_FLAG_PAD_LOW;
|
||||
(*buf_ptr)[*bufoff_ptr + NGHTTP2_FRAME_HEAD_LENGTH] = trail_padlen;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr,
|
||||
trail_padoff + trail_padlen);
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
/* We have to zero out padding bytes so that we won't reveal the
|
||||
possible internal data to the remote peer */
|
||||
memset((*buf_ptr) + trail_padoff, 0, trail_padlen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
326
lib/nghttp2_hd.c
326
lib/nghttp2_hd.c
|
@ -286,13 +286,10 @@ static void nghttp2_hd_ringbuf_pop_back(nghttp2_hd_ringbuf *ringbuf)
|
|||
}
|
||||
|
||||
static int nghttp2_hd_context_init(nghttp2_hd_context *context,
|
||||
nghttp2_hd_role role,
|
||||
nghttp2_hd_side side,
|
||||
size_t deflate_hd_table_bufsize_max)
|
||||
nghttp2_hd_role role)
|
||||
{
|
||||
int rv;
|
||||
context->role = role;
|
||||
context->side = side;
|
||||
context->bad = 0;
|
||||
context->hd_table_bufsize_max = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE;
|
||||
rv = nghttp2_hd_ringbuf_init
|
||||
|
@ -302,41 +299,41 @@ static int nghttp2_hd_context_init(nghttp2_hd_context *context,
|
|||
return rv;
|
||||
}
|
||||
|
||||
context->deflate_hd_table_bufsize_max = deflate_hd_table_bufsize_max;
|
||||
context->deflate_hd_table_bufsize = 0;
|
||||
context->deflate_hd_tablelen = 0;
|
||||
context->hd_table_bufsize = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater, nghttp2_hd_side side)
|
||||
int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater)
|
||||
{
|
||||
return nghttp2_hd_deflate_init2(deflater, side,
|
||||
return nghttp2_hd_deflate_init2(deflater,
|
||||
NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater,
|
||||
nghttp2_hd_side side,
|
||||
size_t deflate_hd_table_bufsize_max)
|
||||
{
|
||||
int rv;
|
||||
rv = nghttp2_hd_context_init(&deflater->ctx, NGHTTP2_HD_ROLE_DEFLATE, side,
|
||||
deflate_hd_table_bufsize_max);
|
||||
rv = nghttp2_hd_context_init(&deflater->ctx, NGHTTP2_HD_ROLE_DEFLATE);
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
deflater->no_refset = 0;
|
||||
deflater->deflate_hd_table_bufsize_max = deflate_hd_table_bufsize_max;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, nghttp2_hd_side side)
|
||||
int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater)
|
||||
{
|
||||
int rv;
|
||||
rv = nghttp2_hd_context_init(&inflater->ctx, NGHTTP2_HD_ROLE_INFLATE, side,
|
||||
NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE);
|
||||
|
||||
rv = nghttp2_hd_context_init(&inflater->ctx, NGHTTP2_HD_ROLE_INFLATE);
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
inflater->settings_hd_table_bufsize_max =
|
||||
NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE;
|
||||
|
||||
inflater->ent_keep = NULL;
|
||||
inflater->name_keep = NULL;
|
||||
inflater->value_keep = NULL;
|
||||
|
@ -559,16 +556,38 @@ static uint8_t* decode_length(ssize_t *res, int *final, ssize_t initial,
|
|||
return in + 1;
|
||||
}
|
||||
|
||||
static int emit_indexed0(uint8_t **buf_ptr, size_t *buflen_ptr,
|
||||
static int emit_clear_refset(uint8_t **buf_ptr, size_t *buflen_ptr,
|
||||
size_t *offset_ptr)
|
||||
{
|
||||
int rv;
|
||||
rv = ensure_write_buffer(buf_ptr, buflen_ptr, *offset_ptr, 1);
|
||||
uint8_t *bufp;
|
||||
rv = ensure_write_buffer(buf_ptr, buflen_ptr, *offset_ptr, 2);
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
*(*buf_ptr + *offset_ptr) = 0x80u;
|
||||
++*offset_ptr;
|
||||
bufp = *buf_ptr + *offset_ptr;
|
||||
*bufp++ = 0x80u;
|
||||
*bufp = 0x80u;
|
||||
*offset_ptr += 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emit_table_size(uint8_t **buf_ptr, size_t *buflen_ptr,
|
||||
size_t *offset_ptr, size_t table_size)
|
||||
{
|
||||
int rv;
|
||||
uint8_t *bufp;
|
||||
size_t blocklen = 1 + count_encoded_length(table_size, 7);
|
||||
rv = ensure_write_buffer(buf_ptr, buflen_ptr, *offset_ptr, blocklen);
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
DEBUGF(fprintf(stderr, "emit table_size=%zu\n", table_size));
|
||||
bufp = *buf_ptr + *offset_ptr;
|
||||
*bufp++ = 0x80u;
|
||||
*bufp = 0;
|
||||
encode_length(bufp, table_size, 7);
|
||||
*offset_ptr += blocklen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -591,15 +610,14 @@ static int emit_indexed_block(uint8_t **buf_ptr, size_t *buflen_ptr,
|
|||
|
||||
static size_t emit_string(uint8_t *buf, size_t buflen,
|
||||
size_t enclen, int huffman,
|
||||
const uint8_t *str, size_t len,
|
||||
nghttp2_hd_side side)
|
||||
const uint8_t *str, size_t len)
|
||||
{
|
||||
size_t rv;
|
||||
*buf = huffman ? 1 << 7 : 0;
|
||||
rv = encode_length(buf, enclen, 7);
|
||||
buf += rv;
|
||||
if(huffman) {
|
||||
nghttp2_hd_huff_encode(buf, buflen - rv, str, len, side);
|
||||
nghttp2_hd_huff_encode(buf, buflen - rv, str, len);
|
||||
} else {
|
||||
assert(enclen == len);
|
||||
memcpy(buf, str, len);
|
||||
|
@ -610,12 +628,11 @@ static size_t emit_string(uint8_t *buf, size_t buflen,
|
|||
static int 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)
|
||||
{
|
||||
int rv;
|
||||
uint8_t *bufp;
|
||||
size_t encvallen = nghttp2_hd_huff_encode_count(value, valuelen, side);
|
||||
size_t encvallen = nghttp2_hd_huff_encode_count(value, valuelen);
|
||||
size_t blocklen = count_encoded_length(index + 1, 6);
|
||||
int huffman = encvallen < valuelen;
|
||||
if(!huffman) {
|
||||
|
@ -630,7 +647,7 @@ static int emit_indname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
|
|||
*bufp = inc_indexing ? 0 : 0x40u;
|
||||
bufp += encode_length(bufp, index + 1, 6);
|
||||
bufp += emit_string(bufp, *buflen_ptr - (bufp - *buf_ptr),
|
||||
encvallen, huffman, value, valuelen, side);
|
||||
encvallen, huffman, value, valuelen);
|
||||
assert(bufp - (*buf_ptr + *offset_ptr) == (ssize_t)blocklen);
|
||||
*offset_ptr += blocklen;
|
||||
return 0;
|
||||
|
@ -638,15 +655,14 @@ static int emit_indname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
|
|||
|
||||
static int 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)
|
||||
{
|
||||
int rv;
|
||||
uint8_t *bufp;
|
||||
size_t encnamelen =
|
||||
nghttp2_hd_huff_encode_count(nv->name, nv->namelen, side);
|
||||
nghttp2_hd_huff_encode_count(nv->name, nv->namelen);
|
||||
size_t encvallen =
|
||||
nghttp2_hd_huff_encode_count(nv->value, nv->valuelen, side);
|
||||
nghttp2_hd_huff_encode_count(nv->value, nv->valuelen);
|
||||
size_t blocklen = 1;
|
||||
int name_huffman = encnamelen < nv->namelen;
|
||||
int value_huffman = encvallen < nv->valuelen;
|
||||
|
@ -665,9 +681,9 @@ static int emit_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
|
|||
bufp = *buf_ptr + *offset_ptr;
|
||||
*bufp++ = inc_indexing ? 0 : 0x40u;
|
||||
bufp += emit_string(bufp, *buflen_ptr - (bufp - *buf_ptr),
|
||||
encnamelen, name_huffman, nv->name, nv->namelen, side);
|
||||
encnamelen, name_huffman, nv->name, nv->namelen);
|
||||
bufp += emit_string(bufp, *buflen_ptr - (bufp - *buf_ptr),
|
||||
encvallen, value_huffman, nv->value, nv->valuelen, side);
|
||||
encvallen, value_huffman, nv->value, nv->valuelen);
|
||||
*offset_ptr += blocklen;
|
||||
return 0;
|
||||
}
|
||||
|
@ -707,11 +723,6 @@ static nghttp2_hd_entry* add_hd_table_incremental(nghttp2_hd_context *context,
|
|||
size_t index = context->hd_table.len - 1;
|
||||
nghttp2_hd_entry* ent = nghttp2_hd_ringbuf_get(&context->hd_table, index);
|
||||
context->hd_table_bufsize -= entry_room(ent->nv.namelen, ent->nv.valuelen);
|
||||
if(context->hd_table_bufsize < context->deflate_hd_table_bufsize) {
|
||||
context->deflate_hd_table_bufsize -= entry_room(ent->nv.namelen,
|
||||
ent->nv.valuelen);
|
||||
--context->deflate_hd_tablelen;
|
||||
}
|
||||
if(context->role == NGHTTP2_HD_ROLE_DEFLATE) {
|
||||
if(ent->flags & NGHTTP2_HD_FLAG_IMPLICIT_EMIT) {
|
||||
/* Emit common header just before it slips away from the
|
||||
|
@ -734,82 +745,19 @@ static nghttp2_hd_entry* add_hd_table_incremental(nghttp2_hd_context *context,
|
|||
free(ent);
|
||||
}
|
||||
}
|
||||
while(context->deflate_hd_table_bufsize + room >
|
||||
context->deflate_hd_table_bufsize_max
|
||||
&& context->deflate_hd_tablelen > 0) {
|
||||
size_t index = context->deflate_hd_tablelen - 1;
|
||||
nghttp2_hd_entry *ent =
|
||||
nghttp2_hd_ringbuf_get(&context->hd_table, index);
|
||||
context->deflate_hd_table_bufsize -= entry_room(ent->nv.namelen,
|
||||
ent->nv.valuelen);
|
||||
--context->deflate_hd_tablelen;
|
||||
if(ent->flags & NGHTTP2_HD_FLAG_IMPLICIT_EMIT) {
|
||||
/* Just like a normal eviction, implicit header must be
|
||||
emitted twice. */
|
||||
rv = emit_implicit(buf_ptr, buflen_ptr, offset_ptr, index);
|
||||
if(rv != 0) {
|
||||
return NULL;
|
||||
}
|
||||
ent->flags ^= NGHTTP2_HD_FLAG_IMPLICIT_EMIT;
|
||||
}
|
||||
if(ent->flags & NGHTTP2_HD_FLAG_REFSET) {
|
||||
/* We need to drop entry from reference set. */
|
||||
rv = emit_indexed_block(buf_ptr, buflen_ptr, offset_ptr, index);
|
||||
if(rv != 0) {
|
||||
return NULL;
|
||||
}
|
||||
ent->flags ^= NGHTTP2_HD_FLAG_REFSET;
|
||||
}
|
||||
/* Release memory. We don't remove entry from the header table
|
||||
at this moment. */
|
||||
if(ent->flags & NGHTTP2_HD_FLAG_NAME_ALLOC) {
|
||||
free(ent->nv.name);
|
||||
ent->nv.name = NULL;
|
||||
ent->flags ^= NGHTTP2_HD_FLAG_NAME_ALLOC;
|
||||
}
|
||||
if(ent->flags & NGHTTP2_HD_FLAG_VALUE_ALLOC) {
|
||||
free(ent->nv.value);
|
||||
ent->nv.value = NULL;
|
||||
ent->flags ^= NGHTTP2_HD_FLAG_VALUE_ALLOC;
|
||||
}
|
||||
}
|
||||
|
||||
new_ent = malloc(sizeof(nghttp2_hd_entry));
|
||||
if(new_ent == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(context->role == NGHTTP2_HD_ROLE_DEFLATE &&
|
||||
room > context->deflate_hd_table_bufsize_max) {
|
||||
uint8_t flags = entry_flags &
|
||||
~(NGHTTP2_HD_FLAG_NAME_ALLOC | NGHTTP2_HD_FLAG_VALUE_ALLOC |
|
||||
NGHTTP2_HD_FLAG_NAME_GIFT | NGHTTP2_HD_FLAG_VALUE_GIFT);
|
||||
rv = nghttp2_hd_entry_init(new_ent, flags,
|
||||
NULL, nv->namelen, NULL, nv->valuelen);
|
||||
if(rv != 0) {
|
||||
free(new_ent);
|
||||
return NULL;
|
||||
}
|
||||
if(flags & NGHTTP2_HD_FLAG_NAME_GIFT) {
|
||||
free(nv->name);
|
||||
nv->name = NULL;
|
||||
}
|
||||
if(flags & NGHTTP2_HD_FLAG_VALUE_GIFT) {
|
||||
free(nv->value);
|
||||
nv->value = NULL;
|
||||
}
|
||||
/* caller must emit indexed repr to toggle off new_ent from
|
||||
reference set. We cannot do it here because it may break the
|
||||
indexing. */
|
||||
} else {
|
||||
rv = nghttp2_hd_entry_init(new_ent,
|
||||
entry_flags,
|
||||
rv = nghttp2_hd_entry_init(new_ent, entry_flags,
|
||||
nv->name, nv->namelen, nv->value, nv->valuelen);
|
||||
if(rv != 0) {
|
||||
free(new_ent);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if(room > context->hd_table_bufsize_max) {
|
||||
/* The entry taking more than NGHTTP2_HD_MAX_BUFFER_SIZE is
|
||||
immediately evicted. */
|
||||
|
@ -817,11 +765,8 @@ static nghttp2_hd_entry* add_hd_table_incremental(nghttp2_hd_context *context,
|
|||
} else {
|
||||
context->hd_table_bufsize += room;
|
||||
nghttp2_hd_ringbuf_push_front(&context->hd_table, new_ent);
|
||||
if(room <= context->deflate_hd_table_bufsize_max) {
|
||||
|
||||
new_ent->flags |= NGHTTP2_HD_FLAG_REFSET;
|
||||
context->deflate_hd_table_bufsize += room;
|
||||
++context->deflate_hd_tablelen;
|
||||
}
|
||||
}
|
||||
return new_ent;
|
||||
}
|
||||
|
@ -851,7 +796,7 @@ static search_result search_hd_table(nghttp2_hd_context *context,
|
|||
uint32_t value_hash = hash(nv->value, nv->valuelen);
|
||||
ssize_t left = -1, right = STATIC_TABLE_LENGTH;
|
||||
|
||||
for(i = 0; i < context->deflate_hd_tablelen; ++i) {
|
||||
for(i = 0; i < context->hd_table.len; ++i) {
|
||||
nghttp2_hd_entry *ent = nghttp2_hd_ringbuf_get(&context->hd_table, i);
|
||||
if(ent->name_hash == name_hash && name_eq(&ent->nv, nv)) {
|
||||
if(res.index == -1) {
|
||||
|
@ -893,35 +838,59 @@ static search_result search_hd_table(nghttp2_hd_context *context,
|
|||
return res;
|
||||
}
|
||||
|
||||
int nghttp2_hd_change_table_size(nghttp2_hd_context *context,
|
||||
size_t hd_table_bufsize_max)
|
||||
static void hd_context_shrink_table_size(nghttp2_hd_context *context)
|
||||
{
|
||||
int rv;
|
||||
rv = nghttp2_hd_ringbuf_reserve
|
||||
(&context->hd_table, hd_table_bufsize_max / NGHTTP2_HD_ENTRY_OVERHEAD);
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
context->hd_table_bufsize_max = hd_table_bufsize_max;
|
||||
if(context->role == NGHTTP2_HD_ROLE_INFLATE) {
|
||||
context->deflate_hd_table_bufsize_max = hd_table_bufsize_max;
|
||||
}
|
||||
while(context->hd_table_bufsize > context->hd_table_bufsize_max &&
|
||||
context->hd_table.len > 0) {
|
||||
size_t index = context->hd_table.len - 1;
|
||||
nghttp2_hd_entry* ent = nghttp2_hd_ringbuf_get(&context->hd_table, index);
|
||||
context->hd_table_bufsize -= entry_room(ent->nv.namelen, ent->nv.valuelen);
|
||||
if(context->hd_table_bufsize < context->deflate_hd_table_bufsize) {
|
||||
context->deflate_hd_table_bufsize -= entry_room(ent->nv.namelen,
|
||||
ent->nv.valuelen);
|
||||
--context->deflate_hd_tablelen;
|
||||
}
|
||||
nghttp2_hd_ringbuf_pop_back(&context->hd_table);
|
||||
if(--ent->ref == 0) {
|
||||
nghttp2_hd_entry_free(ent);
|
||||
free(ent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater,
|
||||
size_t settings_hd_table_bufsize_max)
|
||||
{
|
||||
int rv;
|
||||
size_t next_bufsize = nghttp2_min(settings_hd_table_bufsize_max,
|
||||
deflater->deflate_hd_table_bufsize_max);
|
||||
rv = nghttp2_hd_ringbuf_reserve
|
||||
(&deflater->ctx.hd_table, next_bufsize / NGHTTP2_HD_ENTRY_OVERHEAD);
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
deflater->ctx.hd_table_bufsize_max = settings_hd_table_bufsize_max;
|
||||
|
||||
if(settings_hd_table_bufsize_max >= deflater->deflate_hd_table_bufsize_max) {
|
||||
/* On the next encoding, we sends encoding context update with
|
||||
deflater->deflate_hd_table_bufsize_max if it is strictly
|
||||
smaller than settings_hd_table_bufsize_max. */
|
||||
return 0;
|
||||
}
|
||||
hd_context_shrink_table_size(&deflater->ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater,
|
||||
size_t settings_hd_table_bufsize_max)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv = nghttp2_hd_ringbuf_reserve
|
||||
(&inflater->ctx.hd_table,
|
||||
settings_hd_table_bufsize_max / NGHTTP2_HD_ENTRY_OVERHEAD);
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
inflater->settings_hd_table_bufsize_max = settings_hd_table_bufsize_max;
|
||||
inflater->ctx.hd_table_bufsize_max = settings_hd_table_bufsize_max;
|
||||
hd_context_shrink_table_size(&inflater->ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -962,9 +931,8 @@ nghttp2_hd_entry* nghttp2_hd_table_get(nghttp2_hd_context *context,
|
|||
static int hd_deflate_should_indexing(nghttp2_hd_deflater *deflater,
|
||||
const nghttp2_nv *nv)
|
||||
{
|
||||
size_t table_size = nghttp2_min(deflater->ctx.deflate_hd_table_bufsize_max,
|
||||
deflater->ctx.hd_table_bufsize_max);
|
||||
if(entry_room(nv->namelen, nv->valuelen) > table_size * 3 / 4) {
|
||||
if(entry_room(nv->namelen, nv->valuelen) >
|
||||
deflater->ctx.hd_table_bufsize_max * 3 / 4) {
|
||||
return 0;
|
||||
}
|
||||
#ifdef NGHTTP2_XHD
|
||||
|
@ -1006,9 +974,9 @@ static int deflate_nv(nghttp2_hd_deflater *deflater,
|
|||
nghttp2_hd_entry_free(new_ent);
|
||||
free(new_ent);
|
||||
new_ent = NULL;
|
||||
} else if(new_ent->nv.name != NULL) {
|
||||
/* new_ent->ref > 0 and nv.name is not NULL means that new_ent is
|
||||
in the reference set and in deflate_hd_table_bufsize */
|
||||
} else {
|
||||
/* new_ent->ref > 0 means that new_ent is in the reference
|
||||
set */
|
||||
new_ent->flags |= NGHTTP2_HD_FLAG_EMIT;
|
||||
}
|
||||
rv = emit_indexed_block(buf_ptr, buflen_ptr, offset_ptr, index);
|
||||
|
@ -1080,20 +1048,18 @@ static int deflate_nv(nghttp2_hd_deflater *deflater,
|
|||
if(new_ent->ref == 0) {
|
||||
nghttp2_hd_entry_free(new_ent);
|
||||
free(new_ent);
|
||||
} else if(new_ent->nv.name != NULL) {
|
||||
/* new_ent->ref > 0 and nv.name is not NULL means that new_ent is
|
||||
in the reference set and in deflate_hd_table_bufsize */
|
||||
} else {
|
||||
/* new_ent->ref > 0 means that new_ent is in the reference
|
||||
set. */
|
||||
new_ent->flags |= NGHTTP2_HD_FLAG_EMIT;
|
||||
}
|
||||
incidx = 1;
|
||||
}
|
||||
if(index == -1) {
|
||||
rv = emit_newname_block(buf_ptr, buflen_ptr, offset_ptr, nv, incidx,
|
||||
deflater->ctx.side);
|
||||
rv = emit_newname_block(buf_ptr, buflen_ptr, offset_ptr, nv, incidx);
|
||||
} else {
|
||||
rv = emit_indname_block(buf_ptr, buflen_ptr, offset_ptr, index,
|
||||
nv->value, nv->valuelen, incidx,
|
||||
deflater->ctx.side);
|
||||
nv->value, nv->valuelen, incidx);
|
||||
}
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
|
@ -1135,8 +1101,20 @@ ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
|
|||
return NGHTTP2_ERR_HEADER_COMP;
|
||||
}
|
||||
offset = nv_offset;
|
||||
|
||||
if(deflater->ctx.hd_table_bufsize_max >
|
||||
deflater->deflate_hd_table_bufsize_max) {
|
||||
rv = emit_table_size(buf_ptr, buflen_ptr, &offset,
|
||||
deflater->deflate_hd_table_bufsize_max);
|
||||
if(rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
deflater->ctx.hd_table_bufsize_max =
|
||||
deflater->deflate_hd_table_bufsize_max;
|
||||
}
|
||||
|
||||
if(deflater->no_refset) {
|
||||
rv = emit_indexed0(buf_ptr, buflen_ptr, &offset);
|
||||
rv = emit_clear_refset(buf_ptr, buflen_ptr, &offset);
|
||||
if(rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
@ -1148,7 +1126,7 @@ ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
|
|||
goto fail;
|
||||
}
|
||||
}
|
||||
for(i = 0; i < deflater->ctx.deflate_hd_tablelen; ++i) {
|
||||
for(i = 0; i < deflater->ctx.hd_table.len; ++i) {
|
||||
nghttp2_hd_entry *ent = nghttp2_hd_ringbuf_get(&deflater->ctx.hd_table, i);
|
||||
rv = deflate_post_process_hd_entry(ent, i, buf_ptr, buflen_ptr, &offset);
|
||||
if(rv != 0) {
|
||||
|
@ -1419,7 +1397,12 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
|
|||
for(; in != last;) {
|
||||
switch(inflater->state) {
|
||||
case NGHTTP2_HD_STATE_OPCODE:
|
||||
if(*in & 0x80u) {
|
||||
if(*in == 0x80u) {
|
||||
DEBUGF(fprintf(stderr, "Encoding context update\n"));
|
||||
inflater->opcode = NGHTTP2_HD_OPCODE_INDEXED;
|
||||
inflater->state = NGHTTP2_HD_STATE_CONTEXT_UPDATE;
|
||||
++in;
|
||||
} else if(*in & 0x80u) {
|
||||
DEBUGF(fprintf(stderr, "Indexed repr\n"));
|
||||
inflater->opcode = NGHTTP2_HD_OPCODE_INDEXED;
|
||||
inflater->state = NGHTTP2_HD_STATE_READ_INDEX;
|
||||
|
@ -1442,6 +1425,38 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
|
|||
}
|
||||
inflater->left = 0;
|
||||
break;
|
||||
case NGHTTP2_HD_STATE_CONTEXT_UPDATE:
|
||||
if(*in & 0x80u) {
|
||||
if(*in != 0x80u) {
|
||||
rv = NGHTTP2_ERR_HEADER_COMP;
|
||||
goto fail;
|
||||
}
|
||||
++in;
|
||||
DEBUGF(fprintf(stderr, "Clearing reference set\n"));
|
||||
clear_refset(&inflater->ctx);
|
||||
inflater->state = NGHTTP2_HD_STATE_OPCODE;
|
||||
break;
|
||||
}
|
||||
/* Header table size change */
|
||||
DEBUGF(fprintf(stderr, "Header table size change\n"));
|
||||
inflater->state = NGHTTP2_HD_STATE_READ_TABLE_SIZE;
|
||||
break;
|
||||
case NGHTTP2_HD_STATE_READ_TABLE_SIZE:
|
||||
rfin = 0;
|
||||
rv = hd_inflate_read_len(inflater, &rfin, in, last, 7,
|
||||
inflater->settings_hd_table_bufsize_max);
|
||||
if(rv < 0) {
|
||||
goto fail;
|
||||
}
|
||||
in += rv;
|
||||
if(!rfin) {
|
||||
return in - first;
|
||||
}
|
||||
DEBUGF(fprintf(stderr, "table_size=%zd\n", inflater->left));
|
||||
inflater->ctx.hd_table_bufsize_max = inflater->left;
|
||||
hd_context_shrink_table_size(&inflater->ctx);
|
||||
inflater->state = NGHTTP2_HD_STATE_OPCODE;
|
||||
break;
|
||||
case NGHTTP2_HD_STATE_READ_INDEX:
|
||||
rfin = 0;
|
||||
rv = hd_inflate_read_len(inflater, &rfin, in, last,
|
||||
|
@ -1458,12 +1473,7 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
|
|||
DEBUGF(fprintf(stderr, "index=%zd\n", inflater->left));
|
||||
if(inflater->opcode == NGHTTP2_HD_OPCODE_INDEXED) {
|
||||
inflater->index = inflater->left;
|
||||
if(inflater->index == 0) {
|
||||
DEBUGF(fprintf(stderr, "Clearing reference set\n"));
|
||||
clear_refset(&inflater->ctx);
|
||||
inflater->state = NGHTTP2_HD_STATE_OPCODE;
|
||||
break;
|
||||
}
|
||||
assert(inflater->index > 0);
|
||||
--inflater->index;
|
||||
rv = hd_inflate_commit_indexed(inflater, nv_out);
|
||||
if(rv < 0) {
|
||||
|
@ -1505,8 +1515,7 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
|
|||
}
|
||||
rv = 0;
|
||||
if(inflater->huffman_encoded) {
|
||||
nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx,
|
||||
inflater->ctx.side);
|
||||
nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx);
|
||||
rv = nghttp2_buffer_reserve(&inflater->namebuf,
|
||||
guess_huff_decode_len(inflater->left));
|
||||
if(rv != 0) {
|
||||
|
@ -1580,8 +1589,7 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
|
|||
return in - first;
|
||||
}
|
||||
if(inflater->huffman_encoded) {
|
||||
nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx,
|
||||
inflater->ctx.side);
|
||||
nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx);
|
||||
rv = nghttp2_buffer_reserve(&inflater->valuebuf,
|
||||
guess_huff_decode_len(inflater->left));
|
||||
inflater->state = NGHTTP2_HD_STATE_READ_VALUEHUFF;
|
||||
|
@ -1679,19 +1687,21 @@ 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)
|
||||
{
|
||||
return emit_indname_block(buf_ptr, buflen_ptr, offset_ptr,
|
||||
index, value, valuelen, inc_indexing,
|
||||
side);
|
||||
index, value, valuelen, inc_indexing);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return emit_newname_block(buf_ptr, buflen_ptr, offset_ptr, nv, inc_indexing,
|
||||
side);
|
||||
return emit_newname_block(buf_ptr, buflen_ptr, offset_ptr, nv, inc_indexing);
|
||||
}
|
||||
|
||||
int nghttp2_hd_emit_table_size(uint8_t **buf_ptr, size_t *buflen_ptr,
|
||||
size_t *offset_ptr, size_t table_size)
|
||||
{
|
||||
return emit_table_size(buf_ptr, buflen_ptr, offset_ptr, table_size);
|
||||
}
|
||||
|
|
106
lib/nghttp2_hd.h
106
lib/nghttp2_hd.h
|
@ -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;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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,7 +80,10 @@ 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,
|
||||
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,
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -77,6 +77,8 @@ const char* strstatus(nghttp2_error_code error_code)
|
|||
return "CONNECT_ERROR";
|
||||
case NGHTTP2_ENHANCE_YOUR_CALM:
|
||||
return "ENHANCE_YOUR_CALM";
|
||||
case NGHTTP2_INADEQUATE_SECURITY:
|
||||
return "INADEQUATE_SECURITY";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
@ -95,8 +97,6 @@ const char* strsettingsid(int32_t id)
|
|||
return "SETTINGS_MAX_CONCURRENT_STREAMS";
|
||||
case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE:
|
||||
return "SETTINGS_INITIAL_WINDOW_SIZE";
|
||||
case NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS:
|
||||
return "SETTINGS_FLOW_CONTROL_OPTIONS";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
@ -131,13 +131,6 @@ const char* strframetype(uint8_t type)
|
|||
};
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void print_frame_attr_indent()
|
||||
{
|
||||
printf(" ");
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
bool color_output = false;
|
||||
} // namespace
|
||||
|
@ -147,6 +140,22 @@ void set_color_output(bool f)
|
|||
color_output = f;
|
||||
}
|
||||
|
||||
namespace {
|
||||
FILE *outfile = stdout;
|
||||
} // namespace
|
||||
|
||||
void set_output(FILE *file)
|
||||
{
|
||||
outfile = file;
|
||||
}
|
||||
|
||||
namespace {
|
||||
void print_frame_attr_indent()
|
||||
{
|
||||
fprintf(outfile, " ");
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
const char* ansi_esc(const char *code)
|
||||
{
|
||||
|
@ -168,11 +177,11 @@ void print_nv(nghttp2_nv *nva, size_t nvlen, bool indent = true)
|
|||
if(indent) {
|
||||
print_frame_attr_indent();
|
||||
}
|
||||
printf("%s", ansi_esc("\033[1;34m"));
|
||||
fwrite(nv.name, nv.namelen, 1, stdout);
|
||||
printf("%s: ", ansi_escend());
|
||||
fwrite(nv.value, nv.valuelen, 1, stdout);
|
||||
printf("\n");
|
||||
fprintf(outfile, "%s", ansi_esc("\033[1;34m"));
|
||||
fwrite(nv.name, nv.namelen, 1, outfile);
|
||||
fprintf(outfile, "%s: ", ansi_escend());
|
||||
fwrite(nv.value, nv.valuelen, 1, outfile);
|
||||
fprintf(outfile, "\n");
|
||||
}
|
||||
}
|
||||
} // namelen
|
||||
|
@ -180,7 +189,7 @@ void print_nv(nghttp2_nv *nva, size_t nvlen, bool indent = true)
|
|||
void print_timer()
|
||||
{
|
||||
auto millis = get_timer();
|
||||
printf("%s[%3ld.%03ld]%s",
|
||||
fprintf(outfile, "%s[%3ld.%03ld]%s",
|
||||
ansi_esc("\033[33m"),
|
||||
(long int)(millis.count()/1000), (long int)(millis.count()%1000),
|
||||
ansi_escend());
|
||||
|
@ -189,7 +198,7 @@ void print_timer()
|
|||
namespace {
|
||||
void print_frame_hd(const nghttp2_frame_hd& hd)
|
||||
{
|
||||
printf("<length=%zu, flags=0x%02x, stream_id=%d>\n",
|
||||
fprintf(outfile, "<length=%zu, flags=0x%02x, stream_id=%d>\n",
|
||||
hd.length, hd.flags, hd.stream_id);
|
||||
}
|
||||
} // namespace
|
||||
|
@ -203,11 +212,35 @@ void print_flags(const nghttp2_frame_hd& hd)
|
|||
if(hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||
s += "END_STREAM";
|
||||
}
|
||||
if(hd.flags & NGHTTP2_FLAG_END_SEGMENT) {
|
||||
if(!s.empty()) {
|
||||
s += " | ";
|
||||
}
|
||||
s += "END_SEGMENT";
|
||||
}
|
||||
if(hd.flags & NGHTTP2_FLAG_PAD_LOW) {
|
||||
if(!s.empty()) {
|
||||
s += " | ";
|
||||
}
|
||||
s += "PAD_LOW";
|
||||
}
|
||||
if(hd.flags & NGHTTP2_FLAG_PAD_HIGH) {
|
||||
if(!s.empty()) {
|
||||
s += " | ";
|
||||
}
|
||||
s += "PAD_HIGH";
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_HEADERS:
|
||||
if(hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||
s += "END_STREAM";
|
||||
}
|
||||
if(hd.flags & NGHTTP2_FLAG_END_SEGMENT) {
|
||||
if(!s.empty()) {
|
||||
s += " | ";
|
||||
}
|
||||
s += "END_SEGMENT";
|
||||
}
|
||||
if(hd.flags & NGHTTP2_FLAG_END_HEADERS) {
|
||||
if(!s.empty()) {
|
||||
s += " | ";
|
||||
|
@ -220,6 +253,18 @@ void print_flags(const nghttp2_frame_hd& hd)
|
|||
}
|
||||
s += "PRIORITY";
|
||||
}
|
||||
if(hd.flags & NGHTTP2_FLAG_PAD_LOW) {
|
||||
if(!s.empty()) {
|
||||
s += " | ";
|
||||
}
|
||||
s += "PAD_LOW";
|
||||
}
|
||||
if(hd.flags & NGHTTP2_FLAG_PAD_HIGH) {
|
||||
if(!s.empty()) {
|
||||
s += " | ";
|
||||
}
|
||||
s += "PAD_HIGH";
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_SETTINGS:
|
||||
if(hd.flags & NGHTTP2_FLAG_ACK) {
|
||||
|
@ -230,6 +275,18 @@ void print_flags(const nghttp2_frame_hd& hd)
|
|||
if(hd.flags & NGHTTP2_FLAG_END_PUSH_PROMISE) {
|
||||
s += "END_PUSH_PROMISE";
|
||||
}
|
||||
if(hd.flags & NGHTTP2_FLAG_PAD_LOW) {
|
||||
if(!s.empty()) {
|
||||
s += " | ";
|
||||
}
|
||||
s += "PAD_LOW";
|
||||
}
|
||||
if(hd.flags & NGHTTP2_FLAG_PAD_HIGH) {
|
||||
if(!s.empty()) {
|
||||
s += " | ";
|
||||
}
|
||||
s += "PAD_HIGH";
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_PING:
|
||||
if(hd.flags & NGHTTP2_FLAG_ACK) {
|
||||
|
@ -237,7 +294,7 @@ void print_flags(const nghttp2_frame_hd& hd)
|
|||
}
|
||||
break;
|
||||
}
|
||||
printf("; %s\n", s.c_str());
|
||||
fprintf(outfile, "; %s\n", s.c_str());
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
@ -256,7 +313,7 @@ const char* frame_name_ansi_esc(print_type ptype)
|
|||
namespace {
|
||||
void print_frame(print_type ptype, const nghttp2_frame *frame)
|
||||
{
|
||||
printf("%s%s%s frame ",
|
||||
fprintf(outfile, "%s%s%s frame ",
|
||||
frame_name_ansi_esc(ptype),
|
||||
strframetype(frame->hd.type),
|
||||
ansi_escend());
|
||||
|
@ -267,24 +324,30 @@ void print_frame(print_type ptype, const nghttp2_frame *frame)
|
|||
}
|
||||
switch(frame->hd.type) {
|
||||
case NGHTTP2_DATA:
|
||||
if(frame->hd.flags & (NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW)) {
|
||||
print_frame_attr_indent();
|
||||
fprintf(outfile, "(padlen=%zu)\n", frame->data.padlen);
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_HEADERS:
|
||||
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
|
||||
print_frame_attr_indent();
|
||||
printf("(pri=%d)\n", frame->headers.pri);
|
||||
fprintf(outfile, "(");
|
||||
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
|
||||
fprintf(outfile, "pri=%d, ", frame->headers.pri);
|
||||
}
|
||||
fprintf(outfile, "padlen=%zu)\n", frame->headers.padlen);
|
||||
switch(frame->headers.cat) {
|
||||
case NGHTTP2_HCAT_REQUEST:
|
||||
print_frame_attr_indent();
|
||||
printf("; Open new stream\n");
|
||||
fprintf(outfile, "; Open new stream\n");
|
||||
break;
|
||||
case NGHTTP2_HCAT_RESPONSE:
|
||||
print_frame_attr_indent();
|
||||
printf("; First response header\n");
|
||||
fprintf(outfile, "; First response header\n");
|
||||
break;
|
||||
case NGHTTP2_HCAT_PUSH_RESPONSE:
|
||||
print_frame_attr_indent();
|
||||
printf("; First push response header\n");
|
||||
fprintf(outfile, "; First push response header\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -293,20 +356,21 @@ void print_frame(print_type ptype, const nghttp2_frame *frame)
|
|||
break;
|
||||
case NGHTTP2_PRIORITY:
|
||||
print_frame_attr_indent();
|
||||
printf("(pri=%d)\n", frame->priority.pri);
|
||||
fprintf(outfile, "(pri=%d)\n", frame->priority.pri);
|
||||
break;
|
||||
case NGHTTP2_RST_STREAM:
|
||||
print_frame_attr_indent();
|
||||
printf("(error_code=%s(%u))\n",
|
||||
fprintf(outfile, "(error_code=%s(%u))\n",
|
||||
strstatus(frame->rst_stream.error_code),
|
||||
frame->rst_stream.error_code);
|
||||
break;
|
||||
case NGHTTP2_SETTINGS:
|
||||
print_frame_attr_indent();
|
||||
printf("(niv=%lu)\n", static_cast<unsigned long>(frame->settings.niv));
|
||||
fprintf(outfile, "(niv=%lu)\n",
|
||||
static_cast<unsigned long>(frame->settings.niv));
|
||||
for(size_t i = 0; i < frame->settings.niv; ++i) {
|
||||
print_frame_attr_indent();
|
||||
printf("[%s(%d):%u]\n",
|
||||
fprintf(outfile, "[%s(%d):%u]\n",
|
||||
strsettingsid(frame->settings.iv[i].settings_id),
|
||||
frame->settings.iv[i].settings_id,
|
||||
frame->settings.iv[i].value);
|
||||
|
@ -314,18 +378,20 @@ void print_frame(print_type ptype, const nghttp2_frame *frame)
|
|||
break;
|
||||
case NGHTTP2_PUSH_PROMISE:
|
||||
print_frame_attr_indent();
|
||||
printf("(promised_stream_id=%d)\n",
|
||||
frame->push_promise.promised_stream_id);
|
||||
fprintf(outfile, "(promised_stream_id=%d, padlen=%zu)\n",
|
||||
frame->push_promise.promised_stream_id,
|
||||
frame->push_promise.padlen);
|
||||
print_nv(frame->push_promise.nva, frame->push_promise.nvlen);
|
||||
break;
|
||||
case NGHTTP2_PING:
|
||||
print_frame_attr_indent();
|
||||
printf("(opaque_data=%s)\n",
|
||||
fprintf(outfile, "(opaque_data=%s)\n",
|
||||
util::format_hex(frame->ping.opaque_data, 8).c_str());
|
||||
break;
|
||||
case NGHTTP2_GOAWAY:
|
||||
print_frame_attr_indent();
|
||||
printf("(last_stream_id=%d, error_code=%s(%u), opaque_data(%u)=[%s])\n",
|
||||
fprintf(outfile,
|
||||
"(last_stream_id=%d, error_code=%s(%u), opaque_data(%u)=[%s])\n",
|
||||
frame->goaway.last_stream_id,
|
||||
strstatus(frame->goaway.error_code),
|
||||
frame->goaway.error_code,
|
||||
|
@ -335,11 +401,11 @@ void print_frame(print_type ptype, const nghttp2_frame *frame)
|
|||
break;
|
||||
case NGHTTP2_WINDOW_UPDATE:
|
||||
print_frame_attr_indent();
|
||||
printf("(window_size_increment=%d)\n",
|
||||
fprintf(outfile, "(window_size_increment=%d)\n",
|
||||
frame->window_update.window_size_increment);
|
||||
break;
|
||||
default:
|
||||
printf("\n");
|
||||
fprintf(outfile, "\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -356,7 +422,7 @@ int verbose_on_header_callback(nghttp2_session *session,
|
|||
static_cast<uint16_t>(namelen), static_cast<uint16_t>(valuelen)
|
||||
};
|
||||
print_timer();
|
||||
printf(" (stream_id=%d) ", frame->hd.stream_id);
|
||||
fprintf(outfile, " (stream_id=%d) ", frame->hd.stream_id);
|
||||
print_nv(&nv, 1, false /* no indent */);
|
||||
return 0;
|
||||
}
|
||||
|
@ -365,9 +431,9 @@ int verbose_on_frame_recv_callback
|
|||
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data)
|
||||
{
|
||||
print_timer();
|
||||
printf(" recv ");
|
||||
fprintf(outfile, " recv ");
|
||||
print_frame(PRINT_RECV, frame);
|
||||
fflush(stdout);
|
||||
fflush(outfile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -376,9 +442,9 @@ int verbose_on_invalid_frame_recv_callback
|
|||
nghttp2_error_code error_code, void *user_data)
|
||||
{
|
||||
print_timer();
|
||||
printf(" [INVALID; status=%s] recv ", strstatus(error_code));
|
||||
fprintf(outfile, " [INVALID; status=%s] recv ", strstatus(error_code));
|
||||
print_frame(PRINT_RECV, frame);
|
||||
fflush(stdout);
|
||||
fflush(outfile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -387,11 +453,11 @@ void dump_header(const uint8_t *head, size_t headlen)
|
|||
{
|
||||
size_t i;
|
||||
print_frame_attr_indent();
|
||||
printf("Header dump: ");
|
||||
fprintf(outfile, "Header dump: ");
|
||||
for(i = 0; i < headlen; ++i) {
|
||||
printf("%02X ", head[i]);
|
||||
fprintf(outfile, "%02X ", head[i]);
|
||||
}
|
||||
printf("\n");
|
||||
fprintf(outfile, "\n");
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
@ -403,9 +469,9 @@ int verbose_on_unknown_frame_recv_callback(nghttp2_session *session,
|
|||
void *user_data)
|
||||
{
|
||||
print_timer();
|
||||
printf(" recv unknown frame\n");
|
||||
fprintf(outfile, " recv unknown frame\n");
|
||||
dump_header(head, headlen);
|
||||
fflush(stdout);
|
||||
fflush(outfile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -413,9 +479,9 @@ int verbose_on_frame_send_callback
|
|||
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data)
|
||||
{
|
||||
print_timer();
|
||||
printf(" send ");
|
||||
fprintf(outfile, " send ");
|
||||
print_frame(PRINT_SEND, frame);
|
||||
fflush(stdout);
|
||||
fflush(outfile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,12 +27,8 @@
|
|||
|
||||
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_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,7 +109,7 @@ static int inflate_hd(json_t *obj, nghttp2_hd_inflater *inflater, int seq)
|
|||
seq);
|
||||
return -1;
|
||||
}
|
||||
rv = nghttp2_hd_change_table_size(&inflater->ctx,
|
||||
rv = nghttp2_hd_inflate_change_table_size(inflater,
|
||||
json_integer_value(table_size));
|
||||
if(rv != 0) {
|
||||
fprintf(stderr,
|
||||
|
@ -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);
|
||||
|
|
32
src/shrpx.cc
32
src/shrpx.cc
|
@ -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;
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "http2.h"
|
||||
#include "util.h"
|
||||
#include "base64.h"
|
||||
#include "app_helper.h"
|
||||
|
||||
using namespace nghttp2;
|
||||
|
||||
|
@ -205,6 +206,10 @@ int on_header_callback(nghttp2_session *session,
|
|||
const uint8_t *value, size_t valuelen,
|
||||
void *user_data)
|
||||
{
|
||||
if(get_config()->upstream_frame_debug) {
|
||||
verbose_on_header_callback(session, frame, name, namelen, value, valuelen,
|
||||
user_data);
|
||||
}
|
||||
if(frame->hd.type != NGHTTP2_HEADERS ||
|
||||
frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
|
||||
return 0;
|
||||
|
@ -359,6 +364,9 @@ int on_frame_recv_callback
|
|||
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data)
|
||||
{
|
||||
int rv;
|
||||
if(get_config()->upstream_frame_debug) {
|
||||
verbose_on_frame_recv_callback(session, frame, user_data);
|
||||
}
|
||||
auto upstream = static_cast<Http2Upstream*>(user_data);
|
||||
switch(frame->hd.type) {
|
||||
case NGHTTP2_DATA: {
|
||||
|
@ -428,6 +436,9 @@ namespace {
|
|||
int on_frame_send_callback(nghttp2_session* session,
|
||||
const nghttp2_frame *frame, void *user_data)
|
||||
{
|
||||
if(get_config()->upstream_frame_debug) {
|
||||
verbose_on_frame_send_callback(session, frame, user_data);
|
||||
}
|
||||
auto upstream = static_cast<Http2Upstream*>(user_data);
|
||||
if(frame->hd.type == NGHTTP2_SETTINGS &&
|
||||
(frame->hd.flags & NGHTTP2_FLAG_ACK) == 0) {
|
||||
|
@ -508,6 +519,9 @@ Http2Upstream::Http2Upstream(ClientHandler *handler)
|
|||
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;
|
||||
|
|
12
tests/main.c
12
tests/main.c
|
@ -179,12 +179,10 @@ int main(int argc, char* argv[])
|
|||
test_nghttp2_session_defer_data) ||
|
||||
!CU_add_test(pSuite, "session_flow_control",
|
||||
test_nghttp2_session_flow_control) ||
|
||||
!CU_add_test(pSuite, "session_flow_control_disable_remote",
|
||||
test_nghttp2_session_flow_control_disable_remote) ||
|
||||
!CU_add_test(pSuite, "session_flow_control_disable_local",
|
||||
test_nghttp2_session_flow_control_disable_local) ||
|
||||
!CU_add_test(pSuite, "session_flow_control_data_recv",
|
||||
test_nghttp2_session_flow_control_data_recv) ||
|
||||
!CU_add_test(pSuite, "session_flow_control_data_with_padding_recv",
|
||||
test_nghttp2_session_flow_control_data_with_padding_recv) ||
|
||||
!CU_add_test(pSuite, "session_data_read_temporal_failure",
|
||||
test_nghttp2_session_data_read_temporal_failure) ||
|
||||
!CU_add_test(pSuite, "session_on_stream_close",
|
||||
|
@ -199,6 +197,10 @@ int main(int argc, char* argv[])
|
|||
test_nghttp2_session_set_option) ||
|
||||
!CU_add_test(pSuite, "session_data_backoff_by_high_pri_frame",
|
||||
test_nghttp2_session_data_backoff_by_high_pri_frame) ||
|
||||
!CU_add_test(pSuite, "session_pack_data_with_padding",
|
||||
test_nghttp2_session_pack_data_with_padding) ||
|
||||
!CU_add_test(pSuite, "session_pack_headers_with_padding",
|
||||
test_nghttp2_session_pack_headers_with_padding) ||
|
||||
!CU_add_test(pSuite, "pack_settings_payload",
|
||||
test_nghttp2_pack_settings_payload) ||
|
||||
!CU_add_test(pSuite, "frame_pack_headers",
|
||||
|
@ -225,8 +227,6 @@ int main(int argc, char* argv[])
|
|||
test_nghttp2_hd_deflate_same_indexed_repr) ||
|
||||
!CU_add_test(pSuite, "hd_deflate_common_header_eviction",
|
||||
test_nghttp2_hd_deflate_common_header_eviction) ||
|
||||
!CU_add_test(pSuite, "hd_deflate_deflate_buffer",
|
||||
test_nghttp2_hd_deflate_deflate_buffer) ||
|
||||
!CU_add_test(pSuite, "hd_deflate_clear_refset",
|
||||
test_nghttp2_hd_deflate_clear_refset) ||
|
||||
!CU_add_test(pSuite, "hd_inflate_indname_noinc",
|
||||
|
|
|
@ -74,14 +74,16 @@ void test_nghttp2_frame_pack_headers()
|
|||
nghttp2_headers frame, oframe;
|
||||
uint8_t *buf = NULL;
|
||||
size_t buflen = 0;
|
||||
size_t bufoff;
|
||||
ssize_t framelen;
|
||||
nghttp2_nv *nva;
|
||||
ssize_t nvlen;
|
||||
nva_out out;
|
||||
ssize_t nv_offset;
|
||||
|
||||
nva_out_init(&out);
|
||||
nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST);
|
||||
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST);
|
||||
nghttp2_hd_deflate_init(&deflater);
|
||||
nghttp2_hd_inflate_init(&inflater);
|
||||
|
||||
nva = headers();
|
||||
nvlen = HEADERS_LENGTH;
|
||||
|
@ -89,17 +91,22 @@ void test_nghttp2_frame_pack_headers()
|
|||
NGHTTP2_FLAG_END_STREAM|NGHTTP2_FLAG_END_HEADERS,
|
||||
1000000007,
|
||||
1 << 20, nva, nvlen);
|
||||
framelen = nghttp2_frame_pack_headers(&buf, &buflen, &frame, &deflater);
|
||||
framelen = nghttp2_frame_pack_headers(&buf, &buflen, &bufoff, &frame,
|
||||
&deflater);
|
||||
|
||||
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf, framelen));
|
||||
check_frame_header(framelen - NGHTTP2_FRAME_HEAD_LENGTH, NGHTTP2_HEADERS,
|
||||
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf + bufoff,
|
||||
framelen - bufoff));
|
||||
check_frame_header(framelen - bufoff - NGHTTP2_FRAME_HEAD_LENGTH,
|
||||
NGHTTP2_HEADERS,
|
||||
NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS,
|
||||
1000000007, &oframe.hd);
|
||||
/* We didn't include PRIORITY flag so priority is not packed */
|
||||
CU_ASSERT(1 << 30 == oframe.pri);
|
||||
|
||||
CU_ASSERT(framelen - 8 ==
|
||||
inflate_hd(&inflater, &out, buf + 8, framelen - 8));
|
||||
nv_offset = bufoff + NGHTTP2_FRAME_HEAD_LENGTH;
|
||||
CU_ASSERT(framelen - nv_offset ==
|
||||
inflate_hd(&inflater, &out,
|
||||
buf + nv_offset, framelen - nv_offset));
|
||||
|
||||
CU_ASSERT(7 == out.nvlen);
|
||||
CU_ASSERT(nvnameeq("method", &out.nva[0]));
|
||||
|
@ -111,17 +118,22 @@ void test_nghttp2_frame_pack_headers()
|
|||
memset(&oframe, 0, sizeof(oframe));
|
||||
/* Next, include PRIORITY flag */
|
||||
frame.hd.flags |= NGHTTP2_FLAG_PRIORITY;
|
||||
framelen = nghttp2_frame_pack_headers(&buf, &buflen, &frame, &deflater);
|
||||
framelen = nghttp2_frame_pack_headers(&buf, &buflen, &bufoff, &frame,
|
||||
&deflater);
|
||||
|
||||
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf, framelen));
|
||||
check_frame_header(framelen - NGHTTP2_FRAME_HEAD_LENGTH, NGHTTP2_HEADERS,
|
||||
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf + bufoff,
|
||||
framelen - bufoff));
|
||||
check_frame_header(framelen - bufoff - NGHTTP2_FRAME_HEAD_LENGTH,
|
||||
NGHTTP2_HEADERS,
|
||||
NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS |
|
||||
NGHTTP2_FLAG_PRIORITY,
|
||||
1000000007, &oframe.hd);
|
||||
CU_ASSERT(1 << 20 == oframe.pri);
|
||||
|
||||
CU_ASSERT(framelen - 12 ==
|
||||
inflate_hd(&inflater, &out, buf + 12, framelen - 12));
|
||||
nv_offset = bufoff + NGHTTP2_FRAME_HEAD_LENGTH + 4;
|
||||
CU_ASSERT(framelen - nv_offset ==
|
||||
inflate_hd(&inflater, &out,
|
||||
buf + nv_offset, framelen - nv_offset));
|
||||
|
||||
nghttp2_nv_array_sort(out.nva, out.nvlen);
|
||||
CU_ASSERT(nvnameeq("method", &out.nva[0]));
|
||||
|
@ -140,6 +152,7 @@ void test_nghttp2_frame_pack_headers_frame_too_large(void)
|
|||
nghttp2_headers frame;
|
||||
uint8_t *buf = NULL;
|
||||
size_t buflen = 0;
|
||||
size_t bufoff;
|
||||
ssize_t framelen;
|
||||
nghttp2_nv *nva;
|
||||
ssize_t nvlen;
|
||||
|
@ -158,12 +171,13 @@ void test_nghttp2_frame_pack_headers_frame_too_large(void)
|
|||
}
|
||||
|
||||
nvlen = nghttp2_nv_array_copy(&nva, big_hds, big_hdslen);
|
||||
nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST);
|
||||
nghttp2_hd_deflate_init(&deflater);
|
||||
nghttp2_frame_headers_init(&frame,
|
||||
NGHTTP2_FLAG_END_STREAM|NGHTTP2_FLAG_END_HEADERS,
|
||||
1000000007,
|
||||
0, nva, nvlen);
|
||||
framelen = nghttp2_frame_pack_headers(&buf, &buflen, &frame, &deflater);
|
||||
framelen = nghttp2_frame_pack_headers(&buf, &buflen, &bufoff, &frame,
|
||||
&deflater);
|
||||
CU_ASSERT_EQUAL(NGHTTP2_ERR_HEADER_COMP, framelen);
|
||||
|
||||
nghttp2_frame_headers_free(&frame);
|
||||
|
@ -220,15 +234,17 @@ void test_nghttp2_frame_pack_settings()
|
|||
iv[0].value = 256;
|
||||
iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
|
||||
iv[1].value = 16384;
|
||||
iv[2].settings_id = NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS;
|
||||
iv[2].value = 1;
|
||||
iv[2].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
|
||||
iv[2].value = 4096;
|
||||
|
||||
nghttp2_frame_settings_init(&frame, NGHTTP2_FLAG_NONE,
|
||||
nghttp2_frame_iv_copy(iv, 3), 3);
|
||||
framelen = nghttp2_frame_pack_settings(&buf, &buflen, &frame);
|
||||
CU_ASSERT(NGHTTP2_FRAME_HEAD_LENGTH+3*8 == framelen);
|
||||
CU_ASSERT(NGHTTP2_FRAME_HEAD_LENGTH +
|
||||
3 * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH == framelen);
|
||||
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf, framelen));
|
||||
check_frame_header(3*8, NGHTTP2_SETTINGS, NGHTTP2_FLAG_NONE, 0, &oframe.hd);
|
||||
check_frame_header(3 * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH,
|
||||
NGHTTP2_SETTINGS, NGHTTP2_FLAG_NONE, 0, &oframe.hd);
|
||||
CU_ASSERT(3 == oframe.niv);
|
||||
for(i = 0; i < 3; ++i) {
|
||||
CU_ASSERT(iv[i].settings_id == oframe.iv[i].settings_id);
|
||||
|
@ -247,29 +263,34 @@ void test_nghttp2_frame_pack_push_promise()
|
|||
nghttp2_push_promise frame, oframe;
|
||||
uint8_t *buf = NULL;
|
||||
size_t buflen = 0;
|
||||
size_t bufoff;
|
||||
ssize_t framelen;
|
||||
nghttp2_nv *nva;
|
||||
ssize_t nvlen;
|
||||
nva_out out;
|
||||
ssize_t nv_offset;
|
||||
|
||||
nva_out_init(&out);
|
||||
nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_RESPONSE);
|
||||
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_RESPONSE);
|
||||
nghttp2_hd_deflate_init(&deflater);
|
||||
nghttp2_hd_inflate_init(&inflater);
|
||||
|
||||
nva = headers();
|
||||
nvlen = HEADERS_LENGTH;
|
||||
nghttp2_frame_push_promise_init(&frame, NGHTTP2_FLAG_END_PUSH_PROMISE,
|
||||
1000000007, (1U << 31) - 1, nva, nvlen);
|
||||
framelen = nghttp2_frame_pack_push_promise(&buf, &buflen, &frame, &deflater);
|
||||
framelen = nghttp2_frame_pack_push_promise(&buf, &buflen, &bufoff, &frame,
|
||||
&deflater);
|
||||
|
||||
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf, framelen));
|
||||
check_frame_header(framelen - NGHTTP2_FRAME_HEAD_LENGTH,
|
||||
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe,
|
||||
buf + bufoff, framelen - bufoff));
|
||||
check_frame_header(framelen - bufoff - NGHTTP2_FRAME_HEAD_LENGTH,
|
||||
NGHTTP2_PUSH_PROMISE,
|
||||
NGHTTP2_FLAG_END_PUSH_PROMISE, 1000000007, &oframe.hd);
|
||||
CU_ASSERT((1U << 31) - 1 == oframe.promised_stream_id);
|
||||
|
||||
CU_ASSERT(framelen - 12 ==
|
||||
inflate_hd(&inflater, &out, buf + 12, framelen - 12));
|
||||
nv_offset = bufoff + NGHTTP2_FRAME_HEAD_LENGTH + 4;
|
||||
CU_ASSERT(framelen - nv_offset ==
|
||||
inflate_hd(&inflater, &out, buf + nv_offset, framelen - nv_offset));
|
||||
|
||||
CU_ASSERT(7 == out.nvlen);
|
||||
CU_ASSERT(nvnameeq("method", &out.nva[0]));
|
||||
|
@ -397,22 +418,30 @@ void test_nghttp2_iv_check(void)
|
|||
|
||||
iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
|
||||
iv[0].value = 100;
|
||||
iv[1].settings_id = NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS;
|
||||
iv[1].value = 0;
|
||||
iv[2].settings_id = NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS;
|
||||
iv[2].value = 1;
|
||||
iv[1].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
|
||||
iv[1].value = 1024;
|
||||
|
||||
CU_ASSERT(nghttp2_iv_check(iv, 2, 0));
|
||||
CU_ASSERT(nghttp2_iv_check(iv, 3, 0));
|
||||
/* Re-enabling flow-control*/
|
||||
CU_ASSERT(0 == nghttp2_iv_check(iv, 2, 1));
|
||||
CU_ASSERT(0 == nghttp2_iv_check(iv, 3, 1));
|
||||
CU_ASSERT(nghttp2_iv_check(iv, 2));
|
||||
|
||||
iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
|
||||
iv[1].value = NGHTTP2_MAX_WINDOW_SIZE;
|
||||
CU_ASSERT(nghttp2_iv_check(iv, 2, 0));
|
||||
CU_ASSERT(nghttp2_iv_check(iv, 2));
|
||||
|
||||
/* Too large window size */
|
||||
iv[1].value = (uint32_t)NGHTTP2_MAX_WINDOW_SIZE + 1;
|
||||
CU_ASSERT(0 == nghttp2_iv_check(iv, 2, 0));
|
||||
CU_ASSERT(0 == nghttp2_iv_check(iv, 2));
|
||||
|
||||
/* ENABLE_PUSH only allows 0 or 1 */
|
||||
iv[1].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
|
||||
iv[1].value = 0;
|
||||
CU_ASSERT(nghttp2_iv_check(iv, 2));
|
||||
iv[1].value = 1;
|
||||
CU_ASSERT(nghttp2_iv_check(iv, 2));
|
||||
iv[1].value = 3;
|
||||
CU_ASSERT(!nghttp2_iv_check(iv, 2));
|
||||
|
||||
/* Undefined SETTINGS ID */
|
||||
iv[1].settings_id = 1000000009;
|
||||
iv[1].value = 0;
|
||||
CU_ASSERT(!nghttp2_iv_check(iv, 2));
|
||||
}
|
||||
|
|
|
@ -35,15 +35,6 @@
|
|||
|
||||
#define GET_TABLE_ENT(context, index) nghttp2_hd_table_get(context, index)
|
||||
|
||||
static void assert_nv_equal(nghttp2_nv *a, nghttp2_nv *b, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
nghttp2_nv_array_sort(b, len);
|
||||
for(i = 0; i < len; ++i, ++a, ++b) {
|
||||
CU_ASSERT(nghttp2_nv_equal(a, b));
|
||||
}
|
||||
}
|
||||
|
||||
void test_nghttp2_hd_deflate(void)
|
||||
{
|
||||
nghttp2_hd_deflater deflater;
|
||||
|
@ -68,8 +59,8 @@ void test_nghttp2_hd_deflate(void)
|
|||
nva_out out;
|
||||
|
||||
nva_out_init(&out);
|
||||
CU_ASSERT(0 == nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST));
|
||||
CU_ASSERT(0 == nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST));
|
||||
CU_ASSERT(0 == nghttp2_hd_deflate_init(&deflater));
|
||||
CU_ASSERT(0 == nghttp2_hd_inflate_init(&inflater));
|
||||
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, nv_offset, nva1,
|
||||
sizeof(nva1)/sizeof(nghttp2_nv));
|
||||
CU_ASSERT(blocklen > 0);
|
||||
|
@ -151,8 +142,8 @@ void test_nghttp2_hd_deflate_same_indexed_repr(void)
|
|||
nva_out out;
|
||||
|
||||
nva_out_init(&out);
|
||||
CU_ASSERT(0 == nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST));
|
||||
CU_ASSERT(0 == nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST));
|
||||
CU_ASSERT(0 == nghttp2_hd_deflate_init(&deflater));
|
||||
CU_ASSERT(0 == nghttp2_hd_inflate_init(&inflater));
|
||||
|
||||
/* Encode 2 same headers. cookie:alpha is not in the reference set,
|
||||
so first emit literal repr and then 2 emits of indexed repr. */
|
||||
|
@ -207,8 +198,8 @@ void test_nghttp2_hd_deflate_common_header_eviction(void)
|
|||
nva[i].valuelen = sizeof(value);
|
||||
}
|
||||
|
||||
nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST);
|
||||
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST);
|
||||
nghttp2_hd_deflate_init(&deflater);
|
||||
nghttp2_hd_inflate_init(&inflater);
|
||||
|
||||
/* First emit "h1: ..." to put it in the reference set (index
|
||||
= 0). */
|
||||
|
@ -245,174 +236,6 @@ void test_nghttp2_hd_deflate_common_header_eviction(void)
|
|||
nghttp2_hd_deflate_free(&deflater);
|
||||
}
|
||||
|
||||
void test_nghttp2_hd_deflate_deflate_buffer(void)
|
||||
{
|
||||
nghttp2_hd_deflater deflater;
|
||||
nghttp2_hd_inflater inflater;
|
||||
size_t i;
|
||||
ssize_t blocklen;
|
||||
uint8_t *buf = NULL;
|
||||
size_t buflen = 0;
|
||||
nghttp2_nv nva1[] = { MAKE_NV("k1", "v1"), /* 36 */
|
||||
MAKE_NV("k10", "v10"), /* 38 */
|
||||
MAKE_NV("k100", "v100"), /* 40 */
|
||||
MAKE_NV("k1000", "v1000") /* 42 */
|
||||
}; /* Total: 156 */
|
||||
nghttp2_nv nva2[] = { MAKE_NV("k10", "v10"), /* 38 */
|
||||
MAKE_NV("k1", "v1") /* 36 */
|
||||
};
|
||||
nghttp2_nv nv3;
|
||||
uint8_t val[256];
|
||||
nghttp2_nv nva4[] = { MAKE_NV(":method", "GET"),
|
||||
MAKE_NV(":scheme", "http")
|
||||
};
|
||||
nghttp2_hd_entry *ent;
|
||||
nva_out out;
|
||||
|
||||
nva_out_init(&out);
|
||||
memset(val, 'a', sizeof(val));
|
||||
nv3.name = nv3.value = val;
|
||||
nv3.namelen = nv3.valuelen = sizeof(val);
|
||||
|
||||
/* Check the case where entry from static table is inserted to
|
||||
dynamic header table. And it is out of deflate header table
|
||||
size. */
|
||||
nghttp2_hd_deflate_init2(&deflater, NGHTTP2_HD_SIDE_REQUEST, 32);
|
||||
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST);
|
||||
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0,
|
||||
nva4, ARRLEN(nva4));
|
||||
CU_ASSERT(blocklen > 0);
|
||||
/* Now header table should look like this:
|
||||
*
|
||||
* 0: :scheme, http (-)
|
||||
* 1: :method, GET (-)
|
||||
*
|
||||
* name/value of all entries must be NULL.
|
||||
*/
|
||||
CU_ASSERT(2 == deflater.ctx.hd_table.len);
|
||||
CU_ASSERT(0 == deflater.ctx.deflate_hd_tablelen);
|
||||
CU_ASSERT(0 == deflater.ctx.deflate_hd_table_bufsize);
|
||||
for(i = 0; i < 2; ++i) {
|
||||
ent = nghttp2_hd_table_get(&deflater.ctx, i);
|
||||
CU_ASSERT(ent->nv.name == NULL);
|
||||
CU_ASSERT(ent->nv.value == NULL);
|
||||
CU_ASSERT(0 == (ent->flags & NGHTTP2_HD_FLAG_REFSET));
|
||||
}
|
||||
|
||||
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf, blocklen));
|
||||
|
||||
CU_ASSERT(2 == out.nvlen);
|
||||
assert_nv_equal(nva4, out.nva, 2);
|
||||
|
||||
nva_out_reset(&out);
|
||||
|
||||
nghttp2_hd_deflate_free(&deflater);
|
||||
nghttp2_hd_inflate_free(&inflater);
|
||||
|
||||
/* 156 buffer size can hold all headers in deflate region */
|
||||
nghttp2_hd_deflate_init2(&deflater, NGHTTP2_HD_SIDE_REQUEST, 156);
|
||||
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0,
|
||||
nva1, ARRLEN(nva1));
|
||||
CU_ASSERT(blocklen > 0);
|
||||
/* Now header table should look like this:
|
||||
*
|
||||
* 0: k1000, v100
|
||||
* 1: k100, v100
|
||||
* 2: k10, v10
|
||||
* 3: k1, v1
|
||||
*/
|
||||
CU_ASSERT(4 == deflater.ctx.hd_table.len);
|
||||
CU_ASSERT(4 == deflater.ctx.deflate_hd_tablelen);
|
||||
CU_ASSERT(156 == deflater.ctx.deflate_hd_table_bufsize);
|
||||
for(i = 0; i < 4; ++i) {
|
||||
CU_ASSERT(nghttp2_hd_table_get(&deflater.ctx, i)->nv.name != NULL);
|
||||
CU_ASSERT(nghttp2_hd_table_get(&deflater.ctx, i)->nv.value != NULL);
|
||||
}
|
||||
|
||||
CU_ASSERT(0 == nghttp2_hd_change_table_size(&deflater.ctx, 156));
|
||||
CU_ASSERT(4 == deflater.ctx.hd_table.len);
|
||||
CU_ASSERT(4 == deflater.ctx.deflate_hd_tablelen);
|
||||
CU_ASSERT(156 == deflater.ctx.deflate_hd_table_bufsize);
|
||||
|
||||
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, &nv3, 1);
|
||||
CU_ASSERT(blocklen > 0);
|
||||
/* Now header table should be unchanged, because we don't index
|
||||
large header */
|
||||
CU_ASSERT(4 == deflater.ctx.hd_table.len);
|
||||
CU_ASSERT(4 == deflater.ctx.deflate_hd_tablelen);
|
||||
CU_ASSERT(156 == deflater.ctx.deflate_hd_table_bufsize);
|
||||
|
||||
nghttp2_hd_deflate_free(&deflater);
|
||||
|
||||
/* Check more complex use case */
|
||||
nghttp2_hd_deflate_init2(&deflater, NGHTTP2_HD_SIDE_REQUEST, 155);
|
||||
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST);
|
||||
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0,
|
||||
nva1, ARRLEN(nva1));
|
||||
CU_ASSERT(blocklen > 0);
|
||||
/* Now header table should look like this:
|
||||
*
|
||||
* 0: k1000, v100 (R)
|
||||
* 1: k100, v100 (R)
|
||||
* 2: k10, v10 (R)
|
||||
* 3: k1, v1 (-) <- name, value must be NULL and not in reference set
|
||||
*
|
||||
* But due to the deflate table size limit, name/value of index=3 must
|
||||
* be NULL.
|
||||
*/
|
||||
CU_ASSERT(4 == deflater.ctx.hd_table.len);
|
||||
CU_ASSERT(3 == deflater.ctx.deflate_hd_tablelen);
|
||||
CU_ASSERT(120 == deflater.ctx.deflate_hd_table_bufsize);
|
||||
for(i = 0; i < 3; ++i) {
|
||||
CU_ASSERT(nghttp2_hd_table_get(&deflater.ctx, i)->nv.name != NULL);
|
||||
CU_ASSERT(nghttp2_hd_table_get(&deflater.ctx, i)->nv.value != NULL);
|
||||
}
|
||||
ent = nghttp2_hd_table_get(&deflater.ctx, 3);
|
||||
CU_ASSERT(ent->nv.name == NULL);
|
||||
CU_ASSERT(ent->nv.value == NULL);
|
||||
CU_ASSERT(0 == (ent->flags & NGHTTP2_HD_FLAG_REFSET));
|
||||
|
||||
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf, blocklen));
|
||||
|
||||
CU_ASSERT(4 == out.nvlen);
|
||||
assert_nv_equal(nva1, out.nva, 4);
|
||||
|
||||
nva_out_reset(&out);
|
||||
|
||||
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0,
|
||||
nva2, ARRLEN(nva2));
|
||||
CU_ASSERT(blocklen > 0);
|
||||
/* Now header table should look like this:
|
||||
*
|
||||
* 0: k1, v1 (R)
|
||||
* 1: k1000, v100 (R)
|
||||
* 2: k100, v100 (R)
|
||||
* 3: k10, v10 (-) <- name, value must be NULL
|
||||
* 4: k1, v1 (-) <- name, value must be NULL
|
||||
*/
|
||||
CU_ASSERT(5 == deflater.ctx.hd_table.len);
|
||||
CU_ASSERT(3 == deflater.ctx.deflate_hd_tablelen);
|
||||
CU_ASSERT(118 == deflater.ctx.deflate_hd_table_bufsize);
|
||||
ent = nghttp2_hd_table_get(&deflater.ctx, 3);
|
||||
CU_ASSERT(0 == (ent->flags & NGHTTP2_HD_FLAG_REFSET));
|
||||
ent = nghttp2_hd_table_get(&deflater.ctx, 3);
|
||||
CU_ASSERT(0 == (ent->flags & NGHTTP2_HD_FLAG_REFSET));
|
||||
|
||||
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf, blocklen));
|
||||
|
||||
CU_ASSERT(2 == out.nvlen);
|
||||
/* Sort before comparison */
|
||||
nghttp2_nv_array_sort(nva2, 2);
|
||||
assert_nv_equal(nva2, out.nva, 2);
|
||||
|
||||
nva_out_reset(&out);
|
||||
|
||||
free(buf);
|
||||
nghttp2_hd_inflate_free(&inflater);
|
||||
nghttp2_hd_deflate_free(&deflater);
|
||||
|
||||
}
|
||||
|
||||
void test_nghttp2_hd_deflate_clear_refset(void)
|
||||
{
|
||||
nghttp2_hd_deflater deflater;
|
||||
|
@ -428,10 +251,10 @@ void test_nghttp2_hd_deflate_clear_refset(void)
|
|||
nva_out out;
|
||||
|
||||
nva_out_init(&out);
|
||||
nghttp2_hd_deflate_init2(&deflater, NGHTTP2_HD_SIDE_REQUEST,
|
||||
nghttp2_hd_deflate_init2(&deflater,
|
||||
NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE);
|
||||
nghttp2_hd_deflate_set_no_refset(&deflater, 1);
|
||||
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST);
|
||||
nghttp2_hd_inflate_init(&inflater);
|
||||
|
||||
for(i = 0; i < 2; ++i) {
|
||||
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0,
|
||||
|
@ -466,14 +289,13 @@ void test_nghttp2_hd_inflate_indname_noinc(void)
|
|||
nva_out out;
|
||||
|
||||
nva_out_init(&out);
|
||||
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST);
|
||||
nghttp2_hd_inflate_init(&inflater);
|
||||
|
||||
for(i = 0; i < ARRLEN(nv); ++i) {
|
||||
offset = 0;
|
||||
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 56,
|
||||
nv[i].value, nv[i].valuelen,
|
||||
0,
|
||||
NGHTTP2_HD_SIDE_REQUEST));
|
||||
0));
|
||||
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset));
|
||||
|
||||
CU_ASSERT(1 == out.nvlen);
|
||||
|
@ -497,11 +319,10 @@ void test_nghttp2_hd_inflate_indname_inc(void)
|
|||
nva_out out;
|
||||
|
||||
nva_out_init(&out);
|
||||
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST);
|
||||
nghttp2_hd_inflate_init(&inflater);
|
||||
|
||||
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 56,
|
||||
nv.value, nv.valuelen, 1,
|
||||
NGHTTP2_HD_SIDE_REQUEST));
|
||||
nv.value, nv.valuelen, 1));
|
||||
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset));
|
||||
|
||||
CU_ASSERT(1 == out.nvlen);
|
||||
|
@ -526,21 +347,17 @@ void test_nghttp2_hd_inflate_indname_inc_eviction(void)
|
|||
nva_out out;
|
||||
|
||||
nva_out_init(&out);
|
||||
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST);
|
||||
nghttp2_hd_inflate_init(&inflater);
|
||||
|
||||
memset(value, '0', sizeof(value));
|
||||
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 13,
|
||||
value, sizeof(value), 1,
|
||||
NGHTTP2_HD_SIDE_REQUEST));
|
||||
value, sizeof(value), 1));
|
||||
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 14,
|
||||
value, sizeof(value), 1,
|
||||
NGHTTP2_HD_SIDE_REQUEST));
|
||||
value, sizeof(value), 1));
|
||||
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 15,
|
||||
value, sizeof(value), 1,
|
||||
NGHTTP2_HD_SIDE_REQUEST));
|
||||
value, sizeof(value), 1));
|
||||
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 16,
|
||||
value, sizeof(value), 1,
|
||||
NGHTTP2_HD_SIDE_REQUEST));
|
||||
value, sizeof(value), 1));
|
||||
|
||||
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset));
|
||||
|
||||
|
@ -578,12 +395,11 @@ void test_nghttp2_hd_inflate_newname_noinc(void)
|
|||
nva_out out;
|
||||
|
||||
nva_out_init(&out);
|
||||
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST);
|
||||
nghttp2_hd_inflate_init(&inflater);
|
||||
for(i = 0; i < ARRLEN(nv); ++i) {
|
||||
offset = 0;
|
||||
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &buflen, &offset,
|
||||
&nv[i], 0,
|
||||
NGHTTP2_HD_SIDE_REQUEST));
|
||||
&nv[i], 0));
|
||||
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset));
|
||||
|
||||
CU_ASSERT(1 == out.nvlen);
|
||||
|
@ -607,11 +423,10 @@ void test_nghttp2_hd_inflate_newname_inc(void)
|
|||
nva_out out;
|
||||
|
||||
nva_out_init(&out);
|
||||
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST);
|
||||
nghttp2_hd_inflate_init(&inflater);
|
||||
|
||||
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &buflen, &offset,
|
||||
&nv, 1,
|
||||
NGHTTP2_HD_SIDE_REQUEST));
|
||||
&nv, 1));
|
||||
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset));
|
||||
|
||||
CU_ASSERT(1 == out.nvlen);
|
||||
|
@ -644,11 +459,10 @@ void test_nghttp2_hd_inflate_clearall_inc(void)
|
|||
nv.value = value;
|
||||
nv.valuelen = sizeof(value);
|
||||
|
||||
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST);
|
||||
nghttp2_hd_inflate_init(&inflater);
|
||||
|
||||
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &buflen, &offset,
|
||||
&nv, 1,
|
||||
NGHTTP2_HD_SIDE_REQUEST));
|
||||
&nv, 1));
|
||||
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset));
|
||||
|
||||
CU_ASSERT(1 == out.nvlen);
|
||||
|
@ -672,8 +486,7 @@ void test_nghttp2_hd_inflate_clearall_inc(void)
|
|||
|
||||
offset = 0;
|
||||
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &buflen, &offset,
|
||||
&nv, 1,
|
||||
NGHTTP2_HD_SIDE_REQUEST));
|
||||
&nv, 1));
|
||||
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset));
|
||||
|
||||
CU_ASSERT(1 == out.nvlen);
|
||||
|
@ -699,7 +512,7 @@ void test_nghttp2_hd_inflate_zero_length_huffman(void)
|
|||
buf[2] = 'x';
|
||||
buf[3] = 0x80;
|
||||
|
||||
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST);
|
||||
nghttp2_hd_inflate_init(&inflater);
|
||||
CU_ASSERT(4 == inflate_hd(&inflater, &out, buf, 4));
|
||||
|
||||
CU_ASSERT(1 == out.nvlen);
|
||||
|
@ -715,35 +528,158 @@ void test_nghttp2_hd_inflate_zero_length_huffman(void)
|
|||
void test_nghttp2_hd_change_table_size(void)
|
||||
{
|
||||
nghttp2_hd_deflater deflater;
|
||||
nghttp2_hd_inflater inflater;
|
||||
nghttp2_nv nva[] = { MAKE_NV(":method", "GET"),
|
||||
MAKE_NV(":path", "/") };
|
||||
uint8_t *buf = NULL;
|
||||
size_t buflen = 0;
|
||||
ssize_t rv;
|
||||
nva_out out;
|
||||
size_t offset;
|
||||
|
||||
nva_out_init(&out);
|
||||
|
||||
nghttp2_hd_deflate_init(&deflater);
|
||||
nghttp2_hd_inflate_init(&inflater);
|
||||
|
||||
/* inflater changes notifies 8000 max header table size */
|
||||
CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 8000));
|
||||
CU_ASSERT(0 == nghttp2_hd_deflate_change_table_size(&deflater, 8000));
|
||||
|
||||
CU_ASSERT(127 == deflater.ctx.hd_table.mask);
|
||||
CU_ASSERT(8000 == deflater.ctx.hd_table_bufsize_max);
|
||||
|
||||
CU_ASSERT(255 == inflater.ctx.hd_table.mask);
|
||||
CU_ASSERT(8000 == inflater.ctx.hd_table_bufsize_max);
|
||||
CU_ASSERT(8000 == inflater.settings_hd_table_bufsize_max);
|
||||
|
||||
/* This will emit encoding context update with header table size 4096 */
|
||||
rv = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, 2);
|
||||
CU_ASSERT(rv > 0);
|
||||
CU_ASSERT(2 == deflater.ctx.hd_table.len);
|
||||
CU_ASSERT(4096 == deflater.ctx.hd_table_bufsize_max);
|
||||
|
||||
CU_ASSERT(rv == inflate_hd(&inflater, &out, buf, rv));
|
||||
CU_ASSERT(2 == inflater.ctx.hd_table.len);
|
||||
CU_ASSERT(4096 == inflater.ctx.hd_table_bufsize_max);
|
||||
CU_ASSERT(8000 == inflater.settings_hd_table_bufsize_max);
|
||||
|
||||
nva_out_reset(&out);
|
||||
|
||||
/* inflater changes header table size to 1024 */
|
||||
CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 1024));
|
||||
CU_ASSERT(0 == nghttp2_hd_deflate_change_table_size(&deflater, 1024));
|
||||
|
||||
CU_ASSERT(127 == deflater.ctx.hd_table.mask);
|
||||
CU_ASSERT(1024 == deflater.ctx.hd_table_bufsize_max);
|
||||
|
||||
CU_ASSERT(255 == inflater.ctx.hd_table.mask);
|
||||
CU_ASSERT(1024 == inflater.ctx.hd_table_bufsize_max);
|
||||
CU_ASSERT(1024 == inflater.settings_hd_table_bufsize_max);
|
||||
|
||||
rv = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, 2);
|
||||
CU_ASSERT(rv >= 0);
|
||||
CU_ASSERT(2 == deflater.ctx.hd_table.len);
|
||||
CU_ASSERT(1024 == deflater.ctx.hd_table_bufsize_max);
|
||||
|
||||
CU_ASSERT(rv == inflate_hd(&inflater, &out, buf, rv));
|
||||
CU_ASSERT(2 == inflater.ctx.hd_table.len);
|
||||
CU_ASSERT(1024 == inflater.ctx.hd_table_bufsize_max);
|
||||
CU_ASSERT(1024 == inflater.settings_hd_table_bufsize_max);
|
||||
|
||||
nva_out_reset(&out);
|
||||
|
||||
/* inflater changes header table size to 0 */
|
||||
CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 0));
|
||||
CU_ASSERT(0 == nghttp2_hd_deflate_change_table_size(&deflater, 0));
|
||||
|
||||
CU_ASSERT(127 == deflater.ctx.hd_table.mask);
|
||||
CU_ASSERT(0 == deflater.ctx.hd_table.len);
|
||||
CU_ASSERT(0 == deflater.ctx.hd_table_bufsize_max);
|
||||
|
||||
CU_ASSERT(255 == inflater.ctx.hd_table.mask);
|
||||
CU_ASSERT(0 == inflater.ctx.hd_table.len);
|
||||
CU_ASSERT(0 == inflater.ctx.hd_table_bufsize_max);
|
||||
CU_ASSERT(0 == inflater.settings_hd_table_bufsize_max);
|
||||
|
||||
rv = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, 2);
|
||||
CU_ASSERT(rv >= 0);
|
||||
CU_ASSERT(0 == deflater.ctx.hd_table.len);
|
||||
CU_ASSERT(0 == deflater.ctx.hd_table_bufsize_max);
|
||||
|
||||
CU_ASSERT(rv == inflate_hd(&inflater, &out, buf, rv));
|
||||
CU_ASSERT(0 == inflater.ctx.hd_table.len);
|
||||
CU_ASSERT(0 == inflater.ctx.hd_table_bufsize_max);
|
||||
CU_ASSERT(0 == inflater.settings_hd_table_bufsize_max);
|
||||
|
||||
nva_out_reset(&out);
|
||||
|
||||
free(buf);
|
||||
nghttp2_hd_inflate_free(&inflater);
|
||||
nghttp2_hd_deflate_free(&deflater);
|
||||
|
||||
/* Check table buffer is expanded */
|
||||
buf = NULL;
|
||||
buflen = 0;
|
||||
nghttp2_hd_deflate_init2(&deflater, 8192);
|
||||
nghttp2_hd_inflate_init(&inflater);
|
||||
|
||||
/* First inflater changes header table size to 8000 */
|
||||
CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 8000));
|
||||
CU_ASSERT(0 == nghttp2_hd_deflate_change_table_size(&deflater, 8000));
|
||||
|
||||
nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST);
|
||||
CU_ASSERT(0 == nghttp2_hd_change_table_size(&deflater.ctx, 8000));
|
||||
CU_ASSERT(255 == deflater.ctx.hd_table.mask);
|
||||
CU_ASSERT(8000 == deflater.ctx.hd_table_bufsize_max);
|
||||
|
||||
CU_ASSERT(255 == inflater.ctx.hd_table.mask);
|
||||
CU_ASSERT(8000 == inflater.ctx.hd_table_bufsize_max);
|
||||
CU_ASSERT(8000 == inflater.settings_hd_table_bufsize_max);
|
||||
|
||||
rv = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, 2);
|
||||
CU_ASSERT(rv > 0);
|
||||
CU_ASSERT(2 == deflater.ctx.hd_table.len);
|
||||
CU_ASSERT(8000 == deflater.ctx.hd_table_bufsize_max);
|
||||
|
||||
CU_ASSERT(0 == nghttp2_hd_change_table_size(&deflater.ctx, 16384));
|
||||
CU_ASSERT(511 == deflater.ctx.hd_table.mask);
|
||||
CU_ASSERT(rv == inflate_hd(&inflater, &out, buf, rv));
|
||||
CU_ASSERT(2 == inflater.ctx.hd_table.len);
|
||||
CU_ASSERT(8000 == inflater.ctx.hd_table_bufsize_max);
|
||||
CU_ASSERT(8000 == inflater.settings_hd_table_bufsize_max);
|
||||
|
||||
nva_out_reset(&out);
|
||||
|
||||
CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 16383));
|
||||
CU_ASSERT(0 == nghttp2_hd_deflate_change_table_size(&deflater, 16383));
|
||||
|
||||
CU_ASSERT(255 == deflater.ctx.hd_table.mask);
|
||||
CU_ASSERT(16383 == deflater.ctx.hd_table_bufsize_max);
|
||||
|
||||
CU_ASSERT(511 == inflater.ctx.hd_table.mask);
|
||||
CU_ASSERT(16383 == inflater.ctx.hd_table_bufsize_max);
|
||||
CU_ASSERT(16383 == inflater.settings_hd_table_bufsize_max);
|
||||
|
||||
rv = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, 2);
|
||||
CU_ASSERT(rv >= 0);
|
||||
CU_ASSERT(2 == deflater.ctx.hd_table.len);
|
||||
CU_ASSERT(2 == deflater.ctx.deflate_hd_tablelen);
|
||||
CU_ASSERT(5 ==
|
||||
deflater.ctx.hd_table.buffer[deflater.ctx.hd_table.first]
|
||||
->nv.namelen);
|
||||
CU_ASSERT(8192 == deflater.ctx.hd_table_bufsize_max);
|
||||
|
||||
CU_ASSERT(0 == nghttp2_hd_change_table_size(&deflater.ctx, 0));
|
||||
CU_ASSERT(511 == deflater.ctx.hd_table.mask);
|
||||
CU_ASSERT(0 == deflater.ctx.hd_table.len);
|
||||
CU_ASSERT(0 == deflater.ctx.deflate_hd_tablelen);
|
||||
CU_ASSERT(rv == inflate_hd(&inflater, &out, buf, rv));
|
||||
CU_ASSERT(2 == inflater.ctx.hd_table.len);
|
||||
CU_ASSERT(8192 == inflater.ctx.hd_table_bufsize_max);
|
||||
CU_ASSERT(16383 == inflater.settings_hd_table_bufsize_max);
|
||||
|
||||
nva_out_reset(&out);
|
||||
|
||||
/* Lastly, check the error condition */
|
||||
offset = 0;
|
||||
rv = nghttp2_hd_emit_table_size(&buf, &buflen, &offset, 25600);
|
||||
CU_ASSERT(rv == 0);
|
||||
CU_ASSERT(NGHTTP2_ERR_HEADER_COMP ==
|
||||
inflate_hd(&inflater, &out, buf, offset));
|
||||
|
||||
nva_out_reset(&out);
|
||||
|
||||
free(buf);
|
||||
nghttp2_hd_inflate_free(&inflater);
|
||||
nghttp2_hd_deflate_free(&deflater);
|
||||
}
|
||||
|
||||
|
@ -908,8 +844,8 @@ void test_nghttp2_hd_deflate_inflate(void)
|
|||
MAKE_NV("x-cache-lookup", "HIT from alphabravo:3128"),
|
||||
};
|
||||
|
||||
nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST);
|
||||
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST);
|
||||
nghttp2_hd_deflate_init(&deflater);
|
||||
nghttp2_hd_inflate_init(&inflater);
|
||||
|
||||
check_deflate_inflate(&deflater, &inflater, nv1, ARRLEN(nv1));
|
||||
check_deflate_inflate(&deflater, &inflater, nv2, ARRLEN(nv2));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -33,14 +33,13 @@ static void http2(void)
|
|||
{
|
||||
const unsigned char p[] = {
|
||||
8, 'h', 't', 't', 'p', '/', '1', '.', '1',
|
||||
17, 'H', 'T', 'T', 'P', '-', 'd', 'r', 'a', 'f', 't', '-', '0', '9', '/',
|
||||
'2', '.', '0',
|
||||
5, 'h', '2', '-', '1', '0',
|
||||
6, 's', 'p', 'd', 'y', '/', '3'
|
||||
};
|
||||
unsigned char outlen;
|
||||
unsigned char* out;
|
||||
CU_ASSERT(1 == nghttp2_select_next_protocol(&out, &outlen, p, sizeof(p)));
|
||||
CU_ASSERT(17 == outlen);
|
||||
CU_ASSERT(NGHTTP2_PROTO_VERSION_ID_LEN == outlen);
|
||||
CU_ASSERT(memcmp(NGHTTP2_PROTO_VERSION_ID, out, outlen) == 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
#define OB_DATA(ITEM) nghttp2_outbound_item_get_data_frame(ITEM)
|
||||
|
||||
typedef struct {
|
||||
uint8_t buf[4096];
|
||||
uint8_t buf[65535];
|
||||
size_t length;
|
||||
} accumulator;
|
||||
|
||||
|
@ -71,6 +71,8 @@ typedef struct {
|
|||
int header_cb_called;
|
||||
int begin_headers_cb_called;
|
||||
nghttp2_nv nv;
|
||||
size_t data_chunk_len;
|
||||
size_t padding_boundary;
|
||||
} my_user_data;
|
||||
|
||||
static void scripted_data_feed_init(scripted_data_feed *df,
|
||||
|
@ -187,6 +189,7 @@ static int on_data_chunk_recv_callback(nghttp2_session *session,
|
|||
{
|
||||
my_user_data *ud = (my_user_data*)user_data;
|
||||
++ud->data_chunk_recv_cb_called;
|
||||
ud->data_chunk_len = len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -200,6 +203,17 @@ static int pause_on_data_chunk_recv_callback(nghttp2_session *session,
|
|||
return NGHTTP2_ERR_PAUSE;
|
||||
}
|
||||
|
||||
static ssize_t select_padding_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
size_t max_payloadlen,
|
||||
void *user_data)
|
||||
{
|
||||
my_user_data *ud = (my_user_data*)user_data;
|
||||
return nghttp2_min(max_payloadlen,
|
||||
(frame->hd.length + ud->padding_boundary - 1)
|
||||
/ ud->padding_boundary * ud->padding_boundary);
|
||||
}
|
||||
|
||||
static ssize_t fixed_length_data_source_read_callback
|
||||
(nghttp2_session *session, int32_t stream_id,
|
||||
uint8_t *buf, size_t len, int *eof,
|
||||
|
@ -334,9 +348,10 @@ void test_nghttp2_session_recv(void)
|
|||
};
|
||||
uint8_t *framedata = NULL;
|
||||
size_t framedatalen = 0;
|
||||
size_t bufoff;
|
||||
ssize_t framelen;
|
||||
nghttp2_frame frame;
|
||||
int i;
|
||||
size_t i;
|
||||
nghttp2_outbound_item *item;
|
||||
nghttp2_nv *nva;
|
||||
ssize_t nvlen;
|
||||
|
@ -348,18 +363,18 @@ void test_nghttp2_session_recv(void)
|
|||
callbacks.on_frame_recv_callback = on_frame_recv_callback;
|
||||
user_data.df = &df;
|
||||
nghttp2_session_server_new(&session, &callbacks, &user_data);
|
||||
nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST);
|
||||
nghttp2_hd_deflate_init(&deflater);
|
||||
|
||||
nvlen = nghttp2_nv_array_copy(&nva, nv, ARRLEN(nv));
|
||||
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS,
|
||||
1, NGHTTP2_PRI_DEFAULT, nva, nvlen);
|
||||
framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen,
|
||||
framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff,
|
||||
&frame.headers,
|
||||
&deflater);
|
||||
|
||||
scripted_data_feed_init(&df, framedata, framelen);
|
||||
scripted_data_feed_init(&df, framedata + bufoff, framelen - bufoff);
|
||||
/* Send 1 byte per each read */
|
||||
for(i = 0; i < framelen; ++i) {
|
||||
for(i = 0; i < framelen - bufoff; ++i) {
|
||||
df.feedseq[i] = 1;
|
||||
}
|
||||
nghttp2_frame_headers_free(&frame.headers);
|
||||
|
@ -373,13 +388,13 @@ void test_nghttp2_session_recv(void)
|
|||
/* Received HEADERS without header block, which is valid */
|
||||
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS,
|
||||
5, NGHTTP2_PRI_DEFAULT, NULL, 0);
|
||||
framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen,
|
||||
framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff,
|
||||
&frame.headers,
|
||||
&deflater);
|
||||
|
||||
nghttp2_frame_headers_free(&frame.headers);
|
||||
|
||||
scripted_data_feed_init(&df, framedata, framelen);
|
||||
scripted_data_feed_init(&df, framedata + bufoff, framelen - bufoff);
|
||||
user_data.frame_recv_cb_called = 0;
|
||||
CU_ASSERT(0 == nghttp2_session_recv(session));
|
||||
CU_ASSERT(1 == user_data.frame_recv_cb_called);
|
||||
|
@ -419,6 +434,7 @@ void test_nghttp2_session_recv_invalid_stream_id(void)
|
|||
my_user_data user_data;
|
||||
uint8_t *framedata = NULL;
|
||||
size_t framedatalen = 0;
|
||||
size_t bufoff;
|
||||
ssize_t framelen;
|
||||
nghttp2_frame frame;
|
||||
nghttp2_hd_deflater deflater;
|
||||
|
@ -430,15 +446,15 @@ void test_nghttp2_session_recv_invalid_stream_id(void)
|
|||
user_data.df = &df;
|
||||
user_data.invalid_frame_recv_cb_called = 0;
|
||||
nghttp2_session_server_new(&session, &callbacks, &user_data);
|
||||
nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST);
|
||||
nghttp2_hd_deflate_init(&deflater);
|
||||
|
||||
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 2,
|
||||
NGHTTP2_PRI_DEFAULT, NULL, 0);
|
||||
framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen,
|
||||
framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff,
|
||||
&frame.headers,
|
||||
&deflater);
|
||||
|
||||
scripted_data_feed_init(&df, framedata, framelen);
|
||||
scripted_data_feed_init(&df, framedata + bufoff, framelen - bufoff);
|
||||
nghttp2_frame_headers_free(&frame.headers);
|
||||
|
||||
CU_ASSERT(0 == nghttp2_session_recv(session));
|
||||
|
@ -460,6 +476,7 @@ void test_nghttp2_session_recv_invalid_frame(void)
|
|||
};
|
||||
uint8_t *framedata = NULL;
|
||||
size_t framedatalen = 0;
|
||||
size_t bufoff;
|
||||
ssize_t framelen;
|
||||
nghttp2_frame frame;
|
||||
nghttp2_nv *nva;
|
||||
|
@ -474,15 +491,15 @@ void test_nghttp2_session_recv_invalid_frame(void)
|
|||
user_data.df = &df;
|
||||
user_data.frame_send_cb_called = 0;
|
||||
nghttp2_session_server_new(&session, &callbacks, &user_data);
|
||||
nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST);
|
||||
nghttp2_hd_deflate_init(&deflater);
|
||||
nvlen = nghttp2_nv_array_copy(&nva, nv, ARRLEN(nv));
|
||||
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1,
|
||||
NGHTTP2_PRI_DEFAULT, nva, nvlen);
|
||||
framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen,
|
||||
framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff,
|
||||
&frame.headers,
|
||||
&deflater);
|
||||
|
||||
scripted_data_feed_init(&df, framedata, framelen);
|
||||
scripted_data_feed_init(&df, framedata + bufoff, framelen - bufoff);
|
||||
|
||||
CU_ASSERT(0 == nghttp2_session_recv(session));
|
||||
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||
|
@ -490,7 +507,7 @@ void test_nghttp2_session_recv_invalid_frame(void)
|
|||
|
||||
/* Receive exactly same bytes of HEADERS is treated as subsequent
|
||||
HEADERS (e.g., trailers */
|
||||
scripted_data_feed_init(&df, framedata, framelen);
|
||||
scripted_data_feed_init(&df, framedata + bufoff, framelen - bufoff);
|
||||
|
||||
CU_ASSERT(0 == nghttp2_session_recv(session));
|
||||
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||
|
@ -658,6 +675,7 @@ void test_nghttp2_session_recv_continuation(void)
|
|||
uint8_t *framedata = NULL;
|
||||
size_t framedatacap = 0;
|
||||
size_t framedatalen;
|
||||
size_t bufoff;
|
||||
size_t framedataoff;
|
||||
ssize_t rv;
|
||||
my_user_data ud;
|
||||
|
@ -672,20 +690,21 @@ void test_nghttp2_session_recv_continuation(void)
|
|||
|
||||
nghttp2_session_server_new(&session, &callbacks, &ud);
|
||||
|
||||
nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST);
|
||||
nghttp2_hd_deflate_init(&deflater);
|
||||
|
||||
/* Make 1 HEADERS and insert CONTINUATION header */
|
||||
nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1));
|
||||
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_NONE,
|
||||
1, NGHTTP2_PRI_DEFAULT, nva, nvlen);
|
||||
framedatalen = nghttp2_frame_pack_headers(&framedata, &framedatacap,
|
||||
&bufoff,
|
||||
&frame.headers,
|
||||
&deflater);
|
||||
nghttp2_frame_headers_free(&frame.headers);
|
||||
|
||||
memcpy(data, framedata, 9);
|
||||
memcpy(data, framedata + bufoff, 9);
|
||||
datalen = 9;
|
||||
framedataoff = NGHTTP2_FRAME_HEAD_LENGTH + 1;
|
||||
framedataoff = bufoff + NGHTTP2_FRAME_HEAD_LENGTH + 1;
|
||||
|
||||
nghttp2_put_uint16be(data, 1);
|
||||
|
||||
|
@ -727,18 +746,18 @@ void test_nghttp2_session_recv_continuation(void)
|
|||
/* Expecting CONTINUATION, but get the other frame */
|
||||
nghttp2_session_server_new(&session, &callbacks, &ud);
|
||||
|
||||
nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST);
|
||||
nghttp2_hd_deflate_init(&deflater);
|
||||
|
||||
/* HEADERS without END_HEADERS flag */
|
||||
nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1));
|
||||
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_NONE,
|
||||
1, NGHTTP2_PRI_DEFAULT, nva, nvlen);
|
||||
framedatalen = nghttp2_frame_pack_headers(&framedata, &framedatacap,
|
||||
framedatalen = nghttp2_frame_pack_headers(&framedata, &framedatacap, &bufoff,
|
||||
&frame.headers,
|
||||
&deflater);
|
||||
nghttp2_frame_headers_free(&frame.headers);
|
||||
memcpy(data, framedata, framedatalen);
|
||||
datalen = framedatalen;
|
||||
memcpy(data, framedata + bufoff, framedatalen - bufoff);
|
||||
datalen = framedatalen - bufoff;
|
||||
|
||||
/* Followed by PRIORITY */
|
||||
nghttp2_frame_priority_init(&frame.priority, 1, 0);
|
||||
|
@ -778,25 +797,28 @@ void test_nghttp2_session_recv_premature_headers(void)
|
|||
my_user_data ud;
|
||||
nghttp2_hd_deflater deflater;
|
||||
nghttp2_outbound_item *item;
|
||||
size_t bufoff = 0;
|
||||
|
||||
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||
|
||||
nghttp2_session_server_new(&session, &callbacks, &ud);
|
||||
|
||||
nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST);
|
||||
nghttp2_hd_deflate_init(&deflater);
|
||||
|
||||
nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1));
|
||||
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS,
|
||||
1, NGHTTP2_PRI_DEFAULT, nva, nvlen);
|
||||
framedatalen = nghttp2_frame_pack_headers(&framedata, &framedatacap,
|
||||
&bufoff,
|
||||
&frame.headers,
|
||||
&deflater);
|
||||
nghttp2_frame_headers_free(&frame.headers);
|
||||
|
||||
/* Intentionally feed payload cutting last 1 byte off */
|
||||
nghttp2_put_uint16be(framedata, frame.hd.length - 1);
|
||||
rv = nghttp2_session_mem_recv(session, framedata, framedatalen - 1);
|
||||
CU_ASSERT((ssize_t)framedatalen - 1 == rv);
|
||||
nghttp2_put_uint16be(framedata + bufoff, frame.hd.length - 1);
|
||||
rv = nghttp2_session_mem_recv(session, framedata + bufoff,
|
||||
framedatalen - bufoff - 1);
|
||||
CU_ASSERT((ssize_t)(framedatalen - bufoff - 1) == rv);
|
||||
|
||||
item = nghttp2_session_get_next_ob_item(session);
|
||||
CU_ASSERT(NULL != item);
|
||||
|
@ -828,6 +850,7 @@ void test_nghttp2_session_continue(void)
|
|||
uint8_t buffer[4096];
|
||||
uint8_t *bufp = buffer;
|
||||
size_t buflen;
|
||||
size_t bufoff;
|
||||
nghttp2_frame frame;
|
||||
nghttp2_nv *nva;
|
||||
ssize_t nvlen;
|
||||
|
@ -844,28 +867,30 @@ void test_nghttp2_session_continue(void)
|
|||
|
||||
nghttp2_session_server_new(&session, &callbacks, &user_data);
|
||||
|
||||
nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST);
|
||||
nghttp2_hd_deflate_init(&deflater);
|
||||
|
||||
/* Make 2 HEADERS frames */
|
||||
nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1));
|
||||
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS,
|
||||
1, NGHTTP2_PRI_DEFAULT, nva, nvlen);
|
||||
framelen1 = nghttp2_frame_pack_headers(&framedata, &framedatalen,
|
||||
framelen1 = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff,
|
||||
&frame.headers,
|
||||
&deflater);
|
||||
nghttp2_frame_headers_free(&frame.headers);
|
||||
|
||||
memcpy(buffer, framedata, framelen1);
|
||||
memcpy(buffer, framedata + bufoff, framelen1 - bufoff);
|
||||
framelen1 -= bufoff;
|
||||
|
||||
nvlen = nghttp2_nv_array_copy(&nva, nv2, ARRLEN(nv2));
|
||||
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS,
|
||||
3, NGHTTP2_PRI_DEFAULT, nva, nvlen);
|
||||
framelen2 = nghttp2_frame_pack_headers(&framedata, &framedatalen,
|
||||
framelen2 = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff,
|
||||
&frame.headers,
|
||||
&deflater);
|
||||
nghttp2_frame_headers_free(&frame.headers);
|
||||
|
||||
memcpy(buffer + framelen1, framedata, framelen2);
|
||||
memcpy(buffer + framelen1, framedata + bufoff, framelen2 - bufoff);
|
||||
framelen2 -= bufoff;
|
||||
buflen = framelen1 + framelen2;
|
||||
|
||||
/* Receive 1st HEADERS and pause */
|
||||
|
@ -1359,11 +1384,10 @@ void test_nghttp2_session_on_settings_received(void)
|
|||
iv[2].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
|
||||
iv[2].value = 64*1024;
|
||||
|
||||
iv[3].settings_id = NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS;
|
||||
iv[3].value = 1;
|
||||
iv[3].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
|
||||
iv[3].value = 1024;
|
||||
|
||||
/* Unknown settings ID */
|
||||
iv[4].settings_id = 999;
|
||||
iv[4].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
|
||||
iv[4].value = 0;
|
||||
|
||||
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||
|
@ -1389,8 +1413,10 @@ void test_nghttp2_session_on_settings_received(void)
|
|||
session->remote_settings[NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS]);
|
||||
CU_ASSERT(64*1024 ==
|
||||
session->remote_settings[NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]);
|
||||
CU_ASSERT(1 ==
|
||||
session->remote_settings[NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS]);
|
||||
CU_ASSERT(1024 ==
|
||||
session->remote_settings[NGHTTP2_SETTINGS_HEADER_TABLE_SIZE]);
|
||||
CU_ASSERT(0 ==
|
||||
session->remote_settings[NGHTTP2_SETTINGS_ENABLE_PUSH]);
|
||||
|
||||
CU_ASSERT(64*1024 == stream1->remote_window_size);
|
||||
CU_ASSERT(0 == stream2->remote_window_size);
|
||||
|
@ -1402,10 +1428,6 @@ void test_nghttp2_session_on_settings_received(void)
|
|||
CU_ASSERT(16*1024 == stream1->remote_window_size);
|
||||
CU_ASSERT(-48*1024 == stream2->remote_window_size);
|
||||
|
||||
CU_ASSERT(0 == stream1->remote_flow_control);
|
||||
CU_ASSERT(0 == stream2->remote_flow_control);
|
||||
CU_ASSERT(0 == session->remote_flow_control);
|
||||
|
||||
nghttp2_frame_settings_free(&frame.settings);
|
||||
|
||||
nghttp2_session_del(session);
|
||||
|
@ -2232,7 +2254,8 @@ void test_nghttp2_submit_request_without_data(void)
|
|||
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||
callbacks.send_callback = accumulator_send_callback;
|
||||
CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud));
|
||||
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST);
|
||||
|
||||
nghttp2_hd_inflate_init(&inflater);
|
||||
CU_ASSERT(0 == nghttp2_submit_request(session, NGHTTP2_PRI_DEFAULT,
|
||||
nva, ARRLEN(nva), &data_prd, NULL));
|
||||
item = nghttp2_session_get_next_ob_item(session);
|
||||
|
@ -2303,7 +2326,8 @@ void test_nghttp2_submit_response_without_data(void)
|
|||
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||
callbacks.send_callback = accumulator_send_callback;
|
||||
CU_ASSERT(0 == nghttp2_session_server_new(&session, &callbacks, &ud));
|
||||
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_RESPONSE);
|
||||
|
||||
nghttp2_hd_inflate_init(&inflater);
|
||||
nghttp2_session_open_stream(session, 1, NGHTTP2_FLAG_END_STREAM,
|
||||
NGHTTP2_PRI_DEFAULT,
|
||||
NGHTTP2_STREAM_OPENING, NULL);
|
||||
|
@ -2474,7 +2498,8 @@ void test_nghttp2_submit_headers(void)
|
|||
callbacks.on_frame_send_callback = on_frame_send_callback;
|
||||
|
||||
CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud));
|
||||
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST);
|
||||
|
||||
nghttp2_hd_inflate_init(&inflater);
|
||||
CU_ASSERT(0 == nghttp2_submit_headers(session,
|
||||
NGHTTP2_FLAG_END_STREAM,
|
||||
1, NGHTTP2_PRI_DEFAULT,
|
||||
|
@ -2649,18 +2674,14 @@ void test_nghttp2_submit_settings(void)
|
|||
iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
|
||||
iv[1].value = 16*1024;
|
||||
|
||||
iv[2].settings_id = NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS;
|
||||
iv[2].value = 1;
|
||||
iv[2].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
|
||||
iv[2].value = 50;
|
||||
|
||||
iv[3].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
|
||||
iv[3].value = 50;
|
||||
iv[3].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
|
||||
iv[3].value = 0;
|
||||
|
||||
iv[4].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
|
||||
iv[4].value = 0;
|
||||
|
||||
/* Attempt to re-enable flow-control */
|
||||
iv[5].settings_id = NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS;
|
||||
iv[5].value = 0;
|
||||
iv[4].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
|
||||
iv[4].value = (uint32_t)NGHTTP2_MAX_WINDOW_SIZE + 1;
|
||||
|
||||
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||
callbacks.send_callback = null_send_callback;
|
||||
|
@ -2668,25 +2689,23 @@ void test_nghttp2_submit_settings(void)
|
|||
nghttp2_session_server_new(&session, &callbacks, &ud);
|
||||
|
||||
CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT ==
|
||||
nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 6));
|
||||
nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 5));
|
||||
|
||||
/* Make sure that local settings are not changed */
|
||||
CU_ASSERT(NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS ==
|
||||
session->local_settings[NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS]);
|
||||
CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE ==
|
||||
session->local_settings[NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]);
|
||||
CU_ASSERT(0 ==
|
||||
session->local_settings[NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS]);
|
||||
|
||||
/* Now sends without 6th one */
|
||||
CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 5));
|
||||
/* Now sends without 5th one */
|
||||
CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 4));
|
||||
|
||||
item = nghttp2_session_get_next_ob_item(session);
|
||||
|
||||
CU_ASSERT(NGHTTP2_SETTINGS == OB_CTRL_TYPE(item));
|
||||
|
||||
frame = item->frame;
|
||||
CU_ASSERT(5 == frame->settings.niv);
|
||||
CU_ASSERT(4 == frame->settings.niv);
|
||||
CU_ASSERT(5 == frame->settings.iv[0].value);
|
||||
CU_ASSERT(NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS ==
|
||||
frame->settings.iv[0].settings_id);
|
||||
|
@ -2709,9 +2728,6 @@ void test_nghttp2_submit_settings(void)
|
|||
|
||||
CU_ASSERT(16*1024 ==
|
||||
session->local_settings[NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]);
|
||||
CU_ASSERT(1 ==
|
||||
session->local_settings[NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS]);
|
||||
CU_ASSERT(0 == session->local_flow_control);
|
||||
CU_ASSERT(0 == session->hd_inflater.ctx.hd_table_bufsize_max);
|
||||
|
||||
nghttp2_session_del(session);
|
||||
|
@ -2731,9 +2747,6 @@ void test_nghttp2_submit_settings_update_local_window_size(void)
|
|||
iv[0].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
|
||||
iv[0].value = 16*1024;
|
||||
|
||||
iv[1].settings_id = NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS;
|
||||
iv[1].value = 1;
|
||||
|
||||
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||
callbacks.send_callback = null_send_callback;
|
||||
|
||||
|
@ -2748,7 +2761,6 @@ void test_nghttp2_submit_settings_update_local_window_size(void)
|
|||
stream = nghttp2_session_open_stream(session, 3, NGHTTP2_STREAM_FLAG_NONE,
|
||||
NGHTTP2_PRI_DEFAULT,
|
||||
NGHTTP2_STREAM_OPENED, NULL);
|
||||
stream->local_flow_control = 0;
|
||||
|
||||
CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 1));
|
||||
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||
|
@ -2759,7 +2771,7 @@ void test_nghttp2_submit_settings_update_local_window_size(void)
|
|||
CU_ASSERT(16*1024 + 100 == stream->local_window_size);
|
||||
|
||||
stream = nghttp2_session_get_stream(session, 3);
|
||||
CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE == stream->local_window_size);
|
||||
CU_ASSERT(16*1024 == stream->local_window_size);
|
||||
|
||||
item = nghttp2_session_get_next_ob_item(session);
|
||||
CU_ASSERT(NGHTTP2_WINDOW_UPDATE == OB_CTRL_TYPE(item));
|
||||
|
@ -2767,20 +2779,6 @@ void test_nghttp2_submit_settings_update_local_window_size(void)
|
|||
|
||||
nghttp2_session_del(session);
|
||||
|
||||
/* Check flow control disabled case */
|
||||
nghttp2_session_server_new(&session, &callbacks, NULL);
|
||||
stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
|
||||
NGHTTP2_PRI_DEFAULT,
|
||||
NGHTTP2_STREAM_OPENED, NULL);
|
||||
|
||||
CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 2));
|
||||
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||
CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &ack_frame, 0));
|
||||
|
||||
CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE == stream->local_window_size);
|
||||
|
||||
nghttp2_session_del(session);
|
||||
|
||||
/* Check overflow case */
|
||||
iv[0].value = 128*1024;
|
||||
nghttp2_session_server_new(&session, &callbacks, NULL);
|
||||
|
@ -2793,7 +2791,10 @@ void test_nghttp2_submit_settings_update_local_window_size(void)
|
|||
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||
CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &ack_frame, 0));
|
||||
|
||||
CU_ASSERT(NGHTTP2_STREAM_CLOSING == stream->state);
|
||||
|
||||
item = nghttp2_session_get_next_ob_item(session);
|
||||
CU_ASSERT(NGHTTP2_GOAWAY == OB_CTRL_TYPE(item));
|
||||
CU_ASSERT(NGHTTP2_FLOW_CONTROL_ERROR == OB_CTRL(item)->goaway.error_code);
|
||||
|
||||
nghttp2_session_del(session);
|
||||
nghttp2_frame_settings_free(&ack_frame.settings);
|
||||
|
@ -2875,10 +2876,6 @@ void test_nghttp2_submit_window_update(void)
|
|||
|
||||
CU_ASSERT(0 ==
|
||||
nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, 2, 0));
|
||||
/* Disable local flow control */
|
||||
stream->local_flow_control = 0;
|
||||
CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT ==
|
||||
nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, 2, -1));
|
||||
/* It is ok if stream is closed or does not exist at the call
|
||||
time */
|
||||
CU_ASSERT(0 ==
|
||||
|
@ -3489,84 +3486,6 @@ void test_nghttp2_session_flow_control(void)
|
|||
nghttp2_session_del(session);
|
||||
}
|
||||
|
||||
void test_nghttp2_session_flow_control_disable_remote(void)
|
||||
{
|
||||
nghttp2_session *session;
|
||||
nghttp2_session_callbacks callbacks;
|
||||
my_user_data ud;
|
||||
nghttp2_data_provider data_prd;
|
||||
nghttp2_frame frame;
|
||||
size_t data_size = 128*1024;
|
||||
nghttp2_settings_entry iv = { NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS, 0x1 };
|
||||
|
||||
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||
callbacks.send_callback = null_send_callback;
|
||||
callbacks.on_frame_send_callback = on_frame_send_callback;
|
||||
data_prd.read_callback = fixed_length_data_source_read_callback;
|
||||
|
||||
ud.frame_send_cb_called = 0;
|
||||
ud.data_source_length = data_size;
|
||||
|
||||
/* Initial window size is 64KiB */
|
||||
nghttp2_session_client_new(&session, &callbacks, &ud);
|
||||
nghttp2_submit_request(session, NGHTTP2_PRI_DEFAULT, NULL, 0,
|
||||
&data_prd, NULL);
|
||||
|
||||
/* Sends 64KiB data */
|
||||
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||
CU_ASSERT(data_size - NGHTTP2_INITIAL_WINDOW_SIZE == ud.data_source_length);
|
||||
|
||||
/* Disable flow control entirely */
|
||||
nghttp2_frame_settings_init(&frame.settings, NGHTTP2_FLAG_NONE,
|
||||
dup_iv(&iv, 1), 1);
|
||||
nghttp2_session_on_settings_received(session, &frame, 1);
|
||||
|
||||
/* Check both connection and stream-level remote_flow_control is
|
||||
disabled */
|
||||
CU_ASSERT(0 == nghttp2_session_get_stream(session, 1)->remote_flow_control);
|
||||
CU_ASSERT(0 == session->remote_flow_control);
|
||||
|
||||
/* Sends remaining data */
|
||||
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||
CU_ASSERT(0 == ud.data_source_length);
|
||||
|
||||
nghttp2_frame_settings_free(&frame.settings);
|
||||
nghttp2_session_del(session);
|
||||
}
|
||||
|
||||
void test_nghttp2_session_flow_control_disable_local(void)
|
||||
{
|
||||
nghttp2_session *session;
|
||||
nghttp2_session_callbacks callbacks;
|
||||
nghttp2_stream *stream;
|
||||
nghttp2_settings_entry iv[1];
|
||||
nghttp2_frame ack_frame;
|
||||
|
||||
nghttp2_frame_settings_init(&ack_frame.settings, NGHTTP2_FLAG_ACK, NULL, 0);
|
||||
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||
callbacks.send_callback = null_send_callback;
|
||||
|
||||
nghttp2_session_client_new(&session, &callbacks, NULL);
|
||||
|
||||
stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
|
||||
NGHTTP2_PRI_DEFAULT,
|
||||
NGHTTP2_STREAM_OPENING, NULL);
|
||||
|
||||
iv[0].settings_id = NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS;
|
||||
iv[0].value = 1;
|
||||
|
||||
CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv,
|
||||
ARRLEN(iv)));
|
||||
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||
CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &ack_frame, 0));
|
||||
|
||||
CU_ASSERT(0 == stream->local_flow_control);
|
||||
CU_ASSERT(0 == session->local_flow_control);
|
||||
|
||||
nghttp2_session_del(session);
|
||||
nghttp2_frame_settings_free(&ack_frame.settings);
|
||||
}
|
||||
|
||||
void test_nghttp2_session_flow_control_data_recv(void)
|
||||
{
|
||||
nghttp2_session *session;
|
||||
|
@ -3630,6 +3549,46 @@ void test_nghttp2_session_flow_control_data_recv(void)
|
|||
nghttp2_session_del(session);
|
||||
}
|
||||
|
||||
void test_nghttp2_session_flow_control_data_with_padding_recv(void)
|
||||
{
|
||||
nghttp2_session *session;
|
||||
nghttp2_session_callbacks callbacks;
|
||||
uint8_t data[1024];
|
||||
nghttp2_frame_hd hd;
|
||||
nghttp2_stream *stream;
|
||||
|
||||
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||
callbacks.send_callback = null_send_callback;
|
||||
|
||||
/* Initial window size to 64KiB - 1*/
|
||||
nghttp2_session_client_new(&session, &callbacks, NULL);
|
||||
|
||||
stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
|
||||
NGHTTP2_PRI_DEFAULT,
|
||||
NGHTTP2_STREAM_OPENED, NULL);
|
||||
|
||||
/* Create DATA frame */
|
||||
memset(data, 0, sizeof(data));
|
||||
hd.length = 357;
|
||||
hd.type = NGHTTP2_DATA;
|
||||
hd.flags = NGHTTP2_FLAG_END_STREAM |
|
||||
NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW;;
|
||||
hd.stream_id = 1;
|
||||
nghttp2_frame_pack_frame_hd(data, &hd);
|
||||
/* Add 2 byte padding (PAD_LOW itself is padding) */
|
||||
data[NGHTTP2_FRAME_HEAD_LENGTH] = 1;
|
||||
data[NGHTTP2_FRAME_HEAD_LENGTH + 1] = 1;
|
||||
|
||||
CU_ASSERT((ssize_t)(NGHTTP2_FRAME_HEAD_LENGTH + hd.length) ==
|
||||
nghttp2_session_mem_recv(session, data,
|
||||
NGHTTP2_FRAME_HEAD_LENGTH + hd.length));
|
||||
|
||||
CU_ASSERT((int32_t)hd.length == session->recv_window_size);
|
||||
CU_ASSERT((int32_t)hd.length == stream->recv_window_size);
|
||||
|
||||
nghttp2_session_del(session);
|
||||
}
|
||||
|
||||
void test_nghttp2_session_data_read_temporal_failure(void)
|
||||
{
|
||||
nghttp2_session *session;
|
||||
|
@ -3984,6 +3943,162 @@ void test_nghttp2_session_data_backoff_by_high_pri_frame(void)
|
|||
nghttp2_session_del(session);
|
||||
}
|
||||
|
||||
static void check_session_recv_data_with_padding(const uint8_t *in,
|
||||
size_t inlen,
|
||||
size_t datalen)
|
||||
{
|
||||
nghttp2_session *session;
|
||||
my_user_data ud;
|
||||
nghttp2_session_callbacks callbacks;
|
||||
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.on_frame_recv_callback = on_frame_recv_callback;
|
||||
callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback;
|
||||
nghttp2_session_server_new(&session, &callbacks, &ud);
|
||||
|
||||
nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
|
||||
NGHTTP2_PRI_DEFAULT, NGHTTP2_STREAM_OPENING,
|
||||
NULL);
|
||||
|
||||
ud.frame_recv_cb_called = 0;
|
||||
ud.data_chunk_len = 0;
|
||||
CU_ASSERT((ssize_t)inlen == nghttp2_session_mem_recv(session, in, inlen));
|
||||
|
||||
CU_ASSERT(1 == ud.frame_recv_cb_called);
|
||||
CU_ASSERT(datalen == ud.data_chunk_len);
|
||||
|
||||
nghttp2_session_del(session);
|
||||
}
|
||||
|
||||
void test_nghttp2_session_pack_data_with_padding(void)
|
||||
{
|
||||
nghttp2_session *session;
|
||||
my_user_data ud;
|
||||
nghttp2_session_callbacks callbacks;
|
||||
nghttp2_data_provider data_prd;
|
||||
nghttp2_private_data *frame;
|
||||
size_t datalen = 55;
|
||||
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.send_callback = block_count_send_callback;
|
||||
callbacks.on_frame_send_callback = on_frame_send_callback;
|
||||
callbacks.select_padding_callback = select_padding_callback;
|
||||
|
||||
data_prd.read_callback = fixed_length_data_source_read_callback;
|
||||
|
||||
nghttp2_session_client_new(&session, &callbacks, &ud);
|
||||
|
||||
ud.padding_boundary = 512;
|
||||
|
||||
nghttp2_submit_request(session, NGHTTP2_PRI_DEFAULT, NULL, 0, &data_prd,
|
||||
NULL);
|
||||
ud.block_count = 1;
|
||||
ud.data_source_length = datalen;
|
||||
/* Sends HEADERS */
|
||||
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||
CU_ASSERT(NGHTTP2_HEADERS == ud.sent_frame_type);
|
||||
|
||||
frame = OB_DATA(session->aob.item);
|
||||
|
||||
CU_ASSERT(ud.padding_boundary - datalen == frame->padlen);
|
||||
CU_ASSERT(frame->hd.flags & NGHTTP2_FLAG_PAD_LOW);
|
||||
CU_ASSERT(frame->hd.flags & NGHTTP2_FLAG_PAD_HIGH);
|
||||
|
||||
/* Check reception of this DATA frame */
|
||||
check_session_recv_data_with_padding
|
||||
(session->aob.framebuf + session->aob.framebufoff,
|
||||
session->aob.framebufmark - session->aob.framebufoff,
|
||||
datalen);
|
||||
|
||||
nghttp2_session_del(session);
|
||||
|
||||
/* Check without PAD_HIGH */
|
||||
nghttp2_session_client_new(&session, &callbacks, &ud);
|
||||
|
||||
ud.padding_boundary = 64;
|
||||
|
||||
nghttp2_submit_request(session, NGHTTP2_PRI_DEFAULT, NULL, 0, &data_prd,
|
||||
NULL);
|
||||
ud.block_count = 1;
|
||||
ud.data_source_length = datalen;
|
||||
/* Sends HEADERS */
|
||||
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||
CU_ASSERT(NGHTTP2_HEADERS == ud.sent_frame_type);
|
||||
|
||||
frame = OB_DATA(session->aob.item);
|
||||
CU_ASSERT((frame->padlen + datalen) % ud.padding_boundary == 0);
|
||||
CU_ASSERT(frame->hd.flags & NGHTTP2_FLAG_PAD_LOW);
|
||||
CU_ASSERT(0 == (frame->hd.flags & NGHTTP2_FLAG_PAD_HIGH));
|
||||
|
||||
/* Check reception of this DATA frame */
|
||||
check_session_recv_data_with_padding
|
||||
(session->aob.framebuf + session->aob.framebufoff,
|
||||
session->aob.framebufmark - session->aob.framebufoff,
|
||||
datalen);
|
||||
|
||||
nghttp2_session_del(session);
|
||||
}
|
||||
|
||||
void test_nghttp2_session_pack_headers_with_padding(void)
|
||||
{
|
||||
nghttp2_session *session, *sv_session;
|
||||
accumulator acc;
|
||||
my_user_data ud;
|
||||
nghttp2_session_callbacks callbacks;
|
||||
nghttp2_nv nva[8190];
|
||||
size_t i;
|
||||
|
||||
for(i = 0; i < ARRLEN(nva); ++i) {
|
||||
nva[i].name = (uint8_t*)":path";
|
||||
nva[i].namelen = 5;
|
||||
nva[i].value = (uint8_t*)"/";
|
||||
nva[i].valuelen = 1;
|
||||
}
|
||||
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.send_callback = accumulator_send_callback;
|
||||
callbacks.on_frame_send_callback = on_frame_send_callback;
|
||||
callbacks.select_padding_callback = select_padding_callback;
|
||||
callbacks.on_frame_recv_callback = on_frame_recv_callback;
|
||||
|
||||
acc.length = 0;
|
||||
ud.acc = &acc;
|
||||
|
||||
nghttp2_session_client_new(&session, &callbacks, &ud);
|
||||
nghttp2_session_server_new(&sv_session, &callbacks, &ud);
|
||||
|
||||
ud.padding_boundary = 16385;
|
||||
|
||||
CU_ASSERT(0 ==
|
||||
nghttp2_submit_request(session, NGHTTP2_PRI_DEFAULT,
|
||||
nva, ARRLEN(nva), NULL, NULL));
|
||||
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||
|
||||
CU_ASSERT(acc.length > NGHTTP2_MAX_FRAME_LENGTH);
|
||||
ud.frame_recv_cb_called = 0;
|
||||
CU_ASSERT((ssize_t)acc.length ==
|
||||
nghttp2_session_mem_recv(sv_session, acc.buf, acc.length));
|
||||
CU_ASSERT(1 == ud.frame_recv_cb_called);
|
||||
CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(sv_session));
|
||||
|
||||
/* Check PUSH_PROMISE */
|
||||
CU_ASSERT(0 ==
|
||||
nghttp2_submit_push_promise(sv_session, NGHTTP2_FLAG_NONE, 1,
|
||||
nva, ARRLEN(nva)));
|
||||
acc.length = 0;
|
||||
CU_ASSERT(0 == nghttp2_session_send(sv_session));
|
||||
|
||||
CU_ASSERT(acc.length > NGHTTP2_MAX_FRAME_LENGTH);
|
||||
ud.frame_recv_cb_called = 0;
|
||||
CU_ASSERT((ssize_t)acc.length ==
|
||||
nghttp2_session_mem_recv(session, acc.buf, acc.length));
|
||||
CU_ASSERT(1 == ud.frame_recv_cb_called);
|
||||
CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(session));
|
||||
|
||||
nghttp2_session_del(sv_session);
|
||||
nghttp2_session_del(session);
|
||||
}
|
||||
|
||||
void test_nghttp2_pack_settings_payload(void)
|
||||
{
|
||||
nghttp2_settings_entry iv[2];
|
||||
|
@ -3992,23 +4107,23 @@ void test_nghttp2_pack_settings_payload(void)
|
|||
nghttp2_settings_entry *resiv;
|
||||
size_t resniv;
|
||||
|
||||
iv[0].settings_id = NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS;
|
||||
iv[0].value = 1;
|
||||
iv[0].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
|
||||
iv[0].value = 1023;
|
||||
iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
|
||||
iv[1].value = 4095;
|
||||
|
||||
len = nghttp2_pack_settings_payload(buf, sizeof(buf), iv, 2);
|
||||
CU_ASSERT(16 == len);
|
||||
CU_ASSERT(2 * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH == len);
|
||||
CU_ASSERT(0 == nghttp2_frame_unpack_settings_payload2(&resiv, &resniv,
|
||||
buf, len));
|
||||
CU_ASSERT(2 == resniv);
|
||||
CU_ASSERT(NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS == resiv[0].settings_id);
|
||||
CU_ASSERT(1 == resiv[0].value);
|
||||
CU_ASSERT(NGHTTP2_SETTINGS_HEADER_TABLE_SIZE == resiv[0].settings_id);
|
||||
CU_ASSERT(1023 == resiv[0].value);
|
||||
CU_ASSERT(NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE == resiv[1].settings_id);
|
||||
CU_ASSERT(4095 == resiv[1].value);
|
||||
|
||||
free(resiv);
|
||||
|
||||
len = nghttp2_pack_settings_payload(buf, 15 /* too small */, iv, 2);
|
||||
len = nghttp2_pack_settings_payload(buf, 9 /* too small */, iv, 2);
|
||||
CU_ASSERT(NGHTTP2_ERR_INSUFF_BUFSIZE == len);
|
||||
}
|
||||
|
|
|
@ -80,9 +80,8 @@ void test_nghttp2_session_stream_close_on_headers_push(void);
|
|||
void test_nghttp2_session_stop_data_with_rst_stream(void);
|
||||
void test_nghttp2_session_defer_data(void);
|
||||
void test_nghttp2_session_flow_control(void);
|
||||
void test_nghttp2_session_flow_control_disable_remote(void);
|
||||
void test_nghttp2_session_flow_control_disable_local(void);
|
||||
void test_nghttp2_session_flow_control_data_recv(void);
|
||||
void test_nghttp2_session_flow_control_data_with_padding_recv(void);
|
||||
void test_nghttp2_session_data_read_temporal_failure(void);
|
||||
void test_nghttp2_session_on_stream_close(void);
|
||||
void test_nghttp2_session_on_ctrl_not_send(void);
|
||||
|
@ -90,6 +89,8 @@ void test_nghttp2_session_get_outbound_queue_size(void);
|
|||
void test_nghttp2_session_get_effective_local_window_size(void);
|
||||
void test_nghttp2_session_set_option(void);
|
||||
void test_nghttp2_session_data_backoff_by_high_pri_frame(void);
|
||||
void test_nghttp2_session_pack_data_with_padding(void);
|
||||
void test_nghttp2_session_pack_headers_with_padding(void);
|
||||
void test_nghttp2_pack_settings_payload(void);
|
||||
|
||||
#endif /* NGHTTP2_SESSION_TEST_H */
|
||||
|
|
|
@ -33,11 +33,15 @@ int unpack_frame(nghttp2_frame *frame, const uint8_t *in, size_t len)
|
|||
ssize_t rv = 0;
|
||||
const uint8_t *payload = in + NGHTTP2_FRAME_HEAD_LENGTH;
|
||||
size_t payloadlen = len - NGHTTP2_FRAME_HEAD_LENGTH;
|
||||
size_t payloadoff;
|
||||
|
||||
nghttp2_frame_unpack_frame_hd(&frame->hd, in);
|
||||
switch(frame->hd.type) {
|
||||
case NGHTTP2_HEADERS:
|
||||
payloadoff = ((frame->hd.flags & NGHTTP2_FLAG_PAD_HIGH) > 0) +
|
||||
((frame->hd.flags & NGHTTP2_FLAG_PAD_LOW) > 0);
|
||||
rv = nghttp2_frame_unpack_headers_payload
|
||||
(&frame->headers, payload, payloadlen);
|
||||
(&frame->headers, payload + payloadoff, payloadlen - payloadoff);
|
||||
break;
|
||||
case NGHTTP2_PRIORITY:
|
||||
nghttp2_frame_unpack_priority_payload
|
||||
|
|
|
@ -36,6 +36,24 @@
|
|||
{ (uint8_t*)NAME, (uint8_t*)VALUE, strlen(NAME), strlen(VALUE) }
|
||||
#define ARRLEN(ARR) (sizeof(ARR)/sizeof(ARR[0]))
|
||||
|
||||
#define assert_nv_equal(A, B, len) \
|
||||
do { \
|
||||
size_t alloclen = sizeof(nghttp2_nv) * len; \
|
||||
nghttp2_nv *sa = A, *sb = B; \
|
||||
nghttp2_nv *a = malloc(alloclen); \
|
||||
nghttp2_nv *b = malloc(alloclen); \
|
||||
ssize_t i_; \
|
||||
memcpy(a, sa, alloclen); \
|
||||
memcpy(b, sb, alloclen); \
|
||||
nghttp2_nv_array_sort(a, len); \
|
||||
nghttp2_nv_array_sort(b, len); \
|
||||
for(i_ = 0; i_ < (ssize_t)len; ++i_) { \
|
||||
CU_ASSERT(nghttp2_nv_equal(&a[i_], &b[i_])); \
|
||||
} \
|
||||
free(b); \
|
||||
free(a); \
|
||||
} while(0);
|
||||
|
||||
int unpack_frame(nghttp2_frame *frame, const uint8_t *in, size_t len);
|
||||
|
||||
int strmemeq(const char *a, const uint8_t *b, size_t bn);
|
||||
|
|
Loading…
Reference in New Issue