nghttpd: Use faster request header handling
This commit is contained in:
parent
aaf0dc825d
commit
8e3406ad20
|
@ -0,0 +1,88 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
HEADERS = [
|
||||||
|
':authority',
|
||||||
|
':method',
|
||||||
|
':path',
|
||||||
|
':scheme',
|
||||||
|
# disallowed h1 headers
|
||||||
|
'connection',
|
||||||
|
'expect',
|
||||||
|
'host',
|
||||||
|
'if-modified-since',
|
||||||
|
'keep-alive',
|
||||||
|
'proxy-connection',
|
||||||
|
'te',
|
||||||
|
'transfer-encoding',
|
||||||
|
'upgrade'
|
||||||
|
]
|
||||||
|
|
||||||
|
def to_enum_hd(k):
|
||||||
|
res = 'HD_'
|
||||||
|
for c in k.upper():
|
||||||
|
if c == ':':
|
||||||
|
continue
|
||||||
|
if c == '-':
|
||||||
|
res += '_'
|
||||||
|
continue
|
||||||
|
res += c
|
||||||
|
return res
|
||||||
|
|
||||||
|
def build_header(headers):
|
||||||
|
res = {}
|
||||||
|
for k in headers:
|
||||||
|
size = len(k)
|
||||||
|
if size not in res:
|
||||||
|
res[size] = {}
|
||||||
|
ent = res[size]
|
||||||
|
c = k[-1]
|
||||||
|
if c not in ent:
|
||||||
|
ent[c] = []
|
||||||
|
ent[c].append(k)
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
def gen_enum():
|
||||||
|
print '''\
|
||||||
|
enum {'''
|
||||||
|
for k in sorted(HEADERS):
|
||||||
|
print '''\
|
||||||
|
{},'''.format(to_enum_hd(k))
|
||||||
|
print '''\
|
||||||
|
HD_MAXIDX,
|
||||||
|
};'''
|
||||||
|
|
||||||
|
def gen_index_header():
|
||||||
|
print '''\
|
||||||
|
void index_header(int *hdidx, const uint8_t *s, size_t len, size_t idx) {
|
||||||
|
switch (len) {'''
|
||||||
|
b = build_header(HEADERS)
|
||||||
|
for size in sorted(b.keys()):
|
||||||
|
ents = b[size]
|
||||||
|
print '''\
|
||||||
|
case {}:'''.format(size)
|
||||||
|
print '''\
|
||||||
|
switch (util::lowcase(s[len - 1])) {'''
|
||||||
|
for c in sorted(ents.keys()):
|
||||||
|
headers = sorted(ents[c])
|
||||||
|
print '''\
|
||||||
|
case '{}':'''.format(c)
|
||||||
|
for k in headers:
|
||||||
|
print '''\
|
||||||
|
if (util::strieq("{}", s, {})) {{
|
||||||
|
hdidx[{}] = idx;
|
||||||
|
return;
|
||||||
|
}}'''.format(k[:-1], size - 1, to_enum_hd(k))
|
||||||
|
print '''\
|
||||||
|
break;'''
|
||||||
|
print '''\
|
||||||
|
}
|
||||||
|
break;'''
|
||||||
|
print '''\
|
||||||
|
}
|
||||||
|
}'''
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
gen_enum()
|
||||||
|
print ''
|
||||||
|
gen_index_header()
|
|
@ -89,7 +89,9 @@ void print_session_id(int64_t id) { std::cout << "[id=" << id << "] "; }
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void append_nv(Stream *stream, const std::vector<nghttp2_nv> &nva) {
|
void append_nv(Stream *stream, const std::vector<nghttp2_nv> &nva) {
|
||||||
|
size_t idx = 0;
|
||||||
for (auto &nv : nva) {
|
for (auto &nv : nva) {
|
||||||
|
http2::index_header(stream->hdidx, nv.name, nv.namelen, idx++);
|
||||||
http2::add_header(stream->headers, nv.name, nv.namelen, nv.value,
|
http2::add_header(stream->headers, nv.name, nv.namelen, nv.value,
|
||||||
nv.valuelen, nv.flags & NGHTTP2_NV_FLAG_NO_INDEX);
|
nv.valuelen, nv.flags & NGHTTP2_NV_FLAG_NO_INDEX);
|
||||||
}
|
}
|
||||||
|
@ -270,6 +272,8 @@ Stream::Stream(Http2Handler *handler, int32_t stream_id)
|
||||||
wtimer.data = this;
|
wtimer.data = this;
|
||||||
|
|
||||||
headers.reserve(10);
|
headers.reserve(10);
|
||||||
|
|
||||||
|
http2::init_hdidx(hdidx);
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream::~Stream() {
|
Stream::~Stream() {
|
||||||
|
@ -734,13 +738,12 @@ int Http2Handler::submit_non_final_response(const std::string &status,
|
||||||
|
|
||||||
int Http2Handler::submit_push_promise(Stream *stream,
|
int Http2Handler::submit_push_promise(Stream *stream,
|
||||||
const std::string &push_path) {
|
const std::string &push_path) {
|
||||||
auto itr =
|
auto authority =
|
||||||
std::lower_bound(std::begin(stream->headers), std::end(stream->headers),
|
http2::get_header(stream->hdidx, http2::HD_AUTHORITY, stream->headers);
|
||||||
Header(":authority", ""));
|
|
||||||
|
|
||||||
if (itr == std::end(stream->headers) || (*itr).name != ":authority") {
|
if (!authority) {
|
||||||
itr = std::lower_bound(std::begin(stream->headers),
|
authority =
|
||||||
std::end(stream->headers), Header("host", ""));
|
http2::get_header(stream->hdidx, http2::HD_HOST, stream->headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto nva = std::vector<nghttp2_nv>{
|
auto nva = std::vector<nghttp2_nv>{
|
||||||
|
@ -748,7 +751,7 @@ int Http2Handler::submit_push_promise(Stream *stream,
|
||||||
http2::make_nv_ls(":path", push_path),
|
http2::make_nv_ls(":path", push_path),
|
||||||
get_config()->no_tls ? http2::make_nv_ll(":scheme", "http")
|
get_config()->no_tls ? http2::make_nv_ll(":scheme", "http")
|
||||||
: http2::make_nv_ll(":scheme", "https"),
|
: http2::make_nv_ll(":scheme", "https"),
|
||||||
http2::make_nv_ls(":authority", (*itr).value)};
|
http2::make_nv_ls(":authority", authority->value)};
|
||||||
|
|
||||||
auto promised_stream_id = nghttp2_submit_push_promise(
|
auto promised_stream_id = nghttp2_submit_push_promise(
|
||||||
session_, NGHTTP2_FLAG_END_HEADERS, stream->stream_id, nva.data(),
|
session_, NGHTTP2_FLAG_END_HEADERS, stream->stream_id, nva.data(),
|
||||||
|
@ -896,10 +899,13 @@ namespace {
|
||||||
void prepare_redirect_response(Stream *stream, Http2Handler *hd,
|
void prepare_redirect_response(Stream *stream, Http2Handler *hd,
|
||||||
const std::string &path,
|
const std::string &path,
|
||||||
const std::string &status) {
|
const std::string &status) {
|
||||||
auto scheme = http2::get_unique_header(stream->headers, ":scheme");
|
auto scheme =
|
||||||
auto authority = http2::get_unique_header(stream->headers, ":authority");
|
http2::get_header(stream->hdidx, http2::HD_SCHEME, stream->headers);
|
||||||
|
auto authority =
|
||||||
|
http2::get_header(stream->hdidx, http2::HD_AUTHORITY, stream->headers);
|
||||||
if (!authority) {
|
if (!authority) {
|
||||||
authority = http2::get_unique_header(stream->headers, "host");
|
authority =
|
||||||
|
http2::get_header(stream->hdidx, http2::HD_HOST, stream->headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto redirect_url = scheme->value;
|
auto redirect_url = scheme->value;
|
||||||
|
@ -918,17 +924,15 @@ void prepare_response(Stream *stream, Http2Handler *hd,
|
||||||
bool allow_push = true) {
|
bool allow_push = true) {
|
||||||
int rv;
|
int rv;
|
||||||
auto reqpath =
|
auto reqpath =
|
||||||
(*std::lower_bound(std::begin(stream->headers), std::end(stream->headers),
|
http2::get_header(stream->hdidx, http2::HD_PATH, stream->headers)->value;
|
||||||
Header(":path", ""))).value;
|
|
||||||
auto ims =
|
auto ims =
|
||||||
std::lower_bound(std::begin(stream->headers), std::end(stream->headers),
|
get_header(stream->hdidx, http2::HD_IF_MODIFIED_SINCE, stream->headers);
|
||||||
Header("if-modified-since", ""));
|
|
||||||
|
|
||||||
time_t last_mod = 0;
|
time_t last_mod = 0;
|
||||||
bool last_mod_found = false;
|
bool last_mod_found = false;
|
||||||
if (ims != std::end(stream->headers) && (*ims).name == "if-modified-since") {
|
if (ims) {
|
||||||
last_mod_found = true;
|
last_mod_found = true;
|
||||||
last_mod = util::parse_http_date((*ims).value);
|
last_mod = util::parse_http_date(ims->value);
|
||||||
}
|
}
|
||||||
auto query_pos = reqpath.find("?");
|
auto query_pos = reqpath.find("?");
|
||||||
std::string url;
|
std::string url;
|
||||||
|
@ -1011,10 +1015,6 @@ void prepare_response(Stream *stream, Http2Handler *hd,
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
|
||||||
const char *REQUIRED_HEADERS[] = {":method", ":path", ":scheme", nullptr};
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||||
const uint8_t *name, size_t namelen,
|
const uint8_t *name, size_t namelen,
|
||||||
|
@ -1041,7 +1041,8 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||||
if (namelen > 0 && name[0] == ':') {
|
if (namelen > 0 && name[0] == ':') {
|
||||||
if ((!stream->headers.empty() &&
|
if ((!stream->headers.empty() &&
|
||||||
stream->headers.back().name.c_str()[0] != ':') ||
|
stream->headers.back().name.c_str()[0] != ':') ||
|
||||||
!http2::check_http2_request_pseudo_header(name, namelen)) {
|
!http2::check_http2_request_pseudo_header(stream->hdidx, name,
|
||||||
|
namelen)) {
|
||||||
|
|
||||||
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, frame->hd.stream_id,
|
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, frame->hd.stream_id,
|
||||||
NGHTTP2_PROTOCOL_ERROR);
|
NGHTTP2_PROTOCOL_ERROR);
|
||||||
|
@ -1049,6 +1050,8 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
http2::index_header(stream->hdidx, name, namelen, stream->headers.size());
|
||||||
|
|
||||||
http2::add_header(stream->headers, name, namelen, value, valuelen,
|
http2::add_header(stream->headers, name, namelen, value, valuelen,
|
||||||
flags & NGHTTP2_NV_FLAG_NO_INDEX);
|
flags & NGHTTP2_NV_FLAG_NO_INDEX);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1110,27 +1113,13 @@ int hd_on_frame_recv_callback(nghttp2_session *session,
|
||||||
|
|
||||||
if (frame->headers.cat == NGHTTP2_HCAT_REQUEST) {
|
if (frame->headers.cat == NGHTTP2_HCAT_REQUEST) {
|
||||||
|
|
||||||
http2::normalize_headers(stream->headers);
|
if (!http2::check_http2_request_headers(stream->hdidx)) {
|
||||||
if (!http2::check_http2_request_headers(stream->headers)) {
|
|
||||||
hd->submit_rst_stream(stream, NGHTTP2_PROTOCOL_ERROR);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
for (size_t i = 0; REQUIRED_HEADERS[i]; ++i) {
|
|
||||||
if (!http2::get_unique_header(stream->headers, REQUIRED_HEADERS[i])) {
|
|
||||||
hd->submit_rst_stream(stream, NGHTTP2_PROTOCOL_ERROR);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// intermediary translating from HTTP/1 request to HTTP/2 may
|
|
||||||
// not produce :authority header field. In this case, it should
|
|
||||||
// provide host HTTP/1.1 header field.
|
|
||||||
if (!http2::get_unique_header(stream->headers, ":authority") &&
|
|
||||||
!http2::get_unique_header(stream->headers, "host")) {
|
|
||||||
hd->submit_rst_stream(stream, NGHTTP2_PROTOCOL_ERROR);
|
hd->submit_rst_stream(stream, NGHTTP2_PROTOCOL_ERROR);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto expect100 = http2::get_header(stream->headers, "expect");
|
auto expect100 =
|
||||||
|
http2::get_header(stream->hdidx, http2::HD_EXPECT, stream->headers);
|
||||||
|
|
||||||
if (expect100 && util::strieq("100-continue", expect100->value.c_str())) {
|
if (expect100 && util::strieq("100-continue", expect100->value.c_str())) {
|
||||||
hd->submit_non_final_response("100", frame->hd.stream_id);
|
hd->submit_non_final_response("100", frame->hd.stream_id);
|
||||||
|
|
|
@ -83,6 +83,7 @@ struct Stream {
|
||||||
int64_t body_left;
|
int64_t body_left;
|
||||||
int32_t stream_id;
|
int32_t stream_id;
|
||||||
int file;
|
int file;
|
||||||
|
int hdidx[http2::HD_MAXIDX];
|
||||||
Stream(Http2Handler *handler, int32_t stream_id);
|
Stream(Http2Handler *handler, int32_t stream_id);
|
||||||
~Stream();
|
~Stream();
|
||||||
};
|
};
|
||||||
|
|
198
src/http2.cc
198
src/http2.cc
|
@ -572,6 +572,204 @@ int parse_http_status_code(const std::string &src) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void init_hdidx(int *hdidx) { memset(hdidx, -1, sizeof(hdidx[0]) * HD_MAXIDX); }
|
||||||
|
|
||||||
|
// This function was generated by genheaderfunc.py. Inspired by h2o
|
||||||
|
// header lookup. https://github.com/h2o/h2o
|
||||||
|
void index_header(int *hdidx, const uint8_t *s, size_t len, size_t idx) {
|
||||||
|
switch (len) {
|
||||||
|
case 2:
|
||||||
|
switch (util::lowcase(s[len - 1])) {
|
||||||
|
case 'e':
|
||||||
|
if (util::strieq("t", s, 1)) {
|
||||||
|
hdidx[HD_TE] = idx;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
switch (util::lowcase(s[len - 1])) {
|
||||||
|
case 't':
|
||||||
|
if (util::strieq("hos", s, 3)) {
|
||||||
|
hdidx[HD_HOST] = idx;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
switch (util::lowcase(s[len - 1])) {
|
||||||
|
case 'h':
|
||||||
|
if (util::strieq(":pat", s, 4)) {
|
||||||
|
hdidx[HD_PATH] = idx;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
switch (util::lowcase(s[len - 1])) {
|
||||||
|
case 't':
|
||||||
|
if (util::strieq("expec", s, 5)) {
|
||||||
|
hdidx[HD_EXPECT] = idx;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
switch (util::lowcase(s[len - 1])) {
|
||||||
|
case 'd':
|
||||||
|
if (util::strieq(":metho", s, 6)) {
|
||||||
|
hdidx[HD_METHOD] = idx;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
if (util::strieq(":schem", s, 6)) {
|
||||||
|
hdidx[HD_SCHEME] = idx;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (util::strieq("upgrad", s, 6)) {
|
||||||
|
hdidx[HD_UPGRADE] = idx;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
switch (util::lowcase(s[len - 1])) {
|
||||||
|
case 'e':
|
||||||
|
if (util::strieq("keep-aliv", s, 9)) {
|
||||||
|
hdidx[HD_KEEP_ALIVE] = idx;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
if (util::strieq("connectio", s, 9)) {
|
||||||
|
hdidx[HD_CONNECTION] = idx;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'y':
|
||||||
|
if (util::strieq(":authorit", s, 9)) {
|
||||||
|
hdidx[HD_AUTHORITY] = idx;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
switch (util::lowcase(s[len - 1])) {
|
||||||
|
case 'n':
|
||||||
|
if (util::strieq("proxy-connectio", s, 15)) {
|
||||||
|
hdidx[HD_PROXY_CONNECTION] = idx;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 17:
|
||||||
|
switch (util::lowcase(s[len - 1])) {
|
||||||
|
case 'e':
|
||||||
|
if (util::strieq("if-modified-sinc", s, 16)) {
|
||||||
|
hdidx[HD_IF_MODIFIED_SINCE] = idx;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'g':
|
||||||
|
if (util::strieq("transfer-encodin", s, 16)) {
|
||||||
|
hdidx[HD_TRANSFER_ENCODING] = idx;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool check_http2_request_pseudo_header(int *hdidx, const uint8_t *s,
|
||||||
|
size_t len) {
|
||||||
|
switch (len) {
|
||||||
|
case 5:
|
||||||
|
switch (util::lowcase(s[len - 1])) {
|
||||||
|
case 'h':
|
||||||
|
if (util::strieq(":pat", s, 4)) {
|
||||||
|
if (hdidx[HD_PATH] != -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
switch (util::lowcase(s[len - 1])) {
|
||||||
|
case 'd':
|
||||||
|
if (util::strieq(":metho", s, 6)) {
|
||||||
|
if (hdidx[HD_METHOD] != -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
if (util::strieq(":schem", s, 6)) {
|
||||||
|
if (hdidx[HD_SCHEME] != -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
switch (util::lowcase(s[len - 1])) {
|
||||||
|
case 'y':
|
||||||
|
if (util::strieq(":authorit", s, 9)) {
|
||||||
|
if (hdidx[HD_AUTHORITY] != -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool check_http2_headers(int *hdidx) {
|
||||||
|
if (hdidx[HD_CONNECTION] != -1 || hdidx[HD_KEEP_ALIVE] != -1 ||
|
||||||
|
hdidx[HD_PROXY_CONNECTION] != -1 || hdidx[HD_TE] != -1 ||
|
||||||
|
hdidx[HD_TRANSFER_ENCODING] != -1 || hdidx[HD_UPGRADE] != -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool check_http2_request_headers(int *hdidx) {
|
||||||
|
if (!check_http2_headers(hdidx)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (hdidx[HD_METHOD] == -1 || hdidx[HD_PATH] == -1 ||
|
||||||
|
hdidx[HD_SCHEME] == -1 ||
|
||||||
|
(hdidx[HD_AUTHORITY] == -1 && hdidx[HD_HOST] == -1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Headers::value_type *get_header(int *hdidx, int hdkey,
|
||||||
|
const Headers &nva) {
|
||||||
|
auto i = hdidx[hdkey];
|
||||||
|
if (i == -1) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return &nva[i];
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace http2
|
} // namespace http2
|
||||||
|
|
||||||
} // namespace nghttp2
|
} // namespace nghttp2
|
||||||
|
|
39
src/http2.h
39
src/http2.h
|
@ -218,6 +218,45 @@ int check_nv(const uint8_t *name, size_t namelen, const uint8_t *value,
|
||||||
// Returns parsed HTTP status code. Returns -1 on failure.
|
// Returns parsed HTTP status code. Returns -1 on failure.
|
||||||
int parse_http_status_code(const std::string &src);
|
int parse_http_status_code(const std::string &src);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
HD_AUTHORITY,
|
||||||
|
HD_METHOD,
|
||||||
|
HD_PATH,
|
||||||
|
HD_SCHEME,
|
||||||
|
HD_CONNECTION,
|
||||||
|
HD_EXPECT,
|
||||||
|
HD_HOST,
|
||||||
|
HD_IF_MODIFIED_SINCE,
|
||||||
|
HD_KEEP_ALIVE,
|
||||||
|
HD_PROXY_CONNECTION,
|
||||||
|
HD_TE,
|
||||||
|
HD_TRANSFER_ENCODING,
|
||||||
|
HD_UPGRADE,
|
||||||
|
HD_MAXIDX,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initializes |hdidx|, header index. The |hdidx| must point to the
|
||||||
|
// array containing at least HD_MAXIDX elements.
|
||||||
|
void init_hdidx(int *hdidx);
|
||||||
|
// Indexes header |name| of length |namelen| using index |idx|.
|
||||||
|
void index_header(int *hdidx, const uint8_t *name, size_t namelen, size_t idx);
|
||||||
|
|
||||||
|
// Checks pseudo header |name| of length |namelen| are unique and
|
||||||
|
// allowed for HTTP/2 request.
|
||||||
|
bool check_http2_request_pseudo_header(int *hdidx, const uint8_t *name,
|
||||||
|
size_t namelen);
|
||||||
|
|
||||||
|
// Checks |hdidx| does not contain disallowed headers.
|
||||||
|
bool check_http2_headers(int *hdidx);
|
||||||
|
// Checks |hdidx| does not contain disallowed headers and contains
|
||||||
|
// mandatory headers. This funtions internally calls
|
||||||
|
// check_http2_headers().
|
||||||
|
bool check_http2_request_headers(int *hdidx);
|
||||||
|
|
||||||
|
// Returns header denoted by |hdkey| using index |hdidx|.
|
||||||
|
const Headers::value_type *get_header(int *hdidx, int hdkey,
|
||||||
|
const Headers &nva);
|
||||||
|
|
||||||
} // namespace http2
|
} // namespace http2
|
||||||
|
|
||||||
} // namespace nghttp2
|
} // namespace nghttp2
|
||||||
|
|
Loading…
Reference in New Issue