Merge branch 'nghttpx-more-block-allocator'
This commit is contained in:
commit
35594e09df
56
src/base64.h
56
src/base64.h
|
@ -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
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) ||
|
||||
|
|
70
src/shrpx.cc
70
src/shrpx.cc
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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|.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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>"));
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
131
src/util.cc
131
src/util.cc
|
@ -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);
|
||||
|
|
32
src/util.h
32
src/util.h
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue