From 33879219ff574ab8047845d915320968d80fafdc Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Fri, 6 Feb 2015 21:45:14 +0900 Subject: [PATCH] Refactor ALPN/NPN protocol selection and introduce NGHTTP2_PROTO_ALPN macro --- lib/includes/nghttp2/nghttp2.h | 18 +++++++++++++ lib/nghttp2_npn.c | 43 +++++++++++++++-------------- src/util.cc | 49 +++++++++++----------------------- src/util.h | 12 +++++---- src/util_test.cc | 5 ++-- 5 files changed, 66 insertions(+), 61 deletions(-) diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index 6e5e1bf8..80334d27 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -49,6 +49,24 @@ extern "C" { */ #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 `_. 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 * diff --git a/lib/nghttp2_npn.c b/lib/nghttp2_npn.c index e4978357..a8bdb237 100644 --- a/lib/nghttp2_npn.c +++ b/lib/nghttp2_npn.c @@ -26,29 +26,32 @@ #include +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, const unsigned char *in, unsigned int inlen) { - int http_selected = 0; - unsigned int i = 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; - } - if (in[i] == 8 && i + 1 + in[i] <= inlen && - memcmp(&in[i + 1], "http/1.1", in[i]) == 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 (select_next_protocol(out, outlen, in, inlen, NGHTTP2_PROTO_ALPN, + NGHTTP2_PROTO_ALPN_LEN) == 0) { + return 1; } - if (http_selected) { + if (select_next_protocol(out, outlen, in, inlen, NGHTTP2_HTTP_1_1_ALPN, + NGHTTP2_HTTP_1_1_ALPN_LEN) == 0) { return 0; - } else { - return -1; } + return -1; } diff --git a/src/util.cc b/src/util.cc index f8f255fa..9bcf1d3a 100644 --- a/src/util.cc +++ b/src/util.cc @@ -47,9 +47,6 @@ 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 { 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) { return streq(NGHTTP2_PROTO_VERSION_ID, NGHTTP2_PROTO_VERSION_ID_LEN, proto, 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 { bool select_h2(const unsigned char **out, unsigned char *outlen, - const unsigned char *in, unsigned int inlen, - const unsigned char *target, unsigned int tlen) { - for (auto p = in, end = in + inlen; p < end;) { - auto len = *p++; - if (p + len > end) { - return false; - } - if (len != tlen) { - p += len; - continue; - } - if (memcmp(target, p, tlen) == 0) { - *out = target; - *outlen = tlen; + const unsigned char *in, unsigned int inlen, const char *key, + unsigned int keylen) { + for (auto p = in, end = in + inlen; p + keylen <= end; p += *p + 1) { + if (memcmp(key, p, keylen) == 0) { + *out = p + 1; + *outlen = *p; return true; } - p += len; } 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, const unsigned char *in, unsigned int inlen) { - return select_h2(out, outlen, in, inlen, NGHTTP2_H2_PROTO_ALIAS, - NGHTTP2_H2_PROTO_ALIAS_LEN) || - select_h2( - out, outlen, in, inlen, - reinterpret_cast(NGHTTP2_PROTO_VERSION_ID), - NGHTTP2_PROTO_VERSION_ID_LEN); + return select_h2(out, outlen, in, inlen, NGHTTP2_H2_16_ALPN, + NGHTTP2_H2_16_ALPN_LEN) || + select_h2(out, outlen, in, inlen, NGHTTP2_PROTO_ALPN, + NGHTTP2_PROTO_ALPN_LEN); } std::vector get_default_alpn() { - auto res = std::vector(1 + NGHTTP2_PROTO_VERSION_ID_LEN + 1 + - NGHTTP2_H2_PROTO_ALIAS_LEN); - auto p = res.data(); + auto res = std::vector(NGHTTP2_PROTO_ALPN_LEN + + NGHTTP2_H2_16_ALPN_LEN); + auto p = std::begin(res); - *p++ = NGHTTP2_H2_PROTO_ALIAS_LEN; - memcpy(p, NGHTTP2_H2_PROTO_ALIAS, NGHTTP2_H2_PROTO_ALIAS_LEN); - p += NGHTTP2_H2_PROTO_ALIAS_LEN; - *p++ = NGHTTP2_PROTO_VERSION_ID_LEN; - memcpy(p, NGHTTP2_PROTO_VERSION_ID, NGHTTP2_PROTO_VERSION_ID_LEN); + p = std::copy_n(NGHTTP2_H2_16_ALPN, NGHTTP2_H2_16_ALPN_LEN, p); + p = std::copy_n(NGHTTP2_PROTO_ALPN, NGHTTP2_PROTO_ALPN_LEN, p); return res; } diff --git a/src/util.h b/src/util.h index 186f7673..7b233b8c 100644 --- a/src/util.h +++ b/src/util.h @@ -44,11 +44,13 @@ namespace nghttp2 { -// The additional HTTP/2 protocol ALPN ID we also supports for our -// applications. This will be removed once HTTP/2 specification is -// finalized. -extern const unsigned char NGHTTP2_H2_PROTO_ALIAS[]; -extern size_t NGHTTP2_H2_PROTO_ALIAS_LEN; +// The additional HTTP/2 protocol ALPN protocol identifier we also +// supports for our applications. This will be removed once HTTP/2 +// specification is finalized. +#define NGHTTP2_H2_16_ALPN "\x5h2-16" +#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 { diff --git a/src/util_test.cc b/src/util_test.cc index 05e5dba9..f0871d69 100644 --- a/src/util_test.cc +++ b/src/util_test.cc @@ -160,9 +160,8 @@ void test_util_select_h2(void) { // picked up because it has precedence over the other. const unsigned char t6[] = "\x5h2-14\x5h2-16"; CU_ASSERT(util::select_h2(&out, &outlen, t6, sizeof(t6) - 1)); - CU_ASSERT(memcmp(NGHTTP2_H2_PROTO_ALIAS, out, NGHTTP2_H2_PROTO_ALIAS_LEN) == - 0); - CU_ASSERT(NGHTTP2_H2_PROTO_ALIAS_LEN == outlen); + CU_ASSERT(memcmp(NGHTTP2_H2_16_ID, out, NGHTTP2_H2_16_ID_LEN) == 0); + CU_ASSERT(NGHTTP2_H2_16_ID_LEN == outlen); } void test_util_ipv6_numeric_addr(void) {