Merge pull request #1728 from nghttp2/rfc9218-ext-priority
Implement RFC 9218 extensible prioritization scheme
This commit is contained in:
commit
c44caa0580
|
@ -68,6 +68,7 @@ HEADERS = [
|
||||||
('proxy-connection', None),
|
('proxy-connection', None),
|
||||||
('upgrade', None),
|
('upgrade', None),
|
||||||
(':protocol', None),
|
(':protocol', None),
|
||||||
|
('priority', None),
|
||||||
]
|
]
|
||||||
|
|
||||||
def to_enum_hd(k):
|
def to_enum_hd(k):
|
||||||
|
|
|
@ -23,6 +23,7 @@ set(NGHTTP2_SOURCES
|
||||||
nghttp2_mem.c
|
nghttp2_mem.c
|
||||||
nghttp2_http.c
|
nghttp2_http.c
|
||||||
nghttp2_rcbuf.c
|
nghttp2_rcbuf.c
|
||||||
|
nghttp2_extpri.c
|
||||||
nghttp2_debug.c
|
nghttp2_debug.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,7 @@ OBJECTS = nghttp2_pq.c nghttp2_map.c nghttp2_queue.c \
|
||||||
nghttp2_mem.c \
|
nghttp2_mem.c \
|
||||||
nghttp2_http.c \
|
nghttp2_http.c \
|
||||||
nghttp2_rcbuf.c \
|
nghttp2_rcbuf.c \
|
||||||
|
nghttp2_extpri.c \
|
||||||
nghttp2_debug.c
|
nghttp2_debug.c
|
||||||
|
|
||||||
HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
|
HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
|
||||||
|
@ -66,6 +67,7 @@ HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
|
||||||
nghttp2_mem.h \
|
nghttp2_mem.h \
|
||||||
nghttp2_http.h \
|
nghttp2_http.h \
|
||||||
nghttp2_rcbuf.h \
|
nghttp2_rcbuf.h \
|
||||||
|
nghttp2_extpri.h \
|
||||||
nghttp2_debug.h
|
nghttp2_debug.h
|
||||||
|
|
||||||
libnghttp2_la_SOURCES = $(HFILES) $(OBJECTS)
|
libnghttp2_la_SOURCES = $(HFILES) $(OBJECTS)
|
||||||
|
|
|
@ -705,8 +705,7 @@ typedef enum {
|
||||||
*/
|
*/
|
||||||
NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL = 0x08,
|
NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL = 0x08,
|
||||||
/**
|
/**
|
||||||
* SETTINGS_NO_RFC7540_PRIORITIES (`RFC 9218
|
* SETTINGS_NO_RFC7540_PRIORITIES (:rfc:`9218`)
|
||||||
* <https://datatracker.ietf.org/doc/html/rfc9218>`_)
|
|
||||||
*/
|
*/
|
||||||
NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES = 0x09
|
NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES = 0x09
|
||||||
} nghttp2_settings_id;
|
} nghttp2_settings_id;
|
||||||
|
@ -4233,6 +4232,61 @@ nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
|
||||||
int32_t stream_id,
|
int32_t stream_id,
|
||||||
const nghttp2_priority_spec *pri_spec);
|
const nghttp2_priority_spec *pri_spec);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @macro
|
||||||
|
*
|
||||||
|
* :macro:`NGHTTP2_EXTPRI_DEFAULT_URGENCY` is the default urgency
|
||||||
|
* level for :rfc:`9218` extensible priorities.
|
||||||
|
*/
|
||||||
|
#define NGHTTP2_EXTPRI_DEFAULT_URGENCY 3
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @macro
|
||||||
|
*
|
||||||
|
* :macro:`NGHTTP2_EXTPRI_URGENCY_HIGH` is the highest urgency level
|
||||||
|
* for :rfc:`9218` extensible priorities.
|
||||||
|
*/
|
||||||
|
#define NGHTTP2_EXTPRI_URGENCY_HIGH 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @macro
|
||||||
|
*
|
||||||
|
* :macro:`NGHTTP2_EXTPRI_URGENCY_LOW` is the lowest urgency level for
|
||||||
|
* :rfc:`9218` extensible priorities.
|
||||||
|
*/
|
||||||
|
#define NGHTTP2_EXTPRI_URGENCY_LOW 7
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @macro
|
||||||
|
*
|
||||||
|
* :macro:`NGHTTP2_EXTPRI_URGENCY_LEVELS` is the number of urgency
|
||||||
|
* levels for :rfc:`9218` extensible priorities.
|
||||||
|
*/
|
||||||
|
#define NGHTTP2_EXTPRI_URGENCY_LEVELS (NGHTTP2_EXTPRI_URGENCY_LOW + 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct
|
||||||
|
*
|
||||||
|
* :type:`nghttp2_extpri` is :rfc:`9218` extensible priorities
|
||||||
|
* specification for a stream.
|
||||||
|
*/
|
||||||
|
typedef struct nghttp2_extpri {
|
||||||
|
/**
|
||||||
|
* :member:`urgency` is the urgency of a stream, it must be in
|
||||||
|
* [:macro:`NGHTTP2_EXTPRI_URGENCY_HIGH`,
|
||||||
|
* :macro:`NGHTTP2_EXTPRI_URGENCY_LOW`], inclusive, and 0 is the
|
||||||
|
* highest urgency.
|
||||||
|
*/
|
||||||
|
uint32_t urgency;
|
||||||
|
/**
|
||||||
|
* :member:`inc` indicates that a content can be processed
|
||||||
|
* incrementally or not. If inc is 0, it cannot be processed
|
||||||
|
* incrementally. If inc is 1, it can be processed incrementally.
|
||||||
|
* Other value is not permitted.
|
||||||
|
*/
|
||||||
|
int inc;
|
||||||
|
} nghttp2_extpri;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @function
|
* @function
|
||||||
*
|
*
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* nghttp2 - HTTP/2 C Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 nghttp3 contributors
|
||||||
|
* Copyright (c) 2022 nghttp2 contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "nghttp2_extpri.h"
|
||||||
|
|
||||||
|
uint8_t nghttp2_extpri_to_uint8(const nghttp2_extpri *extpri) {
|
||||||
|
return (uint8_t)((uint32_t)extpri->inc << 7 | extpri->urgency);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nghttp2_extpri_from_uint8(nghttp2_extpri *extpri, uint8_t u8extpri) {
|
||||||
|
extpri->urgency = nghttp2_extpri_uint8_urgency(u8extpri);
|
||||||
|
extpri->inc = nghttp2_extpri_uint8_inc(u8extpri);
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* nghttp2 - HTTP/2 C Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 nghttp3 contributors
|
||||||
|
* Copyright (c) 2022 nghttp2 contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef NGHTTP2_EXTPRI_H
|
||||||
|
#define NGHTTP2_EXTPRI_H
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif /* HAVE_CONFIG_H */
|
||||||
|
|
||||||
|
#include <nghttp2/nghttp2.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NGHTTP2_EXTPRI_INC_MASK is a bit mask to retrieve incremental bit
|
||||||
|
* from a value produced by nghttp2_extpri_to_uint8.
|
||||||
|
*/
|
||||||
|
#define NGHTTP2_EXTPRI_INC_MASK (1 << 7)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* nghttp2_extpri_to_uint8 encodes |pri| into uint8_t variable.
|
||||||
|
*/
|
||||||
|
uint8_t nghttp2_extpri_to_uint8(const nghttp2_extpri *extpri);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* nghttp2_extpri_from_uint8 decodes |u8extpri|, which is produced by
|
||||||
|
* nghttp2_extpri_to_uint8, intto |extpri|.
|
||||||
|
*/
|
||||||
|
void nghttp2_extpri_from_uint8(nghttp2_extpri *extpri, uint8_t u8extpri);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* nghttp2_extpri_uint8_urgency extracts urgency from |PRI| which is
|
||||||
|
* supposed to be constructed by nghttp2_extpri_to_uint8.
|
||||||
|
*/
|
||||||
|
#define nghttp2_extpri_uint8_urgency(PRI) \
|
||||||
|
((uint32_t)((PRI) & ~NGHTTP2_EXTPRI_INC_MASK))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* nghttp2_extpri_uint8_inc extracts inc from |PRI| which is supposed to
|
||||||
|
* be constructed by nghttp2_extpri_to_uint8.
|
||||||
|
*/
|
||||||
|
#define nghttp2_extpri_uint8_inc(PRI) (((PRI)&NGHTTP2_EXTPRI_INC_MASK) != 0)
|
||||||
|
|
||||||
|
#endif /* NGHTTP2_EXTPRI_H */
|
|
@ -269,6 +269,11 @@ static int32_t lookup_token(const uint8_t *name, size_t namelen) {
|
||||||
return NGHTTP2_TOKEN_LOCATION;
|
return NGHTTP2_TOKEN_LOCATION;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'y':
|
||||||
|
if (memeq("priorit", name, 7)) {
|
||||||
|
return NGHTTP2_TOKEN_PRIORITY;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 9:
|
case 9:
|
||||||
|
|
|
@ -112,6 +112,7 @@ typedef enum {
|
||||||
NGHTTP2_TOKEN_PROXY_CONNECTION,
|
NGHTTP2_TOKEN_PROXY_CONNECTION,
|
||||||
NGHTTP2_TOKEN_UPGRADE,
|
NGHTTP2_TOKEN_UPGRADE,
|
||||||
NGHTTP2_TOKEN__PROTOCOL,
|
NGHTTP2_TOKEN__PROTOCOL,
|
||||||
|
NGHTTP2_TOKEN_PRIORITY,
|
||||||
} nghttp2_token;
|
} nghttp2_token;
|
||||||
|
|
||||||
struct nghttp2_hd_entry;
|
struct nghttp2_hd_entry;
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
#include "nghttp2_hd.h"
|
#include "nghttp2_hd.h"
|
||||||
#include "nghttp2_helper.h"
|
#include "nghttp2_helper.h"
|
||||||
|
#include "nghttp2_extpri.h"
|
||||||
|
|
||||||
static uint8_t downcase(uint8_t c) {
|
static uint8_t downcase(uint8_t c) {
|
||||||
return 'A' <= c && c <= 'Z' ? (uint8_t)(c - 'A' + 'a') : c;
|
return 'A' <= c && c <= 'Z' ? (uint8_t)(c - 'A' + 'a') : c;
|
||||||
|
@ -114,6 +115,8 @@ static int check_path(nghttp2_stream *stream) {
|
||||||
|
|
||||||
static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
|
static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
|
||||||
int trailer, int connect_protocol) {
|
int trailer, int connect_protocol) {
|
||||||
|
nghttp2_extpri extpri;
|
||||||
|
|
||||||
if (nv->name->base[0] == ':') {
|
if (nv->name->base[0] == ':') {
|
||||||
if (trailer ||
|
if (trailer ||
|
||||||
(stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
|
(stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
|
||||||
|
@ -212,6 +215,16 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
|
||||||
return NGHTTP2_ERR_HTTP_HEADER;
|
return NGHTTP2_ERR_HTTP_HEADER;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case NGHTTP2_TOKEN_PRIORITY:
|
||||||
|
if (!trailer &&
|
||||||
|
(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)) {
|
||||||
|
nghttp2_extpri_from_uint8(&extpri, stream->http_extpri);
|
||||||
|
if (nghttp2_http_parse_priority(&extpri, nv->value->base,
|
||||||
|
nv->value->len) == 0) {
|
||||||
|
stream->http_extpri = nghttp2_extpri_to_uint8(&extpri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
if (nv->name->base[0] == ':') {
|
if (nv->name->base[0] == ':') {
|
||||||
return NGHTTP2_ERR_HTTP_HEADER;
|
return NGHTTP2_ERR_HTTP_HEADER;
|
||||||
|
@ -541,3 +554,715 @@ void nghttp2_http_record_request_method(nghttp2_stream *stream,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Generated by genchartbl.py */
|
||||||
|
static const int SF_KEY_CHARS[] = {
|
||||||
|
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */,
|
||||||
|
0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */,
|
||||||
|
0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */,
|
||||||
|
0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
|
||||||
|
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */,
|
||||||
|
0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */,
|
||||||
|
0 /* RS */, 0 /* US */, 0 /* SPC */, 0 /* ! */, 0 /* " */,
|
||||||
|
0 /* # */, 0 /* $ */, 0 /* % */, 0 /* & */, 0 /* ' */,
|
||||||
|
0 /* ( */, 0 /* ) */, 1 /* * */, 0 /* + */, 0 /* , */,
|
||||||
|
1 /* - */, 1 /* . */, 0 /* / */, 1 /* 0 */, 1 /* 1 */,
|
||||||
|
1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */,
|
||||||
|
1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */,
|
||||||
|
0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */, 0 /* @ */,
|
||||||
|
0 /* A */, 0 /* B */, 0 /* C */, 0 /* D */, 0 /* E */,
|
||||||
|
0 /* F */, 0 /* G */, 0 /* H */, 0 /* I */, 0 /* J */,
|
||||||
|
0 /* K */, 0 /* L */, 0 /* M */, 0 /* N */, 0 /* O */,
|
||||||
|
0 /* P */, 0 /* Q */, 0 /* R */, 0 /* S */, 0 /* T */,
|
||||||
|
0 /* U */, 0 /* V */, 0 /* W */, 0 /* X */, 0 /* Y */,
|
||||||
|
0 /* Z */, 0 /* [ */, 0 /* \ */, 0 /* ] */, 0 /* ^ */,
|
||||||
|
1 /* _ */, 0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
|
||||||
|
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */,
|
||||||
|
1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */,
|
||||||
|
1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */,
|
||||||
|
1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
|
||||||
|
1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 0 /* | */,
|
||||||
|
0 /* } */, 0 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */,
|
||||||
|
0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
|
||||||
|
0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
|
||||||
|
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
|
||||||
|
0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
|
||||||
|
0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
|
||||||
|
0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
|
||||||
|
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
|
||||||
|
0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
|
||||||
|
0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
|
||||||
|
0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
|
||||||
|
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
|
||||||
|
0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
|
||||||
|
0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
|
||||||
|
0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
|
||||||
|
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
|
||||||
|
0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
|
||||||
|
0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
|
||||||
|
0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
|
||||||
|
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
|
||||||
|
0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
|
||||||
|
0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
|
||||||
|
0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
|
||||||
|
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
|
||||||
|
0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
|
||||||
|
0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
|
||||||
|
0 /* 0xff */,
|
||||||
|
};
|
||||||
|
|
||||||
|
static ssize_t sf_parse_key(const uint8_t *begin, const uint8_t *end) {
|
||||||
|
const uint8_t *p = begin;
|
||||||
|
|
||||||
|
if ((*p < 'a' || 'z' < *p) && *p != '*') {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; p != end && SF_KEY_CHARS[*p]; ++p)
|
||||||
|
;
|
||||||
|
|
||||||
|
return p - begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t sf_parse_integer_or_decimal(nghttp2_sf_value *dest,
|
||||||
|
const uint8_t *begin,
|
||||||
|
const uint8_t *end) {
|
||||||
|
const uint8_t *p = begin;
|
||||||
|
int sign = 1;
|
||||||
|
int64_t value = 0;
|
||||||
|
int type = NGHTTP2_SF_VALUE_TYPE_INTEGER;
|
||||||
|
size_t len = 0;
|
||||||
|
size_t fpos = 0;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (*p == '-') {
|
||||||
|
if (++p == end) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sign = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*p < '0' || '9' < *p) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; p != end; ++p) {
|
||||||
|
switch (*p) {
|
||||||
|
case '0':
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
case '3':
|
||||||
|
case '4':
|
||||||
|
case '5':
|
||||||
|
case '6':
|
||||||
|
case '7':
|
||||||
|
case '8':
|
||||||
|
case '9':
|
||||||
|
value *= 10;
|
||||||
|
value += *p - '0';
|
||||||
|
|
||||||
|
if (++len > 15) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case '.':
|
||||||
|
if (type != NGHTTP2_SF_VALUE_TYPE_INTEGER) {
|
||||||
|
goto fin;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len > 12) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
fpos = len;
|
||||||
|
type = NGHTTP2_SF_VALUE_TYPE_DECIMAL;
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto fin;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fin:
|
||||||
|
switch (type) {
|
||||||
|
case NGHTTP2_SF_VALUE_TYPE_INTEGER:
|
||||||
|
if (dest) {
|
||||||
|
dest->type = (uint8_t)type;
|
||||||
|
dest->i = value * sign;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p - begin;
|
||||||
|
case NGHTTP2_SF_VALUE_TYPE_DECIMAL:
|
||||||
|
if (fpos == len || len - fpos > 3) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dest) {
|
||||||
|
dest->type = (uint8_t)type;
|
||||||
|
dest->d = (double)value;
|
||||||
|
for (i = len - fpos; i > 0; --i) {
|
||||||
|
dest->d /= (double)10;
|
||||||
|
}
|
||||||
|
dest->d *= sign;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p - begin;
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generated by genchartbl.py */
|
||||||
|
static const int SF_DQUOTE_CHARS[] = {
|
||||||
|
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */,
|
||||||
|
0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */,
|
||||||
|
0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */,
|
||||||
|
0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
|
||||||
|
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */,
|
||||||
|
0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */,
|
||||||
|
0 /* RS */, 0 /* US */, 1 /* SPC */, 1 /* ! */, 0 /* " */,
|
||||||
|
1 /* # */, 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
|
||||||
|
1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */, 1 /* , */,
|
||||||
|
1 /* - */, 1 /* . */, 1 /* / */, 1 /* 0 */, 1 /* 1 */,
|
||||||
|
1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */,
|
||||||
|
1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
|
||||||
|
1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */, 1 /* @ */,
|
||||||
|
1 /* A */, 1 /* B */, 1 /* C */, 1 /* D */, 1 /* E */,
|
||||||
|
1 /* F */, 1 /* G */, 1 /* H */, 1 /* I */, 1 /* J */,
|
||||||
|
1 /* K */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
|
||||||
|
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* T */,
|
||||||
|
1 /* U */, 1 /* V */, 1 /* W */, 1 /* X */, 1 /* Y */,
|
||||||
|
1 /* Z */, 1 /* [ */, 0 /* \ */, 1 /* ] */, 1 /* ^ */,
|
||||||
|
1 /* _ */, 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
|
||||||
|
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */,
|
||||||
|
1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */,
|
||||||
|
1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */,
|
||||||
|
1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
|
||||||
|
1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */, 1 /* | */,
|
||||||
|
1 /* } */, 1 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */,
|
||||||
|
0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
|
||||||
|
0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
|
||||||
|
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
|
||||||
|
0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
|
||||||
|
0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
|
||||||
|
0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
|
||||||
|
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
|
||||||
|
0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
|
||||||
|
0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
|
||||||
|
0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
|
||||||
|
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
|
||||||
|
0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
|
||||||
|
0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
|
||||||
|
0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
|
||||||
|
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
|
||||||
|
0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
|
||||||
|
0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
|
||||||
|
0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
|
||||||
|
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
|
||||||
|
0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
|
||||||
|
0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
|
||||||
|
0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
|
||||||
|
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
|
||||||
|
0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
|
||||||
|
0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
|
||||||
|
0 /* 0xff */,
|
||||||
|
};
|
||||||
|
|
||||||
|
static ssize_t sf_parse_string(nghttp2_sf_value *dest, const uint8_t *begin,
|
||||||
|
const uint8_t *end) {
|
||||||
|
const uint8_t *p = begin;
|
||||||
|
|
||||||
|
if (*p++ != '"') {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; p != end; ++p) {
|
||||||
|
switch (*p) {
|
||||||
|
case '\\':
|
||||||
|
if (++p == end) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (*p) {
|
||||||
|
case '"':
|
||||||
|
case '\\':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
if (dest) {
|
||||||
|
dest->type = NGHTTP2_SF_VALUE_TYPE_STRING;
|
||||||
|
dest->s.base = begin + 1;
|
||||||
|
dest->s.len = (size_t)(p - dest->s.base);
|
||||||
|
}
|
||||||
|
|
||||||
|
++p;
|
||||||
|
|
||||||
|
return p - begin;
|
||||||
|
default:
|
||||||
|
if (!SF_DQUOTE_CHARS[*p]) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generated by genchartbl.py */
|
||||||
|
static const int SF_TOKEN_CHARS[] = {
|
||||||
|
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */,
|
||||||
|
0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */,
|
||||||
|
0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */,
|
||||||
|
0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
|
||||||
|
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */,
|
||||||
|
0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */,
|
||||||
|
0 /* RS */, 0 /* US */, 0 /* SPC */, 1 /* ! */, 0 /* " */,
|
||||||
|
1 /* # */, 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
|
||||||
|
0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */, 0 /* , */,
|
||||||
|
1 /* - */, 1 /* . */, 1 /* / */, 1 /* 0 */, 1 /* 1 */,
|
||||||
|
1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */,
|
||||||
|
1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 1 /* : */, 0 /* ; */,
|
||||||
|
0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */, 0 /* @ */,
|
||||||
|
1 /* A */, 1 /* B */, 1 /* C */, 1 /* D */, 1 /* E */,
|
||||||
|
1 /* F */, 1 /* G */, 1 /* H */, 1 /* I */, 1 /* J */,
|
||||||
|
1 /* K */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
|
||||||
|
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* T */,
|
||||||
|
1 /* U */, 1 /* V */, 1 /* W */, 1 /* X */, 1 /* Y */,
|
||||||
|
1 /* Z */, 0 /* [ */, 0 /* \ */, 0 /* ] */, 1 /* ^ */,
|
||||||
|
1 /* _ */, 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
|
||||||
|
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */,
|
||||||
|
1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */,
|
||||||
|
1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */,
|
||||||
|
1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
|
||||||
|
1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 1 /* | */,
|
||||||
|
0 /* } */, 1 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */,
|
||||||
|
0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
|
||||||
|
0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
|
||||||
|
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
|
||||||
|
0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
|
||||||
|
0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
|
||||||
|
0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
|
||||||
|
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
|
||||||
|
0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
|
||||||
|
0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
|
||||||
|
0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
|
||||||
|
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
|
||||||
|
0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
|
||||||
|
0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
|
||||||
|
0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
|
||||||
|
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
|
||||||
|
0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
|
||||||
|
0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
|
||||||
|
0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
|
||||||
|
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
|
||||||
|
0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
|
||||||
|
0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
|
||||||
|
0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
|
||||||
|
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
|
||||||
|
0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
|
||||||
|
0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
|
||||||
|
0 /* 0xff */,
|
||||||
|
};
|
||||||
|
|
||||||
|
static ssize_t sf_parse_token(nghttp2_sf_value *dest, const uint8_t *begin,
|
||||||
|
const uint8_t *end) {
|
||||||
|
const uint8_t *p = begin;
|
||||||
|
|
||||||
|
if ((*p < 'A' || 'Z' < *p) && (*p < 'a' || 'z' < *p) && *p != '*') {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; p != end && SF_TOKEN_CHARS[*p]; ++p)
|
||||||
|
;
|
||||||
|
|
||||||
|
if (dest) {
|
||||||
|
dest->type = NGHTTP2_SF_VALUE_TYPE_TOKEN;
|
||||||
|
dest->s.base = begin;
|
||||||
|
dest->s.len = (size_t)(p - begin);
|
||||||
|
}
|
||||||
|
|
||||||
|
return p - begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generated by genchartbl.py */
|
||||||
|
static const int SF_BYTESEQ_CHARS[] = {
|
||||||
|
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */,
|
||||||
|
0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */,
|
||||||
|
0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */,
|
||||||
|
0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
|
||||||
|
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */,
|
||||||
|
0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */,
|
||||||
|
0 /* RS */, 0 /* US */, 0 /* SPC */, 0 /* ! */, 0 /* " */,
|
||||||
|
0 /* # */, 0 /* $ */, 0 /* % */, 0 /* & */, 0 /* ' */,
|
||||||
|
0 /* ( */, 0 /* ) */, 0 /* * */, 1 /* + */, 0 /* , */,
|
||||||
|
0 /* - */, 0 /* . */, 1 /* / */, 1 /* 0 */, 1 /* 1 */,
|
||||||
|
1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */,
|
||||||
|
1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */,
|
||||||
|
0 /* < */, 1 /* = */, 0 /* > */, 0 /* ? */, 0 /* @ */,
|
||||||
|
1 /* A */, 1 /* B */, 1 /* C */, 1 /* D */, 1 /* E */,
|
||||||
|
1 /* F */, 1 /* G */, 1 /* H */, 1 /* I */, 1 /* J */,
|
||||||
|
1 /* K */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
|
||||||
|
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* T */,
|
||||||
|
1 /* U */, 1 /* V */, 1 /* W */, 1 /* X */, 1 /* Y */,
|
||||||
|
1 /* Z */, 0 /* [ */, 0 /* \ */, 0 /* ] */, 0 /* ^ */,
|
||||||
|
0 /* _ */, 0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
|
||||||
|
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */,
|
||||||
|
1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */,
|
||||||
|
1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */,
|
||||||
|
1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
|
||||||
|
1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 0 /* | */,
|
||||||
|
0 /* } */, 0 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */,
|
||||||
|
0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
|
||||||
|
0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
|
||||||
|
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
|
||||||
|
0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
|
||||||
|
0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
|
||||||
|
0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
|
||||||
|
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
|
||||||
|
0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
|
||||||
|
0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
|
||||||
|
0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
|
||||||
|
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
|
||||||
|
0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
|
||||||
|
0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
|
||||||
|
0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
|
||||||
|
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
|
||||||
|
0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
|
||||||
|
0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
|
||||||
|
0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
|
||||||
|
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
|
||||||
|
0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
|
||||||
|
0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
|
||||||
|
0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
|
||||||
|
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
|
||||||
|
0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
|
||||||
|
0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
|
||||||
|
0 /* 0xff */,
|
||||||
|
};
|
||||||
|
|
||||||
|
static ssize_t sf_parse_byteseq(nghttp2_sf_value *dest, const uint8_t *begin,
|
||||||
|
const uint8_t *end) {
|
||||||
|
const uint8_t *p = begin;
|
||||||
|
|
||||||
|
if (*p++ != ':') {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; p != end; ++p) {
|
||||||
|
switch (*p) {
|
||||||
|
case ':':
|
||||||
|
if (dest) {
|
||||||
|
dest->type = NGHTTP2_SF_VALUE_TYPE_BYTESEQ;
|
||||||
|
dest->s.base = begin + 1;
|
||||||
|
dest->s.len = (size_t)(p - dest->s.base);
|
||||||
|
}
|
||||||
|
|
||||||
|
++p;
|
||||||
|
|
||||||
|
return p - begin;
|
||||||
|
default:
|
||||||
|
if (!SF_BYTESEQ_CHARS[*p]) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t sf_parse_boolean(nghttp2_sf_value *dest, const uint8_t *begin,
|
||||||
|
const uint8_t *end) {
|
||||||
|
const uint8_t *p = begin;
|
||||||
|
int b;
|
||||||
|
|
||||||
|
if (*p++ != '?') {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p == end) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (*p++) {
|
||||||
|
case '0':
|
||||||
|
b = 0;
|
||||||
|
break;
|
||||||
|
case '1':
|
||||||
|
b = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dest) {
|
||||||
|
dest->type = NGHTTP2_SF_VALUE_TYPE_BOOLEAN;
|
||||||
|
dest->b = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p - begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t sf_parse_bare_item(nghttp2_sf_value *dest, const uint8_t *begin,
|
||||||
|
const uint8_t *end) {
|
||||||
|
switch (*begin) {
|
||||||
|
case '-':
|
||||||
|
case '0':
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
case '3':
|
||||||
|
case '4':
|
||||||
|
case '5':
|
||||||
|
case '6':
|
||||||
|
case '7':
|
||||||
|
case '8':
|
||||||
|
case '9':
|
||||||
|
return sf_parse_integer_or_decimal(dest, begin, end);
|
||||||
|
case '"':
|
||||||
|
return sf_parse_string(dest, begin, end);
|
||||||
|
case '*':
|
||||||
|
return sf_parse_token(dest, begin, end);
|
||||||
|
case ':':
|
||||||
|
return sf_parse_byteseq(dest, begin, end);
|
||||||
|
case '?':
|
||||||
|
return sf_parse_boolean(dest, begin, end);
|
||||||
|
default:
|
||||||
|
if (('A' <= *begin && *begin <= 'Z') || ('a' <= *begin && *begin <= 'z')) {
|
||||||
|
return sf_parse_token(dest, begin, end);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define sf_discard_sp_end_err(BEGIN, END, ERR) \
|
||||||
|
for (;; ++(BEGIN)) { \
|
||||||
|
if ((BEGIN) == (END)) { \
|
||||||
|
return (ERR); \
|
||||||
|
} \
|
||||||
|
if (*(BEGIN) != ' ') { \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t sf_parse_params(const uint8_t *begin, const uint8_t *end) {
|
||||||
|
const uint8_t *p = begin;
|
||||||
|
ssize_t slen;
|
||||||
|
|
||||||
|
for (; p != end && *p == ';';) {
|
||||||
|
++p;
|
||||||
|
|
||||||
|
sf_discard_sp_end_err(p, end, -1);
|
||||||
|
|
||||||
|
slen = sf_parse_key(p, end);
|
||||||
|
if (slen < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p += slen;
|
||||||
|
|
||||||
|
if (p == end || *p != '=') {
|
||||||
|
/* Boolean true */
|
||||||
|
} else if (++p == end) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
slen = sf_parse_bare_item(NULL, p, end);
|
||||||
|
if (slen < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p += slen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return p - begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t sf_parse_item(nghttp2_sf_value *dest, const uint8_t *begin,
|
||||||
|
const uint8_t *end) {
|
||||||
|
const uint8_t *p = begin;
|
||||||
|
ssize_t slen;
|
||||||
|
|
||||||
|
slen = sf_parse_bare_item(dest, p, end);
|
||||||
|
if (slen < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p += slen;
|
||||||
|
|
||||||
|
slen = sf_parse_params(p, end);
|
||||||
|
if (slen < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p += slen;
|
||||||
|
|
||||||
|
return p - begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t nghttp2_sf_parse_item(nghttp2_sf_value *dest, const uint8_t *begin,
|
||||||
|
const uint8_t *end) {
|
||||||
|
return sf_parse_item(dest, begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t sf_parse_inner_list(nghttp2_sf_value *dest, const uint8_t *begin,
|
||||||
|
const uint8_t *end) {
|
||||||
|
const uint8_t *p = begin;
|
||||||
|
ssize_t slen;
|
||||||
|
|
||||||
|
if (*p++ != '(') {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
sf_discard_sp_end_err(p, end, -1);
|
||||||
|
|
||||||
|
if (*p == ')') {
|
||||||
|
++p;
|
||||||
|
|
||||||
|
slen = sf_parse_params(p, end);
|
||||||
|
if (slen < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p += slen;
|
||||||
|
|
||||||
|
if (dest) {
|
||||||
|
dest->type = NGHTTP2_SF_VALUE_TYPE_INNER_LIST;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p - begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
slen = sf_parse_item(NULL, p, end);
|
||||||
|
if (slen < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p += slen;
|
||||||
|
|
||||||
|
if (p == end || (*p != ' ' && *p != ')')) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t nghttp2_sf_parse_inner_list(nghttp2_sf_value *dest,
|
||||||
|
const uint8_t *begin, const uint8_t *end) {
|
||||||
|
return sf_parse_inner_list(dest, begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t sf_parse_item_or_inner_list(nghttp2_sf_value *dest,
|
||||||
|
const uint8_t *begin,
|
||||||
|
const uint8_t *end) {
|
||||||
|
if (*begin == '(') {
|
||||||
|
return sf_parse_inner_list(dest, begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sf_parse_item(dest, begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define sf_discard_ows(BEGIN, END) \
|
||||||
|
for (;; ++(BEGIN)) { \
|
||||||
|
if ((BEGIN) == (END)) { \
|
||||||
|
goto fin; \
|
||||||
|
} \
|
||||||
|
if (*(BEGIN) != ' ' && *(BEGIN) != '\t') { \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define sf_discard_ows_end_err(BEGIN, END, ERR) \
|
||||||
|
for (;; ++(BEGIN)) { \
|
||||||
|
if ((BEGIN) == (END)) { \
|
||||||
|
return (ERR); \
|
||||||
|
} \
|
||||||
|
if (*(BEGIN) != ' ' && *(BEGIN) != '\t') { \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value,
|
||||||
|
size_t valuelen) {
|
||||||
|
const uint8_t *p = value, *end = value + valuelen;
|
||||||
|
ssize_t slen;
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
nghttp2_extpri pri = *dest;
|
||||||
|
const uint8_t *key;
|
||||||
|
size_t keylen;
|
||||||
|
|
||||||
|
for (; p != end && *p == ' '; ++p)
|
||||||
|
;
|
||||||
|
|
||||||
|
for (; p != end;) {
|
||||||
|
slen = sf_parse_key(p, end);
|
||||||
|
if (slen < 0) {
|
||||||
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
key = p;
|
||||||
|
keylen = (size_t)slen;
|
||||||
|
|
||||||
|
p += slen;
|
||||||
|
|
||||||
|
if (p == end || *p != '=') {
|
||||||
|
/* Boolean true */
|
||||||
|
val.type = NGHTTP2_SF_VALUE_TYPE_BOOLEAN;
|
||||||
|
val.b = 1;
|
||||||
|
|
||||||
|
slen = sf_parse_params(p, end);
|
||||||
|
if (slen < 0) {
|
||||||
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
} else if (++p == end) {
|
||||||
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
|
} else {
|
||||||
|
slen = sf_parse_item_or_inner_list(&val, p, end);
|
||||||
|
if (slen < 0) {
|
||||||
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p += slen;
|
||||||
|
|
||||||
|
if (keylen == 1) {
|
||||||
|
switch (key[0]) {
|
||||||
|
case 'i':
|
||||||
|
if (val.type != NGHTTP2_SF_VALUE_TYPE_BOOLEAN) {
|
||||||
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
pri.inc = val.b;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
if (val.type != NGHTTP2_SF_VALUE_TYPE_INTEGER ||
|
||||||
|
val.i < NGHTTP2_EXTPRI_URGENCY_HIGH ||
|
||||||
|
NGHTTP2_EXTPRI_URGENCY_LOW < val.i) {
|
||||||
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
pri.urgency = (uint32_t)val.i;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sf_discard_ows(p, end);
|
||||||
|
|
||||||
|
if (*p++ != ',') {
|
||||||
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
sf_discard_ows_end_err(p, end, NGHTTP2_ERR_INVALID_ARGUMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
fin:
|
||||||
|
*dest = pri;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -94,4 +94,55 @@ int nghttp2_http_on_data_chunk(nghttp2_stream *stream, size_t n);
|
||||||
void nghttp2_http_record_request_method(nghttp2_stream *stream,
|
void nghttp2_http_record_request_method(nghttp2_stream *stream,
|
||||||
nghttp2_frame *frame);
|
nghttp2_frame *frame);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RFC 8941 Structured Field Values.
|
||||||
|
*/
|
||||||
|
typedef enum nghttp2_sf_value_type {
|
||||||
|
NGHTTP2_SF_VALUE_TYPE_BOOLEAN,
|
||||||
|
NGHTTP2_SF_VALUE_TYPE_INTEGER,
|
||||||
|
NGHTTP2_SF_VALUE_TYPE_DECIMAL,
|
||||||
|
NGHTTP2_SF_VALUE_TYPE_STRING,
|
||||||
|
NGHTTP2_SF_VALUE_TYPE_TOKEN,
|
||||||
|
NGHTTP2_SF_VALUE_TYPE_BYTESEQ,
|
||||||
|
NGHTTP2_SF_VALUE_TYPE_INNER_LIST,
|
||||||
|
} nghttp2_sf_value_type;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* nghttp2_sf_value stores Structured Field Values item. For Inner
|
||||||
|
* List, only type is set to NGHTTP2_SF_VALUE_TYPE_INNER_LIST.
|
||||||
|
*/
|
||||||
|
typedef struct nghttp2_sf_value {
|
||||||
|
uint8_t type;
|
||||||
|
union {
|
||||||
|
int b;
|
||||||
|
int64_t i;
|
||||||
|
double d;
|
||||||
|
struct {
|
||||||
|
const uint8_t *base;
|
||||||
|
size_t len;
|
||||||
|
} s;
|
||||||
|
};
|
||||||
|
} nghttp2_sf_value;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* nghttp2_sf_parse_item parses the input sequence [|begin|, |end|)
|
||||||
|
* and stores the parsed an Item in |dest|. It returns the number of
|
||||||
|
* bytes consumed if it succeeds, or -1. This function is declared
|
||||||
|
* here for unit tests.
|
||||||
|
*/
|
||||||
|
ssize_t nghttp2_sf_parse_item(nghttp2_sf_value *dest, const uint8_t *begin,
|
||||||
|
const uint8_t *end);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* nghttp2_sf_parse_inner_list parses the input sequence [|begin|, |end|)
|
||||||
|
* and stores the parsed an Inner List in |dest|. It returns the number of
|
||||||
|
* bytes consumed if it succeeds, or -1. This function is declared
|
||||||
|
* here for unit tests.
|
||||||
|
*/
|
||||||
|
ssize_t nghttp2_sf_parse_inner_list(nghttp2_sf_value *dest,
|
||||||
|
const uint8_t *begin, const uint8_t *end);
|
||||||
|
|
||||||
|
int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value,
|
||||||
|
size_t valuelen);
|
||||||
|
|
||||||
#endif /* NGHTTP2_HTTP_H */
|
#endif /* NGHTTP2_HTTP_H */
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include "nghttp2_option.h"
|
#include "nghttp2_option.h"
|
||||||
#include "nghttp2_http.h"
|
#include "nghttp2_http.h"
|
||||||
#include "nghttp2_pq.h"
|
#include "nghttp2_pq.h"
|
||||||
|
#include "nghttp2_extpri.h"
|
||||||
#include "nghttp2_debug.h"
|
#include "nghttp2_debug.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -399,15 +400,21 @@ static void active_outbound_item_reset(nghttp2_active_outbound_item *aob,
|
||||||
aob->state = NGHTTP2_OB_POP_ITEM;
|
aob->state = NGHTTP2_OB_POP_ITEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define NGHTTP2_STREAM_MAX_CYCLE_GAP ((uint64_t)NGHTTP2_MAX_FRAME_SIZE_MAX)
|
||||||
|
|
||||||
static int stream_less(const void *lhsx, const void *rhsx) {
|
static int stream_less(const void *lhsx, const void *rhsx) {
|
||||||
const nghttp2_stream *lhs, *rhs;
|
const nghttp2_stream *lhs, *rhs;
|
||||||
|
|
||||||
lhs = nghttp2_struct_of(lhsx, nghttp2_stream, pq_entry);
|
lhs = nghttp2_struct_of(lhsx, nghttp2_stream, pq_entry);
|
||||||
rhs = nghttp2_struct_of(rhsx, nghttp2_stream, pq_entry);
|
rhs = nghttp2_struct_of(rhsx, nghttp2_stream, pq_entry);
|
||||||
|
|
||||||
|
if (lhs->cycle == rhs->cycle) {
|
||||||
return lhs->seq < rhs->seq;
|
return lhs->seq < rhs->seq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return rhs->cycle - lhs->cycle <= NGHTTP2_STREAM_MAX_CYCLE_GAP;
|
||||||
|
}
|
||||||
|
|
||||||
int nghttp2_enable_strict_preface = 1;
|
int nghttp2_enable_strict_preface = 1;
|
||||||
|
|
||||||
static int session_new(nghttp2_session **session_ptr,
|
static int session_new(nghttp2_session **session_ptr,
|
||||||
|
@ -418,6 +425,7 @@ static int session_new(nghttp2_session **session_ptr,
|
||||||
size_t nbuffer;
|
size_t nbuffer;
|
||||||
size_t max_deflate_dynamic_table_size =
|
size_t max_deflate_dynamic_table_size =
|
||||||
NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE;
|
NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
if (mem == NULL) {
|
if (mem == NULL) {
|
||||||
mem = nghttp2_mem_default();
|
mem = nghttp2_mem_default();
|
||||||
|
@ -595,7 +603,9 @@ static int session_new(nghttp2_session **session_ptr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nghttp2_pq_init(&(*session_ptr)->ob_data, stream_less, mem);
|
for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) {
|
||||||
|
nghttp2_pq_init(&(*session_ptr)->sched[i].ob_data, stream_less, mem);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -748,6 +758,7 @@ static void inflight_settings_del(nghttp2_inflight_settings *settings,
|
||||||
void nghttp2_session_del(nghttp2_session *session) {
|
void nghttp2_session_del(nghttp2_session *session) {
|
||||||
nghttp2_mem *mem;
|
nghttp2_mem *mem;
|
||||||
nghttp2_inflight_settings *settings;
|
nghttp2_inflight_settings *settings;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
if (session == NULL) {
|
if (session == NULL) {
|
||||||
return;
|
return;
|
||||||
|
@ -761,7 +772,9 @@ void nghttp2_session_del(nghttp2_session *session) {
|
||||||
settings = next;
|
settings = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
nghttp2_pq_free(&session->ob_data);
|
for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) {
|
||||||
|
nghttp2_pq_free(&session->sched[i].ob_data);
|
||||||
|
}
|
||||||
nghttp2_stream_free(&session->root);
|
nghttp2_stream_free(&session->root);
|
||||||
|
|
||||||
/* Have to free streams first, so that we can check
|
/* Have to free streams first, so that we can check
|
||||||
|
@ -857,14 +870,40 @@ int nghttp2_session_reprioritize_stream(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint64_t pq_get_first_cycle(nghttp2_pq *pq) {
|
||||||
|
nghttp2_stream *stream;
|
||||||
|
|
||||||
|
if (nghttp2_pq_empty(pq)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream = nghttp2_struct_of(nghttp2_pq_top(pq), nghttp2_stream, pq_entry);
|
||||||
|
return stream->cycle;
|
||||||
|
}
|
||||||
|
|
||||||
static int session_ob_data_push(nghttp2_session *session,
|
static int session_ob_data_push(nghttp2_session *session,
|
||||||
nghttp2_stream *stream) {
|
nghttp2_stream *stream) {
|
||||||
int rv;
|
int rv;
|
||||||
|
uint32_t urgency;
|
||||||
|
int inc;
|
||||||
|
nghttp2_pq *pq;
|
||||||
|
|
||||||
assert(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES);
|
assert(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES);
|
||||||
assert(stream->queued == 0);
|
assert(stream->queued == 0);
|
||||||
|
|
||||||
rv = nghttp2_pq_push(&session->ob_data, &stream->pq_entry);
|
urgency = nghttp2_extpri_uint8_urgency(stream->extpri);
|
||||||
|
inc = nghttp2_extpri_uint8_inc(stream->extpri);
|
||||||
|
|
||||||
|
assert(urgency < NGHTTP2_EXTPRI_URGENCY_LEVELS);
|
||||||
|
|
||||||
|
pq = &session->sched[urgency].ob_data;
|
||||||
|
|
||||||
|
stream->cycle = pq_get_first_cycle(pq);
|
||||||
|
if (inc) {
|
||||||
|
stream->cycle += stream->last_writelen;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = nghttp2_pq_push(pq, &stream->pq_entry);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -876,10 +915,16 @@ static int session_ob_data_push(nghttp2_session *session,
|
||||||
|
|
||||||
static int session_ob_data_remove(nghttp2_session *session,
|
static int session_ob_data_remove(nghttp2_session *session,
|
||||||
nghttp2_stream *stream) {
|
nghttp2_stream *stream) {
|
||||||
|
uint32_t urgency;
|
||||||
|
|
||||||
assert(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES);
|
assert(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES);
|
||||||
assert(stream->queued == 1);
|
assert(stream->queued == 1);
|
||||||
|
|
||||||
nghttp2_pq_remove(&session->ob_data, &stream->pq_entry);
|
urgency = nghttp2_extpri_uint8_urgency(stream->extpri);
|
||||||
|
|
||||||
|
assert(urgency < NGHTTP2_EXTPRI_URGENCY_LEVELS);
|
||||||
|
|
||||||
|
nghttp2_pq_remove(&session->sched[urgency].ob_data, &stream->pq_entry);
|
||||||
|
|
||||||
stream->queued = 0;
|
stream->queued = 0;
|
||||||
|
|
||||||
|
@ -955,6 +1000,84 @@ static int session_resume_deferred_stream_item(nghttp2_session *session,
|
||||||
return session_ob_data_push(session, stream);
|
return session_ob_data_push(session, stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static nghttp2_outbound_item *
|
||||||
|
session_sched_get_next_outbound_item(nghttp2_session *session) {
|
||||||
|
size_t i;
|
||||||
|
nghttp2_pq_entry *ent;
|
||||||
|
nghttp2_stream *stream;
|
||||||
|
|
||||||
|
for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) {
|
||||||
|
ent = nghttp2_pq_top(&session->sched[i].ob_data);
|
||||||
|
if (!ent) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream = nghttp2_struct_of(ent, nghttp2_stream, pq_entry);
|
||||||
|
return stream->item;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int session_sched_empty(nghttp2_session *session) {
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) {
|
||||||
|
if (!nghttp2_pq_empty(&session->sched[i].ob_data)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void session_sched_reschedule_stream(nghttp2_session *session,
|
||||||
|
nghttp2_stream *stream) {
|
||||||
|
nghttp2_pq *pq;
|
||||||
|
uint32_t urgency = nghttp2_extpri_uint8_urgency(stream->extpri);
|
||||||
|
int inc = nghttp2_extpri_uint8_inc(stream->extpri);
|
||||||
|
uint64_t penalty = (uint64_t)stream->last_writelen;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
(void)rv;
|
||||||
|
|
||||||
|
assert(urgency < NGHTTP2_EXTPRI_URGENCY_LEVELS);
|
||||||
|
|
||||||
|
pq = &session->sched[urgency].ob_data;
|
||||||
|
|
||||||
|
if (!inc || nghttp2_pq_size(pq) == 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nghttp2_pq_remove(pq, &stream->pq_entry);
|
||||||
|
|
||||||
|
stream->cycle += penalty;
|
||||||
|
|
||||||
|
rv = nghttp2_pq_push(pq, &stream->pq_entry);
|
||||||
|
|
||||||
|
assert(0 == rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int session_update_stream_priority(nghttp2_session *session,
|
||||||
|
nghttp2_stream *stream,
|
||||||
|
uint8_t u8extpri) {
|
||||||
|
if (stream->extpri == u8extpri) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream->queued) {
|
||||||
|
session_ob_data_remove(session, stream);
|
||||||
|
|
||||||
|
stream->extpri = u8extpri;
|
||||||
|
|
||||||
|
return session_ob_data_push(session, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->extpri = u8extpri;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int nghttp2_session_add_item(nghttp2_session *session,
|
int nghttp2_session_add_item(nghttp2_session *session,
|
||||||
nghttp2_outbound_item *item) {
|
nghttp2_outbound_item *item) {
|
||||||
/* TODO Return error if stream is not found for the frame requiring
|
/* TODO Return error if stream is not found for the frame requiring
|
||||||
|
@ -2489,8 +2612,6 @@ static int session_prep_frame(nghttp2_session *session,
|
||||||
nghttp2_outbound_item *
|
nghttp2_outbound_item *
|
||||||
nghttp2_session_get_next_ob_item(nghttp2_session *session) {
|
nghttp2_session_get_next_ob_item(nghttp2_session *session) {
|
||||||
nghttp2_outbound_item *item;
|
nghttp2_outbound_item *item;
|
||||||
nghttp2_pq_entry *ent;
|
|
||||||
nghttp2_stream *stream;
|
|
||||||
|
|
||||||
if (nghttp2_outbound_queue_top(&session->ob_urgent)) {
|
if (nghttp2_outbound_queue_top(&session->ob_urgent)) {
|
||||||
return nghttp2_outbound_queue_top(&session->ob_urgent);
|
return nghttp2_outbound_queue_top(&session->ob_urgent);
|
||||||
|
@ -2512,13 +2633,7 @@ nghttp2_session_get_next_ob_item(nghttp2_session *session) {
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
ent = nghttp2_pq_top(&session->ob_data);
|
return session_sched_get_next_outbound_item(session);
|
||||||
if (!ent) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
stream = nghttp2_struct_of(ent, nghttp2_stream, pq_entry);
|
|
||||||
return stream->item;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -2527,8 +2642,6 @@ nghttp2_session_get_next_ob_item(nghttp2_session *session) {
|
||||||
nghttp2_outbound_item *
|
nghttp2_outbound_item *
|
||||||
nghttp2_session_pop_next_ob_item(nghttp2_session *session) {
|
nghttp2_session_pop_next_ob_item(nghttp2_session *session) {
|
||||||
nghttp2_outbound_item *item;
|
nghttp2_outbound_item *item;
|
||||||
nghttp2_pq_entry *ent;
|
|
||||||
nghttp2_stream *stream;
|
|
||||||
|
|
||||||
item = nghttp2_outbound_queue_top(&session->ob_urgent);
|
item = nghttp2_outbound_queue_top(&session->ob_urgent);
|
||||||
if (item) {
|
if (item) {
|
||||||
|
@ -2559,13 +2672,7 @@ nghttp2_session_pop_next_ob_item(nghttp2_session *session) {
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
ent = nghttp2_pq_top(&session->ob_data);
|
return session_sched_get_next_outbound_item(session);
|
||||||
if (!ent) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
stream = nghttp2_struct_of(ent, nghttp2_stream, pq_entry);
|
|
||||||
return stream->item;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -2675,10 +2782,20 @@ static int session_close_stream_on_goaway(nghttp2_session *session,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reschedule_stream(nghttp2_stream *stream) {
|
static void session_reschedule_stream(nghttp2_session *session,
|
||||||
|
nghttp2_stream *stream) {
|
||||||
stream->last_writelen = stream->item->frame.hd.length;
|
stream->last_writelen = stream->item->frame.hd.length;
|
||||||
|
|
||||||
|
if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)) {
|
||||||
nghttp2_stream_reschedule(stream);
|
nghttp2_stream_reschedule(stream);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!session->server) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
session_sched_reschedule_stream(session, stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int session_update_stream_consumed_size(nghttp2_session *session,
|
static int session_update_stream_consumed_size(nghttp2_session *session,
|
||||||
|
@ -3906,6 +4023,19 @@ static int session_end_stream_headers_received(nghttp2_session *session,
|
||||||
nghttp2_frame *frame,
|
nghttp2_frame *frame,
|
||||||
nghttp2_stream *stream) {
|
nghttp2_stream *stream) {
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
|
assert(frame->hd.type == NGHTTP2_HEADERS);
|
||||||
|
|
||||||
|
if (session->server && session_enforce_http_messaging(session) &&
|
||||||
|
frame->headers.cat == NGHTTP2_HCAT_REQUEST &&
|
||||||
|
(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)) {
|
||||||
|
rv = session_update_stream_priority(session, stream, stream->http_extpri);
|
||||||
|
if (rv != 0) {
|
||||||
|
assert(nghttp2_is_fatal(rv));
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((frame->hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) {
|
if ((frame->hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -7080,7 +7210,7 @@ int nghttp2_session_want_write(nghttp2_session *session) {
|
||||||
return session->aob.item || nghttp2_outbound_queue_top(&session->ob_urgent) ||
|
return session->aob.item || nghttp2_outbound_queue_top(&session->ob_urgent) ||
|
||||||
nghttp2_outbound_queue_top(&session->ob_reg) ||
|
nghttp2_outbound_queue_top(&session->ob_reg) ||
|
||||||
((!nghttp2_pq_empty(&session->root.obq) ||
|
((!nghttp2_pq_empty(&session->root.obq) ||
|
||||||
!nghttp2_pq_empty(&session->ob_data)) &&
|
!session_sched_empty(session)) &&
|
||||||
session->remote_window_size > 0) ||
|
session->remote_window_size > 0) ||
|
||||||
(nghttp2_outbound_queue_top(&session->ob_syn) &&
|
(nghttp2_outbound_queue_top(&session->ob_syn) &&
|
||||||
!session_is_outgoing_concurrent_streams_max(session));
|
!session_is_outgoing_concurrent_streams_max(session));
|
||||||
|
@ -7474,9 +7604,7 @@ int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs,
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)) {
|
session_reschedule_stream(session, stream);
|
||||||
reschedule_stream(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (frame->hd.length == 0 && (data_flags & NGHTTP2_DATA_FLAG_EOF) &&
|
if (frame->hd.length == 0 && (data_flags & NGHTTP2_DATA_FLAG_EOF) &&
|
||||||
(data_flags & NGHTTP2_DATA_FLAG_NO_END_STREAM)) {
|
(data_flags & NGHTTP2_DATA_FLAG_NO_END_STREAM)) {
|
||||||
|
|
|
@ -203,9 +203,12 @@ struct nghttp2_session {
|
||||||
response) frame, which are subject to
|
response) frame, which are subject to
|
||||||
SETTINGS_MAX_CONCURRENT_STREAMS limit. */
|
SETTINGS_MAX_CONCURRENT_STREAMS limit. */
|
||||||
nghttp2_outbound_queue ob_syn;
|
nghttp2_outbound_queue ob_syn;
|
||||||
/* Queue for DATA frames which is used when
|
/* Queues for DATA frames which is used when
|
||||||
SETTINGS_NO_RFC7540_PRIORITIES is enabled. */
|
SETTINGS_NO_RFC7540_PRIORITIES is enabled. This implements RFC
|
||||||
|
9218 extensible prioritization scheme. */
|
||||||
|
struct {
|
||||||
nghttp2_pq ob_data;
|
nghttp2_pq ob_data;
|
||||||
|
} sched[NGHTTP2_EXTPRI_URGENCY_LEVELS];
|
||||||
nghttp2_active_outbound_item aob;
|
nghttp2_active_outbound_item aob;
|
||||||
nghttp2_inbound_frame iframe;
|
nghttp2_inbound_frame iframe;
|
||||||
nghttp2_hd_deflater hd_deflater;
|
nghttp2_hd_deflater hd_deflater;
|
||||||
|
|
|
@ -100,6 +100,8 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
||||||
stream->descendant_next_seq = 0;
|
stream->descendant_next_seq = 0;
|
||||||
stream->seq = 0;
|
stream->seq = 0;
|
||||||
stream->last_writelen = 0;
|
stream->last_writelen = 0;
|
||||||
|
|
||||||
|
stream->extpri = stream->http_extpri = NGHTTP2_EXTPRI_DEFAULT_URGENCY;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nghttp2_stream_free(nghttp2_stream *stream) {
|
void nghttp2_stream_free(nghttp2_stream *stream) {
|
||||||
|
|
|
@ -220,6 +220,12 @@ struct nghttp2_stream {
|
||||||
this stream. The nonzero does not necessarily mean WINDOW_UPDATE
|
this stream. The nonzero does not necessarily mean WINDOW_UPDATE
|
||||||
is not queued. */
|
is not queued. */
|
||||||
uint8_t window_update_queued;
|
uint8_t window_update_queued;
|
||||||
|
/* extpri is a stream priority produced by nghttp2_extpri_to_uint8
|
||||||
|
used by RFC 9218 extensible priorities. */
|
||||||
|
uint8_t extpri;
|
||||||
|
/* http_extpri is a stream priority received in HTTP request header
|
||||||
|
fields and produced by nghttp2_extpri_to_uint8. */
|
||||||
|
uint8_t http_extpri;
|
||||||
};
|
};
|
||||||
|
|
||||||
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
||||||
|
|
|
@ -21,6 +21,8 @@ if(HAVE_CUNIT)
|
||||||
nghttp2_npn_test.c
|
nghttp2_npn_test.c
|
||||||
nghttp2_helper_test.c
|
nghttp2_helper_test.c
|
||||||
nghttp2_buf_test.c
|
nghttp2_buf_test.c
|
||||||
|
nghttp2_http_test.c
|
||||||
|
nghttp2_extpri_test.c
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(main EXCLUDE_FROM_ALL
|
add_executable(main EXCLUDE_FROM_ALL
|
||||||
|
|
|
@ -40,14 +40,18 @@ OBJECTS = main.c nghttp2_pq_test.c nghttp2_map_test.c nghttp2_queue_test.c \
|
||||||
nghttp2_hd_test.c \
|
nghttp2_hd_test.c \
|
||||||
nghttp2_npn_test.c \
|
nghttp2_npn_test.c \
|
||||||
nghttp2_helper_test.c \
|
nghttp2_helper_test.c \
|
||||||
nghttp2_buf_test.c
|
nghttp2_buf_test.c \
|
||||||
|
nghttp2_http_test.c \
|
||||||
|
nghttp2_extpri_test.c
|
||||||
|
|
||||||
HFILES = nghttp2_pq_test.h nghttp2_map_test.h nghttp2_queue_test.h \
|
HFILES = nghttp2_pq_test.h nghttp2_map_test.h nghttp2_queue_test.h \
|
||||||
nghttp2_session_test.h \
|
nghttp2_session_test.h \
|
||||||
nghttp2_frame_test.h nghttp2_stream_test.h nghttp2_hd_test.h \
|
nghttp2_frame_test.h nghttp2_stream_test.h nghttp2_hd_test.h \
|
||||||
nghttp2_npn_test.h nghttp2_helper_test.h \
|
nghttp2_npn_test.h nghttp2_helper_test.h \
|
||||||
nghttp2_test_helper.h \
|
nghttp2_test_helper.h \
|
||||||
nghttp2_buf_test.h
|
nghttp2_buf_test.h \
|
||||||
|
nghttp2_http_test.h \
|
||||||
|
nghttp2_extpri_test.h
|
||||||
|
|
||||||
main_SOURCES = $(HFILES) $(OBJECTS)
|
main_SOURCES = $(HFILES) $(OBJECTS)
|
||||||
|
|
||||||
|
|
12
tests/main.c
12
tests/main.c
|
@ -40,6 +40,8 @@
|
||||||
#include "nghttp2_npn_test.h"
|
#include "nghttp2_npn_test.h"
|
||||||
#include "nghttp2_helper_test.h"
|
#include "nghttp2_helper_test.h"
|
||||||
#include "nghttp2_buf_test.h"
|
#include "nghttp2_buf_test.h"
|
||||||
|
#include "nghttp2_http_test.h"
|
||||||
|
#include "nghttp2_extpri_test.h"
|
||||||
|
|
||||||
extern int nghttp2_enable_strict_preface;
|
extern int nghttp2_enable_strict_preface;
|
||||||
|
|
||||||
|
@ -93,6 +95,8 @@ int main(void) {
|
||||||
test_nghttp2_session_recv_headers_early_response) ||
|
test_nghttp2_session_recv_headers_early_response) ||
|
||||||
!CU_add_test(pSuite, "session_recv_headers_for_closed_stream",
|
!CU_add_test(pSuite, "session_recv_headers_for_closed_stream",
|
||||||
test_nghttp2_session_recv_headers_for_closed_stream) ||
|
test_nghttp2_session_recv_headers_for_closed_stream) ||
|
||||||
|
!CU_add_test(pSuite, "session_recv_headers_with_extpri",
|
||||||
|
test_nghttp2_session_recv_headers_with_extpri) ||
|
||||||
!CU_add_test(pSuite, "session_server_recv_push_response",
|
!CU_add_test(pSuite, "session_server_recv_push_response",
|
||||||
test_nghttp2_session_server_recv_push_response) ||
|
test_nghttp2_session_server_recv_push_response) ||
|
||||||
!CU_add_test(pSuite, "session_recv_premature_headers",
|
!CU_add_test(pSuite, "session_recv_premature_headers",
|
||||||
|
@ -427,7 +431,13 @@ int main(void) {
|
||||||
!CU_add_test(pSuite, "bufs_advance", test_nghttp2_bufs_advance) ||
|
!CU_add_test(pSuite, "bufs_advance", test_nghttp2_bufs_advance) ||
|
||||||
!CU_add_test(pSuite, "bufs_next_present",
|
!CU_add_test(pSuite, "bufs_next_present",
|
||||||
test_nghttp2_bufs_next_present) ||
|
test_nghttp2_bufs_next_present) ||
|
||||||
!CU_add_test(pSuite, "bufs_realloc", test_nghttp2_bufs_realloc)) {
|
!CU_add_test(pSuite, "bufs_realloc", test_nghttp2_bufs_realloc) ||
|
||||||
|
!CU_add_test(pSuite, "http_parse_priority",
|
||||||
|
test_nghttp2_http_parse_priority) ||
|
||||||
|
!CU_add_test(pSuite, "sf_parse_item", test_nghttp2_sf_parse_item) ||
|
||||||
|
!CU_add_test(pSuite, "sf_parse_inner_list",
|
||||||
|
test_nghttp2_sf_parse_inner_list) ||
|
||||||
|
!CU_add_test(pSuite, "extpri_to_uint8", test_nghttp2_extpri_to_uint8)) {
|
||||||
CU_cleanup_registry();
|
CU_cleanup_registry();
|
||||||
return (int)CU_get_error();
|
return (int)CU_get_error();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* nghttp2 - HTTP/2 C Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 nghttp3 contributors
|
||||||
|
* Copyright (c) 2022 nghttp2 contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "nghttp2_extpri_test.h"
|
||||||
|
|
||||||
|
#include <CUnit/CUnit.h>
|
||||||
|
|
||||||
|
#include "nghttp2_extpri.h"
|
||||||
|
#include "nghttp2_test_helper.h"
|
||||||
|
|
||||||
|
void test_nghttp2_extpri_to_uint8(void) {
|
||||||
|
{
|
||||||
|
nghttp2_extpri pri = {1, 0};
|
||||||
|
CU_ASSERT(1 == nghttp2_extpri_to_uint8(&pri));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
nghttp2_extpri pri = {1, 1};
|
||||||
|
CU_ASSERT((0x80 | 1) == nghttp2_extpri_to_uint8(&pri));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
nghttp2_extpri pri = {7, 1};
|
||||||
|
CU_ASSERT((0x80 | 7) == nghttp2_extpri_to_uint8(&pri));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
nghttp2_extpri pri = {7, 0};
|
||||||
|
CU_ASSERT(7 == nghttp2_extpri_to_uint8(&pri));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* nghttp2 - HTTP/2 C Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 nghttp3 contributors
|
||||||
|
* Copyright (c) 2022 nghttp2 contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef NGHTTP2_EXTPRI_TEST_H
|
||||||
|
#define NGHTTP2_EXTPRI_TEST_H
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif /* HAVE_CONFIG_H */
|
||||||
|
|
||||||
|
void test_nghttp2_extpri_to_uint8(void);
|
||||||
|
|
||||||
|
#endif /* NGHTTP2_EXTPRI_TEST_H */
|
|
@ -0,0 +1,655 @@
|
||||||
|
/*
|
||||||
|
* nghttp2 - HTTP/2 C Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 nghttp3 contributors
|
||||||
|
* Copyright (c) 2022 nghttp2 contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "nghttp2_http_test.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <CUnit/CUnit.h>
|
||||||
|
|
||||||
|
#include "nghttp2_http.h"
|
||||||
|
#include "nghttp2_test_helper.h"
|
||||||
|
|
||||||
|
void test_nghttp2_http_parse_priority(void) {
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_extpri pri = {(uint32_t)-1, -1};
|
||||||
|
const uint8_t v[] = "";
|
||||||
|
|
||||||
|
rv = nghttp2_http_parse_priority(&pri, v, sizeof(v) - 1);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == rv);
|
||||||
|
CU_ASSERT((uint32_t)-1 == pri.urgency);
|
||||||
|
CU_ASSERT(-1 == pri.inc);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_extpri pri = {(uint32_t)-1, -1};
|
||||||
|
const uint8_t v[] = "u=7,i";
|
||||||
|
|
||||||
|
rv = nghttp2_http_parse_priority(&pri, v, sizeof(v) - 1);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == rv);
|
||||||
|
CU_ASSERT((uint32_t)7 == pri.urgency);
|
||||||
|
CU_ASSERT(1 == pri.inc);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_extpri pri = {(uint32_t)-1, -1};
|
||||||
|
const uint8_t v[] = "u=0,i=?0";
|
||||||
|
|
||||||
|
rv = nghttp2_http_parse_priority(&pri, v, sizeof(v) - 1);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == rv);
|
||||||
|
CU_ASSERT((uint32_t)0 == pri.urgency);
|
||||||
|
CU_ASSERT(0 == pri.inc);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_extpri pri = {(uint32_t)-1, -1};
|
||||||
|
const uint8_t v[] = "u=3, i";
|
||||||
|
|
||||||
|
rv = nghttp2_http_parse_priority(&pri, v, sizeof(v) - 1);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == rv);
|
||||||
|
CU_ASSERT((uint32_t)3 == pri.urgency);
|
||||||
|
CU_ASSERT(1 == pri.inc);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_extpri pri = {(uint32_t)-1, -1};
|
||||||
|
const uint8_t v[] = "u=0, i, i=?0, u=6";
|
||||||
|
|
||||||
|
rv = nghttp2_http_parse_priority(&pri, v, sizeof(v) - 1);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == rv);
|
||||||
|
CU_ASSERT((uint32_t)6 == pri.urgency);
|
||||||
|
CU_ASSERT(0 == pri.inc);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_extpri pri = {(uint32_t)-1, -1};
|
||||||
|
const uint8_t v[] = "u=0,";
|
||||||
|
|
||||||
|
rv = nghttp2_http_parse_priority(&pri, v, sizeof(v) - 1);
|
||||||
|
|
||||||
|
CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_extpri pri = {(uint32_t)-1, -1};
|
||||||
|
const uint8_t v[] = "u=0, ";
|
||||||
|
|
||||||
|
rv = nghttp2_http_parse_priority(&pri, v, sizeof(v) - 1);
|
||||||
|
|
||||||
|
CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_extpri pri = {(uint32_t)-1, -1};
|
||||||
|
const uint8_t v[] = "u=";
|
||||||
|
|
||||||
|
rv = nghttp2_http_parse_priority(&pri, v, sizeof(v) - 1);
|
||||||
|
|
||||||
|
CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_extpri pri = {(uint32_t)-1, -1};
|
||||||
|
const uint8_t v[] = "u";
|
||||||
|
|
||||||
|
rv = nghttp2_http_parse_priority(&pri, v, sizeof(v) - 1);
|
||||||
|
|
||||||
|
CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_extpri pri = {(uint32_t)-1, -1};
|
||||||
|
const uint8_t v[] = "i=?1";
|
||||||
|
|
||||||
|
rv = nghttp2_http_parse_priority(&pri, v, sizeof(v) - 1);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == rv);
|
||||||
|
CU_ASSERT((uint32_t)-1 == pri.urgency);
|
||||||
|
CU_ASSERT(1 == pri.inc);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_extpri pri = {(uint32_t)-1, -1};
|
||||||
|
const uint8_t v[] = "i=?2";
|
||||||
|
|
||||||
|
rv = nghttp2_http_parse_priority(&pri, v, sizeof(v) - 1);
|
||||||
|
|
||||||
|
CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_extpri pri = {(uint32_t)-1, -1};
|
||||||
|
const uint8_t v[] = "i=?";
|
||||||
|
|
||||||
|
rv = nghttp2_http_parse_priority(&pri, v, sizeof(v) - 1);
|
||||||
|
|
||||||
|
CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_extpri pri = {(uint32_t)-1, -1};
|
||||||
|
const uint8_t v[] = "i=";
|
||||||
|
|
||||||
|
rv = nghttp2_http_parse_priority(&pri, v, sizeof(v) - 1);
|
||||||
|
|
||||||
|
CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_extpri pri = {(uint32_t)-1, -1};
|
||||||
|
const uint8_t v[] = "u=-1";
|
||||||
|
|
||||||
|
rv = nghttp2_http_parse_priority(&pri, v, sizeof(v) - 1);
|
||||||
|
|
||||||
|
CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_extpri pri = {(uint32_t)-1, -1};
|
||||||
|
const uint8_t v[] = "u=8";
|
||||||
|
|
||||||
|
rv = nghttp2_http_parse_priority(&pri, v, sizeof(v) - 1);
|
||||||
|
|
||||||
|
CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_extpri pri = {(uint32_t)-1, -1};
|
||||||
|
const uint8_t v[] =
|
||||||
|
"i=?0, u=1, a=(x y z), u=2; i=?0;foo=\",,,\", i=?1;i=?0; u=6";
|
||||||
|
|
||||||
|
rv = nghttp2_http_parse_priority(&pri, v, sizeof(v) - 1);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == rv);
|
||||||
|
CU_ASSERT((uint32_t)2 == pri.urgency);
|
||||||
|
CU_ASSERT(1 == pri.inc);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_extpri pri = {(uint32_t)-1, -1};
|
||||||
|
const uint8_t v[] = {'u', '='};
|
||||||
|
|
||||||
|
rv = nghttp2_http_parse_priority(&pri, v, sizeof(v));
|
||||||
|
|
||||||
|
CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == rv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_nghttp2_sf_parse_item(void) {
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] = "?1";
|
||||||
|
val.type = 0xff;
|
||||||
|
|
||||||
|
CU_ASSERT(2 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_BOOLEAN == val.type);
|
||||||
|
CU_ASSERT(1 == val.b);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] = "?1 ";
|
||||||
|
val.type = 0xff;
|
||||||
|
|
||||||
|
CU_ASSERT(2 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_BOOLEAN == val.type);
|
||||||
|
CU_ASSERT(1 == val.b);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] = "?1;foo=bar";
|
||||||
|
val.type = 0xff;
|
||||||
|
|
||||||
|
CU_ASSERT(10 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_BOOLEAN == val.type);
|
||||||
|
CU_ASSERT(1 == val.b);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint8_t s[] = {'?', '1', ';', 'f', 'o', 'o', '='};
|
||||||
|
|
||||||
|
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s)));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] = "?0";
|
||||||
|
val.type = 0xff;
|
||||||
|
|
||||||
|
CU_ASSERT(2 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_BOOLEAN == val.type);
|
||||||
|
CU_ASSERT(0 == val.b);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] = "?0 ";
|
||||||
|
val.type = 0xff;
|
||||||
|
|
||||||
|
CU_ASSERT(2 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_BOOLEAN == val.type);
|
||||||
|
CU_ASSERT(0 == val.b);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint8_t s[] = "?2";
|
||||||
|
|
||||||
|
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint8_t s[] = "?";
|
||||||
|
|
||||||
|
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint8_t s[] = "?1";
|
||||||
|
|
||||||
|
CU_ASSERT(2 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] = ":cHJldGVuZCB0aGlzIGlzIGJpbmFyeSBjb250ZW50Lg==:";
|
||||||
|
val.type = 0xff;
|
||||||
|
|
||||||
|
CU_ASSERT(46 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_BYTESEQ == val.type);
|
||||||
|
CU_ASSERT(44 == val.s.len);
|
||||||
|
CU_ASSERT(0 == memcmp("cHJldGVuZCB0aGlzIGlzIGJpbmFyeSBjb250ZW50Lg==",
|
||||||
|
val.s.base, val.s.len));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] = ":cHJldGVuZCB0aGlzIGlzIGJpbmFyeSBjb250ZW50Lg==: ";
|
||||||
|
val.type = 0xff;
|
||||||
|
|
||||||
|
CU_ASSERT(46 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_BYTESEQ == val.type);
|
||||||
|
CU_ASSERT(44 == val.s.len);
|
||||||
|
CU_ASSERT(0 == memcmp("cHJldGVuZCB0aGlzIGlzIGJpbmFyeSBjb250ZW50Lg==",
|
||||||
|
val.s.base, val.s.len));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] = "::";
|
||||||
|
val.type = 0xff;
|
||||||
|
|
||||||
|
CU_ASSERT(2 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_BYTESEQ == val.type);
|
||||||
|
CU_ASSERT(0 == val.s.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint8_t s[] = ":cHJldGVuZCB0aGlzIGlzIGJpbmFyeSBjb250ZW50Lg==";
|
||||||
|
|
||||||
|
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint8_t s[] = ":";
|
||||||
|
|
||||||
|
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint8_t s[] = ":@:";
|
||||||
|
|
||||||
|
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint8_t s[] = ":foo:";
|
||||||
|
|
||||||
|
CU_ASSERT(5 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] =
|
||||||
|
":abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=:";
|
||||||
|
val.type = 0xff;
|
||||||
|
|
||||||
|
CU_ASSERT(67 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_BYTESEQ == val.type);
|
||||||
|
CU_ASSERT(65 == val.s.len);
|
||||||
|
CU_ASSERT(
|
||||||
|
0 ==
|
||||||
|
memcmp(
|
||||||
|
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=",
|
||||||
|
val.s.base, val.s.len));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] = "foo123/456";
|
||||||
|
val.type = 0xff;
|
||||||
|
|
||||||
|
CU_ASSERT(10 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_TOKEN == val.type);
|
||||||
|
CU_ASSERT(10 == val.s.len);
|
||||||
|
CU_ASSERT(0 == memcmp(s, val.s.base, val.s.len));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] = "foo123/456 ";
|
||||||
|
val.type = 0xff;
|
||||||
|
|
||||||
|
CU_ASSERT(10 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_TOKEN == val.type);
|
||||||
|
CU_ASSERT(10 == val.s.len);
|
||||||
|
CU_ASSERT(0 == memcmp(s, val.s.base, val.s.len));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] = "*";
|
||||||
|
val.type = 0xff;
|
||||||
|
|
||||||
|
CU_ASSERT(1 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_TOKEN == val.type);
|
||||||
|
CU_ASSERT(1 == val.s.len);
|
||||||
|
CU_ASSERT(0 == memcmp(s, val.s.base, val.s.len));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint8_t s[] = "*";
|
||||||
|
|
||||||
|
CU_ASSERT(1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] = "\"hello world\"";
|
||||||
|
val.type = 0xff;
|
||||||
|
|
||||||
|
CU_ASSERT(13 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_STRING == val.type);
|
||||||
|
CU_ASSERT(11 == val.s.len);
|
||||||
|
CU_ASSERT(0 == memcmp("hello world", val.s.base, val.s.len));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] = "\"hello world\" ";
|
||||||
|
val.type = 0xff;
|
||||||
|
|
||||||
|
CU_ASSERT(13 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_STRING == val.type);
|
||||||
|
CU_ASSERT(11 == val.s.len);
|
||||||
|
CU_ASSERT(0 == memcmp("hello world", val.s.base, val.s.len));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] = "\"foo\\\"\\\\\"";
|
||||||
|
val.type = 0xff;
|
||||||
|
|
||||||
|
CU_ASSERT(9 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_STRING == val.type);
|
||||||
|
CU_ASSERT(7 == val.s.len);
|
||||||
|
CU_ASSERT(0 == memcmp("foo\\\"\\\\", val.s.base, val.s.len));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint8_t s[] = "\"foo\\x\"";
|
||||||
|
|
||||||
|
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint8_t s[] = "\"foo";
|
||||||
|
|
||||||
|
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint8_t s[] = "\"\x7f\"";
|
||||||
|
|
||||||
|
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint8_t s[] = "\"\x1f\"";
|
||||||
|
|
||||||
|
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint8_t s[] = "\"foo\"";
|
||||||
|
|
||||||
|
CU_ASSERT(5 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] = "4.5";
|
||||||
|
val.type = NGHTTP2_SF_VALUE_TYPE_DECIMAL;
|
||||||
|
|
||||||
|
CU_ASSERT(3 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_DECIMAL == val.type);
|
||||||
|
CU_ASSERT(fabs(4.5 - val.d) < 1e-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] = "4.5 ";
|
||||||
|
val.type = NGHTTP2_SF_VALUE_TYPE_DECIMAL;
|
||||||
|
|
||||||
|
CU_ASSERT(3 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_DECIMAL == val.type);
|
||||||
|
CU_ASSERT(fabs(4.5 - val.d) < 1e-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] = "-4.5";
|
||||||
|
val.type = NGHTTP2_SF_VALUE_TYPE_DECIMAL;
|
||||||
|
|
||||||
|
CU_ASSERT(4 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_DECIMAL == val.type);
|
||||||
|
CU_ASSERT(fabs(-4.5 - val.d) < 1e-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint8_t s[] = "4.5";
|
||||||
|
|
||||||
|
CU_ASSERT(3 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] = "123456789012.123";
|
||||||
|
val.type = NGHTTP2_SF_VALUE_TYPE_DECIMAL;
|
||||||
|
|
||||||
|
CU_ASSERT(16 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_DECIMAL == val.type);
|
||||||
|
CU_ASSERT(fabs(123456789012.123 - val.d) < 1e-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint8_t s[] = "1123456789012.123";
|
||||||
|
|
||||||
|
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint8_t s[] = "123456789012.1234";
|
||||||
|
|
||||||
|
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint8_t s[] = "1.";
|
||||||
|
|
||||||
|
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] = "123456789012345";
|
||||||
|
val.type = NGHTTP2_SF_VALUE_TYPE_DECIMAL;
|
||||||
|
|
||||||
|
CU_ASSERT(15 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_INTEGER == val.type);
|
||||||
|
CU_ASSERT(123456789012345 == val.i);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] = "1 ";
|
||||||
|
val.type = NGHTTP2_SF_VALUE_TYPE_DECIMAL;
|
||||||
|
|
||||||
|
CU_ASSERT(1 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_INTEGER == val.type);
|
||||||
|
CU_ASSERT(1 == val.i);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint8_t s[] = "1";
|
||||||
|
|
||||||
|
CU_ASSERT(1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint8_t s[] = "1234567890123456";
|
||||||
|
|
||||||
|
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] = "\"foo\";a; b=\"bar\";c=1.3;d=9;e=baz;f=:aaa:";
|
||||||
|
val.type = 0xff;
|
||||||
|
|
||||||
|
CU_ASSERT(41 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_STRING == val.type);
|
||||||
|
CU_ASSERT(0 == memcmp("foo", val.s.base, val.s.len));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint8_t s[] = "\"foo\";a; b=\"bar";
|
||||||
|
|
||||||
|
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint8_t s[] = "foo;";
|
||||||
|
|
||||||
|
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_nghttp2_sf_parse_inner_list(void) {
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] = "()";
|
||||||
|
val.type = 0xff;
|
||||||
|
|
||||||
|
CU_ASSERT(2 == nghttp2_sf_parse_inner_list(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_INNER_LIST == val.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] = "( )";
|
||||||
|
val.type = 0xff;
|
||||||
|
|
||||||
|
CU_ASSERT(7 == nghttp2_sf_parse_inner_list(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_INNER_LIST == val.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] = "(a)";
|
||||||
|
val.type = 0xff;
|
||||||
|
|
||||||
|
CU_ASSERT(3 == nghttp2_sf_parse_inner_list(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_INNER_LIST == val.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] = "(a b)";
|
||||||
|
val.type = 0xff;
|
||||||
|
|
||||||
|
CU_ASSERT(5 == nghttp2_sf_parse_inner_list(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_INNER_LIST == val.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] = "( a b )";
|
||||||
|
val.type = 0xff;
|
||||||
|
|
||||||
|
CU_ASSERT(10 == nghttp2_sf_parse_inner_list(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_INNER_LIST == val.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
const uint8_t s[] = "( a;foo=bar)";
|
||||||
|
val.type = 0xff;
|
||||||
|
|
||||||
|
CU_ASSERT(12 == nghttp2_sf_parse_inner_list(&val, s, s + sizeof(s) - 1));
|
||||||
|
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_INNER_LIST == val.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint8_t s[] = "(";
|
||||||
|
|
||||||
|
CU_ASSERT(-1 == nghttp2_sf_parse_inner_list(NULL, s, s + sizeof(s) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint8_t s[] = "(a";
|
||||||
|
|
||||||
|
CU_ASSERT(-1 == nghttp2_sf_parse_inner_list(NULL, s, s + sizeof(s) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint8_t s[] = "(a ";
|
||||||
|
|
||||||
|
CU_ASSERT(-1 == nghttp2_sf_parse_inner_list(NULL, s, s + sizeof(s) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint8_t s[] = "(a;b";
|
||||||
|
|
||||||
|
CU_ASSERT(-1 == nghttp2_sf_parse_inner_list(NULL, s, s + sizeof(s) - 1));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* nghttp2 - HTTP/2 C Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 nghttp3 contributors
|
||||||
|
* Copyright (c) 2022 nghttp2 contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef NGHTTP2_HTTP_TEST_H
|
||||||
|
#define NGHTTP2_HTTP_TEST_H
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif /* HAVE_CONFIG_H */
|
||||||
|
|
||||||
|
void test_nghttp2_http_parse_priority(void);
|
||||||
|
void test_nghttp2_sf_parse_item(void);
|
||||||
|
void test_nghttp2_sf_parse_inner_list(void);
|
||||||
|
|
||||||
|
#endif /* NGHTTP2_HTTP_TEST_H */
|
|
@ -35,6 +35,7 @@
|
||||||
#include "nghttp2_helper.h"
|
#include "nghttp2_helper.h"
|
||||||
#include "nghttp2_test_helper.h"
|
#include "nghttp2_test_helper.h"
|
||||||
#include "nghttp2_priority_spec.h"
|
#include "nghttp2_priority_spec.h"
|
||||||
|
#include "nghttp2_extpri.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t buf[65535];
|
uint8_t buf[65535];
|
||||||
|
@ -1828,6 +1829,67 @@ void test_nghttp2_session_recv_headers_for_closed_stream(void) {
|
||||||
nghttp2_session_del(session);
|
nghttp2_session_del(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_nghttp2_session_recv_headers_with_extpri(void) {
|
||||||
|
nghttp2_session *session;
|
||||||
|
nghttp2_session_callbacks callbacks;
|
||||||
|
nghttp2_nv *nva;
|
||||||
|
size_t nvlen;
|
||||||
|
nghttp2_frame frame;
|
||||||
|
nghttp2_bufs bufs;
|
||||||
|
nghttp2_buf *buf;
|
||||||
|
ssize_t rv;
|
||||||
|
nghttp2_hd_deflater deflater;
|
||||||
|
nghttp2_stream *stream;
|
||||||
|
nghttp2_mem *mem;
|
||||||
|
const nghttp2_nv extpri_reqnv[] = {
|
||||||
|
MAKE_NV(":method", "GET"), MAKE_NV(":path", "/"),
|
||||||
|
MAKE_NV(":scheme", "https"), MAKE_NV(":authority", "localhost"),
|
||||||
|
MAKE_NV("priority", "i,u=2"),
|
||||||
|
};
|
||||||
|
nghttp2_settings_entry iv;
|
||||||
|
|
||||||
|
mem = nghttp2_mem_default();
|
||||||
|
frame_pack_bufs_init(&bufs);
|
||||||
|
|
||||||
|
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||||
|
|
||||||
|
nghttp2_session_server_new(&session, &callbacks, NULL);
|
||||||
|
|
||||||
|
iv.settings_id = NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES;
|
||||||
|
iv.value = 1;
|
||||||
|
|
||||||
|
nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, &iv, 1);
|
||||||
|
|
||||||
|
nghttp2_hd_deflate_init(&deflater, mem);
|
||||||
|
|
||||||
|
nvlen = ARRLEN(extpri_reqnv);
|
||||||
|
nghttp2_nv_array_copy(&nva, extpri_reqnv, nvlen, mem);
|
||||||
|
|
||||||
|
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1,
|
||||||
|
NGHTTP2_HCAT_HEADERS, NULL, nva, nvlen);
|
||||||
|
|
||||||
|
rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == rv);
|
||||||
|
CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
|
||||||
|
|
||||||
|
nghttp2_frame_headers_free(&frame.headers, mem);
|
||||||
|
|
||||||
|
buf = &bufs.head->buf;
|
||||||
|
assert(nghttp2_bufs_len(&bufs) == nghttp2_buf_len(buf));
|
||||||
|
|
||||||
|
rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf));
|
||||||
|
|
||||||
|
stream = nghttp2_session_get_stream(session, 1);
|
||||||
|
|
||||||
|
CU_ASSERT(2 == nghttp2_extpri_uint8_urgency(stream->extpri));
|
||||||
|
CU_ASSERT(1 == nghttp2_extpri_uint8_inc(stream->extpri));
|
||||||
|
|
||||||
|
nghttp2_bufs_free(&bufs);
|
||||||
|
nghttp2_hd_deflate_free(&deflater);
|
||||||
|
nghttp2_session_del(session);
|
||||||
|
}
|
||||||
|
|
||||||
void test_nghttp2_session_server_recv_push_response(void) {
|
void test_nghttp2_session_server_recv_push_response(void) {
|
||||||
nghttp2_session *session;
|
nghttp2_session *session;
|
||||||
nghttp2_session_callbacks callbacks;
|
nghttp2_session_callbacks callbacks;
|
||||||
|
@ -11209,7 +11271,8 @@ void test_nghttp2_session_no_rfc7540_priorities(void) {
|
||||||
mem);
|
mem);
|
||||||
|
|
||||||
CU_ASSERT(0 == nghttp2_session_send(session));
|
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||||
CU_ASSERT(1 == nghttp2_pq_size(&session->ob_data));
|
CU_ASSERT(1 == nghttp2_pq_size(
|
||||||
|
&session->sched[NGHTTP2_EXTPRI_DEFAULT_URGENCY].ob_data));
|
||||||
CU_ASSERT(nghttp2_pq_empty(&session->root.obq));
|
CU_ASSERT(nghttp2_pq_empty(&session->root.obq));
|
||||||
|
|
||||||
nghttp2_session_del(session);
|
nghttp2_session_del(session);
|
||||||
|
|
|
@ -40,6 +40,7 @@ void test_nghttp2_session_recv_headers_with_priority(void);
|
||||||
void test_nghttp2_session_recv_headers_with_padding(void);
|
void test_nghttp2_session_recv_headers_with_padding(void);
|
||||||
void test_nghttp2_session_recv_headers_early_response(void);
|
void test_nghttp2_session_recv_headers_early_response(void);
|
||||||
void test_nghttp2_session_recv_headers_for_closed_stream(void);
|
void test_nghttp2_session_recv_headers_for_closed_stream(void);
|
||||||
|
void test_nghttp2_session_recv_headers_with_extpri(void);
|
||||||
void test_nghttp2_session_server_recv_push_response(void);
|
void test_nghttp2_session_server_recv_push_response(void);
|
||||||
void test_nghttp2_session_recv_premature_headers(void);
|
void test_nghttp2_session_recv_premature_headers(void);
|
||||||
void test_nghttp2_session_recv_unknown_frame(void);
|
void test_nghttp2_session_recv_unknown_frame(void);
|
||||||
|
|
Loading…
Reference in New Issue