Commit 06921f35 authored by Tatsuhiro Tsujikawa's avatar Tatsuhiro Tsujikawa

nghttpx: Restructure mode settings

It is very hard to support multiple protocols in backend while
retaining multiple mode settings.  Therefore, we dropped modes except
for default and HTTP/2 proxy mode.  The other removed modes can be
emulated using combinations of options.  Now the backend connection is
not encrypted by default.  To enable encryption on backend connection,
use --backend-tls option.
parent 44d38017
...@@ -125,7 +125,8 @@ OPTIONS = [ ...@@ -125,7 +125,8 @@ OPTIONS = [
"backend-address-family", "backend-address-family",
"frontend-http2-max-concurrent-streams", "frontend-http2-max-concurrent-streams",
"backend-http2-max-concurrent-streams", "backend-http2-max-concurrent-streams",
"backend-connections-per-frontend" "backend-connections-per-frontend",
"backend-tls"
] ]
LOGVARS = [ LOGVARS = [
......
...@@ -1416,9 +1416,9 @@ int lookup_method_token(const uint8_t *name, size_t namelen) { ...@@ -1416,9 +1416,9 @@ int lookup_method_token(const uint8_t *name, size_t namelen) {
return -1; return -1;
} }
const char *to_method_string(int method_token) { StringRef to_method_string(int method_token) {
// we happened to use same value for method with http-parser. // we happened to use same value for method with http-parser.
return http_method_str(static_cast<http_method>(method_token)); return StringRef{http_method_str(static_cast<http_method>(method_token))};
} }
int get_pure_path_component(const char **base, size_t *baselen, int get_pure_path_component(const char **base, size_t *baselen,
......
...@@ -322,7 +322,11 @@ bool expect_response_body(int status_code); ...@@ -322,7 +322,11 @@ bool expect_response_body(int status_code);
int lookup_method_token(const uint8_t *name, size_t namelen); int lookup_method_token(const uint8_t *name, size_t namelen);
int lookup_method_token(const std::string &name); int lookup_method_token(const std::string &name);
const char *to_method_string(int method_token); // Returns string representation of |method_token|. This is wrapper
// function over http_method_str from http-parser. If |method_token|
// is not known to http-parser, "<unknown>" is returned. The returned
// StringRef is guaranteed to be NULL-terminated.
StringRef to_method_string(int method_token);
template <typename InputIt> template <typename InputIt>
std::string normalize_path(InputIt first, InputIt last) { std::string normalize_path(InputIt first, InputIt last) {
......
This diff is collapsed.
...@@ -853,11 +853,11 @@ void ClientHandler::write_accesslog(Downstream *downstream) { ...@@ -853,11 +853,11 @@ void ClientHandler::write_accesslog(Downstream *downstream) {
upstream_accesslog( upstream_accesslog(
get_config()->logging.access.format, get_config()->logging.access.format,
LogSpec{ LogSpec{
downstream, StringRef(ipaddr_), http2::to_method_string(req.method), downstream, StringRef{ipaddr_}, http2::to_method_string(req.method),
req.method == HTTP_CONNECT req.method == HTTP_CONNECT
? StringRef(req.authority) ? StringRef(req.authority)
: (get_config()->http2_proxy || get_config()->client_proxy) : get_config()->http2_proxy
? StringRef(construct_absolute_request_uri(req)) ? StringRef(construct_absolute_request_uri(req))
: req.path.empty() : req.path.empty()
? req.method == HTTP_OPTIONS ? req.method == HTTP_OPTIONS
......
...@@ -571,33 +571,70 @@ int parse_duration(ev_tstamp *dest, const char *opt, const char *optarg) { ...@@ -571,33 +571,70 @@ int parse_duration(ev_tstamp *dest, const char *opt, const char *optarg) {
} // namespace } // namespace
namespace { namespace {
// Parses host-path mapping patterns in |src|, and stores mappings in // Parses host-path mapping patterns in |src_pattern|, and stores
// config. We will store each host-path pattern found in |src| with // mappings in config. We will store each host-path pattern found in
// |addr|. |addr| will be copied accordingly. Also we make a group // |src| with |addr|. |addr| will be copied accordingly. Also we
// based on the pattern. The "/" pattern is considered as catch-all. // make a group based on the pattern. The "/" pattern is considered
void parse_mapping(const DownstreamAddrConfig &addr, const char *src) { // as catch-all. We also parse protocol specified in |src_proto|.
//
// This function returns 0 if it succeeds, or -1.
int parse_mapping(const DownstreamAddrConfig &addr,
const StringRef &src_pattern, const StringRef &src_proto) {
// This returns at least 1 element (it could be empty string). We // This returns at least 1 element (it could be empty string). We
// will append '/' to all patterns, so it becomes catch-all pattern. // will append '/' to all patterns, so it becomes catch-all pattern.
auto mapping = util::split_config_str_list(src, ':'); auto mapping = util::split_str(src_pattern, ':');
assert(!mapping.empty()); assert(!mapping.empty());
auto &addr_groups = mod_config()->conn.downstream.addr_groups; auto &addr_groups = mod_config()->conn.downstream.addr_groups;
auto proto = PROTO_HTTP1;
if (!src_proto.empty()) {
if (!util::istarts_with_l(src_proto, "proto=")) {
LOG(ERROR) << "backend: proto keyword not found";
return -1;
}
auto protostr = StringRef{std::begin(src_proto) + str_size("proto="),
std::end(src_proto)};
if (protostr.empty()) {
LOG(ERROR) << "backend: protocol is empty";
return -1;
}
if (util::streq_l("h2", std::begin(protostr), protostr.size())) {
proto = PROTO_HTTP2;
} else if (util::streq_l("http/1.1", std::begin(protostr),
protostr.size())) {
proto = PROTO_HTTP1;
} else {
LOG(ERROR) << "backend: unknown protocol " << protostr;
return -1;
}
}
for (const auto &raw_pattern : mapping) { for (const auto &raw_pattern : mapping) {
auto done = false; auto done = false;
std::string pattern; std::string pattern;
auto slash = std::find(raw_pattern.first, raw_pattern.second, '/'); auto slash = std::find(std::begin(raw_pattern), std::end(raw_pattern), '/');
if (slash == raw_pattern.second) { if (slash == std::end(raw_pattern)) {
// This effectively makes empty pattern to "/". // This effectively makes empty pattern to "/".
pattern.assign(raw_pattern.first, raw_pattern.second); pattern.assign(std::begin(raw_pattern), std::end(raw_pattern));
util::inp_strlower(pattern); util::inp_strlower(pattern);
pattern += '/'; pattern += '/';
} else { } else {
pattern.assign(raw_pattern.first, slash); pattern.assign(std::begin(raw_pattern), slash);
util::inp_strlower(pattern); util::inp_strlower(pattern);
pattern += http2::normalize_path(slash, raw_pattern.second); pattern += http2::normalize_path(slash, std::end(raw_pattern));
} }
for (auto &g : addr_groups) { for (auto &g : addr_groups) {
if (g.pattern == pattern) { if (g.pattern == pattern) {
if (g.proto != proto) {
LOG(ERROR) << "backend: protocol mismatch. We saw protocol "
<< strproto(g.proto) << " for pattern " << g.pattern
<< ", but another protocol " << strproto(proto);
return -1;
}
g.addrs.push_back(addr); g.addrs.push_back(addr);
done = true; done = true;
break; break;
...@@ -608,11 +645,13 @@ void parse_mapping(const DownstreamAddrConfig &addr, const char *src) { ...@@ -608,11 +645,13 @@ void parse_mapping(const DownstreamAddrConfig &addr, const char *src) {
} }
DownstreamAddrGroupConfig g(StringRef{pattern}); DownstreamAddrGroupConfig g(StringRef{pattern});
g.addrs.push_back(addr); g.addrs.push_back(addr);
g.proto = proto;
mod_config()->router.add_route(StringRef{g.pattern}, addr_groups.size()); mod_config()->router.add_route(StringRef{g.pattern}, addr_groups.size());
addr_groups.push_back(std::move(g)); addr_groups.push_back(std::move(g));
} }
return 0;
} }
} // namespace } // namespace
...@@ -670,6 +709,7 @@ enum { ...@@ -670,6 +709,7 @@ enum {
SHRPX_OPTID_BACKEND_READ_TIMEOUT, SHRPX_OPTID_BACKEND_READ_TIMEOUT,
SHRPX_OPTID_BACKEND_REQUEST_BUFFER, SHRPX_OPTID_BACKEND_REQUEST_BUFFER,
SHRPX_OPTID_BACKEND_RESPONSE_BUFFER, SHRPX_OPTID_BACKEND_RESPONSE_BUFFER,
SHRPX_OPTID_BACKEND_TLS,
SHRPX_OPTID_BACKEND_TLS_SNI_FIELD, SHRPX_OPTID_BACKEND_TLS_SNI_FIELD,
SHRPX_OPTID_BACKEND_WRITE_TIMEOUT, SHRPX_OPTID_BACKEND_WRITE_TIMEOUT,
SHRPX_OPTID_BACKLOG, SHRPX_OPTID_BACKLOG,
...@@ -914,6 +954,11 @@ int option_lookup_token(const char *name, size_t namelen) { ...@@ -914,6 +954,11 @@ int option_lookup_token(const char *name, size_t namelen) {
break; break;
case 11: case 11:
switch (name[10]) { switch (name[10]) {
case 's':
if (util::strieq_l("backend-tl", name, 10)) {
return SHRPX_OPTID_BACKEND_TLS;
}
break;
case 't': case 't':
if (util::strieq_l("write-burs", name, 10)) { if (util::strieq_l("write-burs", name, 10)) {
return SHRPX_OPTID_WRITE_BURST; return SHRPX_OPTID_WRITE_BURST;
...@@ -1495,19 +1540,17 @@ int parse_config(const char *opt, const char *optarg, ...@@ -1495,19 +1540,17 @@ int parse_config(const char *opt, const char *optarg,
switch (optid) { switch (optid) {
case SHRPX_OPTID_BACKEND: { case SHRPX_OPTID_BACKEND: {
auto optarglen = strlen(optarg); auto src = StringRef{optarg};
const char *pat_delim = strchr(optarg, ';'); auto addr_end = std::find(std::begin(src), std::end(src), ';');
if (!pat_delim) {
pat_delim = optarg + optarglen;
}
DownstreamAddrConfig addr{}; DownstreamAddrConfig 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 = std::begin(src) + str_size(SHRPX_UNIX_PATH_PREFIX);
addr.host = ImmutableString(path, pat_delim); addr.host = ImmutableString(path, addr_end);
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, &src[0],
pat_delim - optarg) == -1) { addr_end - std::begin(src)) == -1) {
return -1; return -1;
} }
...@@ -1515,14 +1558,16 @@ int parse_config(const char *opt, const char *optarg, ...@@ -1515,14 +1558,16 @@ int parse_config(const char *opt, const char *optarg,
addr.port = port; addr.port = port;
} }
auto mapping = pat_delim < optarg + optarglen ? pat_delim + 1 : pat_delim; auto mapping = addr_end == std::end(src) ? addr_end : addr_end + 1;
// We may introduce new parameter after additional ';', so don't auto mapping_end = std::find(mapping, std::end(src), ';');
// allow extra ';' in pattern for now.
if (strchr(mapping, ';') != nullptr) { auto proto = mapping_end == std::end(src) ? mapping_end : mapping_end + 1;
LOG(ERROR) << opt << ": ';' must not be used in pattern"; auto proto_end = std::find(proto, std::end(src), ';');
if (parse_mapping(addr, StringRef{mapping, mapping_end},
StringRef{proto, proto_end}) != 0) {
return -1; return -1;
} }
parse_mapping(addr, mapping);
return 0; return 0;
} }
...@@ -1607,13 +1652,13 @@ int parse_config(const char *opt, const char *optarg, ...@@ -1607,13 +1652,13 @@ int parse_config(const char *opt, const char *optarg,
return 0; return 0;
case SHRPX_OPTID_HTTP2_BRIDGE: case SHRPX_OPTID_HTTP2_BRIDGE:
mod_config()->http2_bridge = util::strieq(optarg, "yes"); LOG(ERROR) << opt << ": deprecated. Use backend=<addr>,<port>;;proto=h2 "
"and backend-tls";
return 0; return -1;
case SHRPX_OPTID_CLIENT_PROXY: case SHRPX_OPTID_CLIENT_PROXY:
mod_config()->client_proxy = util::strieq(optarg, "yes"); LOG(ERROR) << opt << ": deprecated. Use http2-proxy, frontend-no-tls, "
"backend=<addr>,<port>;;proto=h2 and backend-tls";
return 0; return -1;
case SHRPX_OPTID_ADD_X_FORWARDED_FOR: case SHRPX_OPTID_ADD_X_FORWARDED_FOR:
mod_config()->http.xff.add = util::strieq(optarg, "yes"); mod_config()->http.xff.add = util::strieq(optarg, "yes");
...@@ -1746,8 +1791,8 @@ int parse_config(const char *opt, const char *optarg, ...@@ -1746,8 +1791,8 @@ int parse_config(const char *opt, const char *optarg,
return 0; return 0;
case SHRPX_OPTID_BACKEND_NO_TLS: case SHRPX_OPTID_BACKEND_NO_TLS:
mod_config()->conn.downstream.no_tls = util::strieq(optarg, "yes"); LOG(WARN) << opt << ": deprecated. backend connection is not encrypted by "
"default. See also " << SHRPX_OPT_BACKEND_TLS;
return 0; return 0;
case SHRPX_OPTID_BACKEND_TLS_SNI_FIELD: case SHRPX_OPTID_BACKEND_TLS_SNI_FIELD:
mod_config()->tls.backend_sni_name = optarg; mod_config()->tls.backend_sni_name = optarg;
...@@ -1834,9 +1879,9 @@ int parse_config(const char *opt, const char *optarg, ...@@ -1834,9 +1879,9 @@ int parse_config(const char *opt, const char *optarg,
return 0; return 0;
case SHRPX_OPTID_CLIENT: case SHRPX_OPTID_CLIENT:
mod_config()->client = util::strieq(optarg, "yes"); LOG(ERROR) << opt << ": deprecated. Use frontend-no-tls, "
"backend=<addr>,<port>;;proto=h2 and backend-tls";
return 0; return -1;
case SHRPX_OPTID_INSECURE: case SHRPX_OPTID_INSECURE:
mod_config()->tls.insecure = util::strieq(optarg, "yes"); mod_config()->tls.insecure = util::strieq(optarg, "yes");
...@@ -2312,7 +2357,11 @@ int parse_config(const char *opt, const char *optarg, ...@@ -2312,7 +2357,11 @@ int parse_config(const char *opt, const char *optarg,
return 0; return 0;
case SHRPX_OPTID_BACKEND_HTTP1_TLS: case SHRPX_OPTID_BACKEND_HTTP1_TLS:
mod_config()->conn.downstream.http1_tls = util::strieq(optarg, "yes"); LOG(WARN) << opt << ": deprecated. Use " << SHRPX_OPT_BACKEND_TLS
<< " instead.";
// fall through
case SHRPX_OPTID_BACKEND_TLS:
mod_config()->conn.downstream.no_tls = !util::strieq(optarg, "yes");
return 0; return 0;
case SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_TLS: case SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_TLS:
...@@ -2533,4 +2582,17 @@ int int_syslog_facility(const char *strfacility) { ...@@ -2533,4 +2582,17 @@ int int_syslog_facility(const char *strfacility) {
return -1; return -1;
} }
StringRef strproto(shrpx_proto proto) {
switch (proto) {
case PROTO_NONE:
return StringRef::from_lit("none");
case PROTO_HTTP1:
return StringRef::from_lit("http/1.1");
case PROTO_HTTP2:
return StringRef::from_lit("h2");
case PROTO_MEMCACHED:
return StringRef::from_lit("memcached");
}
}
} // namespace shrpx } // namespace shrpx
...@@ -234,6 +234,7 @@ constexpr char SHRPX_OPT_BACKEND_HTTP2_MAX_CONCURRENT_STREAMS[] = ...@@ -234,6 +234,7 @@ constexpr char SHRPX_OPT_BACKEND_HTTP2_MAX_CONCURRENT_STREAMS[] =
"backend-http2-max-concurrent-streams"; "backend-http2-max-concurrent-streams";
constexpr char SHRPX_OPT_BACKEND_CONNECTIONS_PER_FRONTEND[] = constexpr char SHRPX_OPT_BACKEND_CONNECTIONS_PER_FRONTEND[] =
"backend-connections-per-frontend"; "backend-connections-per-frontend";
constexpr char SHRPX_OPT_BACKEND_TLS[] = "backend-tls";
constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8; constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
...@@ -599,11 +600,6 @@ struct Config { ...@@ -599,11 +600,6 @@ struct Config {
bool verbose; bool verbose;
bool daemon; bool daemon;
bool http2_proxy; bool http2_proxy;
bool http2_bridge;
bool client_proxy;
bool client;
// true if --client or --client-proxy are enabled.
bool client_mode;
}; };
const Config *get_config(); const Config *get_config();
...@@ -650,6 +646,9 @@ std::unique_ptr<TicketKeys> ...@@ -650,6 +646,9 @@ std::unique_ptr<TicketKeys>
read_tls_ticket_key_file(const std::vector<std::string> &files, read_tls_ticket_key_file(const std::vector<std::string> &files,
const EVP_CIPHER *cipher, const EVP_MD *hmac); const EVP_CIPHER *cipher, const EVP_MD *hmac);
// Returns string representation of |proto|.
StringRef strproto(shrpx_proto proto);
} // namespace shrpx } // namespace shrpx
#endif // SHRPX_CONFIG_H #endif // SHRPX_CONFIG_H
...@@ -264,9 +264,9 @@ int Http2DownstreamConnection::push_request_headers() { ...@@ -264,9 +264,9 @@ int Http2DownstreamConnection::push_request_headers() {
auto &httpconf = get_config()->http; auto &httpconf = get_config()->http;
auto &http2conf = get_config()->http2; auto &http2conf = get_config()->http2;
auto no_host_rewrite = auto no_host_rewrite = httpconf.no_host_rewrite ||
httpconf.no_host_rewrite || get_config()->http2_proxy || get_config()->http2_proxy ||
get_config()->client_proxy || req.method == HTTP_CONNECT; req.method == HTTP_CONNECT;
// http2session_ has already in CONNECTED state, so we can get // http2session_ has already in CONNECTED state, so we can get
// addr_idx here. // addr_idx here.
...@@ -302,7 +302,7 @@ int Http2DownstreamConnection::push_request_headers() { ...@@ -302,7 +302,7 @@ int Http2DownstreamConnection::push_request_headers() {
httpconf.add_request_headers.size()); httpconf.add_request_headers.size());
nva.push_back( nva.push_back(
http2::make_nv_lc_nocopy(":method", http2::to_method_string(req.method))); http2::make_nv_ls_nocopy(":method", http2::to_method_string(req.method)));
if (req.method != HTTP_CONNECT) { if (req.method != HTTP_CONNECT) {
assert(!req.scheme.empty()); assert(!req.scheme.empty());
...@@ -350,8 +350,7 @@ int Http2DownstreamConnection::push_request_headers() { ...@@ -350,8 +350,7 @@ int Http2DownstreamConnection::push_request_headers() {
if (fwdconf.params) { if (fwdconf.params) {
auto params = fwdconf.params; auto params = fwdconf.params;
if (get_config()->http2_proxy || get_config()->client_proxy || if (get_config()->http2_proxy || req.method == HTTP_CONNECT) {
req.method == HTTP_CONNECT) {
params &= ~FORWARDED_PROTO; params &= ~FORWARDED_PROTO;
} }
...@@ -394,8 +393,7 @@ int Http2DownstreamConnection::push_request_headers() { ...@@ -394,8 +393,7 @@ int Http2DownstreamConnection::push_request_headers() {
nva.push_back(http2::make_nv_ls_nocopy("x-forwarded-for", (*xff).value)); nva.push_back(http2::make_nv_ls_nocopy("x-forwarded-for", (*xff).value));
} }
if (!get_config()->http2_proxy && !get_config()->client_proxy && if (!get_config()->http2_proxy && req.method != HTTP_CONNECT) {
req.method != HTTP_CONNECT) {
// We use same protocol with :scheme header field // We use same protocol with :scheme header field
nva.push_back(http2::make_nv_ls_nocopy("x-forwarded-proto", req.scheme)); nva.push_back(http2::make_nv_ls_nocopy("x-forwarded-proto", req.scheme));
} }
......
...@@ -1460,8 +1460,7 @@ int Http2Session::connection_made() { ...@@ -1460,8 +1460,7 @@ int Http2Session::connection_made() {
entry[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; entry[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
entry[1].value = (1 << http2conf.downstream.window_bits) - 1; entry[1].value = (1 << http2conf.downstream.window_bits) - 1;
if (http2conf.no_server_push || get_config()->http2_proxy || if (http2conf.no_server_push || get_config()->http2_proxy) {
get_config()->client_proxy) {
entry[nentry].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH; entry[nentry].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
entry[nentry].value = 0; entry[nentry].value = 0;
++nentry; ++nentry;
......
...@@ -316,7 +316,7 @@ int Http2Upstream::on_request_headers(Downstream *downstream, ...@@ -316,7 +316,7 @@ int Http2Upstream::on_request_headers(Downstream *downstream,
if (path) { if (path) {
if (method_token == HTTP_OPTIONS && path->value == "*") { if (method_token == HTTP_OPTIONS && path->value == "*") {
// Server-wide OPTIONS request. Path is empty. // Server-wide OPTIONS request. Path is empty.
} else if (get_config()->http2_proxy || get_config()->client_proxy) { } else if (get_config()->http2_proxy) {
req.path = http2::value_to_str(path); req.path = http2::value_to_str(path);
} else { } else {
const auto &value = path->value; const auto &value = path->value;
...@@ -1346,8 +1346,7 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) { ...@@ -1346,8 +1346,7 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) {
auto &httpconf = get_config()->http; auto &httpconf = get_config()->http;
if (!get_config()->http2_proxy && !get_config()->client_proxy && if (!get_config()->http2_proxy && !httpconf.no_location_rewrite) {
!httpconf.no_location_rewrite) {
downstream->rewrite_location_response_header(req.scheme); downstream->rewrite_location_response_header(req.scheme);
} }
...@@ -1416,7 +1415,7 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) { ...@@ -1416,7 +1415,7 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) {
http2::copy_headers_to_nva_nocopy(nva, resp.fs.headers()); http2::copy_headers_to_nva_nocopy(nva, resp.fs.headers());
if (!get_config()->http2_proxy && !get_config()->client_proxy) { if (!get_config()->http2_proxy) {
nva.push_back(http2::make_nv_ls_nocopy("server", httpconf.server_name)); nva.push_back(http2::make_nv_ls_nocopy("server", httpconf.server_name));
} else { } else {
auto server = resp.fs.header(http2::HD_SERVER); auto server = resp.fs.header(http2::HD_SERVER);
...@@ -1489,9 +1488,8 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) { ...@@ -1489,9 +1488,8 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) {
if (!http2conf.no_server_push && if (!http2conf.no_server_push &&
nghttp2_session_get_remote_settings(session_, nghttp2_session_get_remote_settings(session_,
NGHTTP2_SETTINGS_ENABLE_PUSH) == 1 && NGHTTP2_SETTINGS_ENABLE_PUSH) == 1 &&
!get_config()->http2_proxy && !get_config()->client_proxy && !get_config()->http2_proxy && (downstream->get_stream_id() % 2) &&
(downstream->get_stream_id() % 2) && resp.fs.header(http2::HD_LINK) && resp.fs.header(http2::HD_LINK) && resp.http_status == 200 &&
resp.http_status == 200 &&
(req.method == HTTP_GET || req.method == HTTP_POST)) { (req.method == HTTP_GET || req.method == HTTP_POST)) {
if (prepare_push_promise(downstream) != 0) { if (prepare_push_promise(downstream) != 0) {
...@@ -1852,7 +1850,7 @@ bool Http2Upstream::push_enabled() const { ...@@ -1852,7 +1850,7 @@ bool Http2Upstream::push_enabled() const {
return !(get_config()->http2.no_server_push || return !(get_config()->http2.no_server_push ||
nghttp2_session_get_remote_settings( nghttp2_session_get_remote_settings(
session_, NGHTTP2_SETTINGS_ENABLE_PUSH) == 0 || session_, NGHTTP2_SETTINGS_ENABLE_PUSH) == 0 ||
get_config()->http2_proxy || get_config()->client_proxy); get_config()->http2_proxy);
} }
int Http2Upstream::initiate_push(Downstream *downstream, const char *uri, int Http2Upstream::initiate_push(Downstream *downstream, const char *uri,
......
...@@ -279,9 +279,8 @@ int HttpDownstreamConnection::push_request_headers() { ...@@ -279,9 +279,8 @@ int HttpDownstreamConnection::push_request_headers() {
// 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.
auto authority = StringRef(downstream_hostport); auto authority = StringRef(downstream_hostport);
auto no_host_rewrite = httpconf.no_host_rewrite || auto no_host_rewrite =
get_config()->http2_proxy || httpconf.no_host_rewrite || get_config()->http2_proxy || connect_method;
get_config()->client_proxy || connect_method;
if (no_host_rewrite && !req.authority.empty()) { if (no_host_rewrite && !req.authority.empty()) {
authority = StringRef(req.authority); authority = StringRef(req.authority);
...@@ -293,12 +292,12 @@ int HttpDownstreamConnection::push_request_headers() { ...@@ -293,12 +292,12 @@ int HttpDownstreamConnection::push_request_headers() {
// Assume that method and request path do not contain \r\n. // Assume that method and request path do not contain \r\n.
auto meth = http2::to_method_string(req.method); auto meth = http2::to_method_string(req.method);
buf->append(meth, strlen(meth)); buf->append(meth);
buf->append(" "); buf->append(" ");
if (connect_method) { if (connect_method) {
buf->append(authority); buf->append(authority);
} else if (get_config()->http2_proxy || get_config()->client_proxy) { } else if (get_config()->http2_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());
...@@ -363,8 +362,7 @@ int HttpDownstreamConnection::push_request_headers() { ...@@ -363,8 +362,7 @@ int HttpDownstreamConnection::push_request_headers() {
if (fwdconf.params) { if (fwdconf.params) {
auto params = fwdconf.params; auto params = fwdconf.params;
if (get_config()->http2_proxy || get_config()->client_proxy || if (get_config()->http2_proxy || connect_method) {
connect_method) {
params &= ~FORWARDED_PROTO; params &= ~FORWARDED_PROTO;
} }
...@@ -407,8 +405,7 @@ int HttpDownstreamConnection::push_request_headers() { ...@@ -407,8 +405,7 @@ int HttpDownstreamConnection::push_request_headers() {
buf->append((*xff).value); buf->append((*xff).value);
buf->append("\r\n"); buf->append("\r\n");
} }
if (!get_config()->http2_proxy && !get_config()->client_proxy && if (!get_config()->http2_proxy && !connect_method) {
!connect_method) {
buf->append("X-Forwarded-Proto: "); buf->append("X-Forwarded-Proto: ");
assert(!req.scheme.empty()); assert(!req.scheme.empty());
buf->append(req.scheme); buf->append(req.scheme);
......
...@@ -232,7 +232,7 @@ void rewrite_request_host_path_from_uri(Request &req, const char *uri, ...@@ -232,7 +232,7 @@ void rewrite_request_host_path_from_uri(Request &req, const char *uri,
path += '?'; path += '?';
path.append(uri + fdata.off, fdata.len); path.append(uri + fdata.off, fdata.len);
} }
if (get_config()->http2_proxy || get_config()->client_proxy) { if (get_config()->http2_proxy) {
req.path = std::move(path); req.path = std::move(path);
} else { } else {
req.path = http2::rewrite_clean_path(std::begin(path), std::end(path)); req.path = http2::rewrite_clean_path(std::begin(path), std::end(path));
...@@ -306,7 +306,7 @@ int htp_hdrs_completecb(http_parser *htp) { ...@@ -306,7 +306,7 @@ int htp_hdrs_completecb(http_parser *htp) {
} }
// checking UF_HOST could be redundant, but just in case ... // checking UF_HOST could be redundant, but just in case ...
if (!(u.field_set & (1 << UF_SCHEMA)) || !(u.field_set & (1 << UF_HOST))) { if (!(u.field_set & (1 << UF_SCHEMA)) || !(u.field_set & (1 << UF_HOST))) {
if (get_config()->http2_proxy || get_config()->client_proxy) { if (get_config()->http2_proxy) {
// Request URI should be absolute-form for client proxy mode // Request URI should be absolute-form for client proxy mode
return -1; return -1;
} }
...@@ -929,8 +929,7 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) { ...@@ -929,8 +929,7 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
auto &httpconf = get_config()->http; auto &httpconf = get_config()->http;
if (!get_config()->http2_proxy && !get_config()->client_proxy && if (!get_config()->http2_proxy && !httpconf.no_location_rewrite) {
!httpconf.no_location_rewrite) {
downstream->rewrite_location_response_header( downstream->rewrite_location_response_header(
get_client_handler()->get_upstream_scheme()); get_client_handler()->get_upstream_scheme());
} }
...@@ -999,7 +998,7 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) { ...@@ -999,7 +998,7 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
} }
} }
if (!get_config()->http2_proxy && !get_config()->client_proxy) { if (!get_config()->http2_proxy) {
buf->append("Server: "); buf->append("Server: ");
buf->append(httpconf.server_name); buf->append(httpconf.server_name);
buf->append("\r\n"); buf->append("\r\n");
......
...@@ -70,7 +70,7 @@ mrb_value request_get_method(mrb_state *mrb, mrb_value self) { ...@@ -70,7 +70,7 @@ mrb_value request_get_method(mrb_state *mrb, mrb_value self) {
const auto &req = downstream->request(); const auto &req = downstream->request();
auto method = http2::to_method_string(req.method); auto method = http2::to_method_string(req.method);
return mrb_str_new_cstr(mrb, method); return mrb_str_new(mrb, method.c_str(), method.size());
} }
} // namespace } // namespace
......
...@@ -262,7 +262,7 @@ void on_ctrl_recv_callback(spdylay_session *session, spdylay_frame_type type, ...@@ -262,7 +262,7 @@ void on_ctrl_recv_callback(spdylay_session *session, spdylay_frame_type type,
} else { } else {
req.scheme = scheme->value; req.scheme = scheme->value;
req.authority = host->value; req.authority = host->value;
if (get_config()->http2_proxy || get_config()->client_proxy) { if (get_config()->http2_proxy) {
req.path = path->value; req.path = path->value;
} else if (method_token == HTTP_OPTIONS && path->value == "*") { } else if (method_token == HTTP_OPTIONS && path->value == "*") {
// Server-wide OPTIONS request. Path is empty. // Server-wide OPTIONS request. Path is empty.
...@@ -1009,8 +1009,7 @@ int SpdyUpstream::on_downstream_header_complete(Downstream *downstream) { ...@@ -1009,8 +1009,7 @@ int SpdyUpstream::on_downstream_header_complete(Downstream *downstream) {
auto &httpconf = get_config()->http; auto &httpconf = get_config()->http;
if (!get_config()->http2_proxy && !get_config()->client_proxy && if (!get_config()->http2_proxy && !httpconf.no_location_rewrite) {
!httpconf.no_location_rewrite) {
downstream->rewrite_location_response_header(req.scheme); downstream->rewrite_location_response_header(req.scheme);
} }
...@@ -1044,7 +1043,7 @@ int SpdyUpstream::on_downstream_header_complete(Downstream *downstream) { ...@@ -1044,7 +1043,7 @@ int SpdyUpstream::on_downstream_header_complete(Downstream *downstream) {
nv[hdidx++] = hd.value.c_str(); nv[hdidx++] = hd.value.c_str();
} }
if (!get_config()->http2_proxy && !get_config()->client_proxy) { if (!get_config()->http2_proxy) {
nv[hdidx++] = "server"; nv[hdidx++] = "server";
nv[hdidx++] = httpconf.server_name.c_str(); nv[hdidx++] = httpconf.server_name.c_str();
} else { } else {
......
...@@ -318,7 +318,7 @@ size_t match_downstream_addr_group_host( ...@@ -318,7 +318,7 @@ size_t match_downstream_addr_group_host(
return group; return group;
} }
group = router.match("", path); group = router.match(StringRef::from_lit(""), path);
if (group != -1) { if (group != -1) {
if (LOG_ENABLED(INFO)) { if (LOG_ENABLED(INFO)) {
LOG(INFO) << "Found pattern with query " << path LOG(INFO) << "Found pattern with query " << path
......
...@@ -400,7 +400,7 @@ public: ...@@ -400,7 +400,7 @@ public:
explicit StringRef(const std::string &s) : base(s.c_str()), len(s.size()) {} explicit StringRef(const std::string &s) : base(s.c_str()), len(s.size()) {}
explicit StringRef(const ImmutableString &s) explicit StringRef(const ImmutableString &s)
: base(s.c_str()), len(s.size()) {} : base(s.c_str()), len(s.size()) {}
StringRef(const char *s) : base(s), len(strlen(s)) {} explicit StringRef(const char *s) : base(s), len(strlen(s)) {}
template <typename CharT> template <typename CharT>
constexpr StringRef(const CharT *s, size_t n) constexpr StringRef(const CharT *s, size_t n)
: base(reinterpret_cast<const char *>(s)), len(n) {} : base(reinterpret_cast<const char *>(s)), len(n) {}
......
...@@ -857,6 +857,27 @@ std::vector<unsigned char> get_default_alpn() { ...@@ -857,6 +857,27 @@ std::vector<unsigned char> get_default_alpn() {
return res; return res;
} }
std::vector<StringRef> split_str(const StringRef &s, char delim) {
size_t len = 1;
auto last = std::end(s);
for (auto first = std::begin(s), d = first;
(d = std::find(first, last, delim)) != last; ++len, first = d + 1)
;
auto list = std::vector<StringRef>(len);
len = 0;
for (auto first = std::begin(s);; ++len) {
auto stop = std::find(first, last, delim);
list[len] = StringRef{first, stop};
if (stop == last) {
break;
}
first = stop + 1;
}
return list;
}
std::vector<Range<const char *>> split_config_str_list(const char *s, std::vector<Range<const char *>> split_config_str_list(const char *s,
char delim) { char delim) {
size_t len = 1; size_t len = 1;
......
...@@ -225,6 +225,11 @@ bool istarts_with_l(const std::string &a, const CharT(&b)[N]) { ...@@ -225,6 +225,11 @@ bool istarts_with_l(const std::string &a, const CharT(&b)[N]) {
return istarts_with(std::begin(a), std::end(a), b, b + N - 1); return istarts_with(std::begin(a), std::end(a), b, b + N - 1);
} }
template <typename CharT, size_t N>
bool istarts_with_l(const StringRef &a, const CharT(&b)[N]) {
return istarts_with(std::begin(a), std::end(a), b, b + N - 1);
}
template <typename InputIterator1, typename InputIterator2> template <typename InputIterator1, typename InputIterator2>
bool ends_with(InputIterator1 first1, InputIterator1 last1, bool ends_with(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, InputIterator2 last2) { InputIterator2 first2, InputIterator2 last2) {
...@@ -543,6 +548,11 @@ std::vector<std::string> parse_config_str_list(const char *s, char delim = ','); ...@@ -543,6 +548,11 @@ std::vector<std::string> parse_config_str_list(const char *s, char delim = ',');
std::vector<Range<const char *>> split_config_str_list(const char *s, std::vector<Range<const char *>> split_config_str_list(const char *s,
char delim); char delim);
// Parses delimited strings in |s| and returns Substrings in |s|
// delimited by |delim|. The any white spaces around substring are
// treated as a part of substring.
std::vector<StringRef> split_str(const StringRef &s, char delim);
// Returns given time |tp| in Common Log format (e.g., // Returns given time |tp| in Common Log format (e.g.,
// 03/Jul/2014:00:19:38 +0900) // 03/Jul/2014:00:19:38 +0900)
// Expected type of |tp| is std::chrono::timepoint // Expected type of |tp| is std::chrono::timepoint
......
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