parent
f0d7323902
commit
78e5149495
|
@ -196,6 +196,7 @@ Http2Handler::~Http2Handler()
|
|||
SSL_shutdown(ssl_);
|
||||
}
|
||||
if(bev_) {
|
||||
bufferevent_disable(bev_, EV_READ | EV_WRITE);
|
||||
bufferevent_free(bev_);
|
||||
}
|
||||
if(ssl_) {
|
||||
|
@ -398,19 +399,30 @@ int Http2Handler::verify_npn_result()
|
|||
{
|
||||
const unsigned char *next_proto = nullptr;
|
||||
unsigned int next_proto_len;
|
||||
// Check the negotiated protocol in NPN or ALPN
|
||||
SSL_get0_next_proto_negotiated(ssl_, &next_proto, &next_proto_len);
|
||||
if(next_proto) {
|
||||
std::string proto(next_proto, next_proto+next_proto_len);
|
||||
if(sessions_->get_config()->verbose) {
|
||||
std::cout << "The negotiated next protocol: " << proto << std::endl;
|
||||
}
|
||||
if(proto == NGHTTP2_PROTO_VERSION_ID) {
|
||||
return 0;
|
||||
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::cout << "The negotiated protocol: " << proto << std::endl;
|
||||
}
|
||||
if(proto == NGHTTP2_PROTO_VERSION_ID) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
SSL_get0_alpn_selected(ssl_, &next_proto, &next_proto_len);
|
||||
#else // OPENSSL_VERSION_NUMBER < 0x10002000L
|
||||
break;
|
||||
#endif // OPENSSL_VERSION_NUMBER < 0x10002000L
|
||||
}
|
||||
}
|
||||
std::cerr << "The negotiated next protocol is not supported."
|
||||
std::cerr << "Client did not advertise HTTP/2.0 protocol."
|
||||
<< " (nghttp2 expects " << NGHTTP2_PROTO_VERSION_ID << ")"
|
||||
<< std::endl;
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Http2Handler::sendcb(const uint8_t *data, size_t len)
|
||||
|
@ -1094,6 +1106,33 @@ int start_listen(event_base *evbase, Sessions *sessions,
|
|||
}
|
||||
} // namespace
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
namespace {
|
||||
int alpn_select_proto_cb(SSL* ssl,
|
||||
const unsigned char **out, unsigned char *outlen,
|
||||
const unsigned char *in, unsigned int inlen,
|
||||
void *arg)
|
||||
{
|
||||
auto config = reinterpret_cast<HttpServer*>(arg)->get_config();
|
||||
if(config->verbose) {
|
||||
std::cout << "[ALPN] client offers:" << std::endl;
|
||||
}
|
||||
if(config->verbose) {
|
||||
for(unsigned int i = 0; i < inlen; i += in[i]+1) {
|
||||
std::cout << " * ";
|
||||
std::cout.write(reinterpret_cast<const char*>(&in[i+1]), in[i]);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
if(nghttp2_select_next_protocol(const_cast<unsigned char**>(out), outlen,
|
||||
in, inlen) <= 0) {
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
}
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
} // namespace
|
||||
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
|
||||
int HttpServer::run()
|
||||
{
|
||||
SSL_CTX *ssl_ctx = nullptr;
|
||||
|
@ -1138,6 +1177,10 @@ int HttpServer::run()
|
|||
next_proto.second = proto_list[0] + 1;
|
||||
|
||||
SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_proto_cb, &next_proto);
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
// ALPN selection callback
|
||||
SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, this);
|
||||
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
}
|
||||
|
||||
auto evbase = event_base_new();
|
||||
|
@ -1152,4 +1195,9 @@ int HttpServer::run()
|
|||
return 0;
|
||||
}
|
||||
|
||||
const Config* HttpServer::get_config() const
|
||||
{
|
||||
return config_;
|
||||
}
|
||||
|
||||
} // namespace nghttp2
|
||||
|
|
|
@ -137,6 +137,7 @@ public:
|
|||
HttpServer(const Config* config);
|
||||
int listen();
|
||||
int run();
|
||||
const Config* get_config() const;
|
||||
private:
|
||||
const Config *config_;
|
||||
};
|
||||
|
|
|
@ -1223,6 +1223,15 @@ void print_stats(const HttpClient& client)
|
|||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void print_protocol_nego_error()
|
||||
{
|
||||
std::cerr << "Server did not select HTTP/2.0 protocol."
|
||||
<< " (nghttp2 expects " << NGHTTP2_PROTO_VERSION_ID << ")"
|
||||
<< std::endl;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int client_select_next_proto_cb(SSL* ssl,
|
||||
unsigned char **out, unsigned char *outlen,
|
||||
|
@ -1231,8 +1240,7 @@ int client_select_next_proto_cb(SSL* ssl,
|
|||
{
|
||||
if(config.verbose) {
|
||||
print_timer();
|
||||
std::cout << " NPN select next protocol: the remote server offers:"
|
||||
<< std::endl;
|
||||
std::cout << "[NPN] server offers:" << std::endl;
|
||||
}
|
||||
for(unsigned int i = 0; i < inlen; i += in[i]+1) {
|
||||
if(config.verbose) {
|
||||
|
@ -1242,15 +1250,8 @@ int client_select_next_proto_cb(SSL* ssl,
|
|||
}
|
||||
}
|
||||
if(nghttp2_select_next_protocol(out, outlen, in, inlen) <= 0) {
|
||||
std::cerr << "Server did not advertise HTTP/2.0 protocol."
|
||||
<< " (nghttp2 expects " << NGHTTP2_PROTO_VERSION_ID << ")"
|
||||
<< std::endl;
|
||||
} else {
|
||||
if(config.verbose) {
|
||||
std::cout << " NPN selected the protocol: ";
|
||||
std::cout.write(reinterpret_cast<const char*>(*out), (size_t)*outlen);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
print_protocol_nego_error();
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
}
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
|
@ -1312,7 +1313,37 @@ void eventcb(bufferevent *bev, short events, void *ptr)
|
|||
if(client->need_upgrade()) {
|
||||
rv = client->on_upgrade_connect();
|
||||
} else {
|
||||
// TODO Check NPN result and fail fast?
|
||||
// Check NPN or ALPN result
|
||||
const unsigned char *next_proto = nullptr;
|
||||
unsigned int next_proto_len;
|
||||
SSL_get0_next_proto_negotiated(client->ssl,
|
||||
&next_proto, &next_proto_len);
|
||||
for(int i = 0; i < 2; ++i) {
|
||||
if(next_proto) {
|
||||
if(config.verbose) {
|
||||
std::cout << "The negotiated protocol: ";
|
||||
std::cout.write(reinterpret_cast<const char*>(next_proto),
|
||||
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) {
|
||||
next_proto = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
SSL_get0_alpn_selected(client->ssl, &next_proto, &next_proto_len);
|
||||
#else // OPENSSL_VERSION_NUMBER < 0x10002000L
|
||||
break;
|
||||
#endif // OPENSSL_VERSION_NUMBER < 0x10002000L
|
||||
}
|
||||
if(!next_proto) {
|
||||
print_protocol_nego_error();
|
||||
client->disconnect();
|
||||
return;
|
||||
}
|
||||
rv = client->on_connect();
|
||||
}
|
||||
if(rv != 0) {
|
||||
|
@ -1404,6 +1435,14 @@ int communicate(const std::string& scheme, const std::string& host,
|
|||
}
|
||||
SSL_CTX_set_next_proto_select_cb(ssl_ctx,
|
||||
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);
|
||||
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
}
|
||||
{
|
||||
HttpClient client{callbacks, evbase, ssl_ctx};
|
||||
|
|
|
@ -299,26 +299,37 @@ int ClientHandler::validate_next_proto()
|
|||
// First set callback for catch all cases
|
||||
set_bev_cb(upstream_readcb, upstream_writecb, upstream_eventcb);
|
||||
SSL_get0_next_proto_negotiated(ssl_, &next_proto, &next_proto_len);
|
||||
if(next_proto) {
|
||||
std::string proto(next_proto, next_proto+next_proto_len);
|
||||
if(LOG_ENABLED(INFO)) {
|
||||
CLOG(INFO, this) << "The negotiated next protocol: " << proto;
|
||||
}
|
||||
if(proto == NGHTTP2_PROTO_VERSION_ID) {
|
||||
set_bev_cb(upstream_http2_connhd_readcb, upstream_writecb,
|
||||
upstream_eventcb);
|
||||
upstream_ = util::make_unique<Http2Upstream>(this);
|
||||
return 0;
|
||||
} else {
|
||||
#ifdef HAVE_SPDYLAY
|
||||
uint16_t version = spdylay_npn_get_version(next_proto, next_proto_len);
|
||||
if(version) {
|
||||
upstream_ = util::make_unique<SpdyUpstream>(version, this);
|
||||
return 0;
|
||||
for(int i = 0; i < 2; ++i) {
|
||||
if(next_proto) {
|
||||
if(LOG_ENABLED(INFO)) {
|
||||
std::string proto(next_proto, next_proto+next_proto_len);
|
||||
CLOG(INFO, this) << "The 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) {
|
||||
set_bev_cb(upstream_http2_connhd_readcb, upstream_writecb,
|
||||
upstream_eventcb);
|
||||
upstream_ = util::make_unique<Http2Upstream>(this);
|
||||
return 0;
|
||||
} else {
|
||||
#ifdef HAVE_SPDYLAY
|
||||
uint16_t version = spdylay_npn_get_version(next_proto, next_proto_len);
|
||||
if(version) {
|
||||
upstream_ = util::make_unique<SpdyUpstream>(version, this);
|
||||
return 0;
|
||||
}
|
||||
#endif // HAVE_SPDYLAY
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
SSL_get0_alpn_selected(ssl_, &next_proto, &next_proto_len);
|
||||
#else // OPENSSL_VERSION_NUMBER < 0x10002000L
|
||||
break;
|
||||
#endif // OPENSSL_VERSION_NUMBER < 0x10002000L
|
||||
}
|
||||
if(!next_proto) {
|
||||
if(LOG_ENABLED(INFO)) {
|
||||
CLOG(INFO, this) << "No proto negotiated.";
|
||||
}
|
||||
|
|
|
@ -1120,15 +1120,30 @@ int on_unknown_frame_recv_callback(nghttp2_session *session,
|
|||
int Http2Session::on_connect()
|
||||
{
|
||||
int rv;
|
||||
const unsigned char *next_proto = nullptr;
|
||||
unsigned int next_proto_len;
|
||||
if(ssl_ctx_) {
|
||||
const unsigned char *next_proto = nullptr;
|
||||
unsigned int next_proto_len;
|
||||
SSL_get0_next_proto_negotiated(ssl_, &next_proto, &next_proto_len);
|
||||
std::string proto(next_proto, next_proto+next_proto_len);
|
||||
if(LOG_ENABLED(INFO)) {
|
||||
SSLOG(INFO, this) << "Negotiated next protocol: " << proto;
|
||||
for(int i = 0; i < 2; ++i) {
|
||||
if(next_proto) {
|
||||
if(LOG_ENABLED(INFO)) {
|
||||
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) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
SSL_get0_alpn_selected(ssl_, &next_proto, &next_proto_len);
|
||||
#else // OPENSSL_VERSION_NUMBER < 0x10002000L
|
||||
break;
|
||||
#endif // OPENSSL_VERSION_NUMBER < 0x10002000L
|
||||
}
|
||||
if(proto != NGHTTP2_PROTO_VERSION_ID) {
|
||||
if(!next_proto) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -132,6 +132,23 @@ int servername_callback(SSL *ssl, int *al, void *arg)
|
|||
}
|
||||
} // namespace
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
namespace {
|
||||
int alpn_select_proto_cb(SSL* ssl,
|
||||
const unsigned char **out,
|
||||
unsigned char *outlen,
|
||||
const unsigned char *in, unsigned int inlen,
|
||||
void *arg)
|
||||
{
|
||||
if(nghttp2_select_next_protocol
|
||||
(const_cast<unsigned char**>(out), outlen, in, inlen) == -1) {
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
}
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
} // namespace
|
||||
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
|
||||
SSL_CTX* create_ssl_context(const char *private_key_file,
|
||||
const char *cert_file)
|
||||
{
|
||||
|
@ -241,11 +258,16 @@ SSL_CTX* create_ssl_context(const char *private_key_file,
|
|||
}
|
||||
SSL_CTX_set_tlsext_servername_callback(ssl_ctx, servername_callback);
|
||||
|
||||
// NPN advertisement
|
||||
auto proto_list_len = set_npn_prefs(proto_list, get_config()->npn_list,
|
||||
get_config()->npn_list_len);
|
||||
next_proto.first = proto_list;
|
||||
next_proto.second = proto_list_len;
|
||||
SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_proto_cb, &next_proto);
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
// ALPN selection callback
|
||||
SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, nullptr);
|
||||
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
return ssl_ctx;
|
||||
}
|
||||
|
||||
|
@ -322,8 +344,18 @@ SSL_CTX* create_ssl_client_context()
|
|||
DIE();
|
||||
}
|
||||
}
|
||||
|
||||
// NPN selection callback
|
||||
SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, nullptr);
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
// ALPN advertisement
|
||||
auto proto_list_len = set_npn_prefs(proto_list, get_config()->npn_list,
|
||||
get_config()->npn_list_len);
|
||||
next_proto.first = proto_list;
|
||||
next_proto.second = proto_list_len;
|
||||
SSL_CTX_set_alpn_protos(ssl_ctx, proto_list, proto_list[0] + 1);
|
||||
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
|
||||
return ssl_ctx;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue