src: Refactor code around ALPN setup

This commit is contained in:
Tatsuhiro Tsujikawa 2014-11-14 23:14:39 +09:00
parent 8e30adbca0
commit d98e9a63d0
9 changed files with 68 additions and 49 deletions

View File

@ -593,11 +593,11 @@ int Http2Handler::verify_npn_result()
SSL_get0_next_proto_negotiated(ssl_, &next_proto, &next_proto_len); SSL_get0_next_proto_negotiated(ssl_, &next_proto, &next_proto_len);
for(int i = 0; i < 2; ++i) { for(int i = 0; i < 2; ++i) {
if(next_proto) { if(next_proto) {
std::string proto(next_proto, next_proto+next_proto_len);
if(sessions_->get_config()->verbose) { if(sessions_->get_config()->verbose) {
std::string proto(next_proto, next_proto+next_proto_len);
std::cout << "The negotiated protocol: " << proto << std::endl; std::cout << "The negotiated protocol: " << proto << std::endl;
} }
if(proto == NGHTTP2_PROTO_VERSION_ID) { if(util::check_h2_is_selected(next_proto, next_proto_len)) {
return 0; return 0;
} }
break; break;
@ -1555,7 +1555,7 @@ int HttpServer::run()
{ {
SSL_CTX *ssl_ctx = nullptr; SSL_CTX *ssl_ctx = nullptr;
std::pair<unsigned char*, size_t> next_proto; std::pair<unsigned char*, size_t> next_proto;
unsigned char proto_list[255];
if(!config_->no_tls) { if(!config_->no_tls) {
ssl_ctx = SSL_CTX_new(SSLv23_server_method()); ssl_ctx = SSL_CTX_new(SSLv23_server_method());
if(!ssl_ctx) { if(!ssl_ctx) {
@ -1646,11 +1646,13 @@ int HttpServer::run()
verify_callback); verify_callback);
} }
proto_list[0] = NGHTTP2_PROTO_VERSION_ID_LEN; auto proto_list = util::get_default_alpn();
memcpy(&proto_list[1], NGHTTP2_PROTO_VERSION_ID,
NGHTTP2_PROTO_VERSION_ID_LEN); std::pair<unsigned char*, size_t> next_proto(proto_list.data(),
next_proto.first = proto_list; proto_list.size());
next_proto.second = proto_list[0] + 1;
next_proto.first = proto_list.data();
next_proto.second = proto_list.size();
SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_proto_cb, &next_proto); SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_proto_cb, &next_proto);
#if OPENSSL_VERSION_NUMBER >= 0x10002000L #if OPENSSL_VERSION_NUMBER >= 0x10002000L

View File

@ -80,16 +80,11 @@ http2_impl::http2_impl()
{} {}
namespace { namespace {
std::array<unsigned char, NGHTTP2_PROTO_VERSION_ID_LEN + 1>& std::vector<unsigned char>&
get_alpn_token() get_alpn_token()
{ {
static std::array<unsigned char, NGHTTP2_PROTO_VERSION_ID_LEN + 1> token; static auto alpn_token = util::get_default_alpn();
return alpn_token;
token[0] = NGHTTP2_PROTO_VERSION_ID_LEN;
std::copy(NGHTTP2_PROTO_VERSION_ID,
NGHTTP2_PROTO_VERSION_ID + NGHTTP2_PROTO_VERSION_ID_LEN,
std::begin(token) + 1);
return token;
} }
} // namespace } // namespace

View File

@ -469,8 +469,7 @@ void eventcb(bufferevent *bev, short events, void *ptr)
return; return;
} }
if(next_proto_len == NGHTTP2_PROTO_VERSION_ID_LEN && if(util::check_h2_is_selected(next_proto, next_proto_len)) {
memcmp(NGHTTP2_PROTO_VERSION_ID, next_proto, next_proto_len) == 0) {
client->session = util::make_unique<Http2Session>(client); client->session = util::make_unique<Http2Session>(client);
} else { } else {
#ifdef HAVE_SPDYLAY #ifdef HAVE_SPDYLAY

View File

@ -1632,9 +1632,7 @@ void eventcb(bufferevent *bev, short events, void *ptr)
next_proto_len); next_proto_len);
std::cout << std::endl; std::cout << std::endl;
} }
if(NGHTTP2_PROTO_VERSION_ID_LEN != next_proto_len || if(!util::check_h2_is_selected(next_proto, next_proto_len)) {
memcmp(NGHTTP2_PROTO_VERSION_ID, next_proto,
NGHTTP2_PROTO_VERSION_ID_LEN) != 0) {
next_proto = nullptr; next_proto = nullptr;
} }
break; break;
@ -1739,11 +1737,9 @@ int communicate(const std::string& scheme, const std::string& host,
client_select_next_proto_cb, nullptr); client_select_next_proto_cb, nullptr);
#if OPENSSL_VERSION_NUMBER >= 0x10002000L #if OPENSSL_VERSION_NUMBER >= 0x10002000L
unsigned char proto_list[255]; auto proto_list = util::get_default_alpn();
proto_list[0] = NGHTTP2_PROTO_VERSION_ID_LEN;
memcpy(&proto_list[1], NGHTTP2_PROTO_VERSION_ID, SSL_CTX_set_alpn_protos(ssl_ctx, proto_list.data(), proto_list.size());
NGHTTP2_PROTO_VERSION_ID_LEN);
SSL_CTX_set_alpn_protos(ssl_ctx, proto_list, proto_list[0] + 1);
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L #endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
} }
{ {

View File

@ -301,9 +301,7 @@ int ClientHandler::validate_next_proto()
next_proto, next_proto_len)) { next_proto, next_proto_len)) {
break; break;
} }
if(next_proto_len == NGHTTP2_PROTO_VERSION_ID_LEN && if(util::check_h2_is_selected(next_proto, next_proto_len)) {
memcmp(NGHTTP2_PROTO_VERSION_ID, next_proto,
NGHTTP2_PROTO_VERSION_ID_LEN) == 0) {
set_bev_cb(upstream_http2_connhd_readcb, upstream_writecb, set_bev_cb(upstream_http2_connhd_readcb, upstream_writecb,
upstream_eventcb); upstream_eventcb);

View File

@ -1355,9 +1355,7 @@ int Http2Session::on_connect()
std::string proto(next_proto, next_proto+next_proto_len); std::string proto(next_proto, next_proto+next_proto_len);
SSLOG(INFO, this) << "Negotiated next protocol: " << proto; SSLOG(INFO, this) << "Negotiated next protocol: " << proto;
} }
if(next_proto_len != NGHTTP2_PROTO_VERSION_ID_LEN || if(!util::check_h2_is_selected(next_proto, next_proto_len)) {
memcmp(NGHTTP2_PROTO_VERSION_ID, next_proto,
NGHTTP2_PROTO_VERSION_ID_LEN) != 0) {
return -1; return -1;
} }
break; break;

View File

@ -86,23 +86,31 @@ int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
std::vector<unsigned char> set_alpn_prefs(const std::vector<char*>& protos) std::vector<unsigned char> set_alpn_prefs(const std::vector<char*>& protos)
{ {
unsigned char out[256]; size_t len = 0;
auto ptr = out;
auto end = ptr + sizeof(out);
for(auto proto : protos) { for(auto proto : protos) {
auto plen = strlen(proto); auto n = strlen(proto);
if(ptr + plen + 1 > end) { if(n > 255) {
LOG(FATAL) << "Too long alpn list"; LOG(FATAL) << "Too long ALPN identifier: " << n;
DIE(); DIE();
} }
*ptr = plen; len += 1 + n;
memcpy(ptr + 1, proto, plen);
ptr += plen + 1;
} }
return std::vector<unsigned char>(out, ptr);
auto out = std::vector<unsigned char>(len);
auto ptr = out.data();
for(auto proto : protos) {
auto proto_len = strlen(proto);
*ptr++ = proto_len;
memcpy(ptr, proto, proto_len);
ptr += proto_len;
}
return out;
} }
namespace { namespace {
@ -445,14 +453,9 @@ SSL_CTX* create_ssl_client_context()
#if OPENSSL_VERSION_NUMBER >= 0x10002000L #if OPENSSL_VERSION_NUMBER >= 0x10002000L
// ALPN advertisement; We only advertise HTTP/2 // ALPN advertisement; We only advertise HTTP/2
unsigned char proto_list[256]; auto proto_list = util::get_default_alpn();
proto_list[0] = NGHTTP2_PROTO_VERSION_ID_LEN; SSL_CTX_set_alpn_protos(ssl_ctx, proto_list.data(), proto_list.size());
memcpy(proto_list + 1, NGHTTP2_PROTO_VERSION_ID,
NGHTTP2_PROTO_VERSION_ID_LEN);
auto proto_list_len = 1 + NGHTTP2_PROTO_VERSION_ID_LEN;
SSL_CTX_set_alpn_protos(ssl_ctx, proto_list, proto_list_len);
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L #endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
return ssl_ctx; return ssl_ctx;

View File

@ -36,6 +36,8 @@
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
#include <nghttp2/nghttp2.h>
#include "timegm.h" #include "timegm.h"
namespace nghttp2 { namespace nghttp2 {
@ -686,6 +688,23 @@ int64_t to_time64(const timeval& tv)
return tv.tv_sec * 1000000 + tv.tv_usec; return tv.tv_sec * 1000000 + tv.tv_usec;
} }
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);
}
std::vector<unsigned char> get_default_alpn()
{
auto res = std::vector<unsigned char>(1 + NGHTTP2_PROTO_VERSION_ID_LEN);
auto p = res.data();
*p++ = NGHTTP2_PROTO_VERSION_ID_LEN;
memcpy(p, NGHTTP2_PROTO_VERSION_ID, NGHTTP2_PROTO_VERSION_ID_LEN);
return res;
}
} // namespace util } // namespace util
} // namespace nghttp2 } // namespace nghttp2

View File

@ -31,6 +31,7 @@
#include <getopt.h> #include <getopt.h>
#include <cstring> #include <cstring>
#include <cassert>
#include <vector> #include <vector>
#include <string> #include <string>
#include <algorithm> #include <algorithm>
@ -470,6 +471,14 @@ bool check_path(const std::string& path);
// unit. // unit.
int64_t to_time64(const timeval& tv); int64_t to_time64(const timeval& tv);
// Returns true if ALPN ID |proto| of length |len| is supported HTTP/2
// protocol identifier.
bool check_h2_is_selected(const unsigned char *alpn, size_t len);
// Returns default ALPN protocol list, which only contains supported
// HTTP/2 protocol identifier.
std::vector<unsigned char> get_default_alpn();
} // namespace util } // namespace util
} // namespace nghttp2 } // namespace nghttp2