From c999ea261edf471aae75e977ad2bae1be96a950a Mon Sep 17 00:00:00 2001 From: yushiqie <1539578852@qq.com> Date: Tue, 30 Apr 2024 12:20:20 +0800 Subject: [PATCH] sync (#26) --- .bazelversion | 2 +- .circleci/config.yml | 28 +- .gitmodules | 2 +- Makefile | 19 +- WORKSPACE | 11 + .../dockerfile/kuscia-envoy-anolis.Dockerfile | 6 +- envoy | 2 +- .../http/kuscia_common/kuscia_header.h | 7 +- kuscia/source/filters/http/kuscia_gress/BUILD | 2 +- .../filters/http/kuscia_gress/gress_filter.cc | 406 ++++++++++-------- .../filters/http/kuscia_gress/gress_filter.h | 151 +++---- 11 files changed, 334 insertions(+), 302 deletions(-) diff --git a/.bazelversion b/.bazelversion index 04edabd..f4965a3 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1 +1 @@ -5.4.1 \ No newline at end of file +6.0.0 \ No newline at end of file diff --git a/.circleci/config.yml b/.circleci/config.yml index ea0a898..9db72d6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -8,12 +8,12 @@ version: 2.1 executors: linux_x64_executor: # declares a reusable executor docker: - - image: envoyproxy/envoy-build-ubuntu:81a93046060dbe5620d5b3aa92632090a9ee4da6 + - image: envoyproxy/envoy-build-ubuntu:7304f974de2724617b7492ccb4c9c58cd420353a resource_class: 2xlarge shell: /bin/bash --login -eo pipefail linux_aarch64_executor: docker: - - image: envoyproxy/envoy-build-ubuntu:81a93046060dbe5620d5b3aa92632090a9ee4da6 + - image: envoyproxy/envoy-build-ubuntu:7304f974de2724617b7492ccb4c9c58cd420353a resource_class: arm.2xlarge shell: /bin/bash --login -eo pipefail @@ -54,26 +54,24 @@ jobs: IMG=secretflow/kuscia-envoy IMG_LATEST={IMG}:latest IMG_TAG={IMG}:{CIRCLETAG} - + ALIYUN_IMG=secretflow-registry.cn-hangzhou.cr.aliyuncs.com/secretflow/kuscia-envoy ALIYUN_IMG_LATEST={ALIYUN_IMG}:latest ALIYUN_IMG_TAG={ALIYUN_IMG}:{CIRCLETAG} - + #login docker docker login -u ${DOCKER_USERNAME} -p ${DOCKER_DEPLOY_TOKEN} - - docker buildx build -t ${IMG_LATEST} --platform linux/amd64 --build-arg ARCH=amd64 -f ./build_image/dockerfile/kuscia-envoy-anolis.Dockerfile . --push - docker buildx build -t ${IMG_LATEST} --platform linux/arm64 --build-arg ARCH=arm64 -f ./build_image/dockerfile/kuscia-envoy-anolis.Dockerfile . --push - docker buildx build -t ${IMG_TAG} --platform linux/amd64 --build-arg ARCH=amd64 -f ./build_image/dockerfile/kuscia-envoy-anolis.Dockerfile . --push - docker buildx build -t ${IMG_TAG} --platform linux/arm64 --build-arg ARCH=arm64 -f ./build_image/dockerfile/kuscia-envoy-anolis.Dockerfile . --push - + + docker buildx build -t ${IMG_LATEST} --platform linux/arm64,linux/amd64 -f ./build_image/dockerfile/kuscia-envoy-anolis.Dockerfile . --push + docker buildx build -t ${IMG_TAG} --platform linux/arm64,linux/amd64 -f ./build_image/dockerfile/kuscia-envoy-anolis.Dockerfile . --push + + # login docker - aliyun docker login -u ${ALIYUN_DOCKER_USERNAME} -p ${ALIYUN_DOCKER_PASSWORD} secretflow-registry.cn-hangzhou.cr.aliyuncs.com - - docker buildx build -t ${ALIYUN_IMG_LATEST} --platform linux/amd64 --build-arg ARCH=amd64 -f ./build_image/dockerfile/kuscia-envoy-anolis.Dockerfile . --push - docker buildx build -t ${ALIYUN_IMG_LATEST} --platform linux/arm64 --build-arg ARCH=arm64 -f ./build_image/dockerfile/kuscia-envoy-anolis.Dockerfile . --push - docker buildx build -t ${ALIYUN_IMG_TAG} --platform linux/amd64 --build-arg ARCH=amd64 -f ./build_image/dockerfile/kuscia-envoy-anolis.Dockerfile . --push - docker buildx build -t ${ALIYUN_IMG_TAG} --platform linux/arm64 --build-arg ARCH=arm64 -f ./build_image/dockerfile/kuscia-envoy-anolis.Dockerfile . --push + docker buildx build -t {ALIYUN_IMG_LATEST} --platform linux/amd64,linux/arm64 -f ./build_image/dockerfile/kuscia-envoy-anolis.Dockerfile . --push + docker buildx build -t {ALIYUN_IMG_TAG} --platform linux/amd64,linux/arm64 -f ./build_image/dockerfile/kuscia-envoy-anolis.Dockerfile . --push + + # Orchestrate jobs using workflows diff --git a/.gitmodules b/.gitmodules index d27b8a8..e3991ac 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "envoy"] path = envoy url = https://github.com/envoyproxy/envoy.git - branch = release/v1.20 + branch = release/v1.25 diff --git a/Makefile b/Makefile index a9ded2e..ff15ea4 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ SHELL := /bin/bash -BUILD_IMAGE = envoyproxy/envoy-build-ubuntu:81a93046060dbe5620d5b3aa92632090a9ee4da6 +BUILD_IMAGE = envoyproxy/envoy-build-ubuntu:7304f974de2724617b7492ccb4c9c58cd420353a # Image URL to use all building image targets DATETIME = $(shell date +"%Y%m%d%H%M%S") @@ -14,7 +14,7 @@ UNAME_M_OUTPUT := $(shell uname -m) # To configure the ARCH variable to either arm64 or amd64 or UNAME_M_OUTPUT ARCH := $(if $(filter aarch64 arm64,$(UNAME_M_OUTPUT)),arm64,$(if $(filter amd64 x86_64,$(UNAME_M_OUTPUT)),amd64,$(UNAME_M_OUTPUT))) -CONTAINER_NAME ?= "build-envoy" +CONTAINER_NAME ?= "build-envoy-$(shell echo ${USER})" COMPILE_MODE ?=opt TARGET ?= "//:envoy" BUILD_OPTS ?="--strip=always" @@ -23,16 +23,24 @@ TEST_COMPILE_MODE = fastbuild TEST_TARGET ?= "//kuscia/test/..." TEST_LOG_LEVEL = debug +GCC_VERSION := $(shell docker exec -it $(CONTAINER_NAME) /bin/bash -c 'gcc --version | grep gcc | head -n 1 | cut -d" " -f4') + define start_docker if [ ! -f "./envoy/BUILD" ]; then\ git submodule update --init;\ fi; if [[ ! -n $$(docker ps -q -f "name=^$(CONTAINER_NAME)$$") ]]; then\ - docker run -itd --rm -v $(shell pwd):/home/admin/dev -v $(shell pwd)/cache:/root/.cache/bazel -w /home/admin/dev --name $(CONTAINER_NAME) \ + docker run -itd --rm -v $(shell pwd)/cache:/root/.cache/bazel -v $(shell pwd):/home/admin/dev -w /home/admin/dev --name $(CONTAINER_NAME) \ -e GOPROXY='https://goproxy.cn,direct' --cap-add=NET_ADMIN $(BUILD_IMAGE);\ docker exec -it $(CONTAINER_NAME) /bin/bash -c 'git config --global --add safe.directory /home/admin/dev';\ fi; - + echo "GCC_VERSION: $(GCC_VERSION)";\ + if [[ ($(ARCH) == "aarch64" || $(ARCH) == "arm64") && $(GCC_VERSION) == "9.4.0" ]]; then\ + echo "ARCH: $(ARCH) - Install gcc-11 g++-11";\ + docker exec $(CONTAINER_NAME) /bin/bash -c 'sudo apt update';\ + docker exec $(CONTAINER_NAME) /bin/bash -c 'sudo apt install -y gcc-11 g++-11';\ + docker exec $(CONTAINER_NAME) /bin/bash -c 'sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 60 --slave /usr/bin/g++ g++ /usr/bin/g++-11';\ + fi; endef define stop_docker @@ -72,7 +80,6 @@ clean: $(call stop_docker) rm -rf output - .PHONY: image image: build-envoy - docker build -t ${IMG} --build-arg ARCH=${ARCH} -f ./build_image/dockerfile/kuscia-envoy-anolis.Dockerfile . + docker build -t ${IMG} -f ./build_image/dockerfile/kuscia-envoy-anolis.Dockerfile . diff --git a/WORKSPACE b/WORKSPACE index 72a6f05..9f4c123 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -5,6 +5,17 @@ local_repository( path = "envoy", ) +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +http_archive( + name = "bazel_gazelle", + sha256 = "501deb3d5695ab658e82f6f6f549ba681ea3ca2a5fb7911154b5aa45596183fa", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.26.0/bazel-gazelle-v0.26.0.tar.gz", + "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.26.0/bazel-gazelle-v0.26.0.tar.gz", + ], +) + load("@envoy//bazel:api_binding.bzl", "envoy_api_binding") envoy_api_binding() diff --git a/build_image/dockerfile/kuscia-envoy-anolis.Dockerfile b/build_image/dockerfile/kuscia-envoy-anolis.Dockerfile index 6c2af53..c97bfaa 100644 --- a/build_image/dockerfile/kuscia-envoy-anolis.Dockerfile +++ b/build_image/dockerfile/kuscia-envoy-anolis.Dockerfile @@ -1,12 +1,12 @@ -FROM openanolis/anolisos:8.8 +FROM openanolis/anolisos:23 -ARG ARCH +ARG TARGETPLATFORM ENV TZ=Asia/Shanghai ARG ROOT_DIR="/home/kuscia" -COPY ./output/linux/$ARCH $ROOT_DIR/ +COPY ./output/$TARGETPLATFORM $ROOT_DIR/ WORKDIR ${ROOT_DIR} diff --git a/envoy b/envoy index bae2e9d..e461edd 160000 --- a/envoy +++ b/envoy @@ -1 +1 @@ -Subproject commit bae2e9d642a6a8ae6c5d3810f77f3e888f0d97da +Subproject commit e461edd823ab1e9f354d64c6e7824f29bedf73cf diff --git a/kuscia/source/filters/http/kuscia_common/kuscia_header.h b/kuscia/source/filters/http/kuscia_common/kuscia_header.h index 8aa959f..e672367 100755 --- a/kuscia/source/filters/http/kuscia_common/kuscia_header.h +++ b/kuscia/source/filters/http/kuscia_common/kuscia_header.h @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. - #pragma once #include "envoy/http/header_map.h" @@ -34,9 +33,7 @@ const Http::LowerCaseString HeaderKeyKusciaToken("Kuscia-Token"); const Http::LowerCaseString HeaderKeyKusciaHost("Kuscia-Host"); const Http::LowerCaseString HeaderKeyOriginSource("Kuscia-Origin-Source"); - const Http::LowerCaseString HeaderKeyErrorMessage("Kuscia-Error-Message"); -const Http::LowerCaseString HeaderKeyFmtError("Kuscia-Error-Formatted"); const Http::LowerCaseString HeaderKeyErrorMessageInternal("Kuscia-Error-Message-Internal"); const Http::LowerCaseString HeaderKeyRecordBody("Kuscia-Record-Body"); @@ -46,8 +43,8 @@ const Http::LowerCaseString HeaderKeyEncryptIv("Kuscia-Encrypt-Iv"); const Http::LowerCaseString HeaderKeyForwardRequestId("Kuscia-Foward-Request-Id"); class KusciaHeader { - public: - static absl::optional getSource(const Http::RequestHeaderMap& headers); +public: + static absl::optional getSource(const Http::RequestHeaderMap& headers); }; // receiver.${peer}.svc/poll?timeout=xxx&service=xxx diff --git a/kuscia/source/filters/http/kuscia_gress/BUILD b/kuscia/source/filters/http/kuscia_gress/BUILD index 80b97fb..0cc8360 100755 --- a/kuscia/source/filters/http/kuscia_gress/BUILD +++ b/kuscia/source/filters/http/kuscia_gress/BUILD @@ -18,7 +18,7 @@ envoy_cc_library( "@envoy//source/extensions/filters/http/common:pass_through_filter_lib", "@envoy//source/common/http:codes_lib", "@com_github_nlohmann_json//:json", - "@envoy//source/common/api:os_sys_calls_lib", + "@envoy//source/common/api:os_sys_calls_lib" ], ) diff --git a/kuscia/source/filters/http/kuscia_gress/gress_filter.cc b/kuscia/source/filters/http/kuscia_gress/gress_filter.cc index cad96db..8dae93e 100755 --- a/kuscia/source/filters/http/kuscia_gress/gress_filter.cc +++ b/kuscia/source/filters/http/kuscia_gress/gress_filter.cc @@ -12,239 +12,277 @@ // See the License for the specific language governing permissions and // limitations under the License. - #include "kuscia/source/filters/http/kuscia_gress/gress_filter.h" - #include "fmt/format.h" +#include "kuscia/source/filters/http/kuscia_common/kuscia_header.h" +#include "source/common/http/codes.h" #include "source/common/http/header_utility.h" #include "source/common/http/headers.h" - -#include "kuscia/source/filters/http/kuscia_common/kuscia_header.h" +#include +#include +#include +#include namespace Envoy { namespace Extensions { namespace HttpFilters { namespace KusciaGress { -static void adjustContentLength(Http::RequestOrResponseHeaderMap& headers, uint64_t delta_length) { - auto length_header = headers.getContentLengthValue(); - if (!length_header.empty()) { - uint64_t old_length; - if (absl::SimpleAtoi(length_header, &old_length)) { - if (old_length != 0) { - headers.setContentLength(old_length + delta_length); - } - } +static std::string replaceNamespaceInHost(absl::string_view host, + absl::string_view new_namespace) { + std::vector fields = absl::StrSplit(host, "."); + for (std::size_t i = 2; i < fields.size(); i++) { + if (fields[i] == "svc") { + fields[i - 1] = new_namespace; + return absl::StrJoin(fields, "."); } + } + return ""; } -static std::string replaceNamespaceInHost(absl::string_view host, absl::string_view new_namespace) { - std::vector fields = absl::StrSplit(host, "."); - for (std::size_t i = 2; i < fields.size(); i++) { - if (fields[i] == "svc") { - fields[i - 1] = new_namespace; - return absl::StrJoin(fields, "."); - } - } - return ""; +static std::string getGatewayDesc(const std::string& domain, const std::string& instance, + const std::string& listener) { + return fmt::format("{}/{}/{}", domain, instance, listener); } -RewriteHostConfig::RewriteHostConfig(const RewriteHost& config) : - rewrite_policy_(config.rewrite_policy()), - header_(config.header()), - specified_host_(config.specified_host()) { - path_matchers_.reserve(config.path_matchers_size()); - for (const auto& pm : config.path_matchers()) { - PathMatcherConstSharedPtr matcher(new Envoy::Matchers::PathMatcher(pm)); - path_matchers_.emplace_back(matcher); - } +static std::string getListener(const StreamInfo::StreamInfo& stream_info) { + std::string address; + auto& provider = stream_info.downstreamAddressProvider(); + if (provider.localAddress() != nullptr) { + address = provider.localAddress()->asString(); + } + if (address.empty()) { + return "-"; + } + return absl::EndsWith(address, ":80") ? "internal" : "external"; } -GressFilterConfig::GressFilterConfig(const GressPbConfig& config) : - instance_(config.instance()), - self_namespace_(config.self_namespace()), - add_origin_source_(config.add_origin_source()), - max_logging_body_size_per_reqeuest_(config.max_logging_body_size_per_reqeuest()) { - rewrite_host_config_.reserve(config.rewrite_host_config_size()); - for (const auto& rh : config.rewrite_host_config()) { - rewrite_host_config_.emplace_back(RewriteHostConfig(rh)); - } +static std::string getCause(const StreamInfo::StreamInfo& stream_info) { + std::string cause; + if (stream_info.responseCodeDetails().has_value()) { + cause = stream_info.responseCodeDetails().value(); + } + return cause; } -Http::FilterHeadersStatus GressFilter::decodeHeaders(Http::RequestHeaderMap& headers, - bool) { - // store some useful headers - request_id_ = std::string(headers.getRequestIdValue()); - host_ = std::string(headers.getHostValue()); - auto record = headers.getByKey(KusciaCommon::HeaderKeyRecordBody); - if (record.has_value() && record.value() == "true") { - record_request_body_ = true; - record_response_body_ = true; - } +std::string strip(absl::string_view sv) { return std::string(sv.data(), sv.size()); } - // rewrite host to choose a new route - if (rewriteHost(headers)) { - decoder_callbacks_->downstreamCallbacks()->clearRouteCache(); - } else { - // replace ".svc:" with ".svc" for internal request - size_t n = host_.rfind(".svc:"); - if (n != std::string::npos) { - std::string substr = host_.substr(0, n + 4); - headers.setHost(substr); - decoder_callbacks_->downstreamCallbacks()->clearRouteCache(); - } +std::string getHeaderValue(const Http::ResponseHeaderMap& headers, + const Http::LowerCaseString& key) { + auto value_header = headers.get(key); + if (!value_header.empty() && value_header[0] != nullptr && !value_header[0]->value().empty()) { + return strip(value_header[0]->value().getStringView()); + } + return ""; +} + +RewriteHostConfig::RewriteHostConfig(const RewriteHost& config) + : rewrite_policy_(config.rewrite_policy()), header_(config.header()), + specified_host_(config.specified_host()) { + path_matchers_.reserve(config.path_matchers_size()); + for (const auto& pm : config.path_matchers()) { + PathMatcherConstSharedPtr matcher(new Envoy::Matchers::PathMatcher(pm)); + path_matchers_.emplace_back(matcher); + } +} + +GressFilterConfig::GressFilterConfig(const GressPbConfig& config) + : instance_(config.instance()), self_namespace_(config.self_namespace()), + add_origin_source_(config.add_origin_source()), + max_logging_body_size_per_reqeuest_(config.max_logging_body_size_per_reqeuest()) { + rewrite_host_config_.reserve(config.rewrite_host_config_size()); + for (const auto& rh : config.rewrite_host_config()) { + rewrite_host_config_.emplace_back(RewriteHostConfig(rh)); + } +} + +Http::FilterHeadersStatus GressFilter::decodeHeaders(Http::RequestHeaderMap& headers, bool) { + // store some useful headers + request_id_ = std::string(headers.getRequestIdValue()); + host_ = std::string(headers.getHostValue()); + auto record = headers.getByKey(KusciaCommon::HeaderKeyRecordBody); + if (record.has_value() && record.value() == "true") { + record_request_body_ = true; + record_response_body_ = true; + } + + // rewrite host to choose a new route + if (rewriteHost(headers)) { + decoder_callbacks_->downstreamCallbacks()->clearRouteCache(); + } else { + // replace ".svc:" with ".svc" for internal request + size_t n = host_.rfind(".svc:"); + if (n != std::string::npos) { + std::string substr = host_.substr(0, n + 4); + headers.setHost(substr); + decoder_callbacks_->downstreamCallbacks()->clearRouteCache(); } + } - // add origin-source if not exist - if (config_->addOriginSource()) { - auto origin_source = headers.getByKey(KusciaCommon::HeaderKeyOriginSource) - .value_or(std::string()); - if (origin_source.empty()) { - headers.addCopy(KusciaCommon::HeaderKeyOriginSource, config_->selfNamespace()); - } + // add origin-source if not exist + if (config_->addOriginSource()) { + auto origin_source = + headers.getByKey(KusciaCommon::HeaderKeyOriginSource).value_or(std::string()); + if (origin_source.empty()) { + headers.addCopy(KusciaCommon::HeaderKeyOriginSource, config_->selfNamespace()); } + } - return Http::FilterHeadersStatus::Continue; + return Http::FilterHeadersStatus::Continue; } Http::FilterDataStatus GressFilter::decodeData(Buffer::Instance& data, bool end_stream) { - if (record_request_body_) { - record_request_body_ = recordBody(req_body_, data, end_stream, true); + if (record_request_body_) { + record_request_body_ = recordBody(req_body_, data, end_stream, true); + } + return Http::FilterDataStatus::Continue; +} + +Http::FilterHeadersStatus GressFilter::encodeHeaders(Http::ResponseHeaderMap& headers, bool) { + uint64_t status_code = 0; + if (absl::SimpleAtoi(headers.getStatusValue(), &status_code)) { + if (!(status_code >= 400 && status_code < 600)) { + return Http::FilterHeadersStatus::Continue; } - return Http::FilterDataStatus::Continue; -} - -Http::FilterHeadersStatus GressFilter::encodeHeaders(Http::ResponseHeaderMap& headers, - bool end_stream) { - // generate error msg - auto result = headers.get(KusciaCommon::HeaderKeyErrorMessage); - if (headers.getStatusValue() != "200") { - std::string err_msg; - auto result = headers.get(KusciaCommon::HeaderKeyErrorMessage); - if (result.empty()) { - auto inner_msg = headers.get(KusciaCommon::HeaderKeyErrorMessageInternal); - if (inner_msg.size() == 1 && inner_msg[0] != nullptr && !inner_msg[0]->value().empty()) { - err_msg = fmt::format("Domain {}.{}: {}", - config_->selfNamespace(), - config_->instance(), - inner_msg[0]->value().getStringView()); - headers.remove(KusciaCommon::HeaderKeyErrorMessageInternal); - } else { - err_msg = fmt::format("Domain {}.{}<--{} return http code {}.", - config_->selfNamespace(), - config_->instance(), - host_, - headers.getStatusValue()); - } - } else if (result[0] != nullptr) { - err_msg = fmt::format("Domain {}.{}<--{}", - config_->selfNamespace(), - config_->instance(), - result[0]->value().getStringView()); - - } - - headers.setCopy(KusciaCommon::HeaderKeyErrorMessage, err_msg); - if (end_stream) { - Envoy::Buffer::OwnedImpl body(err_msg); - adjustContentLength(headers, body.length()); - encoder_callbacks_->addEncodedData(body, true); - headers.setReferenceContentType(Http::Headers::get().ContentTypeValues.Text); - } + } + // 1. if error message key is set in response, then use it as error message + // 2. if internal error message key is set in response, then use it as error message + // 3. if neither of above, then use default error message + std::string error_message = getHeaderValue(headers, KusciaCommon::HeaderKeyErrorMessage); + bool formatted = false; + if (!error_message.empty()) { + formatted = true; + } else { + error_message = getHeaderValue(headers, KusciaCommon::HeaderKeyErrorMessageInternal); + if (error_message.empty()) { + error_message = Http::CodeUtility::toString(static_cast(status_code)); + } else { + headers.remove(KusciaCommon::HeaderKeyErrorMessageInternal); } - return Http::FilterHeadersStatus::Continue; + } + auto& stream_info = encoder_callbacks_->streamInfo(); + std::string rich_message = getRichMessage(stream_info, error_message, formatted); + headers.setCopy(KusciaCommon::HeaderKeyErrorMessage, rich_message); + return Http::FilterHeadersStatus::Continue; } Http::FilterDataStatus GressFilter::encodeData(Buffer::Instance& data, bool end_stream) { - if (record_response_body_) { - record_response_body_ = recordBody(resp_body_, data, end_stream, false); - } - return Http::FilterDataStatus::Continue; + if (record_response_body_) { + record_response_body_ = recordBody(resp_body_, data, end_stream, false); + } + return Http::FilterDataStatus::Continue; +} + +// The presence of trailers means the stream is ended, but encodeData() +// is never called with end_stream=true. +Http::FilterTrailersStatus GressFilter::encodeTrailers(Http::ResponseTrailerMap&) { + if (record_response_body_) { + Buffer::OwnedImpl data; + record_response_body_ = recordBody(resp_body_, data, true, false); + } + return Http::FilterTrailersStatus::Continue; +} + +std::string GressFilter::getRichMessage(const StreamInfo::StreamInfo& stream_info, + const std::string& error_message, bool formatted) { + std::string listener = getListener(stream_info); + std::string gateway_desc = + getGatewayDesc(config_->selfNamespace(), config_->instance(), listener); + std::string cause = getCause(stream_info); + std::string rich_message; + if (formatted) { + rich_message = fmt::format("<{}> => {}", gateway_desc, error_message); + } else if (cause == "via_upstream") { + rich_message = fmt::format("<{}> => ", gateway_desc, error_message); + } else { + rich_message = fmt::format("<{} ${}$ {}>", gateway_desc, cause, error_message); + } + return rich_message; } bool GressFilter::rewriteHost(Http::RequestHeaderMap& headers) { - for (const auto& rh : config_->rewriteHostConfig()) { - if (rewriteHost(headers, rh)) { - return true; - } + for (const auto& rh : config_->rewriteHostConfig()) { + if (rewriteHost(headers, rh)) { + return true; } - return false; + } + return false; } bool GressFilter::rewriteHost(Http::RequestHeaderMap& headers, const RewriteHostConfig& rh) { - auto header_value = headers.getByKey(Http::LowerCaseString(rh.header())).value_or(""); - if (header_value.empty()) { - return false; - } - - if (rh.pathMatchers().size() > 0) { - const absl::string_view path = headers.getPathValue(); - bool path_match = false; - for (const auto& pm : rh.pathMatchers()) { - if (pm->match(path)) { - path_match = true; - break; - } - } - if (!path_match) { - return false; - } - } + auto header_value = headers.getByKey(Http::LowerCaseString(rh.header())).value_or(""); + if (header_value.empty()) { + return false; + } - switch (rh.rewritePolicy()) { - case RewriteHost::RewriteHostWithHeader: { - headers.setHost(header_value); - return true; - } - case RewriteHost::RewriteNamespaceWithHeader: { - auto host_value = replaceNamespaceInHost(headers.getHostValue(), header_value); - if (!host_value.empty()) { - headers.setHost(host_value); - return true; - } + if (rh.pathMatchers().size() > 0) { + const absl::string_view path = headers.getPathValue(); + bool path_match = false; + for (const auto& pm : rh.pathMatchers()) { + if (pm->match(path)) { + path_match = true; break; + } } - case RewriteHost::RewriteHostWithSpecifiedHost: { - if (!rh.specifiedHost().empty()) { - headers.setHost(rh.specifiedHost()); - return true; - } - break; + if (!path_match) { + return false; } - default: - break; + } + + switch (rh.rewritePolicy()) { + case RewriteHost::RewriteHostWithHeader: { + headers.setHost(header_value); + return true; + } + case RewriteHost::RewriteNamespaceWithHeader: { + auto host_value = replaceNamespaceInHost(headers.getHostValue(), header_value); + if (!host_value.empty()) { + headers.setHost(host_value); + return true; + } + break; + } + case RewriteHost::RewriteHostWithSpecifiedHost: { + if (!rh.specifiedHost().empty()) { + headers.setHost(rh.specifiedHost()); + return true; } + break; + } + default: + break; + } - return false; + return false; } -bool GressFilter::recordBody(Buffer::OwnedImpl& body, Buffer::Instance& data, - bool end_stream, bool is_req) { - auto& stream_info = is_req ? decoder_callbacks_->streamInfo() : encoder_callbacks_->streamInfo(); - std::string body_key = is_req ? "request_body" : "response_body"; - - uint64_t logging_size = static_cast(config_->maxLoggingBodySizePerReqeuest()); - bool record_body = true; - if (data.length() > 0) { - if (logging_size > 0 && body.length() + data.length() > logging_size) { - ENVOY_LOG(info, "{} of {} already larger than {}, stop logging", - body_key, request_id_, logging_size); - record_body = false; - Buffer::OwnedImpl empty_buffer{}; - empty_buffer.move(body); - } else { - body.add(data); - } - } +bool GressFilter::recordBody(Buffer::OwnedImpl& body, Buffer::Instance& data, bool end_stream, + bool is_req) { + auto& stream_info = is_req ? decoder_callbacks_->streamInfo() : encoder_callbacks_->streamInfo(); + std::string body_key = is_req ? "request_body" : "response_body"; - if (end_stream && body.length() > 0) { - ProtobufWkt::Value value; - value.set_string_value(body.toString()); - ProtobufWkt::Struct metadata; - (*metadata.mutable_fields())[body_key] = value; - stream_info.setDynamicMetadata("envoy.kuscia", metadata); + uint64_t logging_size = static_cast(config_->maxLoggingBodySizePerReqeuest()); + bool record_body = true; + if (data.length() > 0) { + if (logging_size > 0 && body.length() + data.length() > logging_size) { + ENVOY_LOG(info, "{} of {} already larger than {}, stop logging", body_key, request_id_, + logging_size); + record_body = false; + Buffer::OwnedImpl empty_buffer{}; + empty_buffer.move(body); + } else { + body.add(data); } - return record_body; + } + + if (end_stream && body.length() > 0) { + ProtobufWkt::Value value; + value.set_string_value(body.toString()); + ProtobufWkt::Struct metadata; + (*metadata.mutable_fields())[body_key] = value; + stream_info.setDynamicMetadata("envoy.kuscia", metadata); + } + return record_body; } } // namespace KusciaGress diff --git a/kuscia/source/filters/http/kuscia_gress/gress_filter.h b/kuscia/source/filters/http/kuscia_gress/gress_filter.h index f23c7fc..c6e2355 100755 --- a/kuscia/source/filters/http/kuscia_gress/gress_filter.h +++ b/kuscia/source/filters/http/kuscia_gress/gress_filter.h @@ -12,20 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. - #pragma once -#include -#include - +#include "envoy/common/matchers.h" +#include "include/nlohmann/json.hpp" +#include "kuscia/api/filters/http/kuscia_gress/v3/gress.pb.h" #include "source/common/buffer/buffer_impl.h" #include "source/common/common/logger.h" -#include "source/extensions/filters/http/common/pass_through_filter.h" - -#include "kuscia/api/filters/http/kuscia_gress/v3/gress.pb.h" - -#include "envoy/common/matchers.h" #include "source/common/common/matchers.h" +#include "source/extensions/filters/http/common/pass_through_filter.h" +#include +#include +#include namespace Envoy { namespace Extensions { @@ -38,96 +36,79 @@ using RewritePolicy = RewriteHost::RewritePolicy; using PathMatcherConstSharedPtr = std::shared_ptr; class RewriteHostConfig { - public: - explicit RewriteHostConfig(const RewriteHost& config); - - const std::string& header() const { - return header_; - } - RewritePolicy rewritePolicy() const { - return rewrite_policy_; - } - const std::string& specifiedHost() const { - return specified_host_; - } - - const std::vector& pathMatchers() const { - return path_matchers_; - } - - private: - RewriteHost::RewritePolicy rewrite_policy_; - std::string header_; - std::string specified_host_; - std::vector path_matchers_; +public: + explicit RewriteHostConfig(const RewriteHost& config); + + const std::string& header() const { return header_; } + RewritePolicy rewritePolicy() const { return rewrite_policy_; } + const std::string& specifiedHost() const { return specified_host_; } + + const std::vector& pathMatchers() const { return path_matchers_; } + +private: + RewriteHost::RewritePolicy rewrite_policy_; + std::string header_; + std::string specified_host_; + std::vector path_matchers_; }; class GressFilterConfig { - public: - explicit GressFilterConfig(const GressPbConfig& config); - const std::string& instance() const { - return instance_; - } - - const std::string& selfNamespace() const { - return self_namespace_; - } - - bool addOriginSource() const { - return add_origin_source_; - } - - int32_t maxLoggingBodySizePerReqeuest() { - return max_logging_body_size_per_reqeuest_; - } - - const std::vector& rewriteHostConfig() const { - return rewrite_host_config_; - } - - private: - std::string instance_; - std::string self_namespace_; - bool add_origin_source_; - int32_t max_logging_body_size_per_reqeuest_; - - std::vector rewrite_host_config_; +public: + explicit GressFilterConfig(const GressPbConfig& config); + const std::string& instance() const { return instance_; } + + const std::string& selfNamespace() const { return self_namespace_; } + + bool addOriginSource() const { return add_origin_source_; } + + int32_t maxLoggingBodySizePerReqeuest() { return max_logging_body_size_per_reqeuest_; } + + const std::vector& rewriteHostConfig() const { return rewrite_host_config_; } + +private: + std::string instance_; + std::string self_namespace_; + bool add_origin_source_; + int32_t max_logging_body_size_per_reqeuest_; + + std::vector rewrite_host_config_; }; using GressFilterConfigSharedPtr = std::shared_ptr; - class GressFilter : public Envoy::Http::PassThroughFilter, - public Logger::Loggable { - public: - explicit GressFilter(GressFilterConfigSharedPtr config) : - config_(config), - host_(), - request_id_(), - record_request_body_(false), + public Logger::Loggable { +public: + explicit GressFilter(GressFilterConfigSharedPtr config) + : config_(config), host_(), request_id_(), record_request_body_(false), record_response_body_(false) {} - Http::FilterHeadersStatus decodeHeaders(Http::RequestHeaderMap& headers, - bool) override; - Http::FilterDataStatus decodeData(Buffer::Instance& data, bool end_stream) override; + Http::FilterHeadersStatus decodeHeaders(Http::RequestHeaderMap& headers, bool) override; + Http::FilterDataStatus decodeData(Buffer::Instance& data, bool end_stream) override; + + Http::FilterHeadersStatus encodeHeaders(Http::ResponseHeaderMap& headers, + bool end_stream) override; + Http::FilterDataStatus encodeData(Buffer::Instance& data, bool end_stream) override; + + Http::FilterTrailersStatus encodeTrailers(Http::ResponseTrailerMap& headers) override; + +private: + bool rewriteHost(Http::RequestHeaderMap& headers); + bool rewriteHost(Http::RequestHeaderMap& headers, const RewriteHostConfig& rh); + bool recordBody(Buffer::OwnedImpl& body, Buffer::Instance& data, bool end_stream, bool is_req); - Http::FilterHeadersStatus encodeHeaders(Http::ResponseHeaderMap& headers, - bool end_stream) override; - Http::FilterDataStatus encodeData(Buffer::Instance& data, bool end_stream) override; + std::string getRichMessage(const StreamInfo::StreamInfo& stream_info, + const std::string& error_message, bool formatted); - private: - bool rewriteHost(Http::RequestHeaderMap& headers); - bool rewriteHost(Http::RequestHeaderMap& headers, const RewriteHostConfig& rh); - bool recordBody(Buffer::OwnedImpl& body, Buffer::Instance& data, bool end_stream, bool is_req); + GressFilterConfigSharedPtr config_; + std::string host_; + std::string request_id_; - GressFilterConfigSharedPtr config_; - std::string host_; - std::string request_id_; + bool record_request_body_; + bool record_response_body_; - bool record_request_body_; - bool record_response_body_; - Buffer::OwnedImpl req_body_; - Buffer::OwnedImpl resp_body_; + Buffer::OwnedImpl req_body_; + Buffer::OwnedImpl resp_body_; }; } // namespace KusciaGress