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);
for(int i = 0; i < 2; ++i) {
if(next_proto) {
std::string proto(next_proto, next_proto+next_proto_len);
if(sessions_->get_config()->verbose) {
std::string proto(next_proto, next_proto+next_proto_len);
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;
}
break;
@ -1555,7 +1555,7 @@ int HttpServer::run()
{
SSL_CTX *ssl_ctx = nullptr;
std::pair<unsigned char*, size_t> next_proto;
unsigned char proto_list[255];
if(!config_->no_tls) {
ssl_ctx = SSL_CTX_new(SSLv23_server_method());
if(!ssl_ctx) {
@ -1646,11 +1646,13 @@ int HttpServer::run()
verify_callback);
}
proto_list[0] = NGHTTP2_PROTO_VERSION_ID_LEN;
memcpy(&proto_list[1], NGHTTP2_PROTO_VERSION_ID,
NGHTTP2_PROTO_VERSION_ID_LEN);
next_proto.first = proto_list;
next_proto.second = proto_list[0] + 1;
auto proto_list = util::get_default_alpn();
std::pair<unsigned char*, size_t> next_proto(proto_list.data(),
proto_list.size());
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);
#if OPENSSL_VERSION_NUMBER >= 0x10002000L

View File

@ -80,16 +80,11 @@ http2_impl::http2_impl()
{}
namespace {
std::array<unsigned char, NGHTTP2_PROTO_VERSION_ID_LEN + 1>&
std::vector<unsigned char>&
get_alpn_token()
{
static std::array<unsigned char, NGHTTP2_PROTO_VERSION_ID_LEN + 1> 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;
static auto alpn_token = util::get_default_alpn();
return alpn_token;
}
} // namespace

View File

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

View File

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

View File

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

View File

@ -1355,9 +1355,7 @@ int Http2Session::on_connect()
std::string proto(next_proto, next_proto+next_proto_len);
SSLOG(INFO, this) << "Negotiated next protocol: " << proto;
}
if(next_proto_len != NGHTTP2_PROTO_VERSION_ID_LEN ||
memcmp(NGHTTP2_PROTO_VERSION_ID, next_proto,
NGHTTP2_PROTO_VERSION_ID_LEN) != 0) {
if(!util::check_h2_is_selected(next_proto, next_proto_len)) {
return -1;
}
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)
{
unsigned char out[256];
auto ptr = out;
auto end = ptr + sizeof(out);
size_t len = 0;
for(auto proto : protos) {
auto plen = strlen(proto);
auto n = strlen(proto);
if(ptr + plen + 1 > end) {
LOG(FATAL) << "Too long alpn list";
if(n > 255) {
LOG(FATAL) << "Too long ALPN identifier: " << n;
DIE();
}
*ptr = plen;
memcpy(ptr + 1, proto, plen);
ptr += plen + 1;
len += 1 + n;
}
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 {
@ -445,14 +453,9 @@ SSL_CTX* create_ssl_client_context()
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
// 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;
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);
SSL_CTX_set_alpn_protos(ssl_ctx, proto_list.data(), proto_list.size());
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
return ssl_ctx;

View File

@ -36,6 +36,8 @@
#include <cstring>
#include <iostream>
#include <nghttp2/nghttp2.h>
#include "timegm.h"
namespace nghttp2 {
@ -686,6 +688,23 @@ int64_t to_time64(const timeval& tv)
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 nghttp2

View File

@ -31,6 +31,7 @@
#include <getopt.h>
#include <cstring>
#include <cassert>
#include <vector>
#include <string>
#include <algorithm>
@ -470,6 +471,14 @@ bool check_path(const std::string& path);
// unit.
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 nghttp2