in src/envoy/http/path_rewrite/filter.cc [44:126]
FilterHeadersStatus Filter::decodeHeaders(RequestHeaderMap& headers, bool) {
if (headers.Path() == nullptr) {
// NOTE: this shouldn't happen in practice because ServiceControl filter
// would have already rejected the request.
config_->stats().denied_by_no_path_.inc();
rejectRequest(Envoy::Http::Code::BadRequest, "No path in request headers",
utils::generateRcDetails(utils::kRcDetailFilterPathRewrite,
utils::kRcDetailErrorTypeBadRequest,
utils::kRcDetailErrorMissingPath));
return FilterHeadersStatus::StopIteration;
} else if (headers.Path()->value().size() > PathMaxSize) {
config_->stats().denied_by_oversize_path_.inc();
rejectRequest(Envoy::Http::Code::BadRequest,
absl::StrCat("Path is too long, max allowed size is ",
PathMaxSize, "."),
utils::generateRcDetails(utils::kRcDetailFilterPathRewrite,
utils::kRcDetailErrorTypeBadRequest,
utils::kRcDetailErrorOversizePath));
return Envoy::Http::FilterHeadersStatus::StopIteration;
}
absl::string_view original_path = headers.Path()->value().getStringView();
// Reject requests with fragment identifiers. They should never be sent to
// servers, and it breaks how we handle path translation (query params
// appended incorrectly).
if (absl::StrContains(original_path, "#")) {
config_->stats().denied_by_invalid_path_.inc();
rejectRequest(
Envoy::Http::Code::BadRequest,
"Path cannot contain fragment identifier (#)",
utils::generateRcDetails(utils::kRcDetailFilterPathRewrite,
utils::kRcDetailErrorTypeBadRequest,
utils::kRcDetailErrorFragmentIdentifier));
return FilterHeadersStatus::StopIteration;
}
// Make sure route is calculated
auto route = decoder_callbacks_->route();
// `route` shouldn't be nullptr as the catch-all route match should catch all
// the undefined requests.
if (route == nullptr || route->routeEntry() == nullptr) {
return Envoy::Http::FilterHeadersStatus::Continue;
}
const auto* per_route =
::Envoy::Http::Utility::resolveMostSpecificPerFilterConfig<
PerRouteFilterConfig>(decoder_callbacks_);
if (per_route == nullptr) {
ENVOY_LOG(debug,
"no per-route config, request is passed through unmodified");
config_->stats().path_not_changed_.inc();
return FilterHeadersStatus::Continue;
}
std::string new_path;
// It should be a bug in Envoy RouteMatch generated by control plane if
// url_template is mismatched with the request path
if (!per_route->config_parser().rewrite(original_path, new_path)) {
config_->stats().denied_by_url_template_mismatch_.inc();
rejectRequest(
Envoy::Http::Code::InternalServerError,
absl::StrCat("Request `", utils::readHeaderEntry(headers.Method()), " ",
utils::readHeaderEntry(headers.Path()),
"` is getting wrong route config"),
utils::generateRcDetails(
utils::kRcDetailFilterPathRewrite,
utils::kRcDetailErrorTypeWrongRouteConfig,
absl::StrCat("request_path(",
utils::readHeaderEntry(headers.Path()),
")-mismatched-url_template(",
per_route->config_parser().url_template(), ")")));
return FilterHeadersStatus::StopIteration;
}
config_->stats().path_changed_.inc();
if (!headers.EnvoyOriginalPath()) {
headers.setEnvoyOriginalPath(headers.getPathValue());
}
headers.setPath(new_path);
return FilterHeadersStatus::Continue;
}