Commit 34d5382d authored by Tatsuhiro Tsujikawa's avatar Tatsuhiro Tsujikawa

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

parent dbbf3a4a
......@@ -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};
}
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
// before this call (its element's token field is assigned). Certain
// headers, including disallowed headers in HTTP/2 spec and headers
......
......@@ -2474,7 +2474,7 @@ int main(int argc, char **argv) {
if (get_config()->downstream_addr_groups.empty()) {
DownstreamAddr addr;
addr.host = strcopy(DEFAULT_DOWNSTREAM_HOST);
addr.host = VString(DEFAULT_DOWNSTREAM_HOST);
addr.port = DEFAULT_DOWNSTREAM_PORT;
DownstreamAddrGroup g("/");
......@@ -2513,7 +2513,7 @@ int main(int argc, char **argv) {
LOG(INFO) << "Host-path pattern: group " << i << ": '" << g.pattern.get()
<< "'";
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));
}
}
......@@ -2537,10 +2537,10 @@ int main(int argc, char **argv) {
// hostport. This is used as Host header field to backend and
// not going to be passed to any syscalls.
addr.hostport =
strcopy(util::make_hostport("localhost", get_config()->port));
VString(util::make_hostport("localhost", get_config()->port));
auto path = addr.host.get();
auto pathlen = strlen(path);
auto path = addr.host.c_str();
auto pathlen = addr.host.size();
if (pathlen + 1 > sizeof(addr.addr.su.un.sun_path)) {
LOG(FATAL) << "UNIX domain socket path " << path << " is too long > "
......@@ -2559,10 +2559,11 @@ int main(int argc, char **argv) {
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(
&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
? AF_INET6
: AF_UNSPEC)) == -1) {
......
......@@ -79,9 +79,8 @@ TicketKeys::~TicketKeys() {
}
DownstreamAddr::DownstreamAddr(const DownstreamAddr &other)
: addr(other.addr), host(strcopy(other.host)),
hostport(strcopy(other.hostport)), port(other.port),
host_unix(other.host_unix) {}
: addr(other.addr), host(other.host), hostport(other.hostport),
port(other.port), host_unix(other.host_unix) {}
DownstreamAddr &DownstreamAddr::operator=(const DownstreamAddr &other) {
if (this == &other) {
......@@ -89,8 +88,8 @@ DownstreamAddr &DownstreamAddr::operator=(const DownstreamAddr &other) {
}
addr = other.addr;
host = strcopy(other.host);
hostport = strcopy(other.hostport);
host = other.host;
hostport = other.hostport;
port = other.port;
host_unix = other.host_unix;
......@@ -1394,7 +1393,7 @@ int parse_config(const char *opt, const char *optarg,
DownstreamAddr addr;
if (util::istarts_with(optarg, 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;
} else {
if (split_host_port(host, sizeof(host), &port, optarg,
......@@ -1402,7 +1401,7 @@ int parse_config(const char *opt, const char *optarg,
return -1;
}
addr.host = strcopy(host);
addr.host = VString(host);
addr.port = port;
}
......
......@@ -245,8 +245,8 @@ struct DownstreamAddr {
Address addr;
// backend address. If |host_unix| is true, this is UNIX domain
// socket path.
std::unique_ptr<char[]> host;
std::unique_ptr<char[]> hostport;
VString host;
VString hostport;
// backend port. 0 if |host_unix| is true.
uint16_t port;
// true if |host| contains UNIX domain socket path.
......
......@@ -264,19 +264,18 @@ int Http2DownstreamConnection::push_request_headers() {
// addr_idx here.
auto addr_idx = http2session_->get_addr_idx();
auto group = http2session_->get_group();
auto downstream_hostport = get_config()
->downstream_addr_groups[group]
.addrs[addr_idx]
.hostport.get();
const auto &downstream_hostport =
get_config()->downstream_addr_groups[group].addrs[addr_idx].hostport;
// For HTTP/1.0 request, there is no authority in request. In that
// 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()) {
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;
if (!get_config()->http2_no_cookie_crumbling) {
......@@ -312,12 +311,12 @@ int Http2DownstreamConnection::push_request_headers() {
}
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 {
nva.push_back(http2::make_nv_lc_nocopy("host", authority));
nva.push_back(http2::make_nv_ls_nocopy("host", authority));
}
} 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());
......
......@@ -338,7 +338,7 @@ int Http2Session::initiate_connection() {
if (get_config()->backend_tls_sni_name) {
sni_name = get_config()->backend_tls_sni_name.get();
} else {
sni_name = downstream_addr.host.get();
sni_name = downstream_addr.host.c_str();
}
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_];
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) {
req += ':';
req += util::utos(downstream_addr.port);
}
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";
if (get_config()->downstream_http_proxy_userinfo) {
req += "Proxy-Authorization: Basic ";
......
......@@ -211,27 +211,24 @@ int HttpDownstreamConnection::attach_downstream(Downstream *downstream) {
}
int HttpDownstreamConnection::push_request_headers() {
auto downstream_hostport = get_config()
->downstream_addr_groups[group_]
.addrs[addr_idx_]
.hostport.get();
const auto &downstream_hostport =
get_config()->downstream_addr_groups[group_].addrs[addr_idx_].hostport;
const auto &req = downstream_->request();
auto connect_method = req.method == HTTP_CONNECT;
// For HTTP/1.0 request, there is no authority in request. In that
// 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 ||
get_config()->http2_proxy ||
get_config()->client_proxy || connect_method;
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();
......@@ -241,14 +238,14 @@ int HttpDownstreamConnection::push_request_headers() {
buf->append(" ");
if (connect_method) {
buf->append(authority, authoritylen);
buf->append(authority.c_str(), authority.size());
} else if (get_config()->http2_proxy || get_config()->client_proxy) {
// Construct absolute-form request target because we are going to
// send a request to a HTTP/1 proxy.
assert(!req.scheme.empty());
buf->append(req.scheme);
buf->append("://");
buf->append(authority, authoritylen);
buf->append(authority.c_str(), authority.size());
buf->append(req.path);
} else if (req.method == HTTP_OPTIONS && req.path.empty()) {
// Server-wide OPTIONS
......@@ -257,7 +254,7 @@ int HttpDownstreamConnection::push_request_headers() {
buf->append(req.path);
}
buf->append(" HTTP/1.1\r\nHost: ");
buf->append(authority, authoritylen);
buf->append(authority.c_str(), authority.size());
buf->append("\r\n");
http2::build_http1_headers_from_headers(buf, req.fs.headers());
......
......@@ -973,7 +973,7 @@ int check_cert(SSL *ssl, const DownstreamAddr *addr) {
}
auto hostname = get_config()->backend_tls_sni_name
? get_config()->backend_tls_sni_name.get()
: addr->host.get();
: addr->host.c_str();
if (verify_hostname(cert, hostname, strlen(hostname), &addr->addr) != 0) {
LOG(ERROR) << "Certificate verification failed: hostname does not match";
return -1;
......
......@@ -199,6 +199,47 @@ inline std::unique_ptr<char[]> strcopy(const std::unique_ptr<char[]> &val) {
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,
char **argv) {
try {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment