Refactor ALPN/NPN protocol selection and introduce NGHTTP2_PROTO_ALPN macro
This commit is contained in:
parent
4956bdc4da
commit
33879219ff
|
@ -49,6 +49,24 @@ extern "C" {
|
||||||
*/
|
*/
|
||||||
#define NGHTTP2_PROTO_VERSION_ID_LEN 5
|
#define NGHTTP2_PROTO_VERSION_ID_LEN 5
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @macro
|
||||||
|
*
|
||||||
|
* The seriazlied form of ALPN protocol identifier this library
|
||||||
|
* supports. Notice that first byte is the length of following
|
||||||
|
* protocol identifier. This is the same wire format of `TLS ALPN
|
||||||
|
* extension <https://tools.ietf.org/html/rfc7301>`_. This is useful
|
||||||
|
* to process incoming ALPN tokens in wire format.
|
||||||
|
*/
|
||||||
|
#define NGHTTP2_PROTO_ALPN "\x5h2-14"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @macro
|
||||||
|
*
|
||||||
|
* The length of :macro:`NGHTTP2_PROTO_ALPN`.
|
||||||
|
*/
|
||||||
|
#define NGHTTP2_PROTO_ALPN_LEN (sizeof(NGHTTP2_PROTO_ALPN) - 1)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @macro
|
* @macro
|
||||||
*
|
*
|
||||||
|
|
|
@ -26,29 +26,32 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
static int select_next_protocol(unsigned char **out, unsigned char *outlen,
|
||||||
|
const unsigned char *in, unsigned int inlen,
|
||||||
|
const char *key, unsigned int keylen) {
|
||||||
|
unsigned int i;
|
||||||
|
for (i = 0; i + keylen <= inlen; i += in [i] + 1) {
|
||||||
|
if (memcmp(&in[i], key, keylen) == 0) {
|
||||||
|
*out = (unsigned char *)&in[i + 1];
|
||||||
|
*outlen = in[i];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NGHTTP2_HTTP_1_1_ALPN "\x8http/1.1"
|
||||||
|
#define NGHTTP2_HTTP_1_1_ALPN_LEN (sizeof(NGHTTP2_HTTP_1_1_ALPN) - 1)
|
||||||
|
|
||||||
int nghttp2_select_next_protocol(unsigned char **out, unsigned char *outlen,
|
int nghttp2_select_next_protocol(unsigned char **out, unsigned char *outlen,
|
||||||
const unsigned char *in, unsigned int inlen) {
|
const unsigned char *in, unsigned int inlen) {
|
||||||
int http_selected = 0;
|
if (select_next_protocol(out, outlen, in, inlen, NGHTTP2_PROTO_ALPN,
|
||||||
unsigned int i = 0;
|
NGHTTP2_PROTO_ALPN_LEN) == 0) {
|
||||||
for (; i < inlen; i += in [i] + 1) {
|
|
||||||
if (in[i] == NGHTTP2_PROTO_VERSION_ID_LEN && i + 1 + in[i] <= inlen &&
|
|
||||||
memcmp(&in[i + 1], NGHTTP2_PROTO_VERSION_ID, in[i]) == 0) {
|
|
||||||
*out = (unsigned char *)&in[i + 1];
|
|
||||||
*outlen = in[i];
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (in[i] == 8 && i + 1 + in[i] <= inlen &&
|
if (select_next_protocol(out, outlen, in, inlen, NGHTTP2_HTTP_1_1_ALPN,
|
||||||
memcmp(&in[i + 1], "http/1.1", in[i]) == 0) {
|
NGHTTP2_HTTP_1_1_ALPN_LEN) == 0) {
|
||||||
http_selected = 1;
|
|
||||||
*out = (unsigned char *)&in[i + 1];
|
|
||||||
*outlen = in[i];
|
|
||||||
/* Go through to the next iteration, because "HTTP/2" may be
|
|
||||||
there */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (http_selected) {
|
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
49
src/util.cc
49
src/util.cc
|
@ -47,9 +47,6 @@
|
||||||
|
|
||||||
namespace nghttp2 {
|
namespace nghttp2 {
|
||||||
|
|
||||||
const unsigned char NGHTTP2_H2_PROTO_ALIAS[] = "h2-16";
|
|
||||||
size_t NGHTTP2_H2_PROTO_ALIAS_LEN = sizeof(NGHTTP2_H2_PROTO_ALIAS) - 1;
|
|
||||||
|
|
||||||
namespace util {
|
namespace util {
|
||||||
|
|
||||||
const char DEFAULT_STRIP_CHARSET[] = "\r\n\t ";
|
const char DEFAULT_STRIP_CHARSET[] = "\r\n\t ";
|
||||||
|
@ -786,28 +783,19 @@ int64_t to_time64(const timeval &tv) {
|
||||||
bool check_h2_is_selected(const unsigned char *proto, size_t len) {
|
bool check_h2_is_selected(const unsigned char *proto, size_t len) {
|
||||||
return streq(NGHTTP2_PROTO_VERSION_ID, NGHTTP2_PROTO_VERSION_ID_LEN, proto,
|
return streq(NGHTTP2_PROTO_VERSION_ID, NGHTTP2_PROTO_VERSION_ID_LEN, proto,
|
||||||
len) ||
|
len) ||
|
||||||
streq(NGHTTP2_H2_PROTO_ALIAS, NGHTTP2_H2_PROTO_ALIAS_LEN, proto, len);
|
streq(NGHTTP2_H2_16_ID, NGHTTP2_H2_16_ID_LEN, proto, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
bool select_h2(const unsigned char **out, unsigned char *outlen,
|
bool select_h2(const unsigned char **out, unsigned char *outlen,
|
||||||
const unsigned char *in, unsigned int inlen,
|
const unsigned char *in, unsigned int inlen, const char *key,
|
||||||
const unsigned char *target, unsigned int tlen) {
|
unsigned int keylen) {
|
||||||
for (auto p = in, end = in + inlen; p < end;) {
|
for (auto p = in, end = in + inlen; p + keylen <= end; p += *p + 1) {
|
||||||
auto len = *p++;
|
if (memcmp(key, p, keylen) == 0) {
|
||||||
if (p + len > end) {
|
*out = p + 1;
|
||||||
return false;
|
*outlen = *p;
|
||||||
}
|
|
||||||
if (len != tlen) {
|
|
||||||
p += len;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (memcmp(target, p, tlen) == 0) {
|
|
||||||
*out = target;
|
|
||||||
*outlen = tlen;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
p += len;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -815,24 +803,19 @@ bool select_h2(const unsigned char **out, unsigned char *outlen,
|
||||||
|
|
||||||
bool select_h2(const unsigned char **out, unsigned char *outlen,
|
bool select_h2(const unsigned char **out, unsigned char *outlen,
|
||||||
const unsigned char *in, unsigned int inlen) {
|
const unsigned char *in, unsigned int inlen) {
|
||||||
return select_h2(out, outlen, in, inlen, NGHTTP2_H2_PROTO_ALIAS,
|
return select_h2(out, outlen, in, inlen, NGHTTP2_H2_16_ALPN,
|
||||||
NGHTTP2_H2_PROTO_ALIAS_LEN) ||
|
NGHTTP2_H2_16_ALPN_LEN) ||
|
||||||
select_h2(
|
select_h2(out, outlen, in, inlen, NGHTTP2_PROTO_ALPN,
|
||||||
out, outlen, in, inlen,
|
NGHTTP2_PROTO_ALPN_LEN);
|
||||||
reinterpret_cast<const unsigned char *>(NGHTTP2_PROTO_VERSION_ID),
|
|
||||||
NGHTTP2_PROTO_VERSION_ID_LEN);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<unsigned char> get_default_alpn() {
|
std::vector<unsigned char> get_default_alpn() {
|
||||||
auto res = std::vector<unsigned char>(1 + NGHTTP2_PROTO_VERSION_ID_LEN + 1 +
|
auto res = std::vector<unsigned char>(NGHTTP2_PROTO_ALPN_LEN +
|
||||||
NGHTTP2_H2_PROTO_ALIAS_LEN);
|
NGHTTP2_H2_16_ALPN_LEN);
|
||||||
auto p = res.data();
|
auto p = std::begin(res);
|
||||||
|
|
||||||
*p++ = NGHTTP2_H2_PROTO_ALIAS_LEN;
|
p = std::copy_n(NGHTTP2_H2_16_ALPN, NGHTTP2_H2_16_ALPN_LEN, p);
|
||||||
memcpy(p, NGHTTP2_H2_PROTO_ALIAS, NGHTTP2_H2_PROTO_ALIAS_LEN);
|
p = std::copy_n(NGHTTP2_PROTO_ALPN, NGHTTP2_PROTO_ALPN_LEN, p);
|
||||||
p += NGHTTP2_H2_PROTO_ALIAS_LEN;
|
|
||||||
*p++ = NGHTTP2_PROTO_VERSION_ID_LEN;
|
|
||||||
memcpy(p, NGHTTP2_PROTO_VERSION_ID, NGHTTP2_PROTO_VERSION_ID_LEN);
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
12
src/util.h
12
src/util.h
|
@ -44,11 +44,13 @@
|
||||||
|
|
||||||
namespace nghttp2 {
|
namespace nghttp2 {
|
||||||
|
|
||||||
// The additional HTTP/2 protocol ALPN ID we also supports for our
|
// The additional HTTP/2 protocol ALPN protocol identifier we also
|
||||||
// applications. This will be removed once HTTP/2 specification is
|
// supports for our applications. This will be removed once HTTP/2
|
||||||
// finalized.
|
// specification is finalized.
|
||||||
extern const unsigned char NGHTTP2_H2_PROTO_ALIAS[];
|
#define NGHTTP2_H2_16_ALPN "\x5h2-16"
|
||||||
extern size_t NGHTTP2_H2_PROTO_ALIAS_LEN;
|
#define NGHTTP2_H2_16_ALPN_LEN (sizeof(NGHTTP2_H2_16_ALPN) - 1)
|
||||||
|
#define NGHTTP2_H2_16_ID "h2-16"
|
||||||
|
#define NGHTTP2_H2_16_ID_LEN (sizeof(NGHTTP2_H2_16_ID) - 1)
|
||||||
|
|
||||||
namespace util {
|
namespace util {
|
||||||
|
|
||||||
|
|
|
@ -160,9 +160,8 @@ void test_util_select_h2(void) {
|
||||||
// picked up because it has precedence over the other.
|
// picked up because it has precedence over the other.
|
||||||
const unsigned char t6[] = "\x5h2-14\x5h2-16";
|
const unsigned char t6[] = "\x5h2-14\x5h2-16";
|
||||||
CU_ASSERT(util::select_h2(&out, &outlen, t6, sizeof(t6) - 1));
|
CU_ASSERT(util::select_h2(&out, &outlen, t6, sizeof(t6) - 1));
|
||||||
CU_ASSERT(memcmp(NGHTTP2_H2_PROTO_ALIAS, out, NGHTTP2_H2_PROTO_ALIAS_LEN) ==
|
CU_ASSERT(memcmp(NGHTTP2_H2_16_ID, out, NGHTTP2_H2_16_ID_LEN) == 0);
|
||||||
0);
|
CU_ASSERT(NGHTTP2_H2_16_ID_LEN == outlen);
|
||||||
CU_ASSERT(NGHTTP2_H2_PROTO_ALIAS_LEN == outlen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_util_ipv6_numeric_addr(void) {
|
void test_util_ipv6_numeric_addr(void) {
|
||||||
|
|
Loading…
Reference in New Issue