Merge branch 'nghttpx-more-block-allocator'

This commit is contained in:
Tatsuhiro Tsujikawa 2016-10-03 22:12:28 +09:00
commit 35594e09df
26 changed files with 678 additions and 415 deletions

View File

@ -29,6 +29,9 @@
#include <string>
#include "template.h"
#include "allocator.h"
namespace nghttp2 {
namespace base64 {
@ -87,7 +90,8 @@ InputIt next_decode_input(InputIt first, InputIt last, const int *tbl) {
return first;
}
template <typename InputIt> std::string decode(InputIt first, InputIt last) {
template <typename InputIt, typename OutputIt>
OutputIt decode(InputIt first, InputIt last, OutputIt d_first) {
static constexpr int INDEX_TABLE[] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
@ -104,37 +108,29 @@ template <typename InputIt> std::string decode(InputIt first, InputIt last) {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1};
auto len = last - first;
if (len % 4 != 0) {
return "";
}
std::string res;
res.resize(len / 4 * 3);
auto p = std::begin(res);
assert(std::distance(first, last) % 4 == 0);
auto p = d_first;
for (; first != last;) {
uint32_t n = 0;
for (int i = 1; i <= 4; ++i, ++first) {
auto idx = INDEX_TABLE[static_cast<size_t>(*first)];
if (idx == -1) {
if (i <= 2) {
return "";
return d_first;
}
if (i == 3) {
if (*first == '=' && *(first + 1) == '=' && first + 2 == last) {
*p++ = n >> 16;
res.resize(p - std::begin(res));
return res;
return p;
}
return "";
return d_first;
}
if (*first == '=' && first + 1 == last) {
*p++ = n >> 16;
*p++ = n >> 8 & 0xffu;
res.resize(p - std::begin(res));
return res;
return p;
}
return "";
return d_first;
}
n += idx << (24 - i * 6);
@ -145,9 +141,37 @@ template <typename InputIt> std::string decode(InputIt first, InputIt last) {
*p++ = n & 0xffu;
}
return p;
}
template <typename InputIt> std::string decode(InputIt first, InputIt last) {
auto len = std::distance(first, last);
if (len % 4 != 0) {
return "";
}
std::string res;
res.resize(len / 4 * 3);
res.erase(decode(first, last, std::begin(res)), std::end(res));
return res;
}
template <typename InputIt>
StringRef decode(BlockAllocator &balloc, InputIt first, InputIt last) {
auto len = std::distance(first, last);
if (len % 4 != 0) {
return StringRef::from_lit("");
}
auto iov = make_byte_ref(balloc, len / 4 * 3 + 1);
auto p = iov.base;
p = decode(first, last, p);
*p = '\0';
return StringRef{iov.base, p};
}
} // namespace base64
} // namespace nghttp2

View File

@ -59,31 +59,40 @@ void test_base64_encode(void) {
}
void test_base64_decode(void) {
BlockAllocator balloc(4096, 4096);
{
std::string in = "/w==";
auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("\xff" == out);
CU_ASSERT("\xff" == base64::decode(balloc, std::begin(in), std::end(in)));
}
{
std::string in = "//4=";
auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("\xff\xfe" == out);
CU_ASSERT("\xff\xfe" ==
base64::decode(balloc, std::begin(in), std::end(in)));
}
{
std::string in = "//79";
auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("\xff\xfe\xfd" == out);
CU_ASSERT("\xff\xfe\xfd" ==
base64::decode(balloc, std::begin(in), std::end(in)));
}
{
std::string in = "//79/A==";
auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("\xff\xfe\xfd\xfc" == out);
CU_ASSERT("\xff\xfe\xfd\xfc" ==
base64::decode(balloc, std::begin(in), std::end(in)));
}
{
// we check the number of valid input must be multiples of 4
std::string in = "//79=";
auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("" == out);
CU_ASSERT("" == base64::decode(balloc, std::begin(in), std::end(in)));
}
{
// ending invalid character at the boundary of multiples of 4 is
@ -91,18 +100,21 @@ void test_base64_decode(void) {
std::string in = "bmdodHRw\n";
auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("" == out);
CU_ASSERT("" == base64::decode(balloc, std::begin(in), std::end(in)));
}
{
// after seeing '=', subsequent input must be also '='.
std::string in = "//79/A=A";
auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("" == out);
CU_ASSERT("" == base64::decode(balloc, std::begin(in), std::end(in)));
}
{
// additional '=' at the end is bad
std::string in = "//79/A======";
auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("" == out);
CU_ASSERT("" == base64::decode(balloc, std::begin(in), std::end(in)));
}
}

View File

@ -176,6 +176,9 @@ int main(int argc, char *argv[]) {
!CU_add_test(pSuite, "util_make_hostport",
shrpx::test_util_make_hostport) ||
!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, "util_format_hex", shrpx::test_util_format_hex) ||
!CU_add_test(pSuite, "gzip_inflate", test_nghttp2_gzip_inflate) ||
!CU_add_test(pSuite, "buffer_write", nghttp2::test_buffer_write) ||
!CU_add_test(pSuite, "pool_recycle", nghttp2::test_pool_recycle) ||

View File

@ -86,6 +86,7 @@
#include "app_helper.h"
#include "ssl.h"
#include "template.h"
#include "allocator.h"
extern char **environ;
@ -151,7 +152,7 @@ StartupConfig suconfig;
struct InheritedAddr {
// IP address if TCP socket. Otherwise, UNIX domain socket path.
ImmutableString host;
StringRef host;
uint16_t port;
// true if UNIX domain socket path
bool host_unix;
@ -574,7 +575,7 @@ int create_unix_domain_server_socket(UpstreamAddr &faddr,
<< (faddr.tls ? ", tls" : "");
(*found).used = true;
faddr.fd = (*found).fd;
faddr.hostport = ImmutableString::from_lit("localhost");
faddr.hostport = StringRef::from_lit("localhost");
return 0;
}
@ -639,7 +640,7 @@ int create_unix_domain_server_socket(UpstreamAddr &faddr,
<< (faddr.tls ? ", tls" : "");
faddr.fd = fd;
faddr.hostport = ImmutableString::from_lit("localhost");
faddr.hostport = StringRef::from_lit("localhost");
return 0;
}
@ -791,8 +792,8 @@ int create_tcp_server_socket(UpstreamAddr &faddr,
}
faddr.fd = fd;
faddr.hostport = ImmutableString{
util::make_http_hostport(StringRef{host.data()}, faddr.port)};
faddr.hostport = util::make_http_hostport(mod_config()->balloc,
StringRef{host.data()}, faddr.port);
LOG(NOTICE) << "Listening on " << faddr.hostport
<< (faddr.tls ? ", tls" : "");
@ -806,7 +807,7 @@ namespace {
// function is intended to be used when reloading configuration, and
// |config| is usually a current configuration.
std::vector<InheritedAddr>
get_inherited_addr_from_config(const Config *config) {
get_inherited_addr_from_config(BlockAllocator &balloc, Config *config) {
int rv;
auto &listenerconf = config->conn.listener;
@ -856,7 +857,7 @@ get_inherited_addr_from_config(const Config *config) {
continue;
}
iaddr.host = ImmutableString{host.data()};
iaddr.host = make_string_ref(balloc, StringRef{host.data()});
}
return iaddrs;
@ -867,7 +868,7 @@ namespace {
// Returns array of InheritedAddr constructed from environment
// variables. This function handles the old environment variable
// names used in 1.7.0 or earlier.
std::vector<InheritedAddr> get_inherited_addr_from_env() {
std::vector<InheritedAddr> get_inherited_addr_from_env(Config *config) {
int rv;
std::vector<InheritedAddr> iaddrs;
@ -888,15 +889,14 @@ std::vector<InheritedAddr> get_inherited_addr_from_env() {
}
}
} else {
auto pathenv = getenv(ENV_UNIX_PATH.c_str());
auto fdenv = getenv(ENV_UNIX_FD.c_str());
if (pathenv && fdenv) {
// The return value of getenv may be allocated statically.
if (getenv(ENV_UNIX_PATH.c_str()) && getenv(ENV_UNIX_FD.c_str())) {
auto name = ENV_ACCEPT_PREFIX.str();
name += '1';
std::string value = "unix,";
value += fdenv;
value += getenv(ENV_UNIX_FD.c_str());
value += ',';
value += pathenv;
value += getenv(ENV_UNIX_PATH.c_str());
setenv(name.c_str(), value.c_str(), 0);
}
}
@ -948,7 +948,7 @@ std::vector<InheritedAddr> get_inherited_addr_from_env() {
}
InheritedAddr addr{};
addr.host = ImmutableString{path};
addr.host = make_string_ref(config->balloc, StringRef{path});
addr.host_unix = true;
addr.fd = static_cast<int>(fd);
iaddrs.push_back(std::move(addr));
@ -1002,7 +1002,7 @@ std::vector<InheritedAddr> get_inherited_addr_from_env() {
}
InheritedAddr addr{};
addr.host = ImmutableString{host.data()};
addr.host = make_string_ref(config->balloc, StringRef{host.data()});
addr.port = static_cast<uint16_t>(port);
addr.fd = static_cast<int>(fd);
iaddrs.push_back(std::move(addr));
@ -1209,7 +1209,7 @@ int event_loop() {
redirect_stderr_to_errorlog();
}
auto iaddrs = get_inherited_addr_from_env();
auto iaddrs = get_inherited_addr_from_env(mod_config());
if (create_acceptor_socket(mod_config(), iaddrs) != 0) {
return -1;
@ -1274,7 +1274,7 @@ constexpr auto DEFAULT_ACCESSLOG_FORMAT = StringRef::from_lit(
namespace {
void fill_default_config(Config *config) {
config->num_worker = 1;
config->conf_path = ImmutableString::from_lit("/etc/nghttpx/nghttpx.conf");
config->conf_path = StringRef::from_lit("/etc/nghttpx/nghttpx.conf");
config->pid = getpid();
if (ev_supported_backends() & ~ev_recommended_backends() & EVBACKEND_KQUEUE) {
@ -1306,7 +1306,7 @@ void fill_default_config(Config *config) {
// ocsp update interval = 14400 secs = 4 hours, borrowed from h2o
ocspconf.update_interval = 4_h;
ocspconf.fetch_ocsp_response_file =
ImmutableString::from_lit(PKGDATADIR "/fetch-ocsp-response");
StringRef::from_lit(PKGDATADIR "/fetch-ocsp-response");
}
{
@ -1319,7 +1319,7 @@ void fill_default_config(Config *config) {
auto &httpconf = config->http;
httpconf.server_name =
ImmutableString::from_lit("nghttpx nghttp2/" NGHTTP2_VERSION);
StringRef::from_lit("nghttpx nghttp2/" NGHTTP2_VERSION);
httpconf.no_host_rewrite = true;
httpconf.request_header_field_buffer = 64_k;
httpconf.max_request_header_fields = 100;
@ -1387,10 +1387,11 @@ void fill_default_config(Config *config) {
auto &loggingconf = config->logging;
{
auto &accessconf = loggingconf.access;
accessconf.format = parse_log_format(DEFAULT_ACCESSLOG_FORMAT);
accessconf.format =
parse_log_format(config->balloc, DEFAULT_ACCESSLOG_FORMAT);
auto &errorconf = loggingconf.error;
errorconf.file = ImmutableString::from_lit("/dev/stderr");
errorconf.file = StringRef::from_lit("/dev/stderr");
}
loggingconf.syslog_facility = LOG_DAEMON;
@ -2446,11 +2447,10 @@ int process_options(Config *config,
auto &tlsconf = config->tls;
if (tlsconf.npn_list.empty()) {
tlsconf.npn_list = util::parse_config_str_list(DEFAULT_NPN_LIST);
tlsconf.npn_list = util::split_str(DEFAULT_NPN_LIST, ',');
}
if (tlsconf.tls_proto_list.empty()) {
tlsconf.tls_proto_list =
util::parse_config_str_list(DEFAULT_TLS_PROTO_LIST);
tlsconf.tls_proto_list = util::split_str(DEFAULT_TLS_PROTO_LIST, ',');
}
tlsconf.tls_proto_mask = ssl::create_tls_proto_mask(tlsconf.tls_proto_list);
@ -2466,7 +2466,7 @@ int process_options(Config *config,
if (listenerconf.addrs.empty()) {
UpstreamAddr addr{};
addr.host = ImmutableString::from_lit("*");
addr.host = StringRef::from_lit("*");
addr.port = 3000;
addr.tls = true;
addr.family = AF_INET;
@ -2567,10 +2567,14 @@ int process_options(Config *config,
if (fwdconf.by_node_type == FORWARDED_NODE_OBFUSCATED &&
fwdconf.by_obfuscated.empty()) {
// 2 for '_' and terminal NULL
auto iov = make_byte_ref(config->balloc, SHRPX_OBFUSCATED_NODE_LENGTH + 2);
auto p = iov.base;
*p++ = '_';
std::mt19937 gen(rd());
auto &dst = fwdconf.by_obfuscated;
dst = "_";
dst += util::random_alpha_digit(gen, SHRPX_OBFUSCATED_NODE_LENGTH);
p = util::random_alpha_digit(p, p + SHRPX_OBFUSCATED_NODE_LENGTH, gen);
*p = '\0';
fwdconf.by_obfuscated = StringRef{iov.base, p};
}
if (config->http2.upstream.debug.frame_debug) {
@ -2616,12 +2620,13 @@ void reload_config(WorkerProcess *wp) {
LOG(NOTICE) << "Reloading configuration";
auto cur_config = get_config();
auto cur_config = mod_config();
auto new_config = make_unique<Config>();
fill_default_config(new_config.get());
new_config->conf_path = cur_config->conf_path;
new_config->conf_path =
make_string_ref(new_config->balloc, cur_config->conf_path);
// daemon option is ignored here.
new_config->daemon = cur_config->daemon;
// loop is reused, and ev_loop_flags gets ignored
@ -2633,7 +2638,7 @@ void reload_config(WorkerProcess *wp) {
return;
}
auto iaddrs = get_inherited_addr_from_config(cur_config);
auto iaddrs = get_inherited_addr_from_config(new_config->balloc, cur_config);
if (create_acceptor_socket(new_config.get(), iaddrs) != 0) {
close_not_inherited_fd(new_config.get(), iaddrs);
@ -3027,7 +3032,8 @@ int main(int argc, char **argv) {
break;
case 12:
// --conf
mod_config()->conf_path = ImmutableString{optarg};
mod_config()->conf_path =
make_string_ref(mod_config()->balloc, StringRef{optarg});
break;
case 14:
// --syslog-facility

View File

@ -376,17 +376,18 @@ int ClientHandler::upstream_http1_connhd_read() {
}
ClientHandler::ClientHandler(Worker *worker, int fd, SSL *ssl,
const char *ipaddr, const char *port, int family,
const UpstreamAddr *faddr)
: conn_(worker->get_loop(), fd, ssl, worker->get_mcpool(),
const StringRef &ipaddr, const StringRef &port,
int family, const UpstreamAddr *faddr)
: balloc_(256, 256),
conn_(worker->get_loop(), fd, ssl, worker->get_mcpool(),
get_config()->conn.upstream.timeout.write,
get_config()->conn.upstream.timeout.read,
get_config()->conn.upstream.ratelimit.write,
get_config()->conn.upstream.ratelimit.read, writecb, readcb,
timeoutcb, this, get_config()->tls.dyn_rec.warmup_threshold,
get_config()->tls.dyn_rec.idle_timeout, PROTO_NONE),
ipaddr_(ipaddr),
port_(port),
ipaddr_(make_string_ref(balloc_, ipaddr)),
port_(make_string_ref(balloc_, port)),
faddr_(faddr),
worker_(worker),
left_connhd_len_(NGHTTP2_CLIENT_MAGIC_LEN),
@ -416,13 +417,29 @@ ClientHandler::ClientHandler(Worker *worker, int fd, SSL *ssl,
if (fwdconf.params & FORWARDED_FOR) {
if (fwdconf.for_node_type == FORWARDED_NODE_OBFUSCATED) {
forwarded_for_ = "_";
forwarded_for_ += util::random_alpha_digit(worker_->get_randgen(),
SHRPX_OBFUSCATED_NODE_LENGTH);
// 1 for '_'
auto len = SHRPX_OBFUSCATED_NODE_LENGTH + 1;
// 1 for terminating NUL.
auto buf = make_byte_ref(balloc_, len + 1);
auto p = buf.base;
*p++ = '_';
p = util::random_alpha_digit(p, p + SHRPX_OBFUSCATED_NODE_LENGTH,
worker_->get_randgen());
*p = '\0';
forwarded_for_ = StringRef{buf.base, p};
} else if (family == AF_INET6) {
forwarded_for_ = "[";
forwarded_for_ += ipaddr_;
forwarded_for_ += ']';
// 2 for '[' and ']'
auto len = 2 + ipaddr_.size();
// 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 {
// family == AF_INET or family == AF_UNIX
forwarded_for_ = ipaddr_;
@ -441,7 +458,7 @@ void ClientHandler::setup_upstream_io_callback() {
// upgraded to HTTP/2 through HTTP Upgrade or direct HTTP/2
// connection.
upstream_ = make_unique<HttpsUpstream>(this);
alpn_ = "http/1.1";
alpn_ = StringRef::from_lit("http/1.1");
read_ = &ClientHandler::read_clear;
write_ = &ClientHandler::write_clear;
on_read_ = &ClientHandler::upstream_http1_connhd_read;
@ -524,7 +541,7 @@ int ClientHandler::validate_next_proto() {
}
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.
// The read callback is not called until new data come. So consume
@ -555,7 +572,7 @@ int ClientHandler::validate_next_proto() {
auto http2_upstream = make_unique<Http2Upstream>(this);
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.
// The read callback is not called until new data come. So consume
@ -574,16 +591,16 @@ int ClientHandler::validate_next_proto() {
switch (spdy_version) {
case SPDYLAY_PROTO_SPDY2:
alpn_ = "spdy/2";
alpn_ = StringRef::from_lit("spdy/2");
break;
case SPDYLAY_PROTO_SPDY3:
alpn_ = "spdy/3";
alpn_ = StringRef::from_lit("spdy/3");
break;
case SPDYLAY_PROTO_SPDY3_1:
alpn_ = "spdy/3.1";
alpn_ = StringRef::from_lit("spdy/3.1");
break;
default:
alpn_ = "spdy/unknown";
alpn_ = StringRef::from_lit("spdy/unknown");
}
// At this point, input buffer is already filled with some bytes.
@ -599,7 +616,7 @@ int ClientHandler::validate_next_proto() {
if (proto == StringRef::from_lit("http/1.1")) {
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.
// The read callback is not called until new data come. So consume
@ -629,7 +646,7 @@ int ClientHandler::on_read() {
}
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 {
return should_close_after_write_;
@ -974,7 +991,7 @@ ClientHandler::get_downstream_connection(Downstream *downstream) {
if (shared_addr->affinity == AFFINITY_IP) {
if (!affinity_hash_computed_) {
affinity_hash_ = compute_affinity_from_ip(StringRef{ipaddr_});
affinity_hash_ = compute_affinity_from_ip(ipaddr_);
affinity_hash_computed_ = true;
}
@ -1093,7 +1110,7 @@ SSL *ClientHandler::get_ssl() const { return conn_.tls.ssl; }
void ClientHandler::direct_http2_upgrade() {
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;
write_ = &ClientHandler::write_clear;
}
@ -1118,7 +1135,7 @@ int ClientHandler::perform_http2_upgrade(HttpsUpstream *http) {
upstream_.release();
// TODO We might get other version id in HTTP2-settings, if we
// 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;
write_ = &ClientHandler::write_clear;
@ -1199,7 +1216,7 @@ void ClientHandler::write_accesslog(Downstream *downstream) {
upstream_accesslog(
get_config()->logging.access.format,
LogSpec{
downstream, downstream->get_addr(), StringRef{ipaddr_},
downstream, downstream->get_addr(), ipaddr_,
http2::to_method_string(req.method),
req.method == HTTP_CONNECT
@ -1212,15 +1229,14 @@ void ClientHandler::write_accesslog(Downstream *downstream) {
: StringRef::from_lit("-")
: StringRef(req.path),
StringRef(alpn_),
nghttp2::ssl::get_tls_session_info(&tls_info, conn_.tls.ssl),
alpn_, nghttp2::ssl::get_tls_session_info(&tls_info, conn_.tls.ssl),
std::chrono::system_clock::now(), // time_now
downstream->get_request_start_time(), // request_start_time
std::chrono::high_resolution_clock::now(), // request_end_time
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,
});
}
@ -1231,21 +1247,20 @@ void ClientHandler::write_accesslog(int major, int minor, unsigned int status,
auto highres_now = std::chrono::high_resolution_clock::now();
nghttp2::ssl::TLSSessionInfo tls_info;
upstream_accesslog(get_config()->logging.access.format,
LogSpec{
nullptr, nullptr, StringRef(ipaddr_),
StringRef::from_lit("-"), // method
StringRef::from_lit("-"), // path,
StringRef(alpn_), nghttp2::ssl::get_tls_session_info(
&tls_info, conn_.tls.ssl),
time_now,
highres_now, // request_start_time TODO is
// there a better value?
highres_now, // request_end_time
major, minor, // major, minor
status, body_bytes_sent, StringRef(port_),
faddr_->port, get_config()->pid,
});
upstream_accesslog(
get_config()->logging.access.format,
LogSpec{
nullptr, nullptr, ipaddr_,
StringRef::from_lit("-"), // method
StringRef::from_lit("-"), // path,
alpn_, nghttp2::ssl::get_tls_session_info(&tls_info, conn_.tls.ssl),
time_now,
highres_now, // request_start_time TODO is
// there a better value?
highres_now, // request_end_time
major, minor, // major, minor
status, body_bytes_sent, port_, faddr_->port, get_config()->pid,
});
}
ClientHandler::ReadBuf *ClientHandler::get_rb() { return &rb_; }
@ -1474,8 +1489,9 @@ int ClientHandler::proxy_protocol_read() {
rb_.drain(end + 2 - rb_.pos);
ipaddr_.assign(src_addr, src_addr + src_addrlen);
port_.assign(src_port, src_port + src_portlen);
ipaddr_ =
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)) {
CLOG(INFO, this) << "PROXY-protocol-v1: Finished, " << (rb_.pos - first)
@ -1489,22 +1505,24 @@ StringRef ClientHandler::get_forwarded_by() const {
auto &fwdconf = get_config()->http.forwarded;
if (fwdconf.by_node_type == FORWARDED_NODE_OBFUSCATED) {
return StringRef(fwdconf.by_obfuscated);
return fwdconf.by_obfuscated;
}
return StringRef{faddr_->hostport};
return faddr_->hostport;
}
StringRef ClientHandler::get_forwarded_for() const {
return StringRef{forwarded_for_};
}
StringRef ClientHandler::get_forwarded_for() const { return forwarded_for_; }
const UpstreamAddr *ClientHandler::get_upstream_addr() const { return faddr_; }
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_; }
BlockAllocator &ClientHandler::get_block_allocator() { return balloc_; }
} // namespace shrpx

View File

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

View File

@ -151,7 +151,7 @@ bool is_secure(const StringRef &filename) {
} // namespace
std::unique_ptr<TicketKeys>
read_tls_ticket_key_file(const std::vector<std::string> &files,
read_tls_ticket_key_file(const std::vector<StringRef> &files,
const EVP_CIPHER *cipher, const EVP_MD *hmac) {
auto ticket_keys = make_unique<TicketKeys>();
auto &keys = ticket_keys->keys;
@ -272,29 +272,35 @@ std::string read_passwd_from_file(const StringRef &opt,
}
} // namespace
Headers::value_type parse_header(const StringRef &optarg) {
HeaderRefs::value_type parse_header(BlockAllocator &balloc,
const StringRef &optarg) {
auto colon = std::find(std::begin(optarg), std::end(optarg), ':');
if (colon == std::end(optarg) || colon == std::begin(optarg)) {
return {"", ""};
return {};
}
auto value = colon + 1;
for (; *value == '\t' || *value == ' '; ++value)
;
auto p = Header(std::string{std::begin(optarg), colon},
std::string{value, std::end(optarg)});
util::inp_strlower(p.name);
auto name_iov =
make_byte_ref(balloc, std::distance(std::begin(optarg), colon) + 1);
auto p = name_iov.base;
p = std::copy(std::begin(optarg), colon, p);
util::inp_strlower(name_iov.base, p);
*p = '\0';
if (!nghttp2_check_header_name(
reinterpret_cast<const uint8_t *>(p.name.c_str()), p.name.size()) ||
!nghttp2_check_header_value(
reinterpret_cast<const uint8_t *>(p.value.c_str()), p.value.size())) {
return Header{};
auto nv =
HeaderRef(StringRef{name_iov.base, p},
make_string_ref(balloc, StringRef{value, std::end(optarg)}));
if (!nghttp2_check_header_name(nv.name.byte(), nv.name.size()) ||
!nghttp2_check_header_value(nv.value.byte(), nv.value.size())) {
return {};
}
return p;
return nv;
}
template <typename T>
@ -490,7 +496,8 @@ bool var_token(char c) {
}
} // namespace
std::vector<LogFragment> parse_log_format(const StringRef &optarg) {
std::vector<LogFragment> parse_log_format(BlockAllocator &balloc,
const StringRef &optarg) {
auto literal_start = std::begin(optarg);
auto p = literal_start;
auto eop = std::end(optarg);
@ -553,8 +560,9 @@ std::vector<LogFragment> parse_log_format(const StringRef &optarg) {
}
if (literal_start < var_start) {
res.emplace_back(SHRPX_LOGF_LITERAL,
ImmutableString(literal_start, var_start));
res.emplace_back(
SHRPX_LOGF_LITERAL,
make_string_ref(balloc, StringRef{literal_start, var_start}));
}
literal_start = p;
@ -564,18 +572,24 @@ std::vector<LogFragment> parse_log_format(const StringRef &optarg) {
continue;
}
auto name = std::string(value, var_name + var_namelen);
for (auto &c : name) {
if (c == '_') {
c = '-';
{
auto iov = make_byte_ref(
balloc, std::distance(value, var_name + var_namelen) + 1);
auto p = iov.base;
p = std::copy(value, var_name + var_namelen, p);
for (auto cp = iov.base; cp != p; ++cp) {
if (*cp == '_') {
*cp = '-';
}
}
*p = '\0';
res.emplace_back(type, StringRef{iov.base, p});
}
res.emplace_back(type, ImmutableString(name));
}
if (literal_start != eop) {
res.emplace_back(SHRPX_LOGF_LITERAL, ImmutableString(literal_start, eop));
res.emplace_back(SHRPX_LOGF_LITERAL,
make_string_ref(balloc, StringRef{literal_start, eop}));
}
return res;
@ -804,7 +818,7 @@ namespace {
// as catch-all. We also parse protocol specified in |src_proto|.
//
// This function returns 0 if it succeeds, or -1.
int parse_mapping(Config *config, DownstreamAddrConfig addr,
int parse_mapping(Config *config, DownstreamAddrConfig &addr,
const StringRef &src_pattern, const StringRef &src_params) {
// This returns at least 1 element (it could be empty string). We
// will append '/' to all patterns, so it becomes catch-all pattern.
@ -824,7 +838,7 @@ int parse_mapping(Config *config, DownstreamAddrConfig addr,
addr.rise = params.rise;
addr.proto = params.proto;
addr.tls = params.tls;
addr.sni = ImmutableString{std::begin(params.sni), std::end(params.sni)};
addr.sni = make_string_ref(downstreamconf.balloc, params.sni);
auto &routerconf = downstreamconf.router;
auto &router = routerconf.router;
@ -833,18 +847,31 @@ int parse_mapping(Config *config, DownstreamAddrConfig addr,
for (const auto &raw_pattern : mapping) {
auto done = false;
std::string pattern;
StringRef pattern;
auto slash = std::find(std::begin(raw_pattern), std::end(raw_pattern), '/');
if (slash == std::end(raw_pattern)) {
// This effectively makes empty pattern to "/".
pattern.assign(std::begin(raw_pattern), std::end(raw_pattern));
util::inp_strlower(pattern);
pattern += '/';
// This effectively makes empty pattern to "/". 2 for '/' and
// terminal NULL character.
auto iov = make_byte_ref(downstreamconf.balloc, raw_pattern.size() + 2);
auto p = iov.base;
p = std::copy(std::begin(raw_pattern), std::end(raw_pattern), p);
util::inp_strlower(iov.base, p);
*p++ = '/';
*p = '\0';
pattern = StringRef{iov.base, p};
} else {
pattern.assign(std::begin(raw_pattern), slash);
util::inp_strlower(pattern);
pattern += http2::normalize_path(StringRef{slash, std::end(raw_pattern)},
StringRef{});
auto path = http2::normalize_path(downstreamconf.balloc,
StringRef{slash, std::end(raw_pattern)},
StringRef{});
auto iov = make_byte_ref(downstreamconf.balloc,
std::distance(std::begin(raw_pattern), slash) +
path.size() + 1);
auto p = iov.base;
p = std::copy(std::begin(raw_pattern), slash, p);
util::inp_strlower(iov.base, p);
p = std::copy(std::begin(path), std::end(path), p);
*p = '\0';
pattern = StringRef{iov.base, p};
}
for (auto &g : addr_groups) {
if (g.pattern == pattern) {
@ -863,7 +890,7 @@ int parse_mapping(Config *config, DownstreamAddrConfig addr,
}
auto idx = addr_groups.size();
addr_groups.emplace_back(StringRef{pattern});
addr_groups.emplace_back(pattern);
auto &g = addr_groups.back();
g.addrs.push_back(addr);
g.affinity = params.affinity;
@ -886,10 +913,13 @@ int parse_mapping(Config *config, DownstreamAddrConfig addr,
auto &router = wildcard_patterns.back().router;
router.add_route(path, idx);
auto rev_host = host.str();
std::reverse(std::begin(rev_host), std::end(rev_host));
auto iov = make_byte_ref(downstreamconf.balloc, host.size() + 1);
auto p = iov.base;
p = std::reverse_copy(std::begin(host), std::end(host), p);
*p = '\0';
auto rev_host = StringRef{iov.base, p};
rw_router.add_route(StringRef{rev_host}, wildcard_patterns.size() - 1);
rw_router.add_route(rev_host, wildcard_patterns.size() - 1);
} else {
(*it).router.add_route(path, idx);
}
@ -897,7 +927,7 @@ int parse_mapping(Config *config, DownstreamAddrConfig addr,
continue;
}
router.add_route(StringRef{g.pattern}, idx);
router.add_route(g.pattern, idx);
}
return 0;
}
@ -1804,12 +1834,14 @@ int parse_config(Config *config, int optid, const StringRef &opt,
switch (optid) {
case SHRPX_OPTID_BACKEND: {
auto &downstreamconf = *config->conn.downstream;
auto addr_end = std::find(std::begin(optarg), std::end(optarg), ';');
DownstreamAddrConfig addr{};
if (util::istarts_with(optarg, SHRPX_UNIX_PATH_PREFIX)) {
auto path = std::begin(optarg) + SHRPX_UNIX_PATH_PREFIX.size();
addr.host = ImmutableString(path, addr_end);
addr.host =
make_string_ref(downstreamconf.balloc, StringRef{path, addr_end});
addr.host_unix = true;
} else {
if (split_host_port(host, sizeof(host), &port,
@ -1817,7 +1849,7 @@ int parse_config(Config *config, int optid, const StringRef &opt,
return -1;
}
addr.host = ImmutableString(host);
addr.host = make_string_ref(downstreamconf.balloc, StringRef{host});
addr.port = port;
}
@ -1859,7 +1891,7 @@ int parse_config(Config *config, int optid, const StringRef &opt,
if (util::istarts_with(optarg, SHRPX_UNIX_PATH_PREFIX)) {
auto path = std::begin(optarg) + SHRPX_UNIX_PATH_PREFIX.size();
addr.host = ImmutableString{path, addr_end};
addr.host = make_string_ref(config->balloc, StringRef{path, addr_end});
addr.host_unix = true;
listenerconf.addrs.push_back(std::move(addr));
@ -1872,7 +1904,7 @@ int parse_config(Config *config, int optid, const StringRef &opt,
return -1;
}
addr.host = ImmutableString(host);
addr.host = make_string_ref(config->balloc, StringRef{host});
addr.port = port;
if (util::numeric_host(host, AF_INET)) {
@ -1969,8 +2001,7 @@ int parse_config(Config *config, int optid, const StringRef &opt,
case SHRPX_OPTID_STREAM_WRITE_TIMEOUT:
return parse_duration(&config->http2.timeout.stream_write, opt, optarg);
case SHRPX_OPTID_ACCESSLOG_FILE:
config->logging.access.file =
ImmutableString{std::begin(optarg), std::end(optarg)};
config->logging.access.file = make_string_ref(config->balloc, optarg);
return 0;
case SHRPX_OPTID_ACCESSLOG_SYSLOG:
@ -1978,12 +2009,11 @@ int parse_config(Config *config, int optid, const StringRef &opt,
return 0;
case SHRPX_OPTID_ACCESSLOG_FORMAT:
config->logging.access.format = parse_log_format(optarg);
config->logging.access.format = parse_log_format(config->balloc, optarg);
return 0;
case SHRPX_OPTID_ERRORLOG_FILE:
config->logging.error.file =
ImmutableString{std::begin(optarg), std::end(optarg)};
config->logging.error.file = make_string_ref(config->balloc, optarg);
return 0;
case SHRPX_OPTID_ERRORLOG_SYSLOG:
@ -2087,11 +2117,11 @@ int parse_config(Config *config, int optid, const StringRef &opt,
LOG(WARN) << opt << ": deprecated. Use sni keyword in --backend option. "
"For now, all sni values of all backends are "
"overridden by the given value " << optarg;
config->tls.backend_sni_name = optarg.str();
config->tls.backend_sni_name = make_string_ref(config->balloc, optarg);
return 0;
case SHRPX_OPTID_PID_FILE:
config->pid_file = ImmutableString{std::begin(optarg), std::end(optarg)};
config->pid_file = make_string_ref(config->balloc, optarg);
return 0;
case SHRPX_OPTID_USER: {
@ -2101,15 +2131,14 @@ int parse_config(Config *config, int optid, const StringRef &opt,
<< strerror(errno);
return -1;
}
config->user = ImmutableString{pwd->pw_name};
config->user = make_string_ref(config->balloc, StringRef{pwd->pw_name});
config->uid = pwd->pw_uid;
config->gid = pwd->pw_gid;
return 0;
}
case SHRPX_OPTID_PRIVATE_KEY_FILE:
config->tls.private_key_file =
ImmutableString{std::begin(optarg), std::end(optarg)};
config->tls.private_key_file = make_string_ref(config->balloc, optarg);
return 0;
case SHRPX_OPTID_PRIVATE_KEY_PASSWD_FILE: {
@ -2118,18 +2147,17 @@ int parse_config(Config *config, int optid, const StringRef &opt,
LOG(ERROR) << opt << ": Couldn't read key file's passwd from " << optarg;
return -1;
}
config->tls.private_key_passwd = ImmutableString{passwd};
config->tls.private_key_passwd =
make_string_ref(config->balloc, StringRef{passwd});
return 0;
}
case SHRPX_OPTID_CERTIFICATE_FILE:
config->tls.cert_file =
ImmutableString{std::begin(optarg), std::end(optarg)};
config->tls.cert_file = make_string_ref(config->balloc, optarg);
return 0;
case SHRPX_OPTID_DH_PARAM_FILE:
config->tls.dh_param_file =
ImmutableString{std::begin(optarg), std::end(optarg)};
config->tls.dh_param_file = make_string_ref(config->balloc, optarg);
return 0;
case SHRPX_OPTID_SUBCERT: {
@ -2154,7 +2182,9 @@ int parse_config(Config *config, int optid, const StringRef &opt,
return -1;
}
config->tls.subcerts.emplace_back(private_key_file.str(), cert_file.str());
config->tls.subcerts.emplace_back(
make_string_ref(config->balloc, private_key_file),
make_string_ref(config->balloc, cert_file));
return 0;
}
@ -2185,7 +2215,7 @@ int parse_config(Config *config, int optid, const StringRef &opt,
return 0;
}
case SHRPX_OPTID_CIPHERS:
config->tls.ciphers = ImmutableString{std::begin(optarg), std::end(optarg)};
config->tls.ciphers = make_string_ref(config->balloc, optarg);
return 0;
case SHRPX_OPTID_CLIENT:
@ -2197,7 +2227,7 @@ int parse_config(Config *config, int optid, const StringRef &opt,
return 0;
case SHRPX_OPTID_CACERT:
config->tls.cacert = ImmutableString{std::begin(optarg), std::end(optarg)};
config->tls.cacert = make_string_ref(config->balloc, optarg);
return 0;
case SHRPX_OPTID_BACKEND_IPV4:
@ -2228,11 +2258,12 @@ int parse_config(Config *config, int optid, const StringRef &opt,
// Surprisingly, u.field_set & UF_USERINFO is nonzero even if
// userinfo component is empty string.
if (!uf.empty()) {
proxy.userinfo = util::percent_decode(std::begin(uf), std::end(uf));
proxy.userinfo = util::percent_decode(config->balloc, uf);
}
}
if (u.field_set & UF_HOST) {
http2::copy_url_component(proxy.host, &u, UF_HOST, optarg.c_str());
proxy.host = make_string_ref(
config->balloc, util::get_uri_field(optarg.c_str(), u, UF_HOST));
} else {
LOG(ERROR) << opt << ": no hostname specified";
return -1;
@ -2275,11 +2306,11 @@ int parse_config(Config *config, int optid, const StringRef &opt,
LOG(WARN) << opt << ": not implemented yet";
return 0;
case SHRPX_OPTID_NPN_LIST:
config->tls.npn_list = util::parse_config_str_list(optarg);
config->tls.npn_list = util::split_str(optarg, ',');
return 0;
case SHRPX_OPTID_TLS_PROTO_LIST:
config->tls.tls_proto_list = util::parse_config_str_list(optarg);
config->tls.tls_proto_list = util::split_str(optarg, ',');
return 0;
case SHRPX_OPTID_VERIFY_CLIENT:
@ -2287,28 +2318,26 @@ int parse_config(Config *config, int optid, const StringRef &opt,
return 0;
case SHRPX_OPTID_VERIFY_CLIENT_CACERT:
config->tls.client_verify.cacert =
ImmutableString{std::begin(optarg), std::end(optarg)};
config->tls.client_verify.cacert = make_string_ref(config->balloc, optarg);
return 0;
case SHRPX_OPTID_CLIENT_PRIVATE_KEY_FILE:
config->tls.client.private_key_file =
ImmutableString{std::begin(optarg), std::end(optarg)};
make_string_ref(config->balloc, optarg);
return 0;
case SHRPX_OPTID_CLIENT_CERT_FILE:
config->tls.client.cert_file =
ImmutableString{std::begin(optarg), std::end(optarg)};
config->tls.client.cert_file = make_string_ref(config->balloc, optarg);
return 0;
case SHRPX_OPTID_FRONTEND_HTTP2_DUMP_REQUEST_HEADER:
config->http2.upstream.debug.dump.request_header_file =
ImmutableString{std::begin(optarg), std::end(optarg)};
make_string_ref(config->balloc, optarg);
return 0;
case SHRPX_OPTID_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER:
config->http2.upstream.debug.dump.response_header_file =
ImmutableString{std::begin(optarg), std::end(optarg)};
make_string_ref(config->balloc, optarg);
return 0;
case SHRPX_OPTID_HTTP2_NO_COOKIE_CRUMBLING:
@ -2350,16 +2379,16 @@ int parse_config(Config *config, int optid, const StringRef &opt,
AltSvc altsvc{};
altsvc.protocol_id = tokens[0].str();
altsvc.protocol_id = make_string_ref(config->balloc, tokens[0]);
altsvc.port = port;
altsvc.service = tokens[1].str();
altsvc.service = make_string_ref(config->balloc, tokens[1]);
if (tokens.size() > 2) {
altsvc.host = tokens[2].str();
altsvc.host = make_string_ref(config->balloc, tokens[2]);
if (tokens.size() > 3) {
altsvc.origin = tokens[3].str();
altsvc.origin = make_string_ref(config->balloc, tokens[3]);
}
}
@ -2369,7 +2398,7 @@ int parse_config(Config *config, int optid, const StringRef &opt,
}
case SHRPX_OPTID_ADD_REQUEST_HEADER:
case SHRPX_OPTID_ADD_RESPONSE_HEADER: {
auto p = parse_header(optarg);
auto p = parse_header(config->balloc, optarg);
if (p.name.empty()) {
LOG(ERROR) << opt << ": invalid header field: " << optarg;
return -1;
@ -2425,7 +2454,8 @@ int parse_config(Config *config, int optid, const StringRef &opt,
case SHRPX_OPTID_LISTENER_DISABLE_TIMEOUT:
return parse_duration(&config->conn.listener.timeout.sleep, opt, optarg);
case SHRPX_OPTID_TLS_TICKET_KEY_FILE:
config->tls.ticket.files.push_back(optarg.str());
config->tls.ticket.files.emplace_back(
make_string_ref(config->balloc, optarg));
return 0;
case SHRPX_OPTID_RLIMIT_NOFILE: {
int n;
@ -2475,7 +2505,7 @@ int parse_config(Config *config, int optid, const StringRef &opt,
return 0;
case SHRPX_OPTID_FETCH_OCSP_RESPONSE_FILE:
config->tls.ocsp.fetch_ocsp_response_file =
ImmutableString{std::begin(optarg), std::end(optarg)};
make_string_ref(config->balloc, optarg);
return 0;
case SHRPX_OPTID_OCSP_UPDATE_INTERVAL:
@ -2553,14 +2583,14 @@ int parse_config(Config *config, int optid, const StringRef &opt,
switch (optid) {
case SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED: {
auto &memcachedconf = config->tls.session_cache.memcached;
memcachedconf.host = ImmutableString{host};
memcachedconf.host = make_string_ref(config->balloc, StringRef{host});
memcachedconf.port = port;
memcachedconf.tls = params.tls;
break;
}
case SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED: {
auto &memcachedconf = config->tls.ticket.memcached;
memcachedconf.host = ImmutableString{host};
memcachedconf.host = make_string_ref(config->balloc, StringRef{host});
memcachedconf.port = port;
memcachedconf.tls = params.tls;
break;
@ -2603,7 +2633,7 @@ int parse_config(Config *config, int optid, const StringRef &opt,
case SHRPX_OPTID_MRUBY_FILE:
#ifdef HAVE_MRUBY
config->mruby_file = ImmutableString{std::begin(optarg), std::end(optarg)};
config->mruby_file = make_string_ref(config->balloc, optarg);
#else // !HAVE_MRUBY
LOG(WARN) << opt
<< ": ignored because mruby support is disabled at build time.";
@ -2662,9 +2692,9 @@ int parse_config(Config *config, int optid, const StringRef &opt,
case SHRPX_OPTID_FORWARDED_BY:
fwdconf.by_node_type = static_cast<shrpx_forwarded_node_type>(type);
if (optarg[0] == '_') {
fwdconf.by_obfuscated = optarg.str();
fwdconf.by_obfuscated = make_string_ref(config->balloc, optarg);
} else {
fwdconf.by_obfuscated = "";
fwdconf.by_obfuscated = StringRef::from_lit("");
}
break;
case SHRPX_OPTID_FORWARDED_FOR:
@ -2689,12 +2719,12 @@ int parse_config(Config *config, int optid, const StringRef &opt,
return 0;
case SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE:
config->tls.session_cache.memcached.cert_file =
ImmutableString{std::begin(optarg), std::end(optarg)};
make_string_ref(config->balloc, optarg);
return 0;
case SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE:
config->tls.session_cache.memcached.private_key_file =
ImmutableString{std::begin(optarg), std::end(optarg)};
make_string_ref(config->balloc, optarg);
return 0;
case SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_TLS:
@ -2703,12 +2733,12 @@ int parse_config(Config *config, int optid, const StringRef &opt,
return 0;
case SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_CERT_FILE:
config->tls.ticket.memcached.cert_file =
ImmutableString{std::begin(optarg), std::end(optarg)};
make_string_ref(config->balloc, optarg);
return 0;
case SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE:
config->tls.ticket.memcached.private_key_file =
ImmutableString{std::begin(optarg), std::end(optarg)};
make_string_ref(config->balloc, optarg);
return 0;
case SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_ADDRESS_FAMILY:
@ -2748,8 +2778,7 @@ int parse_config(Config *config, int optid, const StringRef &opt,
return parse_duration(&config->conn.downstream->timeout.max_backoff, opt,
optarg);
case SHRPX_OPTID_SERVER_NAME:
config->http.server_name =
ImmutableString{std::begin(optarg), std::end(optarg)};
config->http.server_name = make_string_ref(config->balloc, optarg);
return 0;
case SHRPX_OPTID_NO_SERVER_REWRITE:
@ -3071,13 +3100,13 @@ int configure_downstream_group(Config *config, bool http2_proxy,
if (addr_groups.empty()) {
DownstreamAddrConfig addr{};
addr.host = ImmutableString::from_lit(DEFAULT_DOWNSTREAM_HOST);
addr.host = StringRef::from_lit(DEFAULT_DOWNSTREAM_HOST);
addr.port = DEFAULT_DOWNSTREAM_PORT;
addr.proto = PROTO_HTTP1;
DownstreamAddrGroupConfig g(StringRef::from_lit("/"));
g.addrs.push_back(std::move(addr));
router.add_route(StringRef{g.pattern}, addr_groups.size());
router.add_route(g.pattern, addr_groups.size());
addr_groups.push_back(std::move(g));
} else if (http2_proxy) {
// We don't support host mapping in these cases. Move all
@ -3090,7 +3119,7 @@ int configure_downstream_group(Config *config, bool http2_proxy,
std::vector<DownstreamAddrGroupConfig>().swap(addr_groups);
// maybe not necessary?
routerconf = RouterConfig{};
router.add_route(StringRef{catch_all.pattern}, addr_groups.size());
router.add_route(catch_all.pattern, addr_groups.size());
addr_groups.push_back(std::move(catch_all));
}
@ -3100,7 +3129,7 @@ int configure_downstream_group(Config *config, bool http2_proxy,
auto &sni = tlsconf.backend_sni_name;
for (auto &addr_group : addr_groups) {
for (auto &addr : addr_group.addrs) {
addr.sni = ImmutableString{sni};
addr.sni = StringRef{sni};
}
}
}
@ -3147,7 +3176,7 @@ int configure_downstream_group(Config *config, bool http2_proxy,
// for AF_UNIX socket, we use "localhost" as host for backend
// hostport. This is used as Host header field to backend and
// not going to be passed to any syscalls.
addr.hostport = ImmutableString::from_lit("localhost");
addr.hostport = StringRef::from_lit("localhost");
auto path = addr.host.c_str();
auto pathlen = addr.host.size();
@ -3171,10 +3200,11 @@ int configure_downstream_group(Config *config, bool http2_proxy,
continue;
}
addr.hostport = ImmutableString(
util::make_http_hostport(StringRef(addr.host), addr.port));
addr.hostport =
util::make_http_hostport(downstreamconf.balloc, addr.host, addr.port);
auto hostport = util::make_hostport(StringRef{addr.host}, addr.port);
auto hostport =
util::make_hostport(downstreamconf.balloc, addr.host, addr.port);
if (resolve_hostname(&addr.addr, addr.host.c_str(), addr.port,
downstreamconf.family, resolve_flags) == -1) {

View File

@ -54,6 +54,7 @@
#include "template.h"
#include "http2.h"
#include "network.h"
#include "allocator.h"
using namespace nghttp2;
@ -336,7 +337,7 @@ enum shrpx_forwarded_node_type {
};
struct AltSvc {
std::string protocol_id, host, origin, service;
StringRef protocol_id, host, origin, service;
uint16_t port;
};
@ -352,12 +353,13 @@ enum UpstreamAltMode {
struct UpstreamAddr {
// The frontend address (e.g., FQDN, hostname, IP address). If
// |host_unix| is true, this is UNIX domain socket path.
ImmutableString host;
// |host_unix| is true, this is UNIX domain socket path. This must
// be NULL terminated string.
StringRef host;
// For TCP socket, this is <IP address>:<PORT>. For IPv6 address,
// address is surrounded by square brackets. If socket is UNIX
// domain socket, this is "localhost".
ImmutableString hostport;
StringRef hostport;
// frontend port. 0 if |host_unix| is true.
uint16_t port;
// For TCP socket, this is either AF_INET or AF_INET6. For UNIX
@ -375,13 +377,13 @@ struct UpstreamAddr {
struct DownstreamAddrConfig {
Address addr;
// backend address. If |host_unix| is true, this is UNIX domain
// socket path.
ImmutableString host;
// socket path. This must be NULL terminated string.
StringRef host;
// <HOST>:<PORT>. This does not treat 80 and 443 specially. If
// |host_unix| is true, this is "localhost".
ImmutableString hostport;
StringRef hostport;
// hostname sent as SNI field
ImmutableString sni;
StringRef sni;
size_t fall;
size_t rise;
// Application protocol used in this group
@ -404,9 +406,9 @@ struct AffinityHash {
struct DownstreamAddrGroupConfig {
DownstreamAddrGroupConfig(const StringRef &pattern)
: pattern(pattern.c_str(), pattern.size()), affinity(AFFINITY_NONE) {}
: pattern(pattern), affinity(AFFINITY_NONE) {}
ImmutableString pattern;
StringRef pattern;
std::vector<DownstreamAddrConfig> addrs;
// Bunch of session affinity hash. Only used if affinity ==
// AFFINITY_IP.
@ -437,9 +439,9 @@ struct TicketKeys {
struct HttpProxy {
Address addr;
// host in http proxy URI
std::string host;
StringRef host;
// userinfo in http proxy URI, not percent-encoded form
std::string userinfo;
StringRef userinfo;
// port in http proxy URI
uint16_t port;
};
@ -452,10 +454,10 @@ struct TLSConfig {
uint16_t port;
// Hostname of memcached server. This is also used as SNI field
// if TLS is enabled.
ImmutableString host;
StringRef host;
// Client private key and certificate for authentication
ImmutableString private_key_file;
ImmutableString cert_file;
StringRef private_key_file;
StringRef cert_file;
ev_tstamp interval;
// Maximum number of retries when getting TLS ticket key from
// mamcached, due to network error.
@ -468,7 +470,7 @@ struct TLSConfig {
int family;
bool tls;
} memcached;
std::vector<std::string> files;
std::vector<StringRef> files;
const EVP_CIPHER *cipher;
// true if --tls-ticket-key-cipher is used
bool cipher_given;
@ -481,10 +483,10 @@ struct TLSConfig {
uint16_t port;
// Hostname of memcached server. This is also used as SNI field
// if TLS is enabled.
ImmutableString host;
StringRef host;
// Client private key and certificate for authentication
ImmutableString private_key_file;
ImmutableString cert_file;
StringRef private_key_file;
StringRef cert_file;
// Address family of memcached connection. One of either
// AF_INET, AF_INET6 or AF_UNSPEC.
int family;
@ -501,7 +503,7 @@ struct TLSConfig {
// OCSP realted configurations
struct {
ev_tstamp update_interval;
ImmutableString fetch_ocsp_response_file;
StringRef fetch_ocsp_response_file;
bool disabled;
} ocsp;
@ -509,36 +511,36 @@ struct TLSConfig {
struct {
// Path to file containing CA certificate solely used for client
// certificate validation
ImmutableString cacert;
StringRef cacert;
bool enabled;
} client_verify;
// Client private key and certificate used in backend connections.
struct {
ImmutableString private_key_file;
ImmutableString cert_file;
StringRef private_key_file;
StringRef cert_file;
} client;
// The list of (private key file, certificate file) pair
std::vector<std::pair<std::string, std::string>> subcerts;
std::vector<std::pair<StringRef, StringRef>> subcerts;
std::vector<unsigned char> alpn_prefs;
// list of supported NPN/ALPN protocol strings in the order of
// preference.
std::vector<std::string> npn_list;
std::vector<StringRef> npn_list;
// list of supported SSL/TLS protocol strings.
std::vector<std::string> tls_proto_list;
std::vector<StringRef> tls_proto_list;
BIO_METHOD *bio_method;
// Bit mask to disable SSL/TLS protocol versions. This will be
// passed to SSL_CTX_set_options().
long int tls_proto_mask;
std::string backend_sni_name;
StringRef backend_sni_name;
std::chrono::seconds session_timeout;
ImmutableString private_key_file;
ImmutableString private_key_passwd;
ImmutableString cert_file;
ImmutableString dh_param_file;
ImmutableString ciphers;
ImmutableString cacert;
StringRef private_key_file;
StringRef private_key_passwd;
StringRef cert_file;
StringRef dh_param_file;
StringRef ciphers;
StringRef cacert;
bool insecure;
bool no_http2_cipher_black_list;
};
@ -556,7 +558,7 @@ struct HttpConfig {
// obfuscated value used in "by" parameter of Forwarded header
// field. This is only used when user defined static obfuscated
// string is provided.
std::string by_obfuscated;
StringRef by_obfuscated;
// bitwise-OR of one or more of shrpx_forwarded_param values.
uint32_t params;
// type of value recorded in "by" parameter of Forwarded header
@ -573,9 +575,9 @@ struct HttpConfig {
} xff;
std::vector<AltSvc> altsvcs;
std::vector<ErrorPage> error_pages;
Headers add_request_headers;
Headers add_response_headers;
ImmutableString server_name;
HeaderRefs add_request_headers;
HeaderRefs add_response_headers;
StringRef server_name;
size_t request_header_field_buffer;
size_t max_request_header_fields;
size_t response_header_field_buffer;
@ -590,8 +592,8 @@ struct Http2Config {
struct {
struct {
struct {
ImmutableString request_header_file;
ImmutableString response_header_file;
StringRef request_header_file;
StringRef response_header_file;
FILE *request_header;
FILE *response_header;
} dump;
@ -634,12 +636,12 @@ struct Http2Config {
struct LoggingConfig {
struct {
std::vector<LogFragment> format;
ImmutableString file;
StringRef file;
// Send accesslog to syslog, ignoring accesslog_file.
bool syslog;
} access;
struct {
ImmutableString file;
StringRef file;
// Send errorlog to syslog, ignoring errorlog_file.
bool syslog;
} error;
@ -655,10 +657,11 @@ struct RateLimitConfig {
// field. router includes all path patterns sharing the same wildcard
// host.
struct WildcardPattern {
WildcardPattern(const StringRef &host)
: host(std::begin(host), std::end(host)) {}
WildcardPattern(const StringRef &host) : host(host) {}
ImmutableString host;
// This might not be NULL terminated. Currently it is only used for
// comparison.
StringRef host;
Router router;
};
@ -676,7 +679,8 @@ struct RouterConfig {
struct DownstreamConfig {
DownstreamConfig()
: timeout{},
: balloc(1024, 1024),
timeout{},
addr_group_catch_all{0},
connections_per_host{0},
connections_per_frontend{0},
@ -684,6 +688,16 @@ struct DownstreamConfig {
response_buffer_size{0},
family{0} {}
DownstreamConfig(const DownstreamConfig &) = delete;
DownstreamConfig(DownstreamConfig &&) = delete;
DownstreamConfig &operator=(const DownstreamConfig &) = delete;
DownstreamConfig &operator=(DownstreamConfig &&) = delete;
// Allocator to allocate memory for Downstream configuration. Since
// we may swap around DownstreamConfig in arbitrary times with API
// calls, we should use their own allocator instead of per Config
// allocator.
BlockAllocator balloc;
struct {
ev_tstamp read;
ev_tstamp write;
@ -745,7 +759,25 @@ struct APIConfig {
};
struct Config {
Config() = default;
Config()
: balloc(4096, 4096),
downstream_http_proxy{},
http{},
http2{},
tls{},
logging{},
conn{},
api{},
num_worker{0},
padding{0},
rlimit_nofile{0},
uid{0},
gid{0},
pid{0},
verbose{false},
daemon{false},
http2_proxy{false},
ev_loop_flags{0} {}
~Config();
Config(Config &&) = delete;
@ -753,6 +785,10 @@ struct Config {
Config &operator=(Config &&) = delete;
Config &operator=(const Config &&) = delete;
// Allocator to allocate memory for this object except for
// DownstreamConfig. Currently, it is used to allocate memory for
// strings.
BlockAllocator balloc;
HttpProxy downstream_http_proxy;
HttpConfig http;
Http2Config http2;
@ -760,10 +796,10 @@ struct Config {
LoggingConfig logging;
ConnectionConfig conn;
APIConfig api;
ImmutableString pid_file;
ImmutableString conf_path;
ImmutableString user;
ImmutableString mruby_file;
StringRef pid_file;
StringRef conf_path;
StringRef user;
StringRef mruby_file;
size_t num_worker;
size_t padding;
size_t rlimit_nofile;
@ -958,9 +994,11 @@ int load_config(Config *config, const char *filename,
// like "NAME: VALUE". We require that NAME is non empty string. ":"
// is allowed at the start of the NAME, but NAME == ":" is not
// allowed. This function returns pair of NAME and VALUE.
Headers::value_type parse_header(const StringRef &optarg);
HeaderRefs::value_type parse_header(BlockAllocator &balloc,
const StringRef &optarg);
std::vector<LogFragment> parse_log_format(const StringRef &optarg);
std::vector<LogFragment> parse_log_format(BlockAllocator &balloc,
const StringRef &optarg);
// Returns string for syslog |facility|.
StringRef str_syslog_facility(int facility);
@ -975,7 +1013,7 @@ FILE *open_file_for_write(const char *filename);
// expected file size. This function returns TicketKey if it
// succeeds, or nullptr.
std::unique_ptr<TicketKeys>
read_tls_ticket_key_file(const std::vector<std::string> &files,
read_tls_ticket_key_file(const std::vector<StringRef> &files,
const EVP_CIPHER *cipher, const EVP_MD *hmac);
// Returns string representation of |proto|.

View File

@ -37,40 +37,45 @@
namespace shrpx {
void test_shrpx_config_parse_header(void) {
auto p = parse_header(StringRef::from_lit("a: b"));
BlockAllocator balloc(4096, 4096);
auto p = parse_header(balloc, StringRef::from_lit("a: b"));
CU_ASSERT("a" == p.name);
CU_ASSERT("b" == p.value);
p = parse_header(StringRef::from_lit("a: b"));
p = parse_header(balloc, StringRef::from_lit("a: b"));
CU_ASSERT("a" == p.name);
CU_ASSERT("b" == p.value);
p = parse_header(StringRef::from_lit(":a: b"));
p = parse_header(balloc, StringRef::from_lit(":a: b"));
CU_ASSERT(p.name.empty());
p = parse_header(StringRef::from_lit("a: :b"));
p = parse_header(balloc, StringRef::from_lit("a: :b"));
CU_ASSERT("a" == p.name);
CU_ASSERT(":b" == p.value);
p = parse_header(StringRef::from_lit(": b"));
p = parse_header(balloc, StringRef::from_lit(": b"));
CU_ASSERT(p.name.empty());
p = parse_header(StringRef::from_lit("alpha: bravo charlie"));
p = parse_header(balloc, StringRef::from_lit("alpha: bravo charlie"));
CU_ASSERT("alpha" == p.name);
CU_ASSERT("bravo charlie" == p.value);
p = parse_header(StringRef::from_lit("a,: b"));
p = parse_header(balloc, StringRef::from_lit("a,: b"));
CU_ASSERT(p.name.empty());
p = parse_header(StringRef::from_lit("a: b\x0a"));
p = parse_header(balloc, StringRef::from_lit("a: b\x0a"));
CU_ASSERT(p.name.empty());
}
void test_shrpx_config_parse_log_format(void) {
auto res = parse_log_format(StringRef::from_lit(
R"($remote_addr - $remote_user [$time_local] )"
R"("$request" $status $body_bytes_sent )"
R"("${http_referer}" $http_host "$http_user_agent")"));
BlockAllocator balloc(4096, 4096);
auto res = parse_log_format(
balloc, StringRef::from_lit(
R"($remote_addr - $remote_user [$time_local] )"
R"("$request" $status $body_bytes_sent )"
R"("${http_referer}" $http_host "$http_user_agent")"));
CU_ASSERT(16 == res.size());
CU_ASSERT(SHRPX_LOGF_REMOTE_ADDR == res[0].type);
@ -115,35 +120,35 @@ void test_shrpx_config_parse_log_format(void) {
CU_ASSERT(SHRPX_LOGF_LITERAL == res[15].type);
CU_ASSERT("\"" == res[15].value);
res = parse_log_format(StringRef::from_lit("$"));
res = parse_log_format(balloc, StringRef::from_lit("$"));
CU_ASSERT(1 == res.size());
CU_ASSERT(SHRPX_LOGF_LITERAL == res[0].type);
CU_ASSERT("$" == res[0].value);
res = parse_log_format(StringRef::from_lit("${"));
res = parse_log_format(balloc, StringRef::from_lit("${"));
CU_ASSERT(1 == res.size());
CU_ASSERT(SHRPX_LOGF_LITERAL == res[0].type);
CU_ASSERT("${" == res[0].value);
res = parse_log_format(StringRef::from_lit("${a"));
res = parse_log_format(balloc, StringRef::from_lit("${a"));
CU_ASSERT(1 == res.size());
CU_ASSERT(SHRPX_LOGF_LITERAL == res[0].type);
CU_ASSERT("${a" == res[0].value);
res = parse_log_format(StringRef::from_lit("${a "));
res = parse_log_format(balloc, StringRef::from_lit("${a "));
CU_ASSERT(1 == res.size());
CU_ASSERT(SHRPX_LOGF_LITERAL == res[0].type);
CU_ASSERT("${a " == res[0].value);
res = parse_log_format(StringRef::from_lit("$$remote_addr"));
res = parse_log_format(balloc, StringRef::from_lit("$$remote_addr"));
CU_ASSERT(2 == res.size());
@ -168,8 +173,8 @@ void test_shrpx_config_read_tls_ticket_key_file(void) {
close(fd1);
close(fd2);
auto ticket_keys =
read_tls_ticket_key_file({file1, file2}, EVP_aes_128_cbc(), EVP_sha256());
auto ticket_keys = read_tls_ticket_key_file(
{StringRef{file1}, StringRef{file2}}, EVP_aes_128_cbc(), EVP_sha256());
unlink(file1);
unlink(file2);
CU_ASSERT(ticket_keys.get() != nullptr);
@ -211,8 +216,8 @@ void test_shrpx_config_read_tls_ticket_key_file_aes_256(void) {
close(fd1);
close(fd2);
auto ticket_keys =
read_tls_ticket_key_file({file1, file2}, EVP_aes_256_cbc(), EVP_sha256());
auto ticket_keys = read_tls_ticket_key_file(
{StringRef{file1}, StringRef{file2}}, EVP_aes_256_cbc(), EVP_sha256());
unlink(file1);
unlink(file2);
CU_ASSERT(ticket_keys.get() != nullptr);

View File

@ -224,8 +224,8 @@ int ConnectionHandler::create_single_worker() {
#ifdef HAVE_NEVERBLEED
nb_.get(),
#endif // HAVE_NEVERBLEED
StringRef{tlsconf.cacert}, StringRef{memcachedconf.cert_file},
StringRef{memcachedconf.private_key_file}, nullptr);
tlsconf.cacert, memcachedconf.cert_file, memcachedconf.private_key_file,
nullptr);
all_ssl_ctx_.push_back(session_cache_ssl_ctx);
}
@ -280,8 +280,8 @@ int ConnectionHandler::create_worker_thread(size_t num) {
#ifdef HAVE_NEVERBLEED
nb_.get(),
#endif // HAVE_NEVERBLEED
StringRef{tlsconf.cacert}, StringRef{memcachedconf.cert_file},
StringRef{memcachedconf.private_key_file}, nullptr);
tlsconf.cacert, memcachedconf.cert_file,
memcachedconf.private_key_file, nullptr);
all_ssl_ctx_.push_back(session_cache_ssl_ctx);
}
auto worker = make_unique<Worker>(
@ -835,8 +835,8 @@ SSL_CTX *ConnectionHandler::create_tls_ticket_key_memcached_ssl_ctx() {
#ifdef HAVE_NEVERBLEED
nb_.get(),
#endif // HAVE_NEVERBLEED
StringRef{tlsconf.cacert}, StringRef{memcachedconf.cert_file},
StringRef{memcachedconf.private_key_file}, nullptr);
tlsconf.cacert, memcachedconf.cert_file, memcachedconf.private_key_file,
nullptr);
all_ssl_ctx_.push_back(ssl_ctx);

View File

@ -46,12 +46,11 @@ StringRef create_error_html(BlockAllocator &balloc, unsigned int http_status) {
}
auto status_string = http2::get_status_string(balloc, http_status);
const auto &server_name = httpconf.server_name;
return concat_string_ref(
balloc, StringRef::from_lit(R"(<!DOCTYPE html><html lang="en"><title>)"),
status_string, StringRef::from_lit("</title><body><h1>"), status_string,
StringRef::from_lit("</h1><footer>"), StringRef{server_name},
StringRef::from_lit("</h1><footer>"), httpconf.server_name,
StringRef::from_lit("</footer></body></html>"));
}

View File

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

View File

@ -108,15 +108,16 @@ int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
int Http2Upstream::upgrade_upstream(HttpsUpstream *http) {
int rv;
auto http2_settings = http->get_downstream()->get_http2_settings().str();
util::to_base64(http2_settings);
auto &balloc = http->get_downstream()->get_block_allocator();
auto settings_payload =
base64::decode(std::begin(http2_settings), std::end(http2_settings));
auto http2_settings = http->get_downstream()->get_http2_settings();
http2_settings = util::to_base64(balloc, http2_settings);
auto settings_payload = base64::decode(balloc, std::begin(http2_settings),
std::end(http2_settings));
rv = nghttp2_session_upgrade2(
session_, reinterpret_cast<const uint8_t *>(settings_payload.c_str()),
settings_payload.size(),
session_, settings_payload.byte(), settings_payload.size(),
http->get_downstream()->request().method == HTTP_HEAD, nullptr);
if (rv != 0) {
if (LOG_ENABLED(INFO)) {
@ -1429,8 +1430,8 @@ int Http2Upstream::send_reply(Downstream *downstream, const uint8_t *body,
}
if (!resp.fs.header(http2::HD_SERVER)) {
nva.push_back(http2::make_nv_ls_nocopy(
"server", StringRef{get_config()->http.server_name}));
nva.push_back(
http2::make_nv_ls_nocopy("server", get_config()->http.server_name));
}
for (auto &p : httpconf.add_response_headers) {
@ -1481,8 +1482,7 @@ int Http2Upstream::error_reply(Downstream *downstream,
auto nva = std::array<nghttp2_nv, 5>{
{http2::make_nv_ls_nocopy(":status", response_status),
http2::make_nv_ll("content-type", "text/html; charset=UTF-8"),
http2::make_nv_ls_nocopy("server",
StringRef{get_config()->http.server_name}),
http2::make_nv_ls_nocopy("server", get_config()->http.server_name),
http2::make_nv_ls_nocopy("content-length", content_length),
http2::make_nv_ls_nocopy("date", date)}};
@ -1629,8 +1629,7 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) {
http2::copy_headers_to_nva_nocopy(nva, resp.fs.headers());
if (!get_config()->http2_proxy && !httpconf.no_server_rewrite) {
nva.push_back(
http2::make_nv_ls_nocopy("server", StringRef{httpconf.server_name}));
nva.push_back(http2::make_nv_ls_nocopy("server", httpconf.server_name));
} else {
auto server = resp.fs.header(http2::HD_SERVER);
if (server) {

View File

@ -960,13 +960,14 @@ std::unique_ptr<Downstream> HttpsUpstream::pop_downstream() {
}
namespace {
void write_altsvc(DefaultMemchunks *buf, const AltSvc &altsvc) {
buf->append(util::percent_encode_token(altsvc.protocol_id));
void write_altsvc(DefaultMemchunks *buf, BlockAllocator &balloc,
const AltSvc &altsvc) {
buf->append(util::percent_encode_token(balloc, altsvc.protocol_id));
buf->append("=\"");
buf->append(util::quote_string(altsvc.host));
buf->append(":");
buf->append(util::quote_string(balloc, altsvc.host));
buf->append(':');
buf->append(altsvc.service);
buf->append("\"");
buf->append('"');
}
} // namespace
@ -1073,10 +1074,10 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
buf->append("Alt-Svc: ");
auto &altsvcs = httpconf.altsvcs;
write_altsvc(buf, altsvcs[0]);
write_altsvc(buf, downstream->get_block_allocator(), altsvcs[0]);
for (size_t i = 1; i < altsvcs.size(); ++i) {
buf->append(", ");
write_altsvc(buf, altsvcs[i]);
write_altsvc(buf, downstream->get_block_allocator(), altsvcs[i]);
}
buf->append("\r\n");
}

View File

@ -290,7 +290,7 @@ void upstream_accesslog(const std::vector<LogFragment> &lfv,
break;
case SHRPX_LOGF_HTTP:
if (req) {
auto hd = req->fs.header(StringRef(lf.value));
auto hd = req->fs.header(lf.value);
if (hd) {
std::tie(p, avail) = copy((*hd).value, avail, p);
break;

View File

@ -137,10 +137,10 @@ enum LogFragmentType {
};
struct LogFragment {
LogFragment(LogFragmentType type, ImmutableString value = ImmutableString())
LogFragment(LogFragmentType type, StringRef value = StringRef::from_lit(""))
: type(type), value(std::move(value)) {}
LogFragmentType type;
ImmutableString value;
StringRef value;
};
struct LogSpec {

View File

@ -100,7 +100,7 @@ MemcachedConnection::MemcachedConnection(const Address *addr,
connectcb, readcb, timeoutcb, this, 0, 0., PROTO_MEMCACHED),
do_read_(&MemcachedConnection::noop),
do_write_(&MemcachedConnection::noop),
sni_name_(sni_name.str()),
sni_name_(sni_name),
connect_blocker_(gen, loop, [] {}, [] {}),
parse_state_{},
addr_(addr),
@ -268,7 +268,7 @@ int MemcachedConnection::tls_handshake() {
auto &tlsconf = get_config()->tls;
if (!tlsconf.insecure &&
ssl::check_cert(conn_.tls.ssl, addr_, StringRef(sni_name_)) != 0) {
ssl::check_cert(conn_.tls.ssl, addr_, sni_name_) != 0) {
connect_blocker_.on_failure();
return -1;
}

View File

@ -135,7 +135,7 @@ private:
std::deque<std::unique_ptr<MemcachedRequest>> sendq_;
std::deque<MemcachedSendbuf> sendbufv_;
std::function<int(MemcachedConnection &)> do_read_, do_write_;
std::string sni_name_;
StringRef sni_name_;
ssl::TLSSessionCache tls_session_cache_;
ConnectBlocker connect_blocker_;
MemcachedParseState parse_state_;

View File

@ -103,7 +103,7 @@ int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
} // namespace
int set_alpn_prefs(std::vector<unsigned char> &out,
const std::vector<std::string> &protos) {
const std::vector<StringRef> &protos) {
size_t len = 0;
for (const auto &proto : protos) {
@ -125,8 +125,7 @@ int set_alpn_prefs(std::vector<unsigned char> &out,
for (const auto &proto : protos) {
*ptr++ = proto.size();
memcpy(ptr, proto.c_str(), proto.size());
ptr += proto.size();
ptr = std::copy(std::begin(proto), std::end(proto), ptr);
}
return 0;
@ -243,6 +242,7 @@ int tls_session_new_cb(SSL *ssl, SSL_SESSION *session) {
auto handler = static_cast<ClientHandler *>(conn->data);
auto worker = handler->get_worker();
auto dispatcher = worker->get_session_cache_memcached_dispatcher();
auto &balloc = handler->get_block_allocator();
const unsigned char *id;
unsigned int idlen;
@ -256,7 +256,8 @@ int tls_session_new_cb(SSL *ssl, SSL_SESSION *session) {
auto req = make_unique<MemcachedRequest>();
req->op = MEMCACHED_OP_ADD;
req->key = MEMCACHED_SESSION_CACHE_KEY_PREFIX.str();
req->key += util::format_hex(id, idlen);
req->key +=
util::format_hex(balloc, StringRef{id, static_cast<size_t>(idlen)});
auto sessionlen = i2d_SSL_SESSION(session, nullptr);
req->value.resize(sessionlen);
@ -295,6 +296,7 @@ SSL_SESSION *tls_session_get_cb(SSL *ssl,
auto handler = static_cast<ClientHandler *>(conn->data);
auto worker = handler->get_worker();
auto dispatcher = worker->get_session_cache_memcached_dispatcher();
auto &balloc = handler->get_block_allocator();
if (conn->tls.cached_session) {
if (LOG_ENABLED(INFO)) {
@ -318,7 +320,8 @@ SSL_SESSION *tls_session_get_cb(SSL *ssl,
auto req = make_unique<MemcachedRequest>();
req->op = MEMCACHED_OP_GET;
req->key = MEMCACHED_SESSION_CACHE_KEY_PREFIX.str();
req->key += util::format_hex(id, idlen);
req->key +=
util::format_hex(balloc, StringRef{id, static_cast<size_t>(idlen)});
req->cb = [conn](MemcachedRequest *, MemcachedResult res) {
if (LOG_ENABLED(INFO)) {
LOG(INFO) << "Memcached: returned status code " << res.status_code;
@ -465,8 +468,7 @@ int alpn_select_proto_cb(SSL *ssl, const unsigned char **out,
auto proto_len = *p;
if (proto_id + proto_len <= end &&
util::streq(StringRef{target_proto_id},
StringRef{proto_id, proto_len})) {
util::streq(target_proto_id, StringRef{proto_id, proto_len})) {
*out = reinterpret_cast<const unsigned char *>(proto_id);
*outlen = proto_len;
@ -493,7 +495,7 @@ constexpr TLSProtocol TLS_PROTOS[] = {
TLSProtocol{StringRef::from_lit("TLSv1.1"), SSL_OP_NO_TLSv1_1},
TLSProtocol{StringRef::from_lit("TLSv1.0"), SSL_OP_NO_TLSv1}};
long int create_tls_proto_mask(const std::vector<std::string> &tls_proto_list) {
long int create_tls_proto_mask(const std::vector<StringRef> &tls_proto_list) {
long int res = 0;
for (auto &supported : TLS_PROTOS) {
@ -829,16 +831,16 @@ SSL *create_ssl(SSL_CTX *ssl_ctx) {
ClientHandler *accept_connection(Worker *worker, int fd, sockaddr *addr,
int addrlen, const UpstreamAddr *faddr) {
char host[NI_MAXHOST];
char service[NI_MAXSERV];
std::array<char, NI_MAXHOST> host;
std::array<char, NI_MAXSERV> service;
int rv;
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';
} else {
rv = getnameinfo(addr, addrlen, host, sizeof(host), service,
sizeof(service), NI_NUMERICHOST | NI_NUMERICSERV);
rv = getnameinfo(addr, addrlen, host.data(), host.size(), service.data(),
service.size(), NI_NUMERICHOST | NI_NUMERICSERV);
if (rv != 0) {
LOG(ERROR) << "getnameinfo() failed: " << gai_strerror(rv);
@ -867,8 +869,8 @@ ClientHandler *accept_connection(Worker *worker, int fd, sockaddr *addr,
}
}
return new ClientHandler(worker, fd, ssl, host, service, addr->sa_family,
faddr);
return new ClientHandler(worker, fd, ssl, StringRef{host.data()},
StringRef{service.data()}, addr->sa_family, faddr);
}
bool tls_hostname_match(const StringRef &pattern, const StringRef &hostname) {
@ -1316,10 +1318,10 @@ int cert_lookup_tree_add_cert_from_x509(CertLookupTree *lt, size_t idx,
return 0;
}
bool in_proto_list(const std::vector<std::string> &protos,
bool in_proto_list(const std::vector<StringRef> &protos,
const StringRef &needle) {
for (auto &proto : protos) {
if (util::streq(StringRef{proto}, needle)) {
if (util::streq(proto, needle)) {
return true;
}
}
@ -1443,8 +1445,8 @@ SSL_CTX *setup_downstream_client_ssl_context(
#ifdef HAVE_NEVERBLEED
nb,
#endif // HAVE_NEVERBLEED
StringRef{tlsconf.cacert}, StringRef{tlsconf.client.cert_file},
StringRef{tlsconf.client.private_key_file}, select_next_proto_cb);
tlsconf.cacert, tlsconf.client.cert_file, tlsconf.client.private_key_file,
select_next_proto_cb);
}
void setup_downstream_http2_alpn(SSL *ssl) {

View File

@ -101,11 +101,6 @@ ClientHandler *accept_connection(Worker *worker, int fd, sockaddr *addr,
int check_cert(SSL *ssl, const Address *addr, const StringRef &host);
int check_cert(SSL *ssl, const DownstreamAddr *addr);
// Retrieves DNS and IP address in subjectAltNames and commonName from
// the |cert|.
void get_altnames(X509 *cert, std::vector<std::string> &dns_names,
std::vector<std::string> &ip_addrs, std::string &common_name);
struct WildcardRevPrefix {
WildcardRevPrefix(const StringRef &prefix, size_t idx)
: prefix(std::begin(prefix), std::end(prefix)), idx(idx) {}
@ -172,7 +167,7 @@ int cert_lookup_tree_add_cert_from_x509(CertLookupTree *lt, size_t idx,
// Returns true if |proto| is included in the
// protocol list |protos|.
bool in_proto_list(const std::vector<std::string> &protos,
bool in_proto_list(const std::vector<StringRef> &protos,
const StringRef &proto);
// Returns true if security requirement for HTTP/2 is fulfilled.
@ -181,10 +176,10 @@ bool check_http2_requirement(SSL *ssl);
// Returns SSL/TLS option mask to disable SSL/TLS protocol version not
// included in |tls_proto_list|. The returned mask can be directly
// passed to SSL_CTX_set_options().
long int create_tls_proto_mask(const std::vector<std::string> &tls_proto_list);
long int create_tls_proto_mask(const std::vector<StringRef> &tls_proto_list);
int set_alpn_prefs(std::vector<unsigned char> &out,
const std::vector<std::string> &protos);
const std::vector<StringRef> &protos);
// Setups server side SSL_CTX. This function inspects get_config()
// and if upstream_no_tls is true, returns nullptr. Otherwise

View File

@ -182,7 +182,8 @@ void Worker::replace_downstream_config(
auto &dst = downstream_addr_groups_[i];
dst = std::make_shared<DownstreamAddrGroup>();
dst->pattern = src.pattern;
dst->pattern =
ImmutableString{std::begin(src.pattern), std::end(src.pattern)};
auto shared_addr = std::make_shared<SharedDownstreamAddr>();
@ -198,13 +199,14 @@ void Worker::replace_downstream_config(
auto &dst_addr = shared_addr->addrs[j];
dst_addr.addr = src_addr.addr;
dst_addr.host = src_addr.host;
dst_addr.hostport = src_addr.hostport;
dst_addr.host = make_string_ref(shared_addr->balloc, src_addr.host);
dst_addr.hostport =
make_string_ref(shared_addr->balloc, src_addr.hostport);
dst_addr.port = src_addr.port;
dst_addr.host_unix = src_addr.host_unix;
dst_addr.proto = src_addr.proto;
dst_addr.tls = src_addr.tls;
dst_addr.sni = src_addr.sni;
dst_addr.sni = make_string_ref(shared_addr->balloc, src_addr.sni);
dst_addr.fall = src_addr.fall;
dst_addr.rise = src_addr.rise;

View File

@ -48,6 +48,7 @@
#include "shrpx_ssl.h"
#include "shrpx_live_check.h"
#include "shrpx_connect_blocker.h"
#include "allocator.h"
using namespace nghttp2;
@ -75,15 +76,15 @@ struct DownstreamAddr {
Address addr;
// backend address. If |host_unix| is true, this is UNIX domain
// socket path.
ImmutableString host;
ImmutableString hostport;
StringRef host;
StringRef hostport;
// backend port. 0 if |host_unix| is true.
uint16_t port;
// true if |host| contains UNIX domain socket path.
bool host_unix;
// sni field to send remote server if TLS is enabled.
ImmutableString sni;
StringRef sni;
std::unique_ptr<ConnectBlocker> connect_blocker;
std::unique_ptr<LiveCheck> live_check;
@ -128,8 +129,18 @@ struct WeightedPri {
struct SharedDownstreamAddr {
SharedDownstreamAddr()
: next{0}, http1_pri{}, http2_pri{}, affinity{AFFINITY_NONE} {}
: balloc(1024, 1024),
next{0},
http1_pri{},
http2_pri{},
affinity{AFFINITY_NONE} {}
SharedDownstreamAddr(const SharedDownstreamAddr &) = delete;
SharedDownstreamAddr(SharedDownstreamAddr &&) = delete;
SharedDownstreamAddr &operator=(const SharedDownstreamAddr &) = delete;
SharedDownstreamAddr &operator=(SharedDownstreamAddr &&) = delete;
BlockAllocator balloc;
std::vector<DownstreamAddr> addrs;
// Bunch of session affinity hash. Only used if affinity ==
// AFFINITY_IP.
@ -162,6 +173,11 @@ struct SharedDownstreamAddr {
struct DownstreamAddrGroup {
DownstreamAddrGroup() : retired{false} {};
DownstreamAddrGroup(const DownstreamAddrGroup &) = delete;
DownstreamAddrGroup(DownstreamAddrGroup &&) = delete;
DownstreamAddrGroup &operator=(const DownstreamAddrGroup &) = delete;
DownstreamAddrGroup &operator=(DownstreamAddrGroup &&) = delete;
ImmutableString pattern;
std::shared_ptr<SharedDownstreamAddr> shared_addr;
// true if this group is no longer used for new request. If this is

View File

@ -131,11 +131,10 @@ bool in_attr_char(char c) {
std::find(std::begin(bad), std::end(bad), c) == std::end(bad);
}
std::string percent_encode_token(const std::string &target) {
std::string dest;
dest.resize(target.size() * 3);
auto p = std::begin(dest);
StringRef percent_encode_token(BlockAllocator &balloc,
const StringRef &target) {
auto iov = make_byte_ref(balloc, target.size() * 3 + 1);
auto p = iov.base;
for (auto first = std::begin(target); first != std::end(target); ++first) {
uint8_t c = *first;
@ -149,8 +148,10 @@ std::string percent_encode_token(const std::string &target) {
*p++ = UPPER_XDIGITS[c >> 4];
*p++ = UPPER_XDIGITS[(c & 0x0f)];
}
dest.resize(p - std::begin(dest));
return dest;
*p = '\0';
return StringRef{iov.base, p};
}
uint32_t hex_to_uint(char c) {
@ -166,25 +167,27 @@ uint32_t hex_to_uint(char c) {
return c;
}
std::string quote_string(const std::string &target) {
StringRef quote_string(BlockAllocator &balloc, const StringRef &target) {
auto cnt = std::count(std::begin(target), std::end(target), '"');
if (cnt == 0) {
return target;
return make_string_ref(balloc, target);
}
std::string res;
res.reserve(target.size() + cnt);
auto iov = make_byte_ref(balloc, target.size() + cnt + 1);
auto p = iov.base;
for (auto c : target) {
if (c == '"') {
res += "\\\"";
*p++ = '\\';
*p++ = '"';
} else {
res += c;
*p++ = c;
}
}
*p = '\0';
return res;
return StringRef{iov.base, p};
}
namespace {
@ -376,6 +379,21 @@ std::string format_hex(const unsigned char *s, size_t len) {
return res;
}
StringRef format_hex(BlockAllocator &balloc, const StringRef &s) {
auto iov = make_byte_ref(balloc, s.size() * 2 + 1);
auto p = iov.base;
for (auto cc : s) {
uint8_t c = cc;
*p++ = LOWER_XDIGITS[c >> 4];
*p++ = LOWER_XDIGITS[c & 0xf];
}
*p = '\0';
return StringRef{iov.base, p};
}
void to_token68(std::string &base64str) {
std::transform(std::begin(base64str), std::end(base64str),
std::begin(base64str), [](char c) {
@ -392,22 +410,32 @@ void to_token68(std::string &base64str) {
std::end(base64str));
}
void to_base64(std::string &token68str) {
std::transform(std::begin(token68str), std::end(token68str),
std::begin(token68str), [](char c) {
switch (c) {
case '-':
return '+';
case '_':
return '/';
default:
return c;
}
});
if (token68str.size() & 0x3) {
token68str.append(4 - (token68str.size() & 0x3), '=');
StringRef to_base64(BlockAllocator &balloc, const StringRef &token68str) {
// At most 3 padding '='
auto len = token68str.size() + 3;
auto iov = make_byte_ref(balloc, len + 1);
auto p = iov.base;
p = std::transform(std::begin(token68str), std::end(token68str), p,
[](char c) {
switch (c) {
case '-':
return '+';
case '_':
return '/';
default:
return c;
}
});
auto rem = token68str.size() & 0x3;
if (rem) {
p = std::fill_n(p, 4 - rem, '=');
}
return;
*p = '\0';
return StringRef{iov.base, p};
}
namespace {
@ -1119,29 +1147,30 @@ std::string dtos(double n) {
return utos(static_cast<int64_t>(n)) + "." + (f.size() == 1 ? "0" : "") + f;
}
std::string make_http_hostport(const StringRef &host, uint16_t port) {
StringRef make_http_hostport(BlockAllocator &balloc, const StringRef &host,
uint16_t port) {
if (port != 80 && port != 443) {
return make_hostport(host, port);
return make_hostport(balloc, host, port);
}
auto ipv6 = ipv6_numeric_addr(host.c_str());
std::string hostport;
hostport.resize(host.size() + (ipv6 ? 2 : 0));
auto p = &hostport[0];
auto iov = make_byte_ref(balloc, host.size() + (ipv6 ? 2 : 0) + 1);
auto p = iov.base;
if (ipv6) {
*p++ = '[';
}
p = std::copy_n(host.c_str(), host.size(), p);
p = std::copy(std::begin(host), std::end(host), p);
if (ipv6) {
*p++ = ']';
}
return hostport;
*p = '\0';
return StringRef{iov.base, p};
}
std::string make_hostport(const StringRef &host, uint16_t port) {
@ -1169,6 +1198,34 @@ std::string make_hostport(const StringRef &host, uint16_t port) {
return hostport;
}
StringRef make_hostport(BlockAllocator &balloc, const StringRef &host,
uint16_t port) {
auto ipv6 = ipv6_numeric_addr(host.c_str());
auto serv = utos(port);
auto iov =
make_byte_ref(balloc, host.size() + (ipv6 ? 2 : 0) + 1 + serv.size());
auto p = iov.base;
if (ipv6) {
*p++ = '[';
}
p = std::copy(std::begin(host), std::end(host), p);
if (ipv6) {
*p++ = ']';
}
*p++ = ':';
p = std::copy(std::begin(serv), std::end(serv), p);
*p = '\0';
return StringRef{iov.base, p};
}
namespace {
void hexdump8(FILE *out, const uint8_t *first, const uint8_t *last) {
auto stop = std::min(first + 8, last);

View File

@ -129,11 +129,11 @@ std::string percent_decode(InputIt first, InputIt last) {
StringRef percent_decode(BlockAllocator &balloc, const StringRef &src);
// Percent encode |target| if character is not in token or '%'.
std::string percent_encode_token(const std::string &target);
StringRef percent_encode_token(BlockAllocator &balloc, const StringRef &target);
// Returns quotedString version of |target|. Currently, this function
// just replace '"' with '\"'.
std::string quote_string(const std::string &target);
StringRef quote_string(BlockAllocator &balloc, const StringRef &target);
std::string format_hex(const unsigned char *s, size_t len);
@ -145,6 +145,8 @@ template <size_t N> std::string format_hex(const std::array<uint8_t, N> &s) {
return format_hex(s.data(), s.size());
}
StringRef format_hex(BlockAllocator &balloc, const StringRef &s);
std::string http_date(time_t t);
// Returns given time |t| from epoch in Common Log format (e.g.,
@ -424,7 +426,8 @@ template <typename T> std::string utox(T n) {
}
void to_token68(std::string &base64str);
void to_base64(std::string &token68str);
StringRef to_base64(BlockAllocator &balloc, const StringRef &token68str);
void show_candidates(const char *unkopt, option *options);
@ -630,12 +633,16 @@ std::string format_duration(double t);
// Creates "host:port" string using given |host| and |port|. If
// |host| is numeric IPv6 address (e.g., ::1), it is enclosed by "["
// and "]". If |port| is 80 or 443, port part is omitted.
std::string make_http_hostport(const StringRef &host, uint16_t port);
StringRef make_http_hostport(BlockAllocator &balloc, const StringRef &host,
uint16_t port);
// Just like make_http_hostport(), but doesn't treat 80 and 443
// specially.
std::string make_hostport(const StringRef &host, uint16_t port);
StringRef make_hostport(BlockAllocator &balloc, const StringRef &host,
uint16_t port);
// Dumps |src| of length |len| in the format similar to `hexdump -C`.
void hexdump(FILE *out, const uint8_t *src, size_t len);
@ -665,16 +672,17 @@ uint64_t get_uint64(const uint8_t *data);
int read_mime_types(std::map<std::string, std::string> &res,
const char *filename);
template <typename Generator>
std::string random_alpha_digit(Generator &gen, size_t len) {
std::string res;
res.reserve(len);
// Fills random alpha and digit byte to the range [|first|, |last|).
// Returns the one beyond the |last|.
template <typename OutputIt, typename Generator>
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);
for (; len > 0; --len) {
res += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"[dis(
gen)];
for (; first != last; ++first) {
*first = s[dis(gen)];
}
return res;
return first;
}
template <typename OutputIterator, typename CharT, size_t N>

View File

@ -26,6 +26,7 @@
#include <cstring>
#include <iostream>
#include <random>
#include <CUnit/CUnit.h>
@ -113,13 +114,12 @@ void test_util_inp_strlower(void) {
}
void test_util_to_base64(void) {
std::string x = "AAA--B_";
util::to_base64(x);
CU_ASSERT("AAA++B/=" == x);
BlockAllocator balloc(4096, 4096);
x = "AAA--B_B";
util::to_base64(x);
CU_ASSERT("AAA++B/B" == x);
CU_ASSERT("AAA++B/=" ==
util::to_base64(balloc, StringRef::from_lit("AAA--B_")));
CU_ASSERT("AAA++B/B" ==
util::to_base64(balloc, StringRef::from_lit("AAA--B_B")));
}
void test_util_to_token68(void) {
@ -133,10 +133,15 @@ void test_util_to_token68(void) {
}
void test_util_percent_encode_token(void) {
CU_ASSERT("h2" == util::percent_encode_token("h2"));
CU_ASSERT("h3~" == util::percent_encode_token("h3~"));
CU_ASSERT("100%25" == util::percent_encode_token("100%"));
CU_ASSERT("http%202" == util::percent_encode_token("http 2"));
BlockAllocator balloc(4096, 4096);
CU_ASSERT("h2" ==
util::percent_encode_token(balloc, StringRef::from_lit("h2")));
CU_ASSERT("h3~" ==
util::percent_encode_token(balloc, StringRef::from_lit("h3~")));
CU_ASSERT("100%25" ==
util::percent_encode_token(balloc, StringRef::from_lit("100%")));
CU_ASSERT("http%202" ==
util::percent_encode_token(balloc, StringRef::from_lit("http 2")));
}
void test_util_percent_encode_path(void) {
@ -169,9 +174,12 @@ void test_util_percent_decode(void) {
}
void test_util_quote_string(void) {
CU_ASSERT("alpha" == util::quote_string("alpha"));
CU_ASSERT("" == util::quote_string(""));
CU_ASSERT("\\\"alpha\\\"" == util::quote_string("\"alpha\""));
BlockAllocator balloc(4096, 4096);
CU_ASSERT("alpha" ==
util::quote_string(balloc, StringRef::from_lit("alpha")));
CU_ASSERT("" == util::quote_string(balloc, StringRef::from_lit("")));
CU_ASSERT("\\\"alpha\\\"" ==
util::quote_string(balloc, StringRef::from_lit("\"alpha\"")));
}
void test_util_utox(void) {
@ -494,12 +502,15 @@ void test_util_parse_config_str_list(void) {
}
void test_util_make_http_hostport(void) {
CU_ASSERT("localhost" ==
util::make_http_hostport(StringRef::from_lit("localhost"), 80));
BlockAllocator balloc(4096, 4096);
CU_ASSERT("localhost" == util::make_http_hostport(
balloc, StringRef::from_lit("localhost"), 80));
CU_ASSERT("[::1]" ==
util::make_http_hostport(StringRef::from_lit("::1"), 443));
CU_ASSERT("localhost:3000" ==
util::make_http_hostport(StringRef::from_lit("localhost"), 3000));
util::make_http_hostport(balloc, StringRef::from_lit("::1"), 443));
CU_ASSERT(
"localhost:3000" ==
util::make_http_hostport(balloc, StringRef::from_lit("localhost"), 3000));
}
void test_util_make_hostport(void) {
@ -507,6 +518,12 @@ void test_util_make_hostport(void) {
util::make_hostport(StringRef::from_lit("localhost"), 80));
CU_ASSERT("[::1]:443" ==
util::make_hostport(StringRef::from_lit("::1"), 443));
BlockAllocator balloc(4096, 4096);
CU_ASSERT("localhost:80" ==
util::make_hostport(balloc, StringRef::from_lit("localhost"), 80));
CU_ASSERT("[::1]:443" ==
util::make_hostport(balloc, StringRef::from_lit("::1"), 443));
}
void test_util_strifind(void) {
@ -528,4 +545,27 @@ void test_util_strifind(void) {
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'));
}
}
void test_util_format_hex(void) {
BlockAllocator balloc(4096, 4096);
CU_ASSERT("0ff0" ==
util::format_hex(balloc, StringRef::from_lit("\x0f\xf0")));
CU_ASSERT("" == util::format_hex(balloc, StringRef::from_lit("")));
}
} // namespace shrpx

View File

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