-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
router redirect: use port from the request if redirect_port not specified #25573
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,6 +20,9 @@ minor_behavior_changes: | |
- area: http2 | ||
change: | | ||
Request authorities are now validated with a library function from QUICHE rather than nghttp2. This behavior change can be reverted by setting ``envoy.reloadable_features.http2_validate_authority_with_quiche`` to ``false``. | ||
- area: router redirect | ||
change: | | ||
when ``port_redirect`` is not specified, the request's port is used. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this a breaking change? Our current API, which exposes this option, has the following enum option:
AFAIK this was the previous behavior in envoy with port unset. With this new change, it will use another port There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
If port_redirect is set explicitly, there is no change in behavior. Does your API requires this param or can it be left unspecified? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry to clarify, when a user sets that in our API we do not set port_redirect and explicitly expect the "automatically set to 80 for HTTP and 443 for HTTPS.". This behavior is changed by this PR, which I think represents a breaking API change for envoy. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for explaining. To be precise, Envoy did not add port 80 or 443, but simply stripped the incoming port. The result was that port was auto chosen based on the protocol: http or https.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah.. you are right :-( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. API LGTM revoked until we resolve this, thanks for noticing @howardjohn There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @howardjohn if Istio's API says
It could now explicitly set these published port values in from the original API PR istio/api#2088 it looks like this is what istio would have wanted envoy to do There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It really doesn't matter what Istio does or docs say, this is a breaking change in Envoy which will extend beyond Istio. |
||
|
||
bug_fixes: | ||
# *Changes expected to improve the state of the world and are unlikely to have negative effects* | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1053,41 +1053,33 @@ absl::optional<std::string> RouteEntryImplBase::currentUrlPathAfterRewriteWithMa | |
return {}; | ||
} | ||
|
||
bool RouteEntryImplBase::newSchemePortMismatch(absl::string_view request_protocol, | ||
absl::string_view request_port, | ||
absl::string_view new_scheme) const { | ||
// In the rare case that X-Forwarded-Proto and scheme disagree (say http URL over an HTTPS | ||
// connection), do port stripping based on X-Forwarded-Proto so http://foo.com:80 won't | ||
// have the port stripped when served over TLS. | ||
return ((new_scheme != request_protocol) && | ||
(((request_protocol == Http::Headers::get().SchemeValues.Https.c_str()) && | ||
request_port == ":443") || | ||
((request_protocol == Http::Headers::get().SchemeValues.Http.c_str()) && | ||
request_port == ":80"))); | ||
} | ||
|
||
absl::string_view RouteEntryImplBase::processRequestHost(const Http::RequestHeaderMap& headers, | ||
absl::string_view new_scheme, | ||
absl::string_view new_port) const { | ||
|
||
absl::string_view request_host = headers.getHostValue(); | ||
size_t host_end; | ||
if (request_host.empty()) { | ||
return request_host; | ||
} | ||
// Detect if IPv6 URI | ||
if (request_host[0] == '[') { | ||
host_end = request_host.rfind("]:"); | ||
if (host_end != absl::string_view::npos) { | ||
host_end += 1; // advance to : | ||
} | ||
} else { | ||
host_end = request_host.rfind(':'); | ||
} | ||
const size_t host_end = Http::HeaderUtility::getPortStart(request_host); | ||
|
||
if (host_end != absl::string_view::npos) { | ||
absl::string_view request_port = request_host.substr(host_end); | ||
// In the rare case that X-Forwarded-Proto and scheme disagree (say http URL over an HTTPS | ||
// connection), do port stripping based on X-Forwarded-Proto so http://foo.com:80 won't | ||
// have the port stripped when served over TLS. | ||
absl::string_view request_protocol = headers.getForwardedProtoValue(); | ||
bool remove_port = !new_port.empty(); | ||
|
||
if (new_scheme != request_protocol) { | ||
remove_port |= (request_protocol == Http::Headers::get().SchemeValues.Https.c_str()) && | ||
request_port == ":443"; | ||
remove_port |= (request_protocol == Http::Headers::get().SchemeValues.Http.c_str()) && | ||
request_port == ":80"; | ||
} | ||
|
||
if (remove_port) { | ||
if (!new_port.empty() || | ||
newSchemePortMismatch(headers.getForwardedProtoValue(), request_port, new_scheme)) { | ||
return request_host.substr(0, host_end); | ||
} | ||
} | ||
|
@@ -1117,6 +1109,17 @@ std::string RouteEntryImplBase::newPath(const Http::RequestHeaderMap& headers) c | |
final_port = redirect_config_->port_redirect_.c_str(); | ||
} else { | ||
final_port = ""; | ||
const absl::string_view current_path = headers.getHostValue(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Out of curiosity, this is a direct response but not necessarily a redirect when you get here I think, what's to stop this applying even if it's not a redirect? |
||
const auto port_start = Http::HeaderUtility::getPortStart(current_path); | ||
if (port_start != absl::string_view::npos) { | ||
const auto deduced_port = current_path.substr(port_start); | ||
// use deduced port only when scheme did not change to avoid using port 80 when scheme | ||
// changed from http to https and to avoid using port 443 when scheme changed from | ||
// https to http. | ||
if (!newSchemePortMismatch(headers.getForwardedProtoValue(), deduced_port, final_scheme)) { | ||
htuch marked this conversation as resolved.
Show resolved
Hide resolved
|
||
final_port = deduced_port; | ||
} | ||
} | ||
} | ||
|
||
if (redirect_config_ != nullptr && !redirect_config_->host_redirect_.empty()) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "request port" is ambiguous as there can be multiple ports associated with a given request. Is it from
:authority
? from the actual L4 port?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is from headers, not L4.