nghttpx: Add BlockAllocator to ClientHandler

This commit is contained in:
Tatsuhiro Tsujikawa 2016-09-30 23:09:02 +09:00
parent 68a6d8c50b
commit 8a9810ed32
9 changed files with 114 additions and 76 deletions

View File

@ -176,6 +176,8 @@ int main(int argc, char *argv[]) {
!CU_add_test(pSuite, "util_make_hostport", !CU_add_test(pSuite, "util_make_hostport",
shrpx::test_util_make_hostport) || shrpx::test_util_make_hostport) ||
!CU_add_test(pSuite, "util_strifind", shrpx::test_util_strifind) || !CU_add_test(pSuite, "util_strifind", shrpx::test_util_strifind) ||
!CU_add_test(pSuite, "util_random_alpha_digit",
shrpx::test_util_random_alpha_digit) ||
!CU_add_test(pSuite, "gzip_inflate", test_nghttp2_gzip_inflate) || !CU_add_test(pSuite, "gzip_inflate", test_nghttp2_gzip_inflate) ||
!CU_add_test(pSuite, "buffer_write", nghttp2::test_buffer_write) || !CU_add_test(pSuite, "buffer_write", nghttp2::test_buffer_write) ||
!CU_add_test(pSuite, "pool_recycle", nghttp2::test_pool_recycle) || !CU_add_test(pSuite, "pool_recycle", nghttp2::test_pool_recycle) ||

View File

@ -2569,8 +2569,10 @@ int process_options(Config *config,
fwdconf.by_obfuscated.empty()) { fwdconf.by_obfuscated.empty()) {
std::mt19937 gen(rd()); std::mt19937 gen(rd());
auto &dst = fwdconf.by_obfuscated; auto &dst = fwdconf.by_obfuscated;
dst = "_"; dst.resize(1 + SHRPX_OBFUSCATED_NODE_LENGTH);
dst += util::random_alpha_digit(gen, SHRPX_OBFUSCATED_NODE_LENGTH); auto p = std::begin(dst);
*p++ = '_';
util::random_alpha_digit(p, std::end(dst), gen);
} }
if (config->http2.upstream.debug.frame_debug) { if (config->http2.upstream.debug.frame_debug) {

View File

@ -376,17 +376,18 @@ int ClientHandler::upstream_http1_connhd_read() {
} }
ClientHandler::ClientHandler(Worker *worker, int fd, SSL *ssl, ClientHandler::ClientHandler(Worker *worker, int fd, SSL *ssl,
const char *ipaddr, const char *port, int family, const StringRef &ipaddr, const StringRef &port,
const UpstreamAddr *faddr) int family, const UpstreamAddr *faddr)
: conn_(worker->get_loop(), fd, ssl, worker->get_mcpool(), : balloc_(128, 128),
conn_(worker->get_loop(), fd, ssl, worker->get_mcpool(),
get_config()->conn.upstream.timeout.write, get_config()->conn.upstream.timeout.write,
get_config()->conn.upstream.timeout.read, get_config()->conn.upstream.timeout.read,
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, PROTO_NONE), get_config()->tls.dyn_rec.idle_timeout, PROTO_NONE),
ipaddr_(ipaddr), ipaddr_(make_string_ref(balloc_, ipaddr)),
port_(port), port_(make_string_ref(balloc_, port)),
faddr_(faddr), faddr_(faddr),
worker_(worker), worker_(worker),
left_connhd_len_(NGHTTP2_CLIENT_MAGIC_LEN), left_connhd_len_(NGHTTP2_CLIENT_MAGIC_LEN),
@ -416,13 +417,28 @@ ClientHandler::ClientHandler(Worker *worker, int fd, SSL *ssl,
if (fwdconf.params & FORWARDED_FOR) { if (fwdconf.params & FORWARDED_FOR) {
if (fwdconf.for_node_type == FORWARDED_NODE_OBFUSCATED) { if (fwdconf.for_node_type == FORWARDED_NODE_OBFUSCATED) {
forwarded_for_ = "_"; // 1 for '_'
forwarded_for_ += util::random_alpha_digit(worker_->get_randgen(), auto len = SHRPX_OBFUSCATED_NODE_LENGTH + 1;
SHRPX_OBFUSCATED_NODE_LENGTH); // 1 for terminating NUL.
auto buf = make_byte_ref(balloc_, len + 1);
auto p = buf.base;
*p++ = '_';
p = util::random_alpha_digit(p, p + len - 1, worker_->get_randgen());
*p = '\0';
forwarded_for_ = StringRef{buf.base, p};
} else if (family == AF_INET6) { } else if (family == AF_INET6) {
forwarded_for_ = "["; // 2 for '[' and ']'
forwarded_for_ += ipaddr_; auto len = 2 + ipaddr_.size();
forwarded_for_ += ']'; // 1 for terminating NUL.
auto buf = make_byte_ref(balloc_, len + 1);
auto p = buf.base;
*p++ = '[';
p = std::copy(std::begin(ipaddr_), std::end(ipaddr_), p);
*p++ = ']';
*p = '\0';
forwarded_for_ = StringRef{buf.base, p};
} else { } else {
// family == AF_INET or family == AF_UNIX // family == AF_INET or family == AF_UNIX
forwarded_for_ = ipaddr_; forwarded_for_ = ipaddr_;
@ -441,7 +457,7 @@ void ClientHandler::setup_upstream_io_callback() {
// upgraded to HTTP/2 through HTTP Upgrade or direct HTTP/2 // upgraded to HTTP/2 through HTTP Upgrade or direct HTTP/2
// connection. // connection.
upstream_ = make_unique<HttpsUpstream>(this); upstream_ = make_unique<HttpsUpstream>(this);
alpn_ = "http/1.1"; alpn_ = StringRef::from_lit("http/1.1");
read_ = &ClientHandler::read_clear; read_ = &ClientHandler::read_clear;
write_ = &ClientHandler::write_clear; write_ = &ClientHandler::write_clear;
on_read_ = &ClientHandler::upstream_http1_connhd_read; on_read_ = &ClientHandler::upstream_http1_connhd_read;
@ -524,7 +540,7 @@ int ClientHandler::validate_next_proto() {
} }
upstream_ = make_unique<HttpsUpstream>(this); upstream_ = make_unique<HttpsUpstream>(this);
alpn_ = "http/1.1"; alpn_ = StringRef::from_lit("http/1.1");
// At this point, input buffer is already filled with some bytes. // At this point, input buffer is already filled with some bytes.
// The read callback is not called until new data come. So consume // The read callback is not called until new data come. So consume
@ -555,7 +571,7 @@ int ClientHandler::validate_next_proto() {
auto http2_upstream = make_unique<Http2Upstream>(this); auto http2_upstream = make_unique<Http2Upstream>(this);
upstream_ = std::move(http2_upstream); upstream_ = std::move(http2_upstream);
alpn_.assign(std::begin(proto), std::end(proto)); alpn_ = make_string_ref(balloc_, proto);
// At this point, input buffer is already filled with some bytes. // At this point, input buffer is already filled with some bytes.
// The read callback is not called until new data come. So consume // The read callback is not called until new data come. So consume
@ -574,16 +590,16 @@ int ClientHandler::validate_next_proto() {
switch (spdy_version) { switch (spdy_version) {
case SPDYLAY_PROTO_SPDY2: case SPDYLAY_PROTO_SPDY2:
alpn_ = "spdy/2"; alpn_ = StringRef::from_lit("spdy/2");
break; break;
case SPDYLAY_PROTO_SPDY3: case SPDYLAY_PROTO_SPDY3:
alpn_ = "spdy/3"; alpn_ = StringRef::from_lit("spdy/3");
break; break;
case SPDYLAY_PROTO_SPDY3_1: case SPDYLAY_PROTO_SPDY3_1:
alpn_ = "spdy/3.1"; alpn_ = StringRef::from_lit("spdy/3.1");
break; break;
default: default:
alpn_ = "spdy/unknown"; alpn_ = StringRef::from_lit("spdy/unknown");
} }
// At this point, input buffer is already filled with some bytes. // At this point, input buffer is already filled with some bytes.
@ -599,7 +615,7 @@ int ClientHandler::validate_next_proto() {
if (proto == StringRef::from_lit("http/1.1")) { if (proto == StringRef::from_lit("http/1.1")) {
upstream_ = make_unique<HttpsUpstream>(this); upstream_ = make_unique<HttpsUpstream>(this);
alpn_ = proto.str(); alpn_ = StringRef::from_lit("http/1.1");
// At this point, input buffer is already filled with some bytes. // At this point, input buffer is already filled with some bytes.
// The read callback is not called until new data come. So consume // The read callback is not called until new data come. So consume
@ -629,7 +645,7 @@ int ClientHandler::on_read() {
} }
int ClientHandler::on_write() { return on_write_(*this); } int ClientHandler::on_write() { return on_write_(*this); }
const std::string &ClientHandler::get_ipaddr() const { return ipaddr_; } const StringRef &ClientHandler::get_ipaddr() const { return ipaddr_; }
bool ClientHandler::get_should_close_after_write() const { bool ClientHandler::get_should_close_after_write() const {
return should_close_after_write_; return should_close_after_write_;
@ -974,7 +990,7 @@ ClientHandler::get_downstream_connection(Downstream *downstream) {
if (shared_addr->affinity == AFFINITY_IP) { if (shared_addr->affinity == AFFINITY_IP) {
if (!affinity_hash_computed_) { if (!affinity_hash_computed_) {
affinity_hash_ = compute_affinity_from_ip(StringRef{ipaddr_}); affinity_hash_ = compute_affinity_from_ip(ipaddr_);
affinity_hash_computed_ = true; affinity_hash_computed_ = true;
} }
@ -1093,7 +1109,7 @@ SSL *ClientHandler::get_ssl() const { return conn_.tls.ssl; }
void ClientHandler::direct_http2_upgrade() { void ClientHandler::direct_http2_upgrade() {
upstream_ = make_unique<Http2Upstream>(this); upstream_ = make_unique<Http2Upstream>(this);
alpn_ = NGHTTP2_CLEARTEXT_PROTO_VERSION_ID; alpn_ = StringRef::from_lit(NGHTTP2_CLEARTEXT_PROTO_VERSION_ID);
on_read_ = &ClientHandler::upstream_read; on_read_ = &ClientHandler::upstream_read;
write_ = &ClientHandler::write_clear; write_ = &ClientHandler::write_clear;
} }
@ -1118,7 +1134,7 @@ int ClientHandler::perform_http2_upgrade(HttpsUpstream *http) {
upstream_.release(); upstream_.release();
// TODO We might get other version id in HTTP2-settings, if we // TODO We might get other version id in HTTP2-settings, if we
// support aliasing for h2, but we just use library default for now. // support aliasing for h2, but we just use library default for now.
alpn_ = NGHTTP2_CLEARTEXT_PROTO_VERSION_ID; alpn_ = StringRef::from_lit(NGHTTP2_CLEARTEXT_PROTO_VERSION_ID);
on_read_ = &ClientHandler::upstream_http2_connhd_read; on_read_ = &ClientHandler::upstream_http2_connhd_read;
write_ = &ClientHandler::write_clear; write_ = &ClientHandler::write_clear;
@ -1199,7 +1215,7 @@ void ClientHandler::write_accesslog(Downstream *downstream) {
upstream_accesslog( upstream_accesslog(
get_config()->logging.access.format, get_config()->logging.access.format,
LogSpec{ LogSpec{
downstream, downstream->get_addr(), StringRef{ipaddr_}, downstream, downstream->get_addr(), ipaddr_,
http2::to_method_string(req.method), http2::to_method_string(req.method),
req.method == HTTP_CONNECT req.method == HTTP_CONNECT
@ -1212,15 +1228,14 @@ void ClientHandler::write_accesslog(Downstream *downstream) {
: StringRef::from_lit("-") : StringRef::from_lit("-")
: StringRef(req.path), : StringRef(req.path),
StringRef(alpn_), alpn_, nghttp2::ssl::get_tls_session_info(&tls_info, conn_.tls.ssl),
nghttp2::ssl::get_tls_session_info(&tls_info, conn_.tls.ssl),
std::chrono::system_clock::now(), // time_now std::chrono::system_clock::now(), // time_now
downstream->get_request_start_time(), // request_start_time downstream->get_request_start_time(), // request_start_time
std::chrono::high_resolution_clock::now(), // request_end_time std::chrono::high_resolution_clock::now(), // request_end_time
req.http_major, req.http_minor, resp.http_status, req.http_major, req.http_minor, resp.http_status,
downstream->response_sent_body_length, StringRef(port_), faddr_->port, downstream->response_sent_body_length, port_, faddr_->port,
get_config()->pid, get_config()->pid,
}); });
} }
@ -1231,21 +1246,20 @@ void ClientHandler::write_accesslog(int major, int minor, unsigned int status,
auto highres_now = std::chrono::high_resolution_clock::now(); auto highres_now = std::chrono::high_resolution_clock::now();
nghttp2::ssl::TLSSessionInfo tls_info; nghttp2::ssl::TLSSessionInfo tls_info;
upstream_accesslog(get_config()->logging.access.format, upstream_accesslog(
LogSpec{ get_config()->logging.access.format,
nullptr, nullptr, StringRef(ipaddr_), LogSpec{
StringRef::from_lit("-"), // method nullptr, nullptr, ipaddr_,
StringRef::from_lit("-"), // path, StringRef::from_lit("-"), // method
StringRef(alpn_), nghttp2::ssl::get_tls_session_info( StringRef::from_lit("-"), // path,
&tls_info, conn_.tls.ssl), alpn_, nghttp2::ssl::get_tls_session_info(&tls_info, conn_.tls.ssl),
time_now, time_now,
highres_now, // request_start_time TODO is highres_now, // request_start_time TODO is
// there a better value? // there a better value?
highres_now, // request_end_time highres_now, // request_end_time
major, minor, // major, minor major, minor, // major, minor
status, body_bytes_sent, StringRef(port_), status, body_bytes_sent, port_, faddr_->port, get_config()->pid,
faddr_->port, get_config()->pid, });
});
} }
ClientHandler::ReadBuf *ClientHandler::get_rb() { return &rb_; } ClientHandler::ReadBuf *ClientHandler::get_rb() { return &rb_; }
@ -1474,8 +1488,9 @@ int ClientHandler::proxy_protocol_read() {
rb_.drain(end + 2 - rb_.pos); rb_.drain(end + 2 - rb_.pos);
ipaddr_.assign(src_addr, src_addr + src_addrlen); ipaddr_ =
port_.assign(src_port, src_port + src_portlen); make_string_ref(balloc_, StringRef{src_addr, src_addr + src_addrlen});
port_ = make_string_ref(balloc_, StringRef{src_port, src_port + src_portlen});
if (LOG_ENABLED(INFO)) { if (LOG_ENABLED(INFO)) {
CLOG(INFO, this) << "PROXY-protocol-v1: Finished, " << (rb_.pos - first) CLOG(INFO, this) << "PROXY-protocol-v1: Finished, " << (rb_.pos - first)
@ -1495,16 +1510,16 @@ StringRef ClientHandler::get_forwarded_by() const {
return StringRef{faddr_->hostport}; return StringRef{faddr_->hostport};
} }
StringRef ClientHandler::get_forwarded_for() const { StringRef ClientHandler::get_forwarded_for() const { return forwarded_for_; }
return StringRef{forwarded_for_};
}
const UpstreamAddr *ClientHandler::get_upstream_addr() const { return faddr_; } const UpstreamAddr *ClientHandler::get_upstream_addr() const { return faddr_; }
Connection *ClientHandler::get_connection() { return &conn_; }; Connection *ClientHandler::get_connection() { return &conn_; };
void ClientHandler::set_tls_sni(const StringRef &sni) { sni_ = sni.str(); } void ClientHandler::set_tls_sni(const StringRef &sni) {
sni_ = make_string_ref(balloc_, sni);
}
StringRef ClientHandler::get_tls_sni() const { return StringRef{sni_}; } StringRef ClientHandler::get_tls_sni() const { return sni_; }
} // namespace shrpx } // namespace shrpx

View File

@ -37,6 +37,7 @@
#include "shrpx_connection.h" #include "shrpx_connection.h"
#include "buffer.h" #include "buffer.h"
#include "memchunk.h" #include "memchunk.h"
#include "allocator.h"
using namespace nghttp2; using namespace nghttp2;
@ -54,8 +55,8 @@ struct DownstreamAddr;
class ClientHandler { class ClientHandler {
public: public:
ClientHandler(Worker *worker, int fd, SSL *ssl, const char *ipaddr, ClientHandler(Worker *worker, int fd, SSL *ssl, const StringRef &ipaddr,
const char *port, int family, const UpstreamAddr *faddr); const StringRef &port, int family, const UpstreamAddr *faddr);
~ClientHandler(); ~ClientHandler();
int noop(); int noop();
@ -90,8 +91,7 @@ public:
void reset_upstream_write_timeout(ev_tstamp t); void reset_upstream_write_timeout(ev_tstamp t);
int validate_next_proto(); int validate_next_proto();
const std::string &get_ipaddr() const; const StringRef &get_ipaddr() const;
const std::string &get_port() const;
bool get_should_close_after_write() const; bool get_should_close_after_write() const;
void set_should_close_after_write(bool f); void set_should_close_after_write(bool f);
Upstream *get_upstream(); Upstream *get_upstream();
@ -163,20 +163,21 @@ public:
StringRef get_tls_sni() const; StringRef get_tls_sni() const;
private: private:
BlockAllocator balloc_;
Connection conn_; Connection conn_;
ev_timer reneg_shutdown_timer_; ev_timer reneg_shutdown_timer_;
std::unique_ptr<Upstream> upstream_; std::unique_ptr<Upstream> upstream_;
// IP address of client. If UNIX domain socket is used, this is // IP address of client. If UNIX domain socket is used, this is
// "localhost". // "localhost".
std::string ipaddr_; StringRef ipaddr_;
std::string port_; StringRef port_;
// The ALPN identifier negotiated for this connection. // The ALPN identifier negotiated for this connection.
std::string alpn_; StringRef alpn_;
// The client address used in "for" parameter of Forwarded header // The client address used in "for" parameter of Forwarded header
// field. // field.
std::string forwarded_for_; StringRef forwarded_for_;
// lowercased TLS SNI which client sent. // lowercased TLS SNI which client sent.
std::string sni_; StringRef sni_;
std::function<int(ClientHandler &)> read_, write_; std::function<int(ClientHandler &)> read_, write_;
std::function<int(ClientHandler &)> on_read_, on_write_; std::function<int(ClientHandler &)> on_read_, on_write_;
// Address of frontend listening socket // Address of frontend listening socket

View File

@ -357,7 +357,7 @@ int Http2DownstreamConnection::push_request_headers() {
if (xffconf.add) { if (xffconf.add) {
StringRef xff_value; StringRef xff_value;
auto addr = StringRef{upstream->get_client_handler()->get_ipaddr()}; auto addr = upstream->get_client_handler()->get_ipaddr();
if (xff) { if (xff) {
xff_value = concat_string_ref(balloc, xff->value, xff_value = concat_string_ref(balloc, xff->value,
StringRef::from_lit(", "), addr); StringRef::from_lit(", "), addr);

View File

@ -829,16 +829,16 @@ SSL *create_ssl(SSL_CTX *ssl_ctx) {
ClientHandler *accept_connection(Worker *worker, int fd, sockaddr *addr, ClientHandler *accept_connection(Worker *worker, int fd, sockaddr *addr,
int addrlen, const UpstreamAddr *faddr) { int addrlen, const UpstreamAddr *faddr) {
char host[NI_MAXHOST]; std::array<char, NI_MAXHOST> host;
char service[NI_MAXSERV]; std::array<char, NI_MAXSERV> service;
int rv; int rv;
if (addr->sa_family == AF_UNIX) { if (addr->sa_family == AF_UNIX) {
std::copy_n("localhost", sizeof("localhost"), host); std::copy_n("localhost", sizeof("localhost"), std::begin(host));
service[0] = '\0'; service[0] = '\0';
} else { } else {
rv = getnameinfo(addr, addrlen, host, sizeof(host), service, rv = getnameinfo(addr, addrlen, host.data(), host.size(), service.data(),
sizeof(service), NI_NUMERICHOST | NI_NUMERICSERV); service.size(), NI_NUMERICHOST | NI_NUMERICSERV);
if (rv != 0) { if (rv != 0) {
LOG(ERROR) << "getnameinfo() failed: " << gai_strerror(rv); LOG(ERROR) << "getnameinfo() failed: " << gai_strerror(rv);
@ -867,8 +867,8 @@ ClientHandler *accept_connection(Worker *worker, int fd, sockaddr *addr,
} }
} }
return new ClientHandler(worker, fd, ssl, host, service, addr->sa_family, return new ClientHandler(worker, fd, ssl, StringRef{host.data()},
faddr); StringRef{service.data()}, addr->sa_family, faddr);
} }
bool tls_hostname_match(const StringRef &pattern, const StringRef &hostname) { bool tls_hostname_match(const StringRef &pattern, const StringRef &hostname) {

View File

@ -665,16 +665,17 @@ uint64_t get_uint64(const uint8_t *data);
int read_mime_types(std::map<std::string, std::string> &res, int read_mime_types(std::map<std::string, std::string> &res,
const char *filename); const char *filename);
template <typename Generator> // Fills random alpha and digit byte to the range [|first|, |last|).
std::string random_alpha_digit(Generator &gen, size_t len) { // Returns the one beyond the |last|.
std::string res; template <typename OutputIt, typename Generator>
res.reserve(len); OutputIt random_alpha_digit(OutputIt first, OutputIt last, Generator &gen) {
constexpr uint8_t s[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
std::uniform_int_distribution<> dis(0, 26 * 2 + 10 - 1); std::uniform_int_distribution<> dis(0, 26 * 2 + 10 - 1);
for (; len > 0; --len) { for (; first != last; ++first) {
res += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"[dis( *first = s[dis(gen)];
gen)];
} }
return res; return first;
} }
template <typename OutputIterator, typename CharT, size_t N> template <typename OutputIterator, typename CharT, size_t N>

View File

@ -26,6 +26,7 @@
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
#include <random>
#include <CUnit/CUnit.h> #include <CUnit/CUnit.h>
@ -528,4 +529,19 @@ void test_util_strifind(void) {
StringRef::from_lit("http1"))); StringRef::from_lit("http1")));
} }
void test_util_random_alpha_digit(void) {
std::random_device rd;
std::mt19937 gen(rd());
std::array<uint8_t, 19> data;
auto p = util::random_alpha_digit(std::begin(data), std::end(data), gen);
CU_ASSERT(std::end(data) == p);
for (auto b : data) {
CU_ASSERT(('A' <= b && b <= 'Z') || ('a' <= b && b <= 'z') ||
('0' <= b && b <= '9'));
}
}
} // namespace shrpx } // namespace shrpx

View File

@ -62,6 +62,7 @@ void test_util_parse_config_str_list(void);
void test_util_make_http_hostport(void); void test_util_make_http_hostport(void);
void test_util_make_hostport(void); void test_util_make_hostport(void);
void test_util_strifind(void); void test_util_strifind(void);
void test_util_random_alpha_digit(void);
} // namespace shrpx } // namespace shrpx