Commit b12af8c4 authored by Tatsuhiro Tsujikawa's avatar Tatsuhiro Tsujikawa

nghttpx: Refactor backend proxy configuration

parent f5b4fd23
......@@ -972,8 +972,6 @@ void fill_default_config() {
mod_config()->pid = getpid();
mod_config()->backend_ipv4 = false;
mod_config()->backend_ipv6 = false;
mod_config()->downstream_http_proxy_userinfo = nullptr;
mod_config()->downstream_http_proxy_host = nullptr;
mod_config()->downstream_http_proxy_port = 0;
mod_config()->read_rate = 0;
mod_config()->read_burst = 0;
......@@ -2572,13 +2570,12 @@ int main(int argc, char **argv) {
}
}
if (get_config()->downstream_http_proxy_host) {
auto &proxy = mod_config()->downstream_http_proxy;
if (!proxy.host.empty()) {
if (LOG_ENABLED(INFO)) {
LOG(INFO) << "Resolving backend http proxy address";
}
if (resolve_hostname(&mod_config()->downstream_http_proxy_addr,
get_config()->downstream_http_proxy_host.get(),
get_config()->downstream_http_proxy_port,
if (resolve_hostname(&proxy.addr, proxy.host.c_str(), proxy.port,
AF_UNSPEC) == -1) {
exit(EXIT_FAILURE);
}
......
......@@ -1705,6 +1705,10 @@ int parse_config(const char *opt, const char *optarg,
return 0;
case SHRPX_OPTID_BACKEND_HTTP_PROXY_URI: {
auto &proxy = mod_config()->downstream_http_proxy;
// Reset here so that multiple option occurrence does not merge
// the results.
proxy = {};
// parse URI and get hostname, port and optionally userinfo.
http_parser_url u{};
int rv = http_parser_parse_url(optarg, strlen(optarg), 0, &u);
......@@ -1715,19 +1719,17 @@ int parse_config(const char *opt, const char *optarg,
// Surprisingly, u.field_set & UF_USERINFO is nonzero even if
// userinfo component is empty string.
if (!val.empty()) {
val = util::percent_decode(std::begin(val), std::end(val));
mod_config()->downstream_http_proxy_userinfo = strcopy(val);
proxy.userinfo = util::percent_decode(std::begin(val), std::end(val));
}
}
if (u.field_set & UF_HOST) {
http2::copy_url_component(val, &u, UF_HOST, optarg);
mod_config()->downstream_http_proxy_host = strcopy(val);
http2::copy_url_component(proxy.host, &u, UF_HOST, optarg);
} else {
LOG(ERROR) << opt << ": no hostname specified";
return -1;
}
if (u.field_set & UF_PORT) {
mod_config()->downstream_http_proxy_port = u.port;
proxy.port = u.port;
} else {
LOG(ERROR) << opt << ": no port specified";
return -1;
......
......@@ -283,6 +283,15 @@ struct TicketKeys {
std::vector<TicketKey> keys;
};
struct HttpProxy {
Address addr;
// host in http proxy URI
std::string host;
// userinfo in http proxy URI, not percent-encoded form
std::string userinfo;
uint16_t port;
};
struct Config {
// The list of (private key file, certificate file) pair
std::vector<std::pair<std::string, std::string>> subcerts;
......@@ -298,11 +307,10 @@ struct Config {
std::vector<std::string> npn_list;
// list of supported SSL/TLS protocol strings.
std::vector<std::string> tls_proto_list;
// binary form of http proxy host and port
Address downstream_http_proxy_addr;
Address session_cache_memcached_addr;
Address tls_ticket_key_memcached_addr;
Router router;
HttpProxy downstream_http_proxy;
// obfuscated value used in "by" parameter of Forwarded header
// field.
std::string forwarded_by_obfuscated;
......@@ -335,10 +343,6 @@ struct Config {
std::unique_ptr<char[]> conf_path;
std::unique_ptr<char[]> ciphers;
std::unique_ptr<char[]> cacert;
// userinfo in http proxy URI, not percent-encoded form
std::unique_ptr<char[]> downstream_http_proxy_userinfo;
// host in http proxy URI
std::unique_ptr<char[]> downstream_http_proxy_host;
std::unique_ptr<char[]> http2_upstream_dump_request_header_file;
std::unique_ptr<char[]> http2_upstream_dump_response_header_file;
// Path to file containing CA certificate solely used for client
......
......@@ -271,27 +271,24 @@ int Http2Session::initiate_connection() {
auto &downstream_addr = addrs[addr_idx_];
if (get_config()->downstream_http_proxy_host && state_ == DISCONNECTED) {
const auto &proxy = get_config()->downstream_http_proxy;
if (!proxy.host.empty() && state_ == DISCONNECTED) {
if (LOG_ENABLED(INFO)) {
SSLOG(INFO, this) << "Connecting to the proxy "
<< get_config()->downstream_http_proxy_host.get() << ":"
<< get_config()->downstream_http_proxy_port;
SSLOG(INFO, this) << "Connecting to the proxy " << proxy.host << ":"
<< proxy.port;
}
conn_.fd = util::create_nonblock_socket(
get_config()->downstream_http_proxy_addr.su.storage.ss_family);
conn_.fd = util::create_nonblock_socket(proxy.addr.su.storage.ss_family);
if (conn_.fd == -1) {
connect_blocker_->on_failure();
return -1;
}
rv = connect(conn_.fd, &get_config()->downstream_http_proxy_addr.su.sa,
get_config()->downstream_http_proxy_addr.len);
rv = connect(conn_.fd, &proxy.addr.su.sa, proxy.addr.len);
if (rv != 0 && errno != EINPROGRESS) {
SSLOG(ERROR, this) << "Failed to connect to the proxy "
<< get_config()->downstream_http_proxy_host.get()
<< ":" << get_config()->downstream_http_proxy_port;
SSLOG(ERROR, this) << "Failed to connect to the proxy " << proxy.host
<< ":" << proxy.port;
connect_blocker_->on_failure();
return -1;
}
......@@ -523,12 +520,10 @@ int Http2Session::downstream_connect_proxy() {
req += " HTTP/1.1\r\nHost: ";
req.append(downstream_addr.host.c_str(), downstream_addr.host.size());
req += "\r\n";
if (get_config()->downstream_http_proxy_userinfo) {
const auto &proxy = get_config()->downstream_http_proxy;
if (!proxy.userinfo.empty()) {
req += "Proxy-Authorization: Basic ";
size_t len = strlen(get_config()->downstream_http_proxy_userinfo.get());
req += base64::encode(get_config()->downstream_http_proxy_userinfo.get(),
get_config()->downstream_http_proxy_userinfo.get() +
len);
req += base64::encode(std::begin(proxy.userinfo), std::end(proxy.userinfo));
req += "\r\n";
}
req += "\r\n";
......
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