nghttpx: Use VString for DownstreamAddr::host and hostport to remember size
This commit is contained in:
parent
dbbf3a4a10
commit
34d5382d66
|
@ -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
|
||||
|
|
15
src/shrpx.cc
15
src/shrpx.cc
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue