nghttpx: Move downstream proto to DownstreamAddrGroup

This commit is contained in:
Tatsuhiro Tsujikawa 2016-02-28 16:56:14 +09:00
parent e7601cde8a
commit 1832f78684
15 changed files with 85 additions and 49 deletions

View File

@ -2067,13 +2067,15 @@ void process_options(
upstreamconf.no_tls = true; upstreamconf.no_tls = true;
} }
shrpx_proto default_proto;
if (get_config()->client_mode || get_config()->http2_bridge) { if (get_config()->client_mode || get_config()->http2_bridge) {
downstreamconf.proto = PROTO_HTTP2; default_proto = PROTO_HTTP2;
} else { } else {
downstreamconf.proto = PROTO_HTTP; default_proto = PROTO_HTTP1;
} }
if (downstreamconf.proto == PROTO_HTTP && !downstreamconf.http1_tls) { if (!get_config()->client_mode && !get_config()->http2_bridge &&
!downstreamconf.http1_tls) {
downstreamconf.no_tls = true; downstreamconf.no_tls = true;
} }
@ -2102,6 +2104,7 @@ void process_options(
addr.port = DEFAULT_DOWNSTREAM_PORT; addr.port = DEFAULT_DOWNSTREAM_PORT;
DownstreamAddrGroupConfig g(StringRef::from_lit("/")); DownstreamAddrGroupConfig g(StringRef::from_lit("/"));
g.proto = default_proto;
g.addrs.push_back(std::move(addr)); g.addrs.push_back(std::move(addr));
mod_config()->router.add_route(StringRef{g.pattern}, addr_groups.size()); mod_config()->router.add_route(StringRef{g.pattern}, addr_groups.size());
addr_groups.push_back(std::move(g)); addr_groups.push_back(std::move(g));
@ -2113,12 +2116,19 @@ void process_options(
std::move(std::begin(g.addrs), std::end(g.addrs), std::move(std::begin(g.addrs), std::end(g.addrs),
std::back_inserter(catch_all.addrs)); std::back_inserter(catch_all.addrs));
} }
catch_all.proto = default_proto;
std::vector<DownstreamAddrGroupConfig>().swap(addr_groups); std::vector<DownstreamAddrGroupConfig>().swap(addr_groups);
// maybe not necessary? // maybe not necessary?
mod_config()->router = Router(); mod_config()->router = Router();
mod_config()->router.add_route(StringRef{catch_all.pattern}, mod_config()->router.add_route(StringRef{catch_all.pattern},
addr_groups.size()); addr_groups.size());
addr_groups.push_back(std::move(catch_all)); addr_groups.push_back(std::move(catch_all));
} else {
for (auto &g : addr_groups) {
if (g.proto == PROTO_NONE) {
g.proto = default_proto;
}
}
} }
if (LOG_ENABLED(INFO)) { if (LOG_ENABLED(INFO)) {

View File

@ -385,7 +385,7 @@ ClientHandler::ClientHandler(Worker *worker, int fd, SSL *ssl,
get_config()->conn.upstream.ratelimit.write, get_config()->conn.upstream.ratelimit.write,
get_config()->conn.upstream.ratelimit.read, writecb, readcb, get_config()->conn.upstream.ratelimit.read, writecb, readcb,
timeoutcb, this, get_config()->tls.dyn_rec.warmup_threshold, timeoutcb, this, get_config()->tls.dyn_rec.warmup_threshold,
get_config()->tls.dyn_rec.idle_timeout), get_config()->tls.dyn_rec.idle_timeout, PROTO_NONE),
ipaddr_(ipaddr), ipaddr_(ipaddr),
port_(port), port_(port),
faddr_(faddr), faddr_(faddr),
@ -712,7 +712,7 @@ ClientHandler::get_downstream_connection(Downstream *downstream) {
<< " Create new one"; << " Create new one";
} }
if (downstreamconf.proto == PROTO_HTTP2) { if (group.proto == PROTO_HTTP2) {
if (group.http2_freelist.empty()) { if (group.http2_freelist.empty()) {
if (LOG_ENABLED(INFO)) { if (LOG_ENABLED(INFO)) {
CLOG(INFO, this) CLOG(INFO, this)

View File

@ -235,7 +235,7 @@ constexpr char SHRPX_OPT_BACKEND_HTTP2_MAX_CONCURRENT_STREAMS[] =
constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8; constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
enum shrpx_proto { PROTO_HTTP2, PROTO_HTTP }; enum shrpx_proto { PROTO_NONE, PROTO_HTTP1, PROTO_HTTP2, PROTO_MEMCACHED };
enum shrpx_forwarded_param { enum shrpx_forwarded_param {
FORWARDED_NONE = 0, FORWARDED_NONE = 0,
@ -306,6 +306,8 @@ struct DownstreamAddrGroupConfig {
ImmutableString pattern; ImmutableString pattern;
std::vector<DownstreamAddrConfig> addrs; std::vector<DownstreamAddrConfig> addrs;
// Application protocol used in this group
shrpx_proto proto;
}; };
struct TicketKey { struct TicketKey {
@ -561,8 +563,6 @@ struct ConnectionConfig {
size_t connections_per_frontend; size_t connections_per_frontend;
size_t request_buffer_size; size_t request_buffer_size;
size_t response_buffer_size; size_t response_buffer_size;
// downstream protocol; this will be determined by given options.
shrpx_proto proto;
// Address family of backend connection. One of either AF_INET, // Address family of backend connection. One of either AF_INET,
// AF_INET6 or AF_UNSPEC. This is ignored if backend connection // AF_INET6 or AF_UNSPEC. This is ignored if backend connection
// is made via Unix domain socket. // is made via Unix domain socket.

View File

@ -47,7 +47,7 @@ Connection::Connection(struct ev_loop *loop, int fd, SSL *ssl,
const RateLimitConfig &read_limit, IOCb writecb, const RateLimitConfig &read_limit, IOCb writecb,
IOCb readcb, TimerCb timeoutcb, void *data, IOCb readcb, TimerCb timeoutcb, void *data,
size_t tls_dyn_rec_warmup_threshold, size_t tls_dyn_rec_warmup_threshold,
ev_tstamp tls_dyn_rec_idle_timeout) ev_tstamp tls_dyn_rec_idle_timeout, shrpx_proto proto)
: tls{DefaultMemchunks(mcpool), DefaultPeekMemchunks(mcpool)}, : tls{DefaultMemchunks(mcpool), DefaultPeekMemchunks(mcpool)},
wlimit(loop, &wev, write_limit.rate, write_limit.burst), wlimit(loop, &wev, write_limit.rate, write_limit.burst),
rlimit(loop, &rev, read_limit.rate, read_limit.burst, this), rlimit(loop, &rev, read_limit.rate, read_limit.burst, this),
@ -58,7 +58,8 @@ Connection::Connection(struct ev_loop *loop, int fd, SSL *ssl,
data(data), data(data),
fd(fd), fd(fd),
tls_dyn_rec_warmup_threshold(tls_dyn_rec_warmup_threshold), tls_dyn_rec_warmup_threshold(tls_dyn_rec_warmup_threshold),
tls_dyn_rec_idle_timeout(tls_dyn_rec_idle_timeout) { tls_dyn_rec_idle_timeout(tls_dyn_rec_idle_timeout),
proto(proto) {
ev_io_init(&wev, writecb, fd, EV_WRITE); ev_io_init(&wev, writecb, fd, EV_WRITE);
ev_io_init(&rev, readcb, fd, EV_READ); ev_io_init(&rev, readcb, fd, EV_READ);

View File

@ -77,7 +77,7 @@ struct Connection {
const RateLimitConfig &write_limit, const RateLimitConfig &write_limit,
const RateLimitConfig &read_limit, IOCb writecb, IOCb readcb, const RateLimitConfig &read_limit, IOCb writecb, IOCb readcb,
TimerCb timeoutcb, void *data, size_t tls_dyn_rec_warmup_threshold, TimerCb timeoutcb, void *data, size_t tls_dyn_rec_warmup_threshold,
ev_tstamp tls_dyn_rec_idle_timeout); ev_tstamp tls_dyn_rec_idle_timeout, shrpx_proto proto);
~Connection(); ~Connection();
void disconnect(); void disconnect();
@ -133,6 +133,10 @@ struct Connection {
int fd; int fd;
size_t tls_dyn_rec_warmup_threshold; size_t tls_dyn_rec_warmup_threshold;
ev_tstamp tls_dyn_rec_idle_timeout; ev_tstamp tls_dyn_rec_idle_timeout;
// Application protocol used over the connection. This field is not
// used in this object at the moment. The rest of the program may
// use this value when it is useful.
shrpx_proto proto;
}; };
} // namespace shrpx } // namespace shrpx

View File

@ -203,7 +203,7 @@ int ConnectionHandler::create_single_worker() {
nb_.get(), nb_.get(),
#endif // HAVE_NEVERBLEED #endif // HAVE_NEVERBLEED
StringRef{tlsconf.cacert}, StringRef{memcachedconf.cert_file}, StringRef{tlsconf.cacert}, StringRef{memcachedconf.cert_file},
StringRef{memcachedconf.private_key_file}, StringRef(), nullptr); StringRef{memcachedconf.private_key_file}, nullptr);
all_ssl_ctx_.push_back(session_cache_ssl_ctx); all_ssl_ctx_.push_back(session_cache_ssl_ctx);
} }
@ -253,7 +253,7 @@ int ConnectionHandler::create_worker_thread(size_t num) {
nb_.get(), nb_.get(),
#endif // HAVE_NEVERBLEED #endif // HAVE_NEVERBLEED
StringRef{tlsconf.cacert}, StringRef{memcachedconf.cert_file}, StringRef{tlsconf.cacert}, StringRef{memcachedconf.cert_file},
StringRef{memcachedconf.private_key_file}, StringRef{}, nullptr); StringRef{memcachedconf.private_key_file}, nullptr);
all_ssl_ctx_.push_back(session_cache_ssl_ctx); all_ssl_ctx_.push_back(session_cache_ssl_ctx);
} }
auto worker = auto worker =
@ -767,7 +767,7 @@ SSL_CTX *ConnectionHandler::create_tls_ticket_key_memcached_ssl_ctx() {
nb_.get(), nb_.get(),
#endif // HAVE_NEVERBLEED #endif // HAVE_NEVERBLEED
StringRef{tlsconf.cacert}, StringRef{memcachedconf.cert_file}, StringRef{tlsconf.cacert}, StringRef{memcachedconf.cert_file},
StringRef{memcachedconf.private_key_file}, StringRef{}, nullptr); StringRef{memcachedconf.private_key_file}, nullptr);
all_ssl_ctx_.push_back(ssl_ctx); all_ssl_ctx_.push_back(ssl_ctx);

View File

@ -173,7 +173,7 @@ Http2Session::Http2Session(struct ev_loop *loop, SSL_CTX *ssl_ctx,
get_config()->conn.downstream.timeout.write, get_config()->conn.downstream.timeout.write,
get_config()->conn.downstream.timeout.read, {}, {}, writecb, readcb, get_config()->conn.downstream.timeout.read, {}, {}, writecb, readcb,
timeoutcb, this, get_config()->tls.dyn_rec.warmup_threshold, timeoutcb, this, get_config()->tls.dyn_rec.warmup_threshold,
get_config()->tls.dyn_rec.idle_timeout), get_config()->tls.dyn_rec.idle_timeout, PROTO_HTTP2),
wb_(worker->get_mcpool()), wb_(worker->get_mcpool()),
worker_(worker), worker_(worker),
ssl_ctx_(ssl_ctx), ssl_ctx_(ssl_ctx),
@ -398,6 +398,8 @@ int Http2Session::initiate_connection() {
return -1; return -1;
} }
ssl::setup_downstream_http2_alpn(ssl);
conn_.set_ssl(ssl); conn_.set_ssl(ssl);
} }

View File

@ -824,9 +824,7 @@ Http2Upstream::Http2Upstream(ClientHandler *handler)
downstream_queue_( downstream_queue_(
get_config()->http2_proxy get_config()->http2_proxy
? get_config()->conn.downstream.connections_per_host ? get_config()->conn.downstream.connections_per_host
: get_config()->conn.downstream.proto == PROTO_HTTP : get_config()->conn.downstream.connections_per_frontend,
? get_config()->conn.downstream.connections_per_frontend
: 0,
!get_config()->http2_proxy), !get_config()->http2_proxy),
handler_(handler), handler_(handler),
session_(nullptr), session_(nullptr),

View File

@ -118,7 +118,7 @@ HttpDownstreamConnection::HttpDownstreamConnection(DownstreamAddrGroup *group,
get_config()->conn.downstream.timeout.write, get_config()->conn.downstream.timeout.write,
get_config()->conn.downstream.timeout.read, {}, {}, connectcb, get_config()->conn.downstream.timeout.read, {}, {}, connectcb,
readcb, timeoutcb, this, get_config()->tls.dyn_rec.warmup_threshold, readcb, timeoutcb, this, get_config()->tls.dyn_rec.warmup_threshold,
get_config()->tls.dyn_rec.idle_timeout), get_config()->tls.dyn_rec.idle_timeout, PROTO_HTTP1),
do_read_(&HttpDownstreamConnection::noop), do_read_(&HttpDownstreamConnection::noop),
do_write_(&HttpDownstreamConnection::noop), do_write_(&HttpDownstreamConnection::noop),
worker_(worker), worker_(worker),
@ -153,6 +153,8 @@ int HttpDownstreamConnection::attach_downstream(Downstream *downstream) {
return -1; return -1;
} }
ssl::setup_downstream_http1_alpn(ssl);
conn_.set_ssl(ssl); conn_.set_ssl(ssl);
} }

View File

@ -96,7 +96,7 @@ MemcachedConnection::MemcachedConnection(const Address *addr,
const StringRef &sni_name, const StringRef &sni_name,
MemchunkPool *mcpool) MemchunkPool *mcpool)
: conn_(loop, -1, nullptr, mcpool, write_timeout, read_timeout, {}, {}, : conn_(loop, -1, nullptr, mcpool, write_timeout, read_timeout, {}, {},
connectcb, readcb, timeoutcb, this, 0, 0.), connectcb, readcb, timeoutcb, this, 0, 0., PROTO_MEMCACHED),
do_read_(&MemcachedConnection::noop), do_read_(&MemcachedConnection::noop),
do_write_(&MemcachedConnection::noop), do_write_(&MemcachedConnection::noop),
sni_name_(sni_name.str()), sni_name_(sni_name.str()),

View File

@ -503,9 +503,7 @@ SpdyUpstream::SpdyUpstream(uint16_t version, ClientHandler *handler)
downstream_queue_( downstream_queue_(
get_config()->http2_proxy get_config()->http2_proxy
? get_config()->conn.downstream.connections_per_host ? get_config()->conn.downstream.connections_per_host
: get_config()->conn.downstream.proto == PROTO_HTTP : get_config()->conn.downstream.connections_per_frontend,
? get_config()->conn.downstream.connections_per_frontend
: 0,
!get_config()->http2_proxy), !get_config()->http2_proxy),
handler_(handler), handler_(handler),
session_(nullptr) { session_(nullptr) {

View File

@ -659,12 +659,28 @@ int select_h1_next_proto_cb(SSL *ssl, unsigned char **out,
} }
} // namespace } // namespace
namespace {
int select_next_proto_cb(SSL *ssl, unsigned char **out, unsigned char *outlen,
const unsigned char *in, unsigned int inlen,
void *arg) {
auto conn = static_cast<Connection *>(SSL_get_app_data(ssl));
switch (conn->proto) {
case PROTO_HTTP1:
return select_h1_next_proto_cb(ssl, out, outlen, in, inlen, arg);
case PROTO_HTTP2:
return select_h2_next_proto_cb(ssl, out, outlen, in, inlen, arg);
default:
return SSL_TLSEXT_ERR_NOACK;
}
}
} // namespace
SSL_CTX *create_ssl_client_context( SSL_CTX *create_ssl_client_context(
#ifdef HAVE_NEVERBLEED #ifdef HAVE_NEVERBLEED
neverbleed_t *nb, neverbleed_t *nb,
#endif // HAVE_NEVERBLEED #endif // HAVE_NEVERBLEED
const StringRef &cacert, const StringRef &cert_file, const StringRef &cacert, const StringRef &cert_file,
const StringRef &private_key_file, const StringRef &alpn, const StringRef &private_key_file,
int (*next_proto_select_cb)(SSL *s, unsigned char **out, int (*next_proto_select_cb)(SSL *s, unsigned char **out,
unsigned char *outlen, const unsigned char *in, unsigned char *outlen, const unsigned char *in,
unsigned int inlen, void *arg)) { unsigned int inlen, void *arg)) {
@ -742,14 +758,10 @@ SSL_CTX *create_ssl_client_context(
#endif // HAVE_NEVERBLEED #endif // HAVE_NEVERBLEED
} }
// NPN selection callback // NPN selection callback. This is required to set SSL_CTX because
// OpenSSL does not offer SSL_set_next_proto_select_cb.
SSL_CTX_set_next_proto_select_cb(ssl_ctx, next_proto_select_cb, nullptr); SSL_CTX_set_next_proto_select_cb(ssl_ctx, next_proto_select_cb, nullptr);
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
// ALPN advertisement
SSL_CTX_set_alpn_protos(ssl_ctx, alpn.byte(), alpn.size());
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
return ssl_ctx; return ssl_ctx;
} }
@ -1303,29 +1315,29 @@ SSL_CTX *setup_downstream_client_ssl_context(
} }
auto &tlsconf = get_config()->tls; auto &tlsconf = get_config()->tls;
auto &downstreamconf = get_config()->conn.downstream;
std::vector<unsigned char> h2alpn;
StringRef alpn;
int (*next_proto_select_cb)(SSL *s, unsigned char **out,
unsigned char *outlen, const unsigned char *in,
unsigned int inlen, void *arg);
if (downstreamconf.proto == PROTO_HTTP2) {
h2alpn = util::get_default_alpn();
alpn = StringRef(h2alpn.data(), h2alpn.size());
next_proto_select_cb = select_h2_next_proto_cb;
} else {
alpn = StringRef::from_lit(NGHTTP2_H1_1_ALPN);
next_proto_select_cb = select_h1_next_proto_cb;
}
return ssl::create_ssl_client_context( return ssl::create_ssl_client_context(
#ifdef HAVE_NEVERBLEED #ifdef HAVE_NEVERBLEED
nb, nb,
#endif // HAVE_NEVERBLEED #endif // HAVE_NEVERBLEED
StringRef{tlsconf.cacert}, StringRef{tlsconf.client.cert_file}, StringRef{tlsconf.cacert}, StringRef{tlsconf.client.cert_file},
StringRef{tlsconf.client.private_key_file}, alpn, next_proto_select_cb); StringRef{tlsconf.client.private_key_file}, select_next_proto_cb);
}
void setup_downstream_http2_alpn(SSL *ssl) {
auto alpn = util::get_default_alpn();
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
// ALPN advertisement
SSL_set_alpn_protos(ssl, alpn.data(), alpn.size());
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
}
void setup_downstream_http1_alpn(SSL *ssl) {
auto alpn = StringRef::from_lit(NGHTTP2_H1_1_ALPN);
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
// ALPN advertisement
SSL_set_alpn_protos(ssl, alpn.byte(), alpn.size());
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
} }
CertLookupTree *create_cert_lookup_tree() { CertLookupTree *create_cert_lookup_tree() {

View File

@ -71,13 +71,14 @@ SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file
#endif // HAVE_NEVERBLEED #endif // HAVE_NEVERBLEED
); );
// Create client side SSL_CTX // Create client side SSL_CTX. This does not configure ALPN settings.
// |next_proto_select_cb| is for NPN.
SSL_CTX *create_ssl_client_context( SSL_CTX *create_ssl_client_context(
#ifdef HAVE_NEVERBLEED #ifdef HAVE_NEVERBLEED
neverbleed_t *nb, neverbleed_t *nb,
#endif // HAVE_NEVERBLEED #endif // HAVE_NEVERBLEED
const StringRef &cacert, const StringRef &cert_file, const StringRef &cacert, const StringRef &cert_file,
const StringRef &private_key_file, const StringRef &alpn, const StringRef &private_key_file,
int (*next_proto_select_cb)(SSL *s, unsigned char **out, int (*next_proto_select_cb)(SSL *s, unsigned char **out,
unsigned char *outlen, const unsigned char *in, unsigned char *outlen, const unsigned char *in,
unsigned int inlen, void *arg)); unsigned int inlen, void *arg));
@ -201,6 +202,11 @@ SSL_CTX *setup_downstream_client_ssl_context(
#endif // HAVE_NEVERBLEED #endif // HAVE_NEVERBLEED
); );
// Sets ALPN settings in |SSL| suitable for HTTP/2 use.
void setup_downstream_http2_alpn(SSL *ssl);
// Sets ALPN settings in |SSL| suitable for HTTP/1.1 use.
void setup_downstream_http1_alpn(SSL *ssl);
// Creates CertLookupTree. If frontend is configured not to use TLS, // Creates CertLookupTree. If frontend is configured not to use TLS,
// this function returns nullptr. // this function returns nullptr.
CertLookupTree *create_cert_lookup_tree(); CertLookupTree *create_cert_lookup_tree();

View File

@ -104,6 +104,7 @@ Worker::Worker(struct ev_loop *loop, SSL_CTX *sv_ssl_ctx, SSL_CTX *cl_ssl_ctx,
dst.pattern = src.pattern; dst.pattern = src.pattern;
dst.addrs.resize(src.addrs.size()); dst.addrs.resize(src.addrs.size());
dst.proto = src.proto;
for (size_t j = 0; j < src.addrs.size(); ++j) { for (size_t j = 0; j < src.addrs.size(); ++j) {
auto &src_addr = src.addrs[j]; auto &src_addr = src.addrs[j];

View File

@ -86,6 +86,8 @@ struct DownstreamAddr {
struct DownstreamAddrGroup { struct DownstreamAddrGroup {
ImmutableString pattern; ImmutableString pattern;
std::vector<DownstreamAddr> addrs; std::vector<DownstreamAddr> addrs;
// Application protocol used in this group
shrpx_proto proto;
// List of Http2Session which is not fully utilized (i.e., the // List of Http2Session which is not fully utilized (i.e., the
// server advertized maximum concurrency is not reached). We will // server advertized maximum concurrency is not reached). We will
// coalesce as much stream as possible in one Http2Session to fully // coalesce as much stream as possible in one Http2Session to fully