Skip to content

Commit 4453ce1

Browse files
wbpcodeCopilot
andauthored
add x-envoy-original-host to keep original host (#39617)
Commit Message: add x-envoy-original-host to keep original host Additional Description: This PR added a x-envoy-original-host to keep original host value if the host rewriting happens. Risk Level: low. Testing: n/a. Docs Changes: n/a. Release Notes: n/a. Platform Specific Features: n/a. --------- Signed-off-by: wangbaiping(wbpcode) <[email protected]> Signed-off-by: code <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent 0672c68 commit 4453ce1

File tree

21 files changed

+147
-196
lines changed

21 files changed

+147
-196
lines changed

api/envoy/config/route/v3/route_components.proto

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,12 +1161,21 @@ message RouteAction {
11611161
// [#extension-category: envoy.path.rewrite]
11621162
core.v3.TypedExtensionConfig path_rewrite_policy = 41;
11631163

1164+
// If one of the host rewrite specifiers is set and the
1165+
// :ref:`suppress_envoy_headers
1166+
// <envoy_v3_api_field_extensions.filters.http.router.v3.Router.suppress_envoy_headers>` flag is not
1167+
// set to true, the router filter will place the original host header value before
1168+
// rewriting into the :ref:`x-envoy-original-host
1169+
// <config_http_filters_router_x-envoy-original-host>` header.
1170+
//
1171+
// And if the
1172+
// :ref:`append_x_forwarded_host <envoy_v3_api_field_config.route.v3.RouteAction.append_x_forwarded_host>`
1173+
// is set to true, the original host value will also be appended to the
1174+
// :ref:`config_http_conn_man_headers_x-forwarded-host` header.
1175+
//
11641176
oneof host_rewrite_specifier {
11651177
// Indicates that during forwarding, the host header will be swapped with
1166-
// this value. Using this option will append the
1167-
// :ref:`config_http_conn_man_headers_x-forwarded-host` header if
1168-
// :ref:`append_x_forwarded_host <envoy_v3_api_field_config.route.v3.RouteAction.append_x_forwarded_host>`
1169-
// is set.
1178+
// this value.
11701179
string host_rewrite_literal = 6
11711180
[(validate.rules).string = {well_known_regex: HTTP_HEADER_VALUE strict: false}];
11721181

@@ -1176,18 +1185,12 @@ message RouteAction {
11761185
// type ``strict_dns`` or ``logical_dns``,
11771186
// or when :ref:`hostname <envoy_v3_api_field_config.endpoint.v3.Endpoint.hostname>`
11781187
// field is not empty. Setting this to true with other cluster types
1179-
// has no effect. Using this option will append the
1180-
// :ref:`config_http_conn_man_headers_x-forwarded-host` header if
1181-
// :ref:`append_x_forwarded_host <envoy_v3_api_field_config.route.v3.RouteAction.append_x_forwarded_host>`
1182-
// is set.
1188+
// has no effect.
11831189
google.protobuf.BoolValue auto_host_rewrite = 7;
11841190

11851191
// Indicates that during forwarding, the host header will be swapped with the content of given
11861192
// downstream or :ref:`custom <config_http_conn_man_headers_custom_request_headers>` header.
1187-
// If header value is empty, host header is left intact. Using this option will append the
1188-
// :ref:`config_http_conn_man_headers_x-forwarded-host` header if
1189-
// :ref:`append_x_forwarded_host <envoy_v3_api_field_config.route.v3.RouteAction.append_x_forwarded_host>`
1190-
// is set.
1193+
// If header value is empty, host header is left intact.
11911194
//
11921195
// .. attention::
11931196
//
@@ -1203,10 +1206,6 @@ message RouteAction {
12031206
// Indicates that during forwarding, the host header will be swapped with
12041207
// the result of the regex substitution executed on path value with query and fragment removed.
12051208
// This is useful for transitioning variable content between path segment and subdomain.
1206-
// Using this option will append the
1207-
// :ref:`config_http_conn_man_headers_x-forwarded-host` header if
1208-
// :ref:`append_x_forwarded_host <envoy_v3_api_field_config.route.v3.RouteAction.append_x_forwarded_host>`
1209-
// is set.
12101209
//
12111210
// For example with the following config:
12121211
//

changelogs/current.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ removed_config_or_runtime:
112112
Removed runtime guard ``envoy.reloadable_features.lua_flow_control_while_http_call`` and legacy code paths.
113113
114114
new_features:
115+
- area: http
116+
change: |
117+
added :ref:`x-envoy-original-host <config_http_filters_router_x-envoy-original-host>` that
118+
used to record the original host header value before it is mutated by the router filter.
115119
- area: stateful_session
116120
change: |
117121
Supports envelope stateful session extension to keep the exist session header value

docs/root/configuration/http/http_filters/router_filter.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,19 @@ or :ref:`regex_rewrite <envoy_v3_api_field_config.route.v3.RouteAction.regex_rew
376376
Envoy will put the original path header in this header. This can be useful for logging and
377377
debugging.
378378

379+
.. _config_http_filters_router_x-envoy-original-host:
380+
381+
x-envoy-original-host
382+
^^^^^^^^^^^^^^^^^^^^^
383+
384+
If the route utilizes
385+
:ref:`host_rewrite_literal <envoy_v3_api_field_config.route.v3.RouteAction.host_rewrite_literal>`,
386+
:ref:`auto_host_rewrite <envoy_v3_api_field_config.route.v3.RouteAction.auto_host_rewrite>`,
387+
:ref:`host_rewrite_header <envoy_v3_api_field_config.route.v3.RouteAction.host_rewrite_header>`,
388+
:ref:`host_rewrite_path_regex <envoy_v3_api_field_config.route.v3.RouteAction.host_rewrite_path_regex>`,
389+
Envoy will put the original host header in this header. This can be useful for logging and
390+
debugging.
391+
379392
.. _config_http_filters_router_x-envoy-upstream-stream-duration-ms:
380393

381394
x-envoy-upstream-stream-duration-ms

envoy/http/header_map.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ class HeaderEntry {
191191
HEADER_FUNC(EnvoyRetriableHeaderNames) \
192192
HEADER_FUNC(EnvoyIsTimeoutRetry) \
193193
HEADER_FUNC(EnvoyOriginalPath) \
194+
HEADER_FUNC(EnvoyOriginalHost) \
194195
HEADER_FUNC(EnvoyOriginalUrl) \
195196
HEADER_FUNC(EnvoyUpstreamAltStatName) \
196197
HEADER_FUNC(EnvoyUpstreamRequestTimeoutAltResponse) \

envoy/router/router.h

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -901,23 +901,6 @@ class RouteEntry : public ResponseEntry {
901901
*/
902902
virtual const std::string& clusterName() const PURE;
903903

904-
/**
905-
* Returns the final host value for the request, taking into account route-level mutations.
906-
*
907-
* The value returned is computed with the following logic in order:
908-
*
909-
* 1. If a host rewrite is configured for the route, it returns that value.
910-
* 2. If a host rewrite header is specified, it attempts to use the value from that header.
911-
* 3. If a host rewrite path regex is configured, it applies the regex to the request path and
912-
* returns the result.
913-
* 4. If none of the above apply, it returns the original host value from the request headers.
914-
*
915-
* @param headers The constant reference to the request headers.
916-
* @note This function will not attempt to restore the port in the host value. If port information
917-
* is required, it should be handled separately.
918-
*/
919-
virtual const std::string getRequestHostValue(const Http::RequestHeaderMap& headers) const PURE;
920-
921904
/**
922905
* Returns the HTTP status code to use when configured cluster is not found.
923906
* @return Http::Code to use when configured cluster is not found.
@@ -946,11 +929,12 @@ class RouteEntry : public ResponseEntry {
946929
* immediately prior to forwarding. It is done this way vs. copying for performance reasons.
947930
* @param headers supplies the request headers, which may be modified during this call.
948931
* @param stream_info holds additional information about the request.
949-
* @param insert_envoy_original_path insert x-envoy-original-path header if path rewritten?
932+
* @param keep_original_host_or_path insert x-envoy-original-path header if path rewritten,
933+
* or x-envoy-original-host header if host rewritten.
950934
*/
951935
virtual void finalizeRequestHeaders(Http::RequestHeaderMap& headers,
952936
const StreamInfo::StreamInfo& stream_info,
953-
bool insert_envoy_original_path) const PURE;
937+
bool keep_original_host_or_path) const PURE;
954938

955939
/**
956940
* Returns the request header transforms that would be applied if finalizeRequestHeaders were

source/common/http/conn_manager_utility.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,11 @@ void ConnectionManagerUtility::cleanInternalHeaders(
325325
request_headers.removeEnvoyDecoratorOperation();
326326
request_headers.removeEnvoyDownstreamServiceCluster();
327327
request_headers.removeEnvoyDownstreamServiceNode();
328+
329+
// TODO(wbpcode): Envoy may should always remove these headers from client because
330+
// these headers are hop by hop headers and should not be sent to upstream.
328331
request_headers.removeEnvoyOriginalPath();
332+
request_headers.removeEnvoyOriginalHost();
329333
}
330334

331335
// Headers to be stripped from edge *and* intermediate-hop external requests.

source/common/http/headers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ class HeaderValues {
176176
const LowerCaseString EnvoyOriginalDstHost{absl::StrCat(prefix(), "-original-dst-host")};
177177
const LowerCaseString EnvoyOriginalMethod{absl::StrCat(prefix(), "-original-method")};
178178
const LowerCaseString EnvoyOriginalPath{absl::StrCat(prefix(), "-original-path")};
179+
const LowerCaseString EnvoyOriginalHost{absl::StrCat(prefix(), "-original-host")};
179180
const LowerCaseString EnvoyOverloaded{absl::StrCat(prefix(), "-overloaded")};
180181
const LowerCaseString EnvoyDropOverload{absl::StrCat(prefix(), "-drop-overload")};
181182
const LowerCaseString EnvoyUnconditionalDropOverload{

source/common/http/null_route_impl.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,6 @@ struct RouteEntryImpl : public Router::RouteEntry {
123123

124124
// Router::RouteEntry
125125
const std::string& clusterName() const override { return cluster_name_; }
126-
const std::string getRequestHostValue(const Http::RequestHeaderMap& headers) const override {
127-
return std::string(headers.getHostValue());
128-
}
129126
const Router::RouteStatsContextOptRef routeStatsContext() const override {
130127
return Router::RouteStatsContextOptRef();
131128
}

source/common/http/utility.cc

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -444,20 +444,21 @@ void Utility::appendVia(RequestOrResponseHeaderMap& headers, const std::string&
444444
}
445445

446446
void Utility::updateAuthority(RequestHeaderMap& headers, absl::string_view hostname,
447-
const bool append_xfh) {
448-
const auto host = headers.getHostValue();
449-
450-
// Only append to x-forwarded-host if the value was not the last value appended.
451-
const auto xfh = headers.getForwardedHostValue();
447+
bool append_xfh, bool keep_old) {
448+
if (const absl::string_view host = headers.getHostValue(); !host.empty()) {
449+
// Insert the x-envoy-original-host header if required.
450+
if (keep_old) {
451+
headers.setEnvoyOriginalHost(host);
452+
}
452453

453-
if (append_xfh && !host.empty()) {
454-
if (!xfh.empty()) {
455-
const auto xfh_split = StringUtil::splitToken(xfh, ",");
456-
if (!xfh_split.empty() && xfh_split.back() != host) {
454+
// Append the x-forwarded-host header if required. Only append to x-forwarded-host
455+
// if the value was not the last value appended.
456+
if (append_xfh) {
457+
const absl::InlinedVector<absl::string_view, 4> xfh_split =
458+
absl::StrSplit(headers.getForwardedHostValue(), ',', absl::SkipWhitespace());
459+
if (xfh_split.empty() || xfh_split.back() != host) {
457460
headers.appendForwardedHost(host, ",");
458461
}
459-
} else {
460-
headers.appendForwardedHost(host, ",");
461462
}
462463
}
463464

source/common/http/utility.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,10 @@ void appendVia(RequestOrResponseHeaderMap& headers, const std::string& via);
202202
* @param headers headers where authority should be updated.
203203
* @param hostname hostname that authority should be updated with.
204204
* @param append_xfh append the original authority to the x-forwarded-host header.
205+
* @param keep_old insert the original authority in the x-envoy-original-host header.
205206
*/
206-
void updateAuthority(RequestHeaderMap& headers, absl::string_view hostname, bool append_xfh);
207+
void updateAuthority(RequestHeaderMap& headers, absl::string_view hostname, bool append_xfh,
208+
bool keep_old);
207209

208210
/**
209211
* Creates an SSL (https) redirect path based on the input host and path headers.

0 commit comments

Comments
 (0)