nghttpx: Use VString for DownstreamAddr::host and hostport to remember size

This commit is contained in:
Tatsuhiro Tsujikawa 2016-01-17 00:52:41 +09:00
parent dbbf3a4a10
commit 34d5382d66
9 changed files with 84 additions and 41 deletions

View File

@ -151,6 +151,12 @@ nghttp2_nv make_nv_ls_nocopy(const char(&name)[N], const std::string &value) {
NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE}; NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE};
} }
template <size_t N>
nghttp2_nv make_nv_ls_nocopy(const char(&name)[N], const StringAdaptor &value) {
return {(uint8_t *)name, (uint8_t *)value.c_str(), N - 1, value.size(),
NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE};
}
// Appends headers in |headers| to |nv|. |headers| must be indexed // Appends headers in |headers| to |nv|. |headers| must be indexed
// before this call (its element's token field is assigned). Certain // before this call (its element's token field is assigned). Certain
// headers, including disallowed headers in HTTP/2 spec and headers // headers, including disallowed headers in HTTP/2 spec and headers

View File

@ -2474,7 +2474,7 @@ int main(int argc, char **argv) {
if (get_config()->downstream_addr_groups.empty()) { if (get_config()->downstream_addr_groups.empty()) {
DownstreamAddr addr; DownstreamAddr addr;
addr.host = strcopy(DEFAULT_DOWNSTREAM_HOST); addr.host = VString(DEFAULT_DOWNSTREAM_HOST);
addr.port = DEFAULT_DOWNSTREAM_PORT; addr.port = DEFAULT_DOWNSTREAM_PORT;
DownstreamAddrGroup g("/"); DownstreamAddrGroup g("/");
@ -2513,7 +2513,7 @@ int main(int argc, char **argv) {
LOG(INFO) << "Host-path pattern: group " << i << ": '" << g.pattern.get() LOG(INFO) << "Host-path pattern: group " << i << ": '" << g.pattern.get()
<< "'"; << "'";
for (auto &addr : g.addrs) { for (auto &addr : g.addrs) {
LOG(INFO) << "group " << i << " -> " << addr.host.get() LOG(INFO) << "group " << i << " -> " << addr.host.c_str()
<< (addr.host_unix ? "" : ":" + util::utos(addr.port)); << (addr.host_unix ? "" : ":" + util::utos(addr.port));
} }
} }
@ -2537,10 +2537,10 @@ int main(int argc, char **argv) {
// hostport. This is used as Host header field to backend and // hostport. This is used as Host header field to backend and
// not going to be passed to any syscalls. // not going to be passed to any syscalls.
addr.hostport = addr.hostport =
strcopy(util::make_hostport("localhost", get_config()->port)); VString(util::make_hostport("localhost", get_config()->port));
auto path = addr.host.get(); auto path = addr.host.c_str();
auto pathlen = strlen(path); auto pathlen = addr.host.size();
if (pathlen + 1 > sizeof(addr.addr.su.un.sun_path)) { if (pathlen + 1 > sizeof(addr.addr.su.un.sun_path)) {
LOG(FATAL) << "UNIX domain socket path " << path << " is too long > " LOG(FATAL) << "UNIX domain socket path " << path << " is too long > "
@ -2559,10 +2559,11 @@ int main(int argc, char **argv) {
continue; continue;
} }
addr.hostport = strcopy(util::make_hostport(addr.host.get(), addr.port)); addr.hostport =
VString(util::make_hostport(addr.host.c_str(), addr.port));
if (resolve_hostname( if (resolve_hostname(
&addr.addr, addr.host.get(), addr.port, &addr.addr, addr.host.c_str(), addr.port,
get_config()->backend_ipv4 ? AF_INET : (get_config()->backend_ipv6 get_config()->backend_ipv4 ? AF_INET : (get_config()->backend_ipv6
? AF_INET6 ? AF_INET6
: AF_UNSPEC)) == -1) { : AF_UNSPEC)) == -1) {

View File

@ -79,9 +79,8 @@ TicketKeys::~TicketKeys() {
} }
DownstreamAddr::DownstreamAddr(const DownstreamAddr &other) DownstreamAddr::DownstreamAddr(const DownstreamAddr &other)
: addr(other.addr), host(strcopy(other.host)), : addr(other.addr), host(other.host), hostport(other.hostport),
hostport(strcopy(other.hostport)), port(other.port), port(other.port), host_unix(other.host_unix) {}
host_unix(other.host_unix) {}
DownstreamAddr &DownstreamAddr::operator=(const DownstreamAddr &other) { DownstreamAddr &DownstreamAddr::operator=(const DownstreamAddr &other) {
if (this == &other) { if (this == &other) {
@ -89,8 +88,8 @@ DownstreamAddr &DownstreamAddr::operator=(const DownstreamAddr &other) {
} }
addr = other.addr; addr = other.addr;
host = strcopy(other.host); host = other.host;
hostport = strcopy(other.hostport); hostport = other.hostport;
port = other.port; port = other.port;
host_unix = other.host_unix; host_unix = other.host_unix;
@ -1394,7 +1393,7 @@ int parse_config(const char *opt, const char *optarg,
DownstreamAddr addr; DownstreamAddr addr;
if (util::istarts_with(optarg, SHRPX_UNIX_PATH_PREFIX)) { if (util::istarts_with(optarg, SHRPX_UNIX_PATH_PREFIX)) {
auto path = optarg + str_size(SHRPX_UNIX_PATH_PREFIX); auto path = optarg + str_size(SHRPX_UNIX_PATH_PREFIX);
addr.host = strcopy(path, pat_delim); addr.host = VString(path, pat_delim);
addr.host_unix = true; addr.host_unix = true;
} else { } else {
if (split_host_port(host, sizeof(host), &port, optarg, if (split_host_port(host, sizeof(host), &port, optarg,
@ -1402,7 +1401,7 @@ int parse_config(const char *opt, const char *optarg,
return -1; return -1;
} }
addr.host = strcopy(host); addr.host = VString(host);
addr.port = port; addr.port = port;
} }

View File

@ -245,8 +245,8 @@ struct DownstreamAddr {
Address addr; Address addr;
// backend address. If |host_unix| is true, this is UNIX domain // backend address. If |host_unix| is true, this is UNIX domain
// socket path. // socket path.
std::unique_ptr<char[]> host; VString host;
std::unique_ptr<char[]> hostport; VString hostport;
// backend port. 0 if |host_unix| is true. // backend port. 0 if |host_unix| is true.
uint16_t port; uint16_t port;
// true if |host| contains UNIX domain socket path. // true if |host| contains UNIX domain socket path.

View File

@ -264,19 +264,18 @@ int Http2DownstreamConnection::push_request_headers() {
// addr_idx here. // addr_idx here.
auto addr_idx = http2session_->get_addr_idx(); auto addr_idx = http2session_->get_addr_idx();
auto group = http2session_->get_group(); auto group = http2session_->get_group();
auto downstream_hostport = get_config() const auto &downstream_hostport =
->downstream_addr_groups[group] get_config()->downstream_addr_groups[group].addrs[addr_idx].hostport;
.addrs[addr_idx]
.hostport.get();
// For HTTP/1.0 request, there is no authority in request. In that // For HTTP/1.0 request, there is no authority in request. In that
// case, we use backend server's host nonetheless. // case, we use backend server's host nonetheless.
const char *authority = downstream_hostport; auto authority = StringAdaptor(downstream_hostport);
if (no_host_rewrite && !req.authority.empty()) { if (no_host_rewrite && !req.authority.empty()) {
authority = req.authority.c_str(); authority = req.authority;
} }
downstream_->set_request_downstream_host(authority); downstream_->set_request_downstream_host(authority.str());
size_t num_cookies = 0; size_t num_cookies = 0;
if (!get_config()->http2_no_cookie_crumbling) { if (!get_config()->http2_no_cookie_crumbling) {
@ -312,12 +311,12 @@ int Http2DownstreamConnection::push_request_headers() {
} }
if (!req.no_authority) { if (!req.no_authority) {
nva.push_back(http2::make_nv_lc_nocopy(":authority", authority)); nva.push_back(http2::make_nv_ls_nocopy(":authority", authority));
} else { } else {
nva.push_back(http2::make_nv_lc_nocopy("host", authority)); nva.push_back(http2::make_nv_ls_nocopy("host", authority));
} }
} else { } else {
nva.push_back(http2::make_nv_lc_nocopy(":authority", authority)); nva.push_back(http2::make_nv_ls_nocopy(":authority", authority));
} }
http2::copy_headers_to_nva_nocopy(nva, req.fs.headers()); http2::copy_headers_to_nva_nocopy(nva, req.fs.headers());

View File

@ -338,7 +338,7 @@ int Http2Session::initiate_connection() {
if (get_config()->backend_tls_sni_name) { if (get_config()->backend_tls_sni_name) {
sni_name = get_config()->backend_tls_sni_name.get(); sni_name = get_config()->backend_tls_sni_name.get();
} else { } else {
sni_name = downstream_addr.host.get(); sni_name = downstream_addr.host.c_str();
} }
if (sni_name && !util::numeric_host(sni_name)) { if (sni_name && !util::numeric_host(sni_name)) {
@ -518,13 +518,13 @@ int Http2Session::downstream_connect_proxy() {
get_config()->downstream_addr_groups[group_].addrs[addr_idx_]; get_config()->downstream_addr_groups[group_].addrs[addr_idx_];
std::string req = "CONNECT "; std::string req = "CONNECT ";
req += downstream_addr.hostport.get(); req.append(downstream_addr.hostport.c_str(), downstream_addr.hostport.size());
if (downstream_addr.port == 80 || downstream_addr.port == 443) { if (downstream_addr.port == 80 || downstream_addr.port == 443) {
req += ':'; req += ':';
req += util::utos(downstream_addr.port); req += util::utos(downstream_addr.port);
} }
req += " HTTP/1.1\r\nHost: "; req += " HTTP/1.1\r\nHost: ";
req += downstream_addr.host.get(); req.append(downstream_addr.host.c_str(), downstream_addr.host.size());
req += "\r\n"; req += "\r\n";
if (get_config()->downstream_http_proxy_userinfo) { if (get_config()->downstream_http_proxy_userinfo) {
req += "Proxy-Authorization: Basic "; req += "Proxy-Authorization: Basic ";

View File

@ -211,27 +211,24 @@ int HttpDownstreamConnection::attach_downstream(Downstream *downstream) {
} }
int HttpDownstreamConnection::push_request_headers() { int HttpDownstreamConnection::push_request_headers() {
auto downstream_hostport = get_config() const auto &downstream_hostport =
->downstream_addr_groups[group_] get_config()->downstream_addr_groups[group_].addrs[addr_idx_].hostport;
.addrs[addr_idx_]
.hostport.get();
const auto &req = downstream_->request(); const auto &req = downstream_->request();
auto connect_method = req.method == HTTP_CONNECT; auto connect_method = req.method == HTTP_CONNECT;
// For HTTP/1.0 request, there is no authority in request. In that // For HTTP/1.0 request, there is no authority in request. In that
// case, we use backend server's host nonetheless. // case, we use backend server's host nonetheless.
const char *authority = downstream_hostport; auto authority = StringAdaptor(downstream_hostport);
auto no_host_rewrite = get_config()->no_host_rewrite || auto no_host_rewrite = get_config()->no_host_rewrite ||
get_config()->http2_proxy || get_config()->http2_proxy ||
get_config()->client_proxy || connect_method; get_config()->client_proxy || connect_method;
if (no_host_rewrite && !req.authority.empty()) { if (no_host_rewrite && !req.authority.empty()) {
authority = req.authority.c_str(); authority = StringAdaptor(req.authority);
} }
auto authoritylen = strlen(authority);
downstream_->set_request_downstream_host(authority); downstream_->set_request_downstream_host(authority.str());
auto buf = downstream_->get_request_buf(); auto buf = downstream_->get_request_buf();
@ -241,14 +238,14 @@ int HttpDownstreamConnection::push_request_headers() {
buf->append(" "); buf->append(" ");
if (connect_method) { if (connect_method) {
buf->append(authority, authoritylen); buf->append(authority.c_str(), authority.size());
} else if (get_config()->http2_proxy || get_config()->client_proxy) { } else if (get_config()->http2_proxy || get_config()->client_proxy) {
// Construct absolute-form request target because we are going to // Construct absolute-form request target because we are going to
// send a request to a HTTP/1 proxy. // send a request to a HTTP/1 proxy.
assert(!req.scheme.empty()); assert(!req.scheme.empty());
buf->append(req.scheme); buf->append(req.scheme);
buf->append("://"); buf->append("://");
buf->append(authority, authoritylen); buf->append(authority.c_str(), authority.size());
buf->append(req.path); buf->append(req.path);
} else if (req.method == HTTP_OPTIONS && req.path.empty()) { } else if (req.method == HTTP_OPTIONS && req.path.empty()) {
// Server-wide OPTIONS // Server-wide OPTIONS
@ -257,7 +254,7 @@ int HttpDownstreamConnection::push_request_headers() {
buf->append(req.path); buf->append(req.path);
} }
buf->append(" HTTP/1.1\r\nHost: "); buf->append(" HTTP/1.1\r\nHost: ");
buf->append(authority, authoritylen); buf->append(authority.c_str(), authority.size());
buf->append("\r\n"); buf->append("\r\n");
http2::build_http1_headers_from_headers(buf, req.fs.headers()); http2::build_http1_headers_from_headers(buf, req.fs.headers());

View File

@ -973,7 +973,7 @@ int check_cert(SSL *ssl, const DownstreamAddr *addr) {
} }
auto hostname = get_config()->backend_tls_sni_name auto hostname = get_config()->backend_tls_sni_name
? get_config()->backend_tls_sni_name.get() ? get_config()->backend_tls_sni_name.get()
: addr->host.get(); : addr->host.c_str();
if (verify_hostname(cert, hostname, strlen(hostname), &addr->addr) != 0) { if (verify_hostname(cert, hostname, strlen(hostname), &addr->addr) != 0) {
LOG(ERROR) << "Certificate verification failed: hostname does not match"; LOG(ERROR) << "Certificate verification failed: hostname does not match";
return -1; return -1;

View File

@ -199,6 +199,47 @@ inline std::unique_ptr<char[]> strcopy(const std::unique_ptr<char[]> &val) {
return strcopy(val.get()); return strcopy(val.get());
} }
struct VString {
VString() : len(0) {}
VString(const char *s, size_t slen) : base(strcopy(s)), len(slen) {}
VString(const char *s) : base(strcopy(s)), len(strlen(s)) {}
VString(const std::string &s) : base(strcopy(s)), len(s.size()) {}
template <typename InputIt>
VString(InputIt first, InputIt last)
: base(strcopy(first, last)), len(std::distance(first, last)) {}
VString(const VString &other) : base(strcopy(other.base)), len(other.len) {}
VString(VString &&) = default;
VString &operator=(const VString &other) {
if (this == &other) {
return *this;
}
base = strcopy(other.base);
len = other.len;
return *this;
}
VString &operator=(VString &&other) = default;
const char *c_str() const { return base.get(); }
size_t size() const { return len; }
std::unique_ptr<char[]> base;
size_t len;
};
struct StringAdaptor {
template <typename T>
StringAdaptor(const T &s)
: base(s.c_str()), len(s.size()) {}
const char *c_str() const { return base; }
size_t size() const { return len; }
std::string str() const { return std::string(base, len); }
const char *base;
size_t len;
};
inline int run_app(std::function<int(int, char **)> app, int argc, inline int run_app(std::function<int(int, char **)> app, int argc,
char **argv) { char **argv) {
try { try {