nghttpx: Add options for X-Forwarded-Proto header field
This commit adds 2 new options to handle X-Forwarded-Proto header field. The --no-add-x-forwarded-proto option makes nghttpx not to append X-Forwarded-Proto value. The --no-strip-incoming-x-forwarded-proto option prevents nghttpx from stripping the header field from client. Previously, nghttpx always strips incoming header field, and set its own header field. This commit preserves this behaviour, and adds additional knobs.
This commit is contained in:
parent
980570de71
commit
cc9190ab37
|
@ -164,6 +164,8 @@ OPTIONS = [
|
||||||
"frontend-max-requests",
|
"frontend-max-requests",
|
||||||
"single-thread",
|
"single-thread",
|
||||||
"single-process",
|
"single-process",
|
||||||
|
"no-add-x-forwarded-proto",
|
||||||
|
"no-strip-incoming-x-forwarded-proto",
|
||||||
]
|
]
|
||||||
|
|
||||||
LOGVARS = [
|
LOGVARS = [
|
||||||
|
|
24
src/shrpx.cc
24
src/shrpx.cc
|
@ -1478,6 +1478,8 @@ void fill_default_config(Config *config) {
|
||||||
httpconf.max_response_header_fields = 500;
|
httpconf.max_response_header_fields = 500;
|
||||||
httpconf.redirect_https_port = StringRef::from_lit("443");
|
httpconf.redirect_https_port = StringRef::from_lit("443");
|
||||||
httpconf.max_requests = std::numeric_limits<size_t>::max();
|
httpconf.max_requests = std::numeric_limits<size_t>::max();
|
||||||
|
httpconf.xfp.add = true;
|
||||||
|
httpconf.xfp.strip_incoming = true;
|
||||||
|
|
||||||
auto &http2conf = config->http2;
|
auto &http2conf = config->http2;
|
||||||
{
|
{
|
||||||
|
@ -2485,6 +2487,15 @@ HTTP:
|
||||||
--strip-incoming-x-forwarded-for
|
--strip-incoming-x-forwarded-for
|
||||||
Strip X-Forwarded-For header field from inbound client
|
Strip X-Forwarded-For header field from inbound client
|
||||||
requests.
|
requests.
|
||||||
|
--no-add-x-forwarded-proto
|
||||||
|
Don't append additional X-Forwarded-Proto header field
|
||||||
|
to the backend request. If inbound client sets
|
||||||
|
X-Forwarded-Proto, and
|
||||||
|
--no-strip-incoming-x-forwarded-proto option is used,
|
||||||
|
they are passed to the backend.
|
||||||
|
--no-strip-incoming-x-forwarded-proto
|
||||||
|
Don't strip X-Forwarded-Proto header field from inbound
|
||||||
|
client requests.
|
||||||
--add-forwarded=<LIST>
|
--add-forwarded=<LIST>
|
||||||
Append RFC 7239 Forwarded header field with parameters
|
Append RFC 7239 Forwarded header field with parameters
|
||||||
specified in comma delimited list <LIST>. The supported
|
specified in comma delimited list <LIST>. The supported
|
||||||
|
@ -3327,6 +3338,9 @@ int main(int argc, char **argv) {
|
||||||
{SHRPX_OPT_FRONTEND_MAX_REQUESTS.c_str(), required_argument, &flag,
|
{SHRPX_OPT_FRONTEND_MAX_REQUESTS.c_str(), required_argument, &flag,
|
||||||
155},
|
155},
|
||||||
{SHRPX_OPT_SINGLE_THREAD.c_str(), no_argument, &flag, 156},
|
{SHRPX_OPT_SINGLE_THREAD.c_str(), no_argument, &flag, 156},
|
||||||
|
{SHRPX_OPT_NO_ADD_X_FORWARDED_PROTO.c_str(), no_argument, &flag, 157},
|
||||||
|
{SHRPX_OPT_NO_STRIP_INCOMING_X_FORWARDED_PROTO.c_str(), no_argument,
|
||||||
|
&flag, 158},
|
||||||
{SHRPX_OPT_SINGLE_PROCESS.c_str(), no_argument, &flag, 159},
|
{SHRPX_OPT_SINGLE_PROCESS.c_str(), no_argument, &flag, 159},
|
||||||
{nullptr, 0, nullptr, 0}};
|
{nullptr, 0, nullptr, 0}};
|
||||||
|
|
||||||
|
@ -4064,6 +4078,16 @@ int main(int argc, char **argv) {
|
||||||
cmdcfgs.emplace_back(SHRPX_OPT_SINGLE_THREAD,
|
cmdcfgs.emplace_back(SHRPX_OPT_SINGLE_THREAD,
|
||||||
StringRef::from_lit("yes"));
|
StringRef::from_lit("yes"));
|
||||||
break;
|
break;
|
||||||
|
case 157:
|
||||||
|
// --no-add-x-forwarded-proto
|
||||||
|
cmdcfgs.emplace_back(SHRPX_OPT_NO_ADD_X_FORWARDED_PROTO,
|
||||||
|
StringRef::from_lit("yes"));
|
||||||
|
break;
|
||||||
|
case 158:
|
||||||
|
// --no-strip-incoming-x-forwarded-proto
|
||||||
|
cmdcfgs.emplace_back(SHRPX_OPT_NO_STRIP_INCOMING_X_FORWARDED_PROTO,
|
||||||
|
StringRef::from_lit("yes"));
|
||||||
|
break;
|
||||||
case 159:
|
case 159:
|
||||||
// --single-process
|
// --single-process
|
||||||
cmdcfgs.emplace_back(SHRPX_OPT_SINGLE_PROCESS,
|
cmdcfgs.emplace_back(SHRPX_OPT_SINGLE_PROCESS,
|
||||||
|
|
|
@ -1905,6 +1905,11 @@ int option_lookup_token(const char *name, size_t namelen) {
|
||||||
return SHRPX_OPTID_FETCH_OCSP_RESPONSE_FILE;
|
return SHRPX_OPTID_FETCH_OCSP_RESPONSE_FILE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'o':
|
||||||
|
if (util::strieq_l("no-add-x-forwarded-prot", name, 23)) {
|
||||||
|
return SHRPX_OPTID_NO_ADD_X_FORWARDED_PROTO;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
if (util::strieq_l("listener-disable-timeou", name, 23)) {
|
if (util::strieq_l("listener-disable-timeou", name, 23)) {
|
||||||
return SHRPX_OPTID_LISTENER_DISABLE_TIMEOUT;
|
return SHRPX_OPTID_LISTENER_DISABLE_TIMEOUT;
|
||||||
|
@ -2101,6 +2106,11 @@ int option_lookup_token(const char *name, size_t namelen) {
|
||||||
return SHRPX_OPTID_FRONTEND_HTTP2_OPTIMIZE_WINDOW_SIZE;
|
return SHRPX_OPTID_FRONTEND_HTTP2_OPTIMIZE_WINDOW_SIZE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'o':
|
||||||
|
if (util::strieq_l("no-strip-incoming-x-forwarded-prot", name, 34)) {
|
||||||
|
return SHRPX_OPTID_NO_STRIP_INCOMING_X_FORWARDED_PROTO;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
if (util::strieq_l("frontend-http2-dump-response-heade", name, 34)) {
|
if (util::strieq_l("frontend-http2-dump-response-heade", name, 34)) {
|
||||||
return SHRPX_OPTID_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER;
|
return SHRPX_OPTID_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER;
|
||||||
|
@ -3363,6 +3373,14 @@ int parse_config(Config *config, int optid, const StringRef &opt,
|
||||||
case SHRPX_OPTID_SINGLE_PROCESS:
|
case SHRPX_OPTID_SINGLE_PROCESS:
|
||||||
config->single_process = util::strieq_l("yes", optarg);
|
config->single_process = util::strieq_l("yes", optarg);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
case SHRPX_OPTID_NO_ADD_X_FORWARDED_PROTO:
|
||||||
|
config->http.xfp.add = !util::strieq_l("yes", optarg);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
case SHRPX_OPTID_NO_STRIP_INCOMING_X_FORWARDED_PROTO:
|
||||||
|
config->http.xfp.strip_incoming = !util::strieq_l("yes", optarg);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
case SHRPX_OPTID_CONF:
|
case SHRPX_OPTID_CONF:
|
||||||
LOG(WARN) << "conf: ignored";
|
LOG(WARN) << "conf: ignored";
|
||||||
|
|
|
@ -337,6 +337,10 @@ constexpr auto SHRPX_OPT_FRONTEND_MAX_REQUESTS =
|
||||||
StringRef::from_lit("frontend-max-requests");
|
StringRef::from_lit("frontend-max-requests");
|
||||||
constexpr auto SHRPX_OPT_SINGLE_THREAD = StringRef::from_lit("single-thread");
|
constexpr auto SHRPX_OPT_SINGLE_THREAD = StringRef::from_lit("single-thread");
|
||||||
constexpr auto SHRPX_OPT_SINGLE_PROCESS = StringRef::from_lit("single-process");
|
constexpr auto SHRPX_OPT_SINGLE_PROCESS = StringRef::from_lit("single-process");
|
||||||
|
constexpr auto SHRPX_OPT_NO_ADD_X_FORWARDED_PROTO =
|
||||||
|
StringRef::from_lit("no-add-x-forwarded-proto");
|
||||||
|
constexpr auto SHRPX_OPT_NO_STRIP_INCOMING_X_FORWARDED_PROTO =
|
||||||
|
StringRef::from_lit("no-strip-incoming-x-forwarded-proto");
|
||||||
|
|
||||||
constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
|
constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
|
||||||
|
|
||||||
|
@ -639,6 +643,10 @@ struct HttpConfig {
|
||||||
bool add;
|
bool add;
|
||||||
bool strip_incoming;
|
bool strip_incoming;
|
||||||
} xff;
|
} xff;
|
||||||
|
struct {
|
||||||
|
bool add;
|
||||||
|
bool strip_incoming;
|
||||||
|
} xfp;
|
||||||
std::vector<AltSvc> altsvcs;
|
std::vector<AltSvc> altsvcs;
|
||||||
std::vector<ErrorPage> error_pages;
|
std::vector<ErrorPage> error_pages;
|
||||||
HeaderRefs add_request_headers;
|
HeaderRefs add_request_headers;
|
||||||
|
@ -1023,6 +1031,7 @@ enum {
|
||||||
SHRPX_OPTID_MAX_REQUEST_HEADER_FIELDS,
|
SHRPX_OPTID_MAX_REQUEST_HEADER_FIELDS,
|
||||||
SHRPX_OPTID_MAX_RESPONSE_HEADER_FIELDS,
|
SHRPX_OPTID_MAX_RESPONSE_HEADER_FIELDS,
|
||||||
SHRPX_OPTID_MRUBY_FILE,
|
SHRPX_OPTID_MRUBY_FILE,
|
||||||
|
SHRPX_OPTID_NO_ADD_X_FORWARDED_PROTO,
|
||||||
SHRPX_OPTID_NO_HOST_REWRITE,
|
SHRPX_OPTID_NO_HOST_REWRITE,
|
||||||
SHRPX_OPTID_NO_HTTP2_CIPHER_BLACK_LIST,
|
SHRPX_OPTID_NO_HTTP2_CIPHER_BLACK_LIST,
|
||||||
SHRPX_OPTID_NO_KQUEUE,
|
SHRPX_OPTID_NO_KQUEUE,
|
||||||
|
@ -1030,6 +1039,7 @@ enum {
|
||||||
SHRPX_OPTID_NO_OCSP,
|
SHRPX_OPTID_NO_OCSP,
|
||||||
SHRPX_OPTID_NO_SERVER_PUSH,
|
SHRPX_OPTID_NO_SERVER_PUSH,
|
||||||
SHRPX_OPTID_NO_SERVER_REWRITE,
|
SHRPX_OPTID_NO_SERVER_REWRITE,
|
||||||
|
SHRPX_OPTID_NO_STRIP_INCOMING_X_FORWARDED_PROTO,
|
||||||
SHRPX_OPTID_NO_VIA,
|
SHRPX_OPTID_NO_VIA,
|
||||||
SHRPX_OPTID_NPN_LIST,
|
SHRPX_OPTID_NPN_LIST,
|
||||||
SHRPX_OPTID_OCSP_UPDATE_INTERVAL,
|
SHRPX_OPTID_OCSP_UPDATE_INTERVAL,
|
||||||
|
|
|
@ -371,8 +371,24 @@ int Http2DownstreamConnection::push_request_headers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!config->http2_proxy && req.method != HTTP_CONNECT) {
|
if (!config->http2_proxy && req.method != HTTP_CONNECT) {
|
||||||
|
auto &xfpconf = httpconf.xfp;
|
||||||
|
auto xfp = xfpconf.strip_incoming
|
||||||
|
? nullptr
|
||||||
|
: req.fs.header(http2::HD_X_FORWARDED_PROTO);
|
||||||
|
|
||||||
|
if (xfpconf.add) {
|
||||||
|
StringRef xfp_value;
|
||||||
// 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));
|
if (xfp) {
|
||||||
|
xfp_value = concat_string_ref(balloc, xfp->value,
|
||||||
|
StringRef::from_lit(", "), req.scheme);
|
||||||
|
} else {
|
||||||
|
xfp_value = req.scheme;
|
||||||
|
}
|
||||||
|
nva.push_back(http2::make_nv_ls_nocopy("x-forwarded-proto", xfp_value));
|
||||||
|
} else if (xfp) {
|
||||||
|
nva.push_back(http2::make_nv_ls_nocopy("x-forwarded-proto", xfp->value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto via = req.fs.header(http2::HD_VIA);
|
auto via = req.fs.header(http2::HD_VIA);
|
||||||
|
|
|
@ -630,10 +630,25 @@ int HttpDownstreamConnection::push_request_headers() {
|
||||||
buf->append("\r\n");
|
buf->append("\r\n");
|
||||||
}
|
}
|
||||||
if (!config->http2_proxy && !connect_method) {
|
if (!config->http2_proxy && !connect_method) {
|
||||||
|
auto &xfpconf = httpconf.xfp;
|
||||||
|
auto xfp = xfpconf.strip_incoming
|
||||||
|
? nullptr
|
||||||
|
: req.fs.header(http2::HD_X_FORWARDED_PROTO);
|
||||||
|
|
||||||
|
if (xfpconf.add) {
|
||||||
buf->append("X-Forwarded-Proto: ");
|
buf->append("X-Forwarded-Proto: ");
|
||||||
|
if (xfp) {
|
||||||
|
buf->append((*xfp).value);
|
||||||
|
buf->append(", ");
|
||||||
|
}
|
||||||
assert(!req.scheme.empty());
|
assert(!req.scheme.empty());
|
||||||
buf->append(req.scheme);
|
buf->append(req.scheme);
|
||||||
buf->append("\r\n");
|
buf->append("\r\n");
|
||||||
|
} else if (xfp) {
|
||||||
|
buf->append("X-Forwarded-Proto: ");
|
||||||
|
buf->append((*xfp).value);
|
||||||
|
buf->append("\r\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
auto via = req.fs.header(http2::HD_VIA);
|
auto via = req.fs.header(http2::HD_VIA);
|
||||||
if (httpconf.no_via) {
|
if (httpconf.no_via) {
|
||||||
|
|
Loading…
Reference in New Issue