Compare commits

...

27 Commits

Author SHA1 Message Date
澄潭
1c415c60c3 rel: Release v1.4.2 (#1159) 2024-07-26 13:55:03 +08:00
澄潭
59acb61926 Update Makefile.core.mk 2024-07-26 13:50:16 +08:00
澄潭
29079f4e2a Support set buffer limit (#1153) 2024-07-25 20:42:39 +08:00
澄潭
95edce024d support custom trace span tag (#1156) 2024-07-25 20:42:09 +08:00
Kent Dong
b6d07a157c feat: Always buffer request body in ai-proxy plugin (#1155) 2024-07-25 19:35:39 +08:00
澄潭
10569f49ae support keep original auth header (#1151) 2024-07-24 19:31:38 +08:00
Jun
2a588c99c7 fix: add full push when higress-https configmap updated and fix certmagic storage (#1105) 2024-07-24 19:30:40 +08:00
Kent Dong
0cfef34bff feat: Support fallback route in ai-proxy plugin (#1123) 2024-07-24 19:25:32 +08:00
rinfx
5c2b5d5750 potential bug fix (#1141) 2024-07-24 19:24:47 +08:00
rinfx
8f483518a9 support take effect on api level (#1150) 2024-07-24 19:23:55 +08:00
Kent Dong
f6ee4ed166 fix: Bypass the response body processing in ai-proxy if it is returned internally (#1149) 2024-07-24 16:18:00 +08:00
Kent Dong
9a9e924037 feat: Make higress-core and higress-gateway as the default container (#1144) 2024-07-24 11:25:16 +08:00
jiaomh
e7d66f691f chore: Update multiple dependencies to the latest version (#1143) 2024-07-23 11:48:44 +08:00
rinfx
8c48fcb423 update template decorator (#1142) 2024-07-22 17:04:55 +08:00
007gzs
ef31e09310 feat: add rust demo plugin request block (#1091)
Co-authored-by: Yi <lynskylate@gmail.com>
2024-07-22 15:49:06 +08:00
韩贤涛
c0f2cafdc8 feat: support ext_auth wasmplugin (#1103) 2024-07-17 15:30:32 +08:00
Kent Dong
d5a9ff3a98 fix: Fix possible type-casting related panics in ai-proxy plugin (#1127) 2024-07-16 18:38:43 +08:00
Kent Dong
f069ad5b0d feat: Add statusCodeDetails info when returning response in Wasm plugins directly (#1116) 2024-07-16 09:52:46 +08:00
xu.zhao
85219b6c53 fix: controller has no right to watch deployment (#1089)
Co-authored-by: Kent Dong <ch3cho@qq.com>
2024-07-15 16:34:24 +08:00
mamba
5041277be3 feat: 🎸 add frontend gray plugin (#1120)
Co-authored-by: Kent Dong <ch3cho@qq.com>
2024-07-15 15:47:04 +08:00
rinfx
c00c8827f9 support service-level match config (#1112) 2024-07-15 14:00:02 +08:00
rinfx
46218058d1 token-ratelimit crash bugfix (#1119) 2024-07-12 15:05:15 +08:00
Kent Dong
5306385e6b feat: Support loading custom parameters in build-and-push-wasm-plugin-image.yaml (#1118) 2024-07-12 14:23:12 +08:00
Se7en
4e881fdd3f doc: update cluster-key-rate-limit doc (#1113)
Co-authored-by: 澄潭 <zty98751@alibaba-inc.com>
Co-authored-by: Kent Dong <ch3cho@qq.com>
2024-07-11 17:31:14 +08:00
Kent Dong
59aa3b5488 fix: Use "controller.name" to refer the controller service in higress-config (#1108) 2024-07-11 16:14:16 +08:00
Kent Dong
c40cf85aad fix: Fix the incorrect image name used in build-and-push-wasm-plugin-image.yaml (#1109) 2024-07-10 13:51:13 +08:00
Kent Dong
7c749b864c fix: Fix some bugs in build-and-push-wasm-plugin-image.yaml (#1107) 2024-07-10 13:41:58 +08:00
187 changed files with 3793 additions and 777 deletions

View File

@@ -16,13 +16,13 @@ on:
type: string
jobs:
build-and-push-image:
build-and-push-wasm-plugin-image:
runs-on: ubuntu-latest
environment:
name: image-registry-msg
env:
IMAGE_REGISTRY_SERVICE: ${{ vars.IMAGE_REGISTRY_SERVICE || 'higress-registry.cn-hangzhou.cr.aliyuncs.com' }}
IMAGE_REPOSITORY: ${{ vars.IMAGE_REPOSITORY || 'plugins' }}
IMAGE_REGISTRY_SERVICE: ${{ vars.IMAGE_REGISTRY || 'higress-registry.cn-hangzhou.cr.aliyuncs.com' }}
IMAGE_REPOSITORY: ${{ vars.PLUGIN_IMAGE_REPOSITORY || 'plugins' }}
GO_VERSION: 1.19
TINYGO_VERSION: 0.28.1
ORAS_VERSION: 1.0.0
@@ -84,18 +84,30 @@ jobs:
- name: Build Image and Push
run: |
push_command=${{ env.PUSH_COMMAND }}
push_command=${push_command#\"}
push_command=${push_command%\"} # 删除PUSH_COMMAND中的双引号确保oras push正常解析
target_image="${{ env.IMAGE_REGISTRY_SERVICE }}/${{ env.IMAGE_REPOSITORY}}/${{ env.PLUGIN_NAME }}:${{ env.VERSION }}"
echo "TargetImage=${target_image}"
cd ${{ github.workspace }}/plugins/wasm-go/extensions/${PLUGIN_NAME}
if [ -f ./.buildrc ]; then
echo 'Found .buildrc file, sourcing it...'
. ./.buildrc
else
echo '.buildrc file not found'
fi
echo "EXTRA_TAGS=${EXTRA_TAGS}"
command="
set -e
cd /workspace/plugins/wasm-go/extensions/${PLUGIN_NAME}
go mod tidy
tinygo build -o ./plugin.wasm -scheduler=none -target=wasi -gc=custom -tags='custommalloc nottinygc_finalizer' ./main.go
tinygo build -o ./plugin.wasm -scheduler=none -target=wasi -gc=custom -tags=\"custommalloc nottinygc_finalizer ${EXTRA_TAGS}\" .
tar czvf plugin.tar.gz plugin.wasm
echo ${{ secrets.REGISTRY_PASSWORD }} | oras login -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin ${{ env.IMAGE_REGISTRY_SERVICE }}
oras push ${IMAGE_REGISTRY_SERVICE}/${IMAGE_REPOSITORY}:${VERSION} ${push_command}
oras push ${target_image} ${push_command}
"
docker exec builder bash -c "$command"

View File

@@ -17,8 +17,8 @@ jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: 1.19
# There are too many lint errors in current code bases
@@ -30,9 +30,9 @@ jobs:
strategy:
matrix:
# TODO(Xunzhuo): Enable C WASM Filters in CI
wasmPluginType: [ GO ]
wasmPluginType: [ GO, RUST ]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Free Up GitHub Actions Ubuntu Runner Disk Space 🔧
uses: jlumbroso/free-disk-space@main
@@ -45,12 +45,12 @@ jobs:
swap-storage: true
- name: "Setup Go"
uses: actions/setup-go@v3
uses: actions/setup-go@v5
with:
go-version: 1.19
- name: Setup Golang Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |-
~/.cache/go-build
@@ -60,7 +60,7 @@ jobs:
${{ runner.os }}-go
- name: Setup Submodule Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |-
.git/modules
@@ -81,4 +81,4 @@ jobs:
runs-on: ubuntu-latest
needs: [ higress-wasmplugin-test ]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

View File

@@ -10,8 +10,8 @@ jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: 1.19
# There are too many lint errors in current code bases
@@ -21,10 +21,10 @@ jobs:
coverage-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup Golang Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |-
~/.cache/go-build
@@ -33,7 +33,7 @@ jobs:
restore-keys: ${{ runner.os }}-go
- name: Setup Submodule Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |-
.git/modules
@@ -46,7 +46,7 @@ jobs:
- name: Run Coverage Tests
run: GOPROXY="https://proxy.golang.org,direct" make go.test.coverage
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
with:
fail_ci_if_error: false
files: ./coverage.xml
@@ -58,17 +58,17 @@ jobs:
needs: [lint,coverage-test]
steps:
- name: "Checkout ${{ github.ref }}"
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: "Setup Go"
uses: actions/setup-go@v3
uses: actions/setup-go@v5
with:
go-version: 1.19
- name: Setup Golang Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |-
~/.cache/go-build
@@ -77,7 +77,7 @@ jobs:
restore-keys: ${{ runner.os }}-go
- name: Setup Submodule Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |-
.git/modules
@@ -90,7 +90,7 @@ jobs:
run: GOPROXY="https://proxy.golang.org,direct" make build
- name: Upload Higress Binary
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: higress
path: out/
@@ -108,12 +108,12 @@ jobs:
- uses: actions/checkout@v3
- name: "Setup Go"
uses: actions/setup-go@v3
uses: actions/setup-go@v5
with:
go-version: 1.19
- name: Setup Golang Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |-
~/.cache/go-build
@@ -123,7 +123,7 @@ jobs:
${{ runner.os }}-go
- name: Setup Submodule Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |-
.git/modules
@@ -139,4 +139,4 @@ jobs:
runs-on: ubuntu-latest
needs: [higress-conformance-test,gateway-conformance-test]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

View File

@@ -16,7 +16,7 @@ jobs:
CONTROLLER_IMAGE_NAME: ${{ vars.CONTROLLER_IMAGE_NAME || 'higress/higress' }}
steps:
- name: "Checkout ${{ github.ref }}"
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 1
@@ -31,12 +31,12 @@ jobs:
swap-storage: true
- name: "Setup Go"
uses: actions/setup-go@v3
uses: actions/setup-go@v5
with:
go-version: 1.19
- name: Setup Golang Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |-
~/.cache/go-build
@@ -45,7 +45,7 @@ jobs:
restore-keys: ${{ runner.os }}-go
- name: Setup Submodule Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |-
envoy
@@ -56,7 +56,7 @@ jobs:
- name: Calculate Docker metadata
id: docker-meta
uses: docker/metadata-action@v4
uses: docker/metadata-action@v5
with:
images: |
${{ env.CONTROLLER_IMAGE_REGISTRY }}/${{ env.CONTROLLER_IMAGE_NAME }}
@@ -67,7 +67,7 @@ jobs:
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }}
- name: Login to Docker Registry
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.CONTROLLER_IMAGE_REGISTRY }}
username: ${{ secrets.REGISTRY_USERNAME }}
@@ -92,7 +92,7 @@ jobs:
PILOT_IMAGE_NAME: ${{ vars.PILOT_IMAGE_NAME || 'higress/pilot' }}
steps:
- name: "Checkout ${{ github.ref }}"
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 1
@@ -107,12 +107,12 @@ jobs:
swap-storage: true
- name: "Setup Go"
uses: actions/setup-go@v3
uses: actions/setup-go@v5
with:
go-version: 1.19
- name: Setup Golang Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |-
~/.cache/go-build
@@ -121,7 +121,7 @@ jobs:
restore-keys: ${{ runner.os }}-go
- name: Setup Submodule Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |-
envoy
@@ -132,7 +132,7 @@ jobs:
- name: Calculate Docker metadata
id: docker-meta
uses: docker/metadata-action@v4
uses: docker/metadata-action@v5
with:
images: |
${{ env.PILOT_IMAGE_REGISTRY }}/${{ env.PILOT_IMAGE_NAME }}
@@ -143,7 +143,7 @@ jobs:
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }}
- name: Login to Docker Registry
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.PILOT_IMAGE_REGISTRY }}
username: ${{ secrets.REGISTRY_USERNAME }}
@@ -169,7 +169,7 @@ jobs:
GATEWAY_IMAGE_NAME: ${{ vars.GATEWAY_IMAGE_NAME || 'higress/gateway' }}
steps:
- name: "Checkout ${{ github.ref }}"
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 1
@@ -184,12 +184,12 @@ jobs:
swap-storage: true
- name: "Setup Go"
uses: actions/setup-go@v3
uses: actions/setup-go@v5
with:
go-version: 1.19
- name: Setup Golang Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |-
~/.cache/go-build
@@ -198,7 +198,7 @@ jobs:
restore-keys: ${{ runner.os }}-go
- name: Setup Submodule Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |-
envoy
@@ -209,7 +209,7 @@ jobs:
- name: Calculate Docker metadata
id: docker-meta
uses: docker/metadata-action@v4
uses: docker/metadata-action@v5
with:
images: |
${{ env.GATEWAY_IMAGE_REGISTRY }}/${{ env.GATEWAY_IMAGE_NAME }}
@@ -220,7 +220,7 @@ jobs:
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }}
- name: Login to Docker Registry
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.GATEWAY_IMAGE_REGISTRY }}
username: ${{ secrets.REGISTRY_USERNAME }}

View File

@@ -34,11 +34,11 @@ jobs:
steps:
# step 1
- name: "Checkout repository"
uses: actions/checkout@v2
uses: actions/checkout@v4
# step 2: Initializes the CodeQL tools for scanning.
- name: "Initialize CodeQL"
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -50,7 +50,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: "Autobuild"
uses: github/codeql-action/autobuild@v1
uses: github/codeql-action/autobuild@v2
# step 4
# Command-line programs to run using the OS shell.
@@ -66,4 +66,4 @@ jobs:
# step 5
- name: "Perform CodeQL Analysis"
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v2

View File

@@ -14,7 +14,7 @@ jobs:
steps:
# Step 1
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
# Step 2
- id: package
name: Prepare Standalone Package

View File

@@ -14,7 +14,7 @@ jobs:
steps:
# Step 1
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
# Step 2
- name: Download Helm Charts Index
uses: doggycool/ossutil-github-action@master

View File

@@ -9,7 +9,7 @@ jobs:
latest-release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Build hgctl latest multiarch binaries
run: |
@@ -46,7 +46,7 @@ jobs:
GITHUB_REPOSITORY: ${{ github.repository_owner }}/${{ github.event.repository.name }}
- name: Recreate the Latest Release and Tag
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v2
with:
draft: false
prerelease: true

View File

@@ -10,7 +10,7 @@ jobs:
steps:
# step 1
- name: Checkout
uses: actions/checkout@v2.4.0
uses: actions/checkout@v4
# step 2
- name: Check License Header
uses: apache/skywalking-eyes/header@25edfc2fd8d52fb266653fb5f6c42da633d85c07
@@ -24,4 +24,4 @@ jobs:
with:
log: info
config: .licenserc.yaml
mode: check
mode: check

View File

@@ -12,7 +12,7 @@ jobs:
env:
HGCTL_VERSION: ${{github.ref_name}}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Build hgctl latest multiarch binaries
run: |
@@ -25,7 +25,7 @@ jobs:
zip -q -r hgctl_${{ env.HGCTL_VERSION }}_windows_arm64.zip out/windows_arm64/
- name: Upload hgctl packages to the GitHub release
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
with:
files: |
@@ -34,4 +34,4 @@ jobs:
hgctl_${{ env.HGCTL_VERSION }}_darwin_amd64.tar.gz
hgctl_${{ env.HGCTL_VERSION }}_darwin_arm64.tar.gz
hgctl_${{ env.HGCTL_VERSION }}_windows_amd64.zip
hgctl_${{ env.HGCTL_VERSION }}_windows_arm64.zip
hgctl_${{ env.HGCTL_VERSION }}_windows_arm64.zip

View File

@@ -138,11 +138,11 @@ export ENVOY_TAR_PATH:=/home/package/envoy.tar.gz
external/package/envoy-amd64.tar.gz:
# cd external/proxy; BUILD_WITH_CONTAINER=1 make test_release
cd external/package; wget -O envoy-amd64.tar.gz "https://github.com/alibaba/higress/releases/download/v1.4.0/envoy-symbol-amd64.tar.gz"
cd external/package; wget -O envoy-amd64.tar.gz "https://github.com/alibaba/higress/releases/download/v1.4.1/envoy-symbol-amd64.tar.gz"
external/package/envoy-arm64.tar.gz:
# cd external/proxy; BUILD_WITH_CONTAINER=1 make test_release
cd external/package; wget -O envoy-arm64.tar.gz "https://github.com/alibaba/higress/releases/download/v1.4.0/envoy-symbol-arm64.tar.gz"
cd external/package; wget -O envoy-arm64.tar.gz "https://github.com/alibaba/higress/releases/download/v1.4.1/envoy-symbol-arm64.tar.gz"
build-pilot:
cd external/istio; rm -rf out/linux_amd64; GOOS_LOCAL=linux TARGET_OS=linux TARGET_ARCH=amd64 BUILD_WITH_CONTAINER=1 make build-linux

View File

@@ -1 +1 @@
v1.4.1
v1.4.2

View File

@@ -0,0 +1,13 @@
diff --git a/source/common/http/headers.h b/source/common/http/headers.h
index a7a8a3393e..6af4a2852d 100644
--- a/source/common/http/headers.h
+++ b/source/common/http/headers.h
@@ -123,7 +123,7 @@ public:
const LowerCaseString TriCostTime{"req-cost-time"};
const LowerCaseString TriStartTime{"req-start-time"};
const LowerCaseString TriRespStartTime{"resp-start-time"};
- const LowerCaseString EnvoyOriginalHost{"original-host"};
+ const LowerCaseString EnvoyOriginalHost{"x-envoy-original-host"};
const LowerCaseString HigressOriginalService{"x-higress-original-service"};
} AliExtendedValues;
#endif

View File

@@ -0,0 +1,43 @@
diff --git a/source/extensions/common/wasm/context.cc b/source/extensions/common/wasm/context.cc
index 9642d8abd3..410baa856f 100644
--- a/source/extensions/common/wasm/context.cc
+++ b/source/extensions/common/wasm/context.cc
@@ -62,6 +62,21 @@ constexpr absl::string_view CelStateKeyPrefix = "wasm.";
#if defined(ALIMESH)
constexpr std::string_view ClearRouteCacheKey = "clear_route_cache";
constexpr std::string_view DisableClearRouteCache = "off";
+constexpr std::string_view SetDecoderBufferLimit = "set_decoder_buffer_limit";
+constexpr std::string_view SetEncoderBufferLimit = "set_encoder_buffer_limit";
+
+bool stringViewToUint32(std::string_view str, uint32_t& out_value) {
+ try {
+ unsigned long temp = std::stoul(std::string(str));
+ if (temp <= std::numeric_limits<uint32_t>::max()) {
+ out_value = static_cast<uint32_t>(temp);
+ return true;
+ }
+ } catch (const std::exception& e) {
+ ENVOY_LOG_MISC(critical, "stringToUint exception '{}'", e.what());
+ }
+ return false;
+}
#endif
using HashPolicy = envoy::config::route::v3::RouteAction::HashPolicy;
@@ -1280,6 +1295,16 @@ WasmResult Context::setProperty(std::string_view path, std::string_view value) {
} else {
disable_clear_route_cache_ = false;
}
+ } else if (path == SetDecoderBufferLimit && decoder_callbacks_) {
+ uint32_t buffer_limit;
+ if (stringViewToUint32(value, buffer_limit)) {
+ decoder_callbacks_->setDecoderBufferLimit(buffer_limit);
+ }
+ } else if (path == SetEncoderBufferLimit && encoder_callbacks_) {
+ uint32_t buffer_limit;
+ if (stringViewToUint32(value, buffer_limit)) {
+ encoder_callbacks_->setEncoderBufferLimit(buffer_limit);
+ }
}
#endif
if (!state->setValue(toAbslStringView(value))) {

View File

@@ -0,0 +1,106 @@
diff --git a/envoy/stream_info/stream_info.h b/envoy/stream_info/stream_info.h
index c6d82db4f4..09717673b0 100644
--- a/envoy/stream_info/stream_info.h
+++ b/envoy/stream_info/stream_info.h
@@ -613,7 +613,21 @@ public:
* @return the number of times the request was attempted upstream, absl::nullopt if the request
* was never attempted upstream.
*/
+
virtual absl::optional<uint32_t> attemptCount() const PURE;
+
+#ifdef ALIMESH
+ /**
+ * @param key the filter state key set by wasm filter.
+ * @param value the filter state value set by wasm filter.
+ */
+ virtual void setCustomSpanTag(const std::string& key, const std::string& value) PURE;
+
+ /**
+ * @return the key-value map of filter states set by wasm filter.
+ */
+ virtual const std::unordered_map<std::string, std::string>& getCustomSpanTagMap() const PURE;
+#endif
};
} // namespace StreamInfo
diff --git a/source/common/stream_info/stream_info_impl.h b/source/common/stream_info/stream_info_impl.h
index 6ce2afe773..d5e7a80b37 100644
--- a/source/common/stream_info/stream_info_impl.h
+++ b/source/common/stream_info/stream_info_impl.h
@@ -291,6 +291,20 @@ struct StreamInfoImpl : public StreamInfo {
absl::optional<uint32_t> attemptCount() const override { return attempt_count_; }
+#ifdef ALIMESH
+ void setCustomSpanTag(const std::string& key, const std::string& value) override {
+ auto it = custom_span_tags_.find(key);
+ if (it != custom_span_tags_.end()) {
+ it->second = value;
+ } else {
+ custom_span_tags_.emplace(key, value);
+ }
+ }
+
+ const std::unordered_map<std::string, std::string>& getCustomSpanTagMap() const override {
+ return custom_span_tags_;
+ }
+#endif
TimeSource& time_source_;
const SystemTime start_time_;
const MonotonicTime start_time_monotonic_;
@@ -350,6 +364,9 @@ private:
absl::optional<Upstream::ClusterInfoConstSharedPtr> upstream_cluster_info_;
std::string filter_chain_name_;
Tracing::Reason trace_reason_;
+#ifdef ALIMESH
+ std::unordered_map<std::string, std::string> custom_span_tags_;
+#endif
};
} // namespace StreamInfo
diff --git a/source/common/tracing/http_tracer_impl.cc b/source/common/tracing/http_tracer_impl.cc
index e55cf00e0a..f94e9101d7 100644
--- a/source/common/tracing/http_tracer_impl.cc
+++ b/source/common/tracing/http_tracer_impl.cc
@@ -214,6 +214,14 @@ void HttpTracerUtility::setCommonTags(Span& span, const Http::ResponseHeaderMap*
span.setTag(Tracing::Tags::get().Component, Tracing::Tags::get().Proxy);
+#ifdef ALIMESH
+ // Wasm filter state
+ const auto& custom_span_tags = stream_info.getCustomSpanTagMap();
+ for (const auto& it : custom_span_tags) {
+ span.setTag(it.first, it.second);
+ }
+#endif
+
if (nullptr != stream_info.upstreamHost()) {
span.setTag(Tracing::Tags::get().UpstreamCluster, stream_info.upstreamHost()->cluster().name());
span.setTag(Tracing::Tags::get().UpstreamClusterName,
diff --git a/source/extensions/common/wasm/context.cc b/source/extensions/common/wasm/context.cc
index 410baa856f..b11ecf1cd6 100644
--- a/source/extensions/common/wasm/context.cc
+++ b/source/extensions/common/wasm/context.cc
@@ -60,6 +60,7 @@ namespace {
constexpr absl::string_view CelStateKeyPrefix = "wasm.";
#if defined(ALIMESH)
+constexpr absl::string_view CustomeTraceSpanTagPrefix = "trace_span_tag.";
constexpr std::string_view ClearRouteCacheKey = "clear_route_cache";
constexpr std::string_view DisableClearRouteCache = "off";
constexpr std::string_view SetDecoderBufferLimit = "set_decoder_buffer_limit";
@@ -1271,6 +1272,13 @@ WasmResult Context::setProperty(std::string_view path, std::string_view value) {
if (!stream_info) {
return WasmResult::NotFound;
}
+#ifdef ALIMESH
+ if (absl::StartsWith(absl::string_view{path.data(), path.size()}, CustomeTraceSpanTagPrefix)) {
+ stream_info->setCustomSpanTag(std::string(path.substr(CustomeTraceSpanTagPrefix.size())),
+ std::string(value));
+ return WasmResult::Ok;
+ }
+#endif
std::string key;
absl::StrAppend(&key, CelStateKeyPrefix, toAbslStringView(path));
CelState* state;

4
go.mod
View File

@@ -255,7 +255,6 @@ require (
go.opentelemetry.io/proto/otlp v0.12.0 // indirect
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/crypto v0.17.0 // indirect
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect
golang.org/x/mod v0.11.0 // indirect
@@ -304,7 +303,7 @@ replace istio.io/client-go => ./external/client-go
replace istio.io/istio => ./external/istio
replace github.com/caddyserver/certmagic => github.com/2456868764/certmagic v1.0.1
replace github.com/caddyserver/certmagic => github.com/2456868764/certmagic v1.0.2
require (
github.com/caddyserver/certmagic v0.20.0
@@ -313,6 +312,7 @@ require (
github.com/kylelemons/godebug v1.1.0
github.com/mholt/acmez v1.2.0
github.com/tidwall/gjson v1.17.0
go.uber.org/zap v1.24.0
golang.org/x/net v0.17.0
helm.sh/helm/v3 v3.7.1
k8s.io/apiextensions-apiserver v0.25.4

4
go.sum
View File

@@ -61,8 +61,8 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/2456868764/certmagic v1.0.1 h1:dRzow2Npe9llFTBhNVl0fVe8Yi/Q14ygNonlaZUyDZQ=
github.com/2456868764/certmagic v1.0.1/go.mod h1:LOn81EQYMPajdew6Ln6SVdHPxPqPv6jwsUg92kiNlcQ=
github.com/2456868764/certmagic v1.0.2 h1:xYoN4z6seONwT85llWXZcASvQME8TOSiSWQvLJsGGsE=
github.com/2456868764/certmagic v1.0.2/go.mod h1:LOn81EQYMPajdew6Ln6SVdHPxPqPv6jwsUg92kiNlcQ=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20210929163055-e81b3f25be97/go.mod h1:WpB7kf89yJUETZxQnP1kgYPNwlT2jjdDYUCoxVggM3g=
github.com/AlecAivazis/survey/v2 v2.3.6 h1:NvTuVHISgTHEHeBFqt6BHOe4Ny/NwGZr7w+F8S9ziyw=
github.com/AlecAivazis/survey/v2 v2.3.6/go.mod h1:4AuI9b7RjAR+G7v9+C4YSlX/YL3K3cWNXgWXOhllqvI=

View File

@@ -1,5 +1,5 @@
apiVersion: v2
appVersion: 1.4.1
appVersion: 1.4.2
description: Helm chart for deploying higress gateways
icon: https://higress.io/img/higress_logo_small.png
home: http://higress.io/
@@ -10,4 +10,4 @@ name: higress-core
sources:
- http://github.com/alibaba/higress
type: application
version: 1.4.1
version: 1.4.2

View File

@@ -88,7 +88,7 @@
{{- if .Values.global.enableHigressIstio }}
discoveryAddress: {{ printf "istiod.%s.svc" .Values.global.istioNamespace }}:15012
{{- else }}
discoveryAddress: higress-controller.{{.Release.Namespace}}.svc:15012
discoveryAddress: {{ include "controller.name" . }}.{{.Release.Namespace}}.svc:15012
{{- end }}
{{- end }}
proxyStatsMatcher:

View File

@@ -9,7 +9,7 @@ rules:
# ingress controller
- apiGroups: ["extensions", "networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get", "list", "watch"]
verbs: ["create", "get", "list", "watch", "update", "delete", "patch"]
- apiGroups: ["extensions", "networking.k8s.io"]
resources: ["ingresses/status"]
verbs: ["*"]
@@ -61,7 +61,7 @@ rules:
# discovery and routing
- apiGroups: [""]
resources: ["pods", "nodes", "services", "namespaces", "endpoints"]
resources: ["pods", "nodes", "services", "namespaces", "endpoints", "deployments"]
verbs: ["get", "list", "watch"]
- apiGroups: ["discovery.k8s.io"]
resources: ["endpointslices"]

View File

@@ -32,6 +32,64 @@ spec:
securityContext:
{{- toYaml .Values.controller.podSecurityContext | nindent 8 }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.controller.securityContext | nindent 12 }}
image: "{{ .Values.controller.hub | default .Values.global.hub }}/{{ .Values.controller.image | default "higress" }}:{{ .Values.controller.tag | default .Chart.AppVersion }}"
args:
- "serve"
- --gatewaySelectorKey=higress
- --gatewaySelectorValue={{ .Release.Namespace }}-{{ include "gateway.name" . }}
- --gatewayHttpPort={{ .Values.gateway.httpPort }}
- --gatewayHttpsPort={{ .Values.gateway.httpsPort }}
{{- if not .Values.global.enableStatus }}
- --enableStatus={{ .Values.global.enableStatus }}
{{- end }}
- --ingressClass={{ .Values.global.ingressClass }}
{{- if .Values.global.watchNamespace }}
- --watchNamespace={{ .Values.global.watchNamespace }}
{{- end }}
- --enableAutomaticHttps={{ .Values.controller.automaticHttps.enabled }}
- --automaticHttpsEmail={{ .Values.controller.automaticHttps.email }}
env:
- name: POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
- name: SERVICE_ACCOUNT
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: spec.serviceAccountName
- name: DOMAIN_SUFFIX
value: {{ .Values.global.proxy.clusterDomain }}
{{- if .Values.controller.env }}
{{- range $key, $val := .Values.controller.env }}
- name: {{ $key }}
value: "{{ $val }}"
{{- end }}
{{- end }}
ports:
{{- range $idx, $port := .Values.controller.ports }}
- name: {{ $port.name }}
containerPort: {{ $port.port }}
protocol: {{ $port.protocol }}
{{- end }}
readinessProbe:
{{- toYaml .Values.controller.probe | nindent 12 }}
{{- if not (or .Values.global.local .Values.global.kind) }}
resources:
{{- toYaml .Values.controller.resources | nindent 12 }}
{{- end }}
volumeMounts:
- name: log
mountPath: /var/log
{{- if not .Values.global.enableHigressIstio }}
- name: discovery
image: "{{ .Values.pilot.hub | default .Values.global.hub }}/{{ .Values.pilot.image | default "pilot" }}:{{ .Values.pilot.tag | default .Chart.AppVersion }}"
@@ -194,64 +252,6 @@ spec:
mountPath: /cacerts
{{- end }}
{{- end }}
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.controller.securityContext | nindent 12 }}
image: "{{ .Values.controller.hub | default .Values.global.hub }}/{{ .Values.controller.image | default "higress" }}:{{ .Values.controller.tag | default .Chart.AppVersion }}"
args:
- "serve"
- --gatewaySelectorKey=higress
- --gatewaySelectorValue={{ .Release.Namespace }}-{{ include "gateway.name" . }}
- --gatewayHttpPort={{ .Values.gateway.httpPort }}
- --gatewayHttpsPort={{ .Values.gateway.httpsPort }}
{{- if not .Values.global.enableStatus }}
- --enableStatus={{ .Values.global.enableStatus }}
{{- end }}
- --ingressClass={{ .Values.global.ingressClass }}
{{- if .Values.global.watchNamespace }}
- --watchNamespace={{ .Values.global.watchNamespace }}
{{- end }}
- --enableAutomaticHttps={{ .Values.controller.automaticHttps.enabled }}
- --automaticHttpsEmail={{ .Values.controller.automaticHttps.email }}
env:
- name: POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
- name: SERVICE_ACCOUNT
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: spec.serviceAccountName
- name: DOMAIN_SUFFIX
value: {{ .Values.global.proxy.clusterDomain }}
{{- if .Values.controller.env }}
{{- range $key, $val := .Values.controller.env }}
- name: {{ $key }}
value: "{{ $val }}"
{{- end }}
{{- end }}
ports:
{{- range $idx, $port := .Values.controller.ports }}
- name: {{ $port.name }}
containerPort: {{ $port.port }}
protocol: {{ $port.protocol }}
{{- end }}
readinessProbe:
{{- toYaml .Values.controller.probe | nindent 12 }}
{{- if not (or .Values.global.local .Values.global.kind) }}
resources:
{{- toYaml .Values.controller.resources | nindent 12 }}
{{- end }}
volumeMounts:
- name: log
mountPath: /var/log
{{- with .Values.controller.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}

View File

@@ -72,40 +72,6 @@ spec:
value: "0"
{{- end }}
containers:
{{- if $o11y.enabled }}
{{- $config := $o11y.promtail }}
- name: promtail
image: {{ $config.image.repository }}:{{ $config.image.tag }}
imagePullPolicy: IfNotPresent
args:
- -config.file=/etc/promtail/promtail.yaml
env:
- name: 'HOSTNAME'
valueFrom:
fieldRef:
fieldPath: 'spec.nodeName'
ports:
- containerPort: {{ $config.port }}
name: http-metrics
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /ready
port: {{ $config.port }}
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
volumeMounts:
- name: promtail-config
mountPath: "/etc/promtail"
- name: log
mountPath: /var/log/proxy
- name: tmp
mountPath: /tmp
{{- end }}
- name: higress-gateway
image: "{{ .Values.gateway.hub | default .Values.global.hub }}/{{ .Values.gateway.image | default "gateway" }}:{{ .Values.gateway.tag | default .Chart.AppVersion }}"
args:
@@ -264,6 +230,40 @@ spec:
- mountPath: /var/log/proxy
name: log
{{- end }}
{{- if $o11y.enabled }}
{{- $config := $o11y.promtail }}
- name: promtail
image: {{ $config.image.repository }}:{{ $config.image.tag }}
imagePullPolicy: IfNotPresent
args:
- -config.file=/etc/promtail/promtail.yaml
env:
- name: 'HOSTNAME'
valueFrom:
fieldRef:
fieldPath: 'spec.nodeName'
ports:
- containerPort: {{ $config.port }}
name: http-metrics
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /ready
port: {{ $config.port }}
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
volumeMounts:
- name: promtail-config
mountPath: "/etc/promtail"
- name: log
mountPath: /var/log/proxy
- name: tmp
mountPath: /tmp
{{- end }}
{{- if .Values.gateway.hostNetwork }}
hostNetwork: {{ .Values.gateway.hostNetwork }}
dnsPolicy: ClusterFirstWithHostNet

View File

@@ -1,9 +1,9 @@
dependencies:
- name: higress-core
repository: file://../core
version: 1.4.1
version: 1.4.2
- name: higress-console
repository: https://higress.io/helm-charts/
version: 1.4.1
digest: sha256:de41b8f771e869aef9b83d2334fea5d34492a1c5df37e5aaff383189877cba23
generated: "2024-06-19T17:10:02.426994+08:00"
version: 1.4.2
digest: sha256:31b557e55584e589b140ae9b89cfc8b99df91771c7d28465c3a2b06a4f35a192
generated: "2024-07-26T13:53:23.225023+08:00"

View File

@@ -1,5 +1,5 @@
apiVersion: v2
appVersion: 1.4.1
appVersion: 1.4.2
description: Helm chart for deploying Higress gateways
icon: https://higress.io/img/higress_logo_small.png
home: http://higress.io/
@@ -12,9 +12,9 @@ sources:
dependencies:
- name: higress-core
repository: "file://../core"
version: 1.4.1
version: 1.4.2
- name: higress-console
repository: "https://higress.io/helm-charts/"
version: 1.4.1
version: 1.4.2
type: application
version: 1.4.1
version: 1.4.2

View File

@@ -391,7 +391,7 @@ func (s *Server) initAutomaticHttps() error {
ServerAddress: s.CertHttpAddress,
Email: s.AutomaticHttpsEmail,
}
certServer, err := cert.NewServer(s.kubeClient.Kube(), certOption)
certServer, err := cert.NewServer(s.kubeClient.Kube(), s.xdsServer, certOption)
if err != nil {
return err
}

View File

@@ -17,10 +17,15 @@ package cert
import (
"context"
"fmt"
"os"
"reflect"
"sync"
"github.com/caddyserver/certmagic"
"github.com/mholt/acmez"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"istio.io/istio/pilot/pkg/model"
"k8s.io/client-go/kubernetes"
)
@@ -28,6 +33,10 @@ const (
EventCertObtained = "cert_obtained"
)
var (
cfg *certmagic.Config
)
type CertMgr struct {
cfg *certmagic.Config
client kubernetes.Interface
@@ -39,9 +48,10 @@ type CertMgr struct {
ingressSolver acmez.Solver
configMgr *ConfigMgr
secretMgr *SecretMgr
XDSUpdater model.XDSUpdater
}
func InitCertMgr(opts *Option, clientSet kubernetes.Interface, config *Config) (*CertMgr, error) {
func InitCertMgr(opts *Option, clientSet kubernetes.Interface, config *Config, XDSUpdater model.XDSUpdater, configMgr *ConfigMgr) (*CertMgr, error) {
CertLog.Infof("certmgr init config: %+v", config)
// Init certmagic config
// First make a pointer to a Cache as we need to reference the same Cache in
@@ -49,21 +59,29 @@ func InitCertMgr(opts *Option, clientSet kubernetes.Interface, config *Config) (
var cache *certmagic.Cache
var storage certmagic.Storage
storage, _ = NewConfigmapStorage(opts.Namespace, clientSet)
renewalWindowRatio := float64(config.RenewBeforeDays / RenewMaxDays)
renewalWindowRatio := float64(config.RenewBeforeDays) / float64(RenewMaxDays)
logger := zap.New(zapcore.NewCore(
zapcore.NewConsoleEncoder(zap.NewProductionEncoderConfig()),
os.Stderr,
zap.DebugLevel,
))
magicConfig := certmagic.Config{
RenewalWindowRatio: renewalWindowRatio,
Storage: storage,
Logger: logger,
}
cache = certmagic.NewCache(certmagic.CacheOptions{
GetConfigForCert: func(cert certmagic.Certificate) (*certmagic.Config, error) {
// Here we use New to get a valid Config associated with the same cache.
// The provided Config is used as a template and will be completed with
// any defaults that are set in the Default config.
return certmagic.New(cache, magicConfig), nil
return cfg, nil
},
Logger: logger,
})
// init certmagic
cfg := certmagic.New(cache, magicConfig)
cfg = certmagic.New(cache, magicConfig)
// Init certmagic acme
issuer := config.GetIssuer(IssuerTypeLetsencrypt)
if issuer == nil {
@@ -85,7 +103,6 @@ func InitCertMgr(opts *Option, clientSet kubernetes.Interface, config *Config) (
// init issuers
cfg.Issuers = []certmagic.Issuer{myACME}
configMgr, _ := NewConfigMgr(opts.Namespace, clientSet)
secretMgr, _ := NewSecretMgr(opts.Namespace, clientSet)
certMgr := &CertMgr{
@@ -97,6 +114,7 @@ func InitCertMgr(opts *Option, clientSet kubernetes.Interface, config *Config) (
configMgr: configMgr,
secretMgr: secretMgr,
cache: cache,
XDSUpdater: XDSUpdater,
}
certMgr.cfg.OnEvent = certMgr.OnEvent
return certMgr, nil
@@ -149,18 +167,31 @@ func (s *CertMgr) Reconcile(ctx context.Context, oldConfig *Config, newConfig *C
// sync email
s.myACME.Email = newIssuer.Email
// sync RenewalWindowRatio
s.cfg.RenewalWindowRatio = float64(newConfig.RenewBeforeDays / RenewMaxDays)
renewalWindowRatio := float64(newConfig.RenewBeforeDays) / float64(RenewMaxDays)
s.cfg.RenewalWindowRatio = renewalWindowRatio
// start cache
s.cache.Start()
// sync domains
s.manageSync(context.Background(), newDomains)
s.configMgr.SetConfig(newConfig)
CertLog.Infof("certMgr start to manageSync domains:+v%", newDomains)
s.manageSync(context.Background(), newDomains)
CertLog.Infof("certMgr manageSync domains done")
} else {
// stop cache maintainAssets
s.cache.Stop()
s.configMgr.SetConfig(newConfig)
}
if oldConfig != nil && newConfig != nil {
if oldConfig.FallbackForInvalidSecret != newConfig.FallbackForInvalidSecret || !reflect.DeepEqual(oldConfig.CredentialConfig, newConfig.CredentialConfig) {
CertLog.Infof("ingress need to full push")
s.XDSUpdater.ConfigUpdate(&model.PushRequest{
Full: true,
Reason: []model.TriggerReason{"higress-https-updated"},
})
}
}
return nil
}

View File

@@ -99,20 +99,22 @@ func ParseTLSSecret(tlsSecret string) (string, string) {
func (c *Config) Validate() error {
// check acmeIssuer
if len(c.ACMEIssuer) == 0 {
return fmt.Errorf("acmeIssuer is empty")
}
for _, issuer := range c.ACMEIssuer {
switch issuer.Name {
case IssuerTypeLetsencrypt:
if issuer.Email == "" {
return fmt.Errorf("acmeIssuer %s email is empty", issuer.Name)
if c.AutomaticHttps {
if len(c.ACMEIssuer) == 0 {
return fmt.Errorf("no acmeIssuer configuration found when automaticHttps is enable")
}
for _, issuer := range c.ACMEIssuer {
switch issuer.Name {
case IssuerTypeLetsencrypt:
if issuer.Email == "" {
return fmt.Errorf("acmeIssuer %s email is empty", issuer.Name)
}
if !ValidateEmail(issuer.Email) {
return fmt.Errorf("acmeIssuer %s email %s is invalid", issuer.Name, issuer.Email)
}
default:
return fmt.Errorf("acmeIssuer name %s is not supported", issuer.Name)
}
if !ValidateEmail(issuer.Email) {
return fmt.Errorf("acmeIssuer %s email %s is invalid", issuer.Name, issuer.Email)
}
default:
return fmt.Errorf("acmeIssuer name %s is not supported", issuer.Name)
}
}
// check credentialConfig

View File

@@ -41,6 +41,7 @@ func NewSecretMgr(namespace string, client kubernetes.Interface) (*SecretMgr, er
}
func (s *SecretMgr) Update(domain string, secretName string, privateKey []byte, certificate []byte, notBefore time.Time, notAfter time.Time, isRenew bool) error {
CertLog.Infof("update secret, domain:%s, secretName:%s, notBefore:%v, notAfter:%v, isRenew:%t", domain, secretName, notBefore, notAfter, isRenew)
name := secretName
namespace := s.namespace
namespaceP, secretP := ParseTLSSecret(secretName)
@@ -77,6 +78,7 @@ func (s *SecretMgr) constructSecret(domain string, name string, namespace string
annotationMap["higress.io/cert-notAfter"] = notAfter.Format("2006-01-02 15:04:05")
annotationMap["higress.io/cert-notBefore"] = notBefore.Format("2006-01-02 15:04:05")
annotationMap["higress.io/cert-renew"] = strconv.FormatBool(isRenew)
annotationMap["higress.io/cert-source"] = string(IssuerTypeLetsencrypt)
if isRenew {
annotationMap["higress.io/cert-renew-time"] = time.Now().Format("2006-01-02 15:04:05")
}

View File

@@ -22,6 +22,7 @@ import (
"time"
"github.com/caddyserver/certmagic"
"istio.io/istio/pilot/pkg/model"
"k8s.io/client-go/kubernetes"
)
@@ -37,12 +38,14 @@ type Server struct {
clientSet kubernetes.Interface
controller *Controller
certMgr *CertMgr
XDSUpdater model.XDSUpdater
}
func NewServer(clientSet kubernetes.Interface, opts *Option) (*Server, error) {
func NewServer(clientSet kubernetes.Interface, XDSUpdater model.XDSUpdater, opts *Option) (*Server, error) {
server := &Server{
clientSet: clientSet,
opts: opts,
clientSet: clientSet,
opts: opts,
XDSUpdater: XDSUpdater,
}
return server, nil
}
@@ -65,7 +68,7 @@ func (s *Server) InitServer() error {
return err
}
// init certmgr
certMgr, err := InitCertMgr(s.opts, s.clientSet, defaultConfig) // config and start
certMgr, err := InitCertMgr(s.opts, s.clientSet, defaultConfig, s.XDSUpdater, configMgr) // config and start
s.certMgr = certMgr
// init controller
controller, err := NewController(s.clientSet, s.opts.Namespace, certMgr, configMgr)

View File

@@ -32,7 +32,7 @@ import (
)
const (
CertificatesPrefix = "/certificates"
CertificatesPrefix = "certificates"
ConfigmapStoreCertficatesPrefix = "higress-cert-store-certificates-"
ConfigmapStoreDefaultName = "higress-cert-store-default"
)
@@ -155,7 +155,7 @@ func (s *ConfigmapStorage) List(ctx context.Context, prefix string, recursive bo
// Check if the prefix corresponds to a specific key
hashPrefix := fastHash([]byte(prefix))
if strings.HasPrefix(prefix, CertificatesPrefix) {
// If the prefix is "/certificates", get all ConfigMaps and traverse each one
// If the prefix is "certificates/", get all ConfigMaps and traverse each one
// List all ConfigMaps in the namespace with label higress.io/cert-https=true
configmaps, err := s.client.CoreV1().ConfigMaps(s.namespace).List(ctx, metav1.ListOptions{FieldSelector: "metadata.annotations['higress.io/cert-https'] == 'true'"})
if err != nil {
@@ -289,14 +289,29 @@ func (s *ConfigmapStorage) String() string {
return "ConfigmapStorage"
}
// getConfigmapStoreNameByKey determines the storage name for a given key.
// It checks if the key starts with 'certificates/' and if so, the key pattern should match one of the following:
// 'certificates/<issuerKey>/<domain>/<domain>.json',
// 'certificates/<issuerKey>/<domain>/<domain>.crt',
// or 'certificates/<issuerKey>/<domain>/<domain>.key'.
// It then returns the corresponding ConfigMap name.
// If the key does not start with 'certificates/', it returns the default store name.
//
// Parameters:
//
// key - The configuration map key that needs to be mapped to a storage name.
//
// Returns:
//
// string - The calculated or default storage name based on the key.
func (s *ConfigmapStorage) getConfigmapStoreNameByKey(key string) string {
parts := strings.SplitN(key, "/", 10)
if len(parts) >= 4 && parts[1] == "certificates" {
domain := strings.TrimSuffix(parts[3], ".crt")
domain = strings.TrimSuffix(domain, ".key")
domain = strings.TrimSuffix(domain, ".json")
issuerKey := parts[2]
return ConfigmapStoreCertficatesPrefix + fastHash([]byte(issuerKey+domain))
if strings.HasPrefix(key, "certificates/") {
parts := strings.Split(key, "/")
if len(parts) >= 4 && parts[0] == "certificates" {
domain := parts[2]
issuerKey := parts[1]
return ConfigmapStoreCertficatesPrefix + fastHash([]byte(issuerKey+domain))
}
}
return ConfigmapStoreDefaultName
}

View File

@@ -39,22 +39,29 @@ func TestGetConfigmapStoreNameByKey(t *testing.T) {
}{
{
name: "certificate crt",
key: "/certificates/issuerKey/domain.crt",
key: "certificates/issuerKey/domain/domain.crt",
expected: "higress-cert-store-certificates-" + fastHash([]byte("issuerKey"+"domain")),
},
{
name: "47.237.14.136.sslip.io crt",
key: "certificates/acme-v02.api.letsencrypt.org-directory/47.237.14.136.sslip.io/47.237.14.136.sslip.io.crt",
expected: "higress-cert-store-certificates-" + fastHash([]byte("acme-v02.api.letsencrypt.org-directory"+"47.237.14.136.sslip.io")),
},
{
name: "certificate meta",
key: "/certificates/issuerKey/domain.json",
key: "certificates/issuerKey/domain/domain.json",
expected: "higress-cert-store-certificates-" + fastHash([]byte("issuerKey"+"domain")),
},
{
name: "certificate key",
key: "/certificates/issuerKey/domain.key",
key: "certificates/issuerKey/domain/domain.key",
expected: "higress-cert-store-certificates-" + fastHash([]byte("issuerKey"+"domain")),
},
{
name: "user key",
key: "/users/hello/2",
key: "users/hello/2",
expected: "higress-cert-store-default",
},
{
@@ -82,7 +89,7 @@ func TestExists(t *testing.T) {
assert.NoError(t, err)
// Store a test key
testKey := "/certificates/issuer1/domain1.crt"
testKey := "certificates/issuer1/domain1/domain1.crt"
err = storage.Store(context.Background(), testKey, []byte("test-data"))
assert.NoError(t, err)
@@ -94,17 +101,17 @@ func TestExists(t *testing.T) {
}{
{
name: "Existing Key",
key: "/certificates/issuer1/domain1.crt",
key: "certificates/issuer1/domain1/domain1.crt",
shouldExist: true,
},
{
name: "Non-Existent Key1",
key: "/certificates/issuer2/domain2.crt",
key: "certificates/issuer2/domain2/domain2.crt",
shouldExist: false,
},
{
name: "Non-Existent Key2",
key: "/users/hello/a",
key: "users/hello/a",
shouldExist: false,
},
// Add more test cases as needed
@@ -129,7 +136,7 @@ func TestLoad(t *testing.T) {
assert.NoError(t, err)
// Store a test key
testKey := "/certificates/issuer1/domain1.crt"
testKey := "certificates/issuer1/domain1/domain1.crt"
testValue := []byte("test-data")
err = storage.Store(context.Background(), testKey, testValue)
assert.NoError(t, err)
@@ -143,13 +150,13 @@ func TestLoad(t *testing.T) {
}{
{
name: "Existing Key",
key: "/certificates/issuer1/domain1.crt",
key: "certificates/issuer1/domain1/domain1.crt",
expected: testValue,
shouldError: false,
},
{
name: "Non-Existent Key",
key: "/certificates/issuer2/domain2.crt",
key: "certificates/issuer2/domain2/domain2.crt",
expected: nil,
shouldError: true,
},
@@ -192,28 +199,28 @@ func TestStore(t *testing.T) {
shouldError bool
}{
{
name: "Store Key with /certificates prefix",
key: "/certificates/issuer1/domain1.crt",
name: "Store Key with certificates prefix",
key: "certificates/issuer1/domain1/domain1.crt",
value: []byte("test-data1"),
expected: map[string]string{fastHash([]byte("/certificates/issuer1/domain1.crt")): `{"k":"/certificates/issuer1/domain1.crt","v":"dGVzdC1kYXRhMQ=="}`},
expected: map[string]string{fastHash([]byte("certificates/issuer1/domain1/domain1.crt")): `{"k":"certificates/issuer1/domain1/domain1.crt","v":"dGVzdC1kYXRhMQ=="}`},
expectedConfigmapName: "higress-cert-store-certificates-" + fastHash([]byte("issuer1"+"domain1")),
shouldError: false,
},
{
name: "Store Key with /certificates prefix (additional data)",
key: "/certificates/issuer2/domain2.crt",
name: "Store Key with certificates prefix (additional data)",
key: "certificates/issuer2/domain2/domain2.crt",
value: []byte("test-data2"),
expected: map[string]string{
fastHash([]byte("/certificates/issuer2/domain2.crt")): `{"k":"/certificates/issuer2/domain2.crt","v":"dGVzdC1kYXRhMg=="}`,
fastHash([]byte("certificates/issuer2/domain2/domain2.crt")): `{"k":"certificates/issuer2/domain2/domain2.crt","v":"dGVzdC1kYXRhMg=="}`,
},
expectedConfigmapName: "higress-cert-store-certificates-" + fastHash([]byte("issuer2"+"domain2")),
shouldError: false,
},
{
name: "Store Key without /certificates prefix",
key: "/other/path/data.txt",
name: "Store Key without certificates prefix",
key: "other/path/data.txt",
value: []byte("test-data3"),
expected: map[string]string{fastHash([]byte("/other/path/data.txt")): `{"k":"/other/path/data.txt","v":"dGVzdC1kYXRhMw=="}`},
expected: map[string]string{fastHash([]byte("other/path/data.txt")): `{"k":"other/path/data.txt","v":"dGVzdC1kYXRhMw=="}`},
expectedConfigmapName: "higress-cert-store-default",
shouldError: false,
},
@@ -256,17 +263,17 @@ func TestList(t *testing.T) {
// Store some test data
// Store some test data
testKeys := []string{
"/certificates/issuer1/domain1.crt",
"/certificates/issuer1/domain2.crt",
"/certificates/issuer1/domain3.crt", // Added another domain for issuer1
"/certificates/issuer2/domain4.crt",
"/certificates/issuer2/domain5.crt",
"/certificates/issuer3/subdomain1/domain6.crt", // Two-level subdirectory under issuer3
"/certificates/issuer3/subdomain1/subdomain2/domain7.crt", // Two more levels under issuer3
"/other-prefix/key1/file1",
"/other-prefix/key1/file2",
"/other-prefix/key2/file3",
"/other-prefix/key2/file4",
"certificates/issuer1/domain1/domain1.crt",
"certificates/issuer1/domain2/domain2.crt",
"certificates/issuer1/domain3/domain3.crt", // Added another domain for issuer1
"certificates/issuer2/domain4/domain4.crt",
"certificates/issuer2/domain5/domain5.crt",
"certificates/issuer3/domain6/domain6.crt", // Two-level subdirectory under issuer3
"certificates/issuer3/subdomain1/subdomain2/domain7.crt", // Two more levels under issuer3
"other-prefix/key1/file1",
"other-prefix/key1/file2",
"other-prefix/key2/file3",
"other-prefix/key2/file4",
}
for _, key := range testKeys {
@@ -283,34 +290,34 @@ func TestList(t *testing.T) {
}{
{
name: "List Certificates (Non-Recursive)",
prefix: "/certificates",
prefix: "certificates",
recursive: false,
expected: []string{"/certificates/issuer1", "/certificates/issuer2", "/certificates/issuer3"},
expected: []string{"certificates/issuer1", "certificates/issuer2", "certificates/issuer3"},
},
{
name: "List Certificates (Recursive)",
prefix: "/certificates",
prefix: "certificates",
recursive: true,
expected: []string{"/certificates/issuer1/domain1.crt", "/certificates/issuer1/domain2.crt", "/certificates/issuer1/domain3.crt", "/certificates/issuer2/domain4.crt", "/certificates/issuer2/domain5.crt", "/certificates/issuer3/subdomain1/domain6.crt", "/certificates/issuer3/subdomain1/subdomain2/domain7.crt"},
expected: []string{"certificates/issuer1/domain1/domain1.crt", "certificates/issuer1/domain2/domain2.crt", "certificates/issuer1/domain3/domain3.crt", "certificates/issuer2/domain4/domain4.crt", "certificates/issuer2/domain5/domain5.crt", "certificates/issuer3/domain6/domain6.crt", "certificates/issuer3/subdomain1/subdomain2/domain7.crt"},
},
{
name: "List Other Prefix (Non-Recursive)",
prefix: "/other-prefix",
prefix: "other-prefix",
recursive: false,
expected: []string{"/other-prefix/key1", "/other-prefix/key2"},
expected: []string{"other-prefix/key1", "other-prefix/key2"},
},
{
name: "List Other Prefix (Non-Recursive)",
prefix: "/other-prefix/key1",
prefix: "other-prefix/key1",
recursive: false,
expected: []string{"/other-prefix/key1/file1", "/other-prefix/key1/file2"},
expected: []string{"other-prefix/key1/file1", "other-prefix/key1/file2"},
},
{
name: "List Other Prefix (Recursive)",
prefix: "/other-prefix",
prefix: "other-prefix",
recursive: true,
expected: []string{"/other-prefix/key1/file1", "/other-prefix/key1/file2", "/other-prefix/key2/file3", "/other-prefix/key2/file4"},
expected: []string{"other-prefix/key1/file1", "other-prefix/key1/file2", "other-prefix/key2/file3", "other-prefix/key2/file4"},
},
}

View File

@@ -0,0 +1 @@
EXTRA_TAGS=proxy_wasm_version_0_2_100

View File

@@ -8,7 +8,7 @@ replace github.com/alibaba/higress/plugins/wasm-go => ../..
require (
github.com/alibaba/higress/plugins/wasm-go v1.3.6-0.20240528060522-53bccf89f441
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f
github.com/tidwall/gjson v1.14.3
github.com/tidwall/resp v0.1.1
github.com/tidwall/sjson v1.2.5

View File

@@ -5,6 +5,7 @@ github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520 h1:IHDghbG
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520/go.mod h1:Nz8ORLaFiLWotg6GeKlJMhv8cci8mM43uEnLA5t8iew=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc h1:t2AT8zb6N/59Y78lyRWedVoVWHNRSCBh0oWCC+bluTQ=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

View File

@@ -222,9 +222,9 @@ func onHttpRequestBody(ctx wrapper.HttpContext, config PluginConfig, body []byte
log.Debugf("cache hit, key:%s", key)
ctx.SetContext(CacheKeyContextKey, nil)
if !stream {
proxywasm.SendHttpResponse(200, [][2]string{{"content-type", "application/json; charset=utf-8"}}, []byte(fmt.Sprintf(config.ReturnResponseTemplate, response.String())), -1)
proxywasm.SendHttpResponseWithDetail(200, "ai-cache.hit", [][2]string{{"content-type", "application/json; charset=utf-8"}}, []byte(fmt.Sprintf(config.ReturnResponseTemplate, response.String())), -1)
} else {
proxywasm.SendHttpResponse(200, [][2]string{{"content-type", "text/event-stream; charset=utf-8"}}, []byte(fmt.Sprintf(config.ReturnStreamResponseTemplate, response.String())), -1)
proxywasm.SendHttpResponseWithDetail(200, "ai-cache.hit", [][2]string{{"content-type", "text/event-stream; charset=utf-8"}}, []byte(fmt.Sprintf(config.ReturnStreamResponseTemplate, response.String())), -1)
}
})
if err != nil {

View File

@@ -1,18 +1,12 @@
# 简介
AI提示词修饰插件,通过在与大模型发起的请求前后插入指定信息来调整大模型的输出
AI提示词装饰器插件支持在LLM的请求前后插入prompt
# 配置说明
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
|----------------|-----------------|------|-----|----------------------------------|
| `decorators` | array of object | 必填 | - | 修饰设置 |
template object 配置说明:
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
|----------------|-----------------|------|-----|----------------------------------|
| `name` | string | 必填 | - | 修饰名称 |
| `decorator.prepend` | array of message object | 必填 | - | 在初始输入之插入的语句 |
| `decorator.append` | array of message object | 必填 | - | 在初始输入之后插入的语句 |
| `prepend` | array of message object | optional | - | 在初始输入之前插入的语句 |
| `append` | array of message object | optional | - | 在初始输入之插入的语句 |
message object 配置说明:
@@ -26,57 +20,50 @@ message object 配置说明:
配置示例如下:
```yaml
decorators:
- name: "hangzhou-guide"
decorator:
prepend:
- role: system
content: "You will always respond in the Chinese language."
- role: user
content: "Assume you are from Hangzhou."
append:
- role: user
content: "Don't introduce Hangzhou's food."
prepend:
- role: system
content: "请使用英语回答问题"
append:
- role: user
content: "每次回答完问题,尝试进行反问"
```
使用以上配置发起请求:
```bash
{
curl http://localhost/test \
-H "content-type: application/json" \
-d '{
"model": "gpt-3.5-turbo",
"messages": [
{
"role": "user",
"content": "Please introduce your home."
"content": "你是谁?"
}
]
}
```
响应如下
经过插件处理后,实际请求为
```
{
"id": "chatcmpl-9UYwQlEg6GwAswEZBDYXl41RU4gab",
"object": "chat.completion",
"created": 1717071182,
"model": "gpt-3.5-turbo-0125",
"choices": [
```bash
curl http://localhost/test \
-H "content-type: application/json" \
-d '{
"model": "gpt-3.5-turbo",
"messages": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "杭州是一个美丽的城市,有着悠久的历史和富有特色的文化。这里风景优美,有西湖、雷峰塔等著名景点,吸引着许多游客前来观光。杭州人民热情好客,城市宁静安逸,是一个适合居住和旅游的地方。"
},
"logprobs": null,
"finish_reason": "stop"
"role": "system",
"content": "请使用英语回答问题"
},
{
"role": "user",
"content": "你是谁?"
},
{
"role": "user",
"content": "每次回答完问题,尝试进行反问"
}
],
"usage": {
"prompt_tokens": 49,
"completion_tokens": 117,
"total_tokens": 166
},
"system_fingerprint": null
]
}
```

View File

@@ -2,9 +2,11 @@ module ai-prompt-decorator
go 1.18
replace github.com/alibaba/higress/plugins/wasm-go => ../..
require (
github.com/alibaba/higress/plugins/wasm-go v1.3.5
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f
github.com/tidwall/gjson v1.14.3
)

View File

@@ -1,12 +1,10 @@
github.com/alibaba/higress/plugins/wasm-go v1.3.5 h1:VOLL3m442IHCSu8mR5AZ4sc6LVT9X0w1hdqDI7oB9jY=
github.com/alibaba/higress/plugins/wasm-go v1.3.5/go.mod h1:kr3V9Ntbspj1eSrX8rgjBsdMXkGupYEf+LM72caGPQc=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520 h1:IHDghbGQ2DTIXHBHxWfqCYQW1fKjyJ/I7W1pMyUDeEA=
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520/go.mod h1:Nz8ORLaFiLWotg6GeKlJMhv8cci8mM43uEnLA5t8iew=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a h1:luYRvxLTE1xYxrXYj7nmjd1U0HHh8pUPiKfdZ0MhCGE=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f h1:ZIiIBRvIw62gA5MJhuwp1+2wWbqL9IGElQ499rUsYYg=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

View File

@@ -1,8 +1,7 @@
package main
import (
"errors"
"strings"
"encoding/json"
"github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper"
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm"
@@ -20,66 +19,53 @@ func main() {
)
}
type Message struct {
Role string `json:"role"`
Content string `json:"content"`
}
type AIPromptDecoratorConfig struct {
decorators map[string]string
Prepend []Message `json:"prepend"`
Append []Message `json:"append"`
}
func removeBrackets(raw string) (string, error) {
startIndex := strings.Index(raw, "{")
endIndex := strings.LastIndex(raw, "}")
if startIndex == -1 || endIndex == -1 {
return raw, errors.New("message format is wrong!")
} else {
return raw[startIndex : endIndex+1], nil
}
}
func parseConfig(json gjson.Result, config *AIPromptDecoratorConfig, log wrapper.Log) error {
config.decorators = make(map[string]string)
for _, v := range json.Get("decorators").Array() {
config.decorators[v.Get("name").String()] = v.Get("decorator").Raw
// log.Info(v.Get("decorator").Raw)
}
return nil
func parseConfig(jsonConfig gjson.Result, config *AIPromptDecoratorConfig, log wrapper.Log) error {
return json.Unmarshal([]byte(jsonConfig.Raw), config)
}
func onHttpRequestHeaders(ctx wrapper.HttpContext, config AIPromptDecoratorConfig, log wrapper.Log) types.Action {
decorator, _ := proxywasm.GetHttpRequestHeader("decorator")
if decorator == "" {
ctx.DontReadRequestBody()
return types.ActionContinue
}
ctx.SetContext("decorator", decorator)
proxywasm.RemoveHttpRequestHeader("decorator")
proxywasm.RemoveHttpRequestHeader("content-length")
return types.ActionContinue
}
func onHttpRequestBody(ctx wrapper.HttpContext, config AIPromptDecoratorConfig, body []byte, log wrapper.Log) types.Action {
decoratorName := ctx.GetContext("decorator").(string)
decorator := config.decorators[decoratorName]
messageJson := `{"messages":[]}`
prependMessage := gjson.Get(decorator, "prepend")
if prependMessage.Exists() {
for _, entry := range prependMessage.Array() {
messageJson, _ = sjson.SetRaw(messageJson, "messages.-1", entry.Raw)
for _, entry := range config.Prepend {
msg, err := json.Marshal(entry)
if err != nil {
log.Errorf("Failed to add prepend message, error: %v", err)
return types.ActionContinue
}
messageJson, _ = sjson.SetRaw(messageJson, "messages.-1", string(msg))
}
rawMessage := gjson.GetBytes(body, "messages")
if rawMessage.Exists() {
for _, entry := range rawMessage.Array() {
messageJson, _ = sjson.SetRaw(messageJson, "messages.-1", entry.Raw)
}
if !rawMessage.Exists() {
log.Errorf("Cannot find messages field in request body")
return types.ActionContinue
}
for _, entry := range rawMessage.Array() {
messageJson, _ = sjson.SetRaw(messageJson, "messages.-1", entry.Raw)
}
appendMessage := gjson.Get(decorator, "append")
if appendMessage.Exists() {
for _, entry := range appendMessage.Array() {
messageJson, _ = sjson.SetRaw(messageJson, "messages.-1", entry.Raw)
for _, entry := range config.Append {
msg, err := json.Marshal(entry)
if err != nil {
log.Errorf("Failed to add prepend message, error: %v", err)
return types.ActionContinue
}
messageJson, _ = sjson.SetRaw(messageJson, "messages.-1", string(msg))
}
newbody, err := sjson.SetRaw(string(body), "messages", gjson.Get(messageJson, "messages").Raw)

View File

@@ -2,9 +2,11 @@ module ai-prompt-template
go 1.18
replace github.com/alibaba/higress/plugins/wasm-go => ../..
require (
github.com/alibaba/higress/plugins/wasm-go v1.3.5
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f
github.com/tidwall/gjson v1.14.3
)

View File

@@ -7,6 +7,7 @@ github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520 h1:IHDghbG
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520/go.mod h1:Nz8ORLaFiLWotg6GeKlJMhv8cci8mM43uEnLA5t8iew=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a h1:luYRvxLTE1xYxrXYj7nmjd1U0HHh8pUPiKfdZ0MhCGE=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

View File

@@ -0,0 +1 @@
EXTRA_TAGS=proxy_wasm_version_0_2_100

View File

@@ -8,7 +8,7 @@ replace github.com/alibaba/higress/plugins/wasm-go => ../..
require (
github.com/alibaba/higress/plugins/wasm-go v0.0.0
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f
github.com/stretchr/testify v1.8.4
github.com/tidwall/gjson v1.14.3
)

View File

@@ -4,8 +4,8 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520 h1:IHDghbGQ2DTIXHBHxWfqCYQW1fKjyJ/I7W1pMyUDeEA=
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520/go.mod h1:Nz8ORLaFiLWotg6GeKlJMhv8cci8mM43uEnLA5t8iew=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc h1:t2AT8zb6N/59Y78lyRWedVoVWHNRSCBh0oWCC+bluTQ=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f h1:ZIiIBRvIw62gA5MJhuwp1+2wWbqL9IGElQ499rUsYYg=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

View File

@@ -21,6 +21,8 @@ const (
pluginName = "ai-proxy"
ctxKeyApiName = "apiKey"
defaultMaxBodyBytes uint32 = 10 * 1024 * 1024
)
func main() {
@@ -64,7 +66,7 @@ func onHttpRequestHeader(ctx wrapper.HttpContext, pluginConfig config.PluginConf
apiName := getOpenAiApiName(path.Path)
if apiName == "" {
log.Debugf("[onHttpRequestHeader] unsupported path: %s", path.Path)
_ = util.SendResponse(404, util.MimeTypeTextPlain, "API not found: "+path.Path)
_ = util.SendResponse(404, "ai-proxy.unknown_api", util.MimeTypeTextPlain, "API not found: "+path.Path)
return types.ActionContinue
}
ctx.SetContext(ctxKeyApiName, apiName)
@@ -75,16 +77,18 @@ func onHttpRequestHeader(ctx wrapper.HttpContext, pluginConfig config.PluginConf
action, err := handler.OnRequestHeaders(ctx, apiName, log)
if err == nil {
if contentType, err := proxywasm.GetHttpRequestHeader("Content-Type"); err == nil && contentType != "" {
ctx.SetRequestBodyBufferLimit(defaultMaxBodyBytes)
// Always return types.HeaderStopIteration to support fallback routing,
// as long as onHttpRequestBody can be called.
return types.HeaderStopIteration
}
return action
}
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to process request headers: %v", err))
_ = util.SendResponse(500, "ai-proxy.proc_req_headers_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to process request headers: %v", err))
return types.ActionContinue
}
if _, needHandleBody := activeProvider.(provider.RequestBodyHandler); needHandleBody {
ctx.DontReadRequestBody()
}
return types.ActionContinue
}
@@ -99,18 +103,24 @@ func onHttpRequestBody(ctx wrapper.HttpContext, pluginConfig config.PluginConfig
log.Debugf("[onHttpRequestBody] provider=%s", activeProvider.GetProviderType())
if handler, ok := activeProvider.(provider.RequestBodyHandler); ok {
apiName := ctx.GetContext(ctxKeyApiName).(provider.ApiName)
apiName, _ := ctx.GetContext(ctxKeyApiName).(provider.ApiName)
action, err := handler.OnRequestBody(ctx, apiName, body, log)
if err == nil {
return action
}
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to process request body: %v", err))
_ = util.SendResponse(500, "ai-proxy.proc_req_body_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to process request body: %v", err))
return types.ActionContinue
}
return types.ActionContinue
}
func onHttpResponseHeaders(ctx wrapper.HttpContext, pluginConfig config.PluginConfig, log wrapper.Log) types.Action {
if !wrapper.IsResponseFromUpstream() {
// Response is not coming from the upstream. Let it pass through.
ctx.DontReadResponseBody()
return types.ActionContinue
}
activeProvider := pluginConfig.GetProvider()
if activeProvider == nil {
@@ -139,12 +149,12 @@ func onHttpResponseHeaders(ctx wrapper.HttpContext, pluginConfig config.PluginCo
}
if handler, ok := activeProvider.(provider.ResponseHeadersHandler); ok {
apiName := ctx.GetContext(ctxKeyApiName).(provider.ApiName)
apiName, _ := ctx.GetContext(ctxKeyApiName).(provider.ApiName)
action, err := handler.OnResponseHeaders(ctx, apiName, log)
if err == nil {
return action
}
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to process response headers: %v", err))
_ = util.SendResponse(500, "ai-proxy.proc_resp_headers_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to process response headers: %v", err))
return types.ActionContinue
}
@@ -171,7 +181,7 @@ func onStreamingResponseBody(ctx wrapper.HttpContext, pluginConfig config.Plugin
log.Debugf("isLastChunk=%v chunk: %s", isLastChunk, string(chunk))
if handler, ok := activeProvider.(provider.StreamingResponseBodyHandler); ok {
apiName := ctx.GetContext(ctxKeyApiName).(provider.ApiName)
apiName, _ := ctx.GetContext(ctxKeyApiName).(provider.ApiName)
modifiedChunk, err := handler.OnStreamingResponseBody(ctx, apiName, chunk, isLastChunk, log)
if err == nil && modifiedChunk != nil {
return modifiedChunk
@@ -193,12 +203,12 @@ func onHttpResponseBody(ctx wrapper.HttpContext, pluginConfig config.PluginConfi
//log.Debugf("response body: %s", string(body))
if handler, ok := activeProvider.(provider.ResponseBodyHandler); ok {
apiName := ctx.GetContext(ctxKeyApiName).(provider.ApiName)
apiName, _ := ctx.GetContext(ctxKeyApiName).(provider.ApiName)
action, err := handler.OnResponseBody(ctx, apiName, body, log)
if err == nil {
return action
}
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to process response body: %v", err))
_ = util.SendResponse(500, "ai-proxy.proc_resp_body_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to process response body: %v", err))
return types.ActionContinue
}
return types.ActionContinue

View File

@@ -58,13 +58,7 @@ func (m *azureProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiNam
_ = util.OverwriteRequestPath(m.serviceUrl.RequestURI())
_ = util.OverwriteRequestHost(m.serviceUrl.Host)
_ = proxywasm.ReplaceHttpRequestHeader("api-key", m.config.apiTokens[0])
if m.contextCache == nil {
ctx.DontReadRequestBody()
} else {
_ = proxywasm.RemoveHttpRequestHeader("Content-Length")
}
_ = proxywasm.RemoveHttpRequestHeader("Content-Length")
return types.ActionContinue, nil
}
@@ -85,11 +79,11 @@ func (m *azureProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName,
}()
if err != nil {
log.Errorf("failed to load context file: %v", err)
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
_ = util.SendResponse(500, "ai-proxy.azure.load_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
}
insertContextMessage(request, content)
if err := replaceJsonRequestBody(request, log); err != nil {
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
_ = util.SendResponse(500, "ai-proxy.azure.insert_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
}
}, log)
if err == nil {

View File

@@ -45,14 +45,8 @@ func (m *baichuanProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName Api
}
_ = util.OverwriteRequestPath(baichuanChatCompletionPath)
_ = util.OverwriteRequestHost(baichuanDomain)
_ = proxywasm.ReplaceHttpRequestHeader("Authorization", "Bearer "+m.config.GetRandomToken())
if m.contextCache == nil {
ctx.DontReadRequestBody()
} else {
_ = proxywasm.RemoveHttpRequestHeader("Content-Length")
}
_ = util.OverwriteRequestAuthorization("Bearer " + m.config.GetRandomToken())
_ = proxywasm.RemoveHttpRequestHeader("Content-Length")
return types.ActionContinue, nil
}
@@ -73,11 +67,11 @@ func (m *baichuanProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiNam
}()
if err != nil {
log.Errorf("failed to load context file: %v", err)
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
_ = util.SendResponse(500, "ai-proxy.baichuan.load_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
}
insertContextMessage(request, content)
if err := replaceJsonRequestBody(request, log); err != nil {
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
_ = util.SendResponse(500, "ai-proxy.baichuan.insert_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
}
}, log)
if err == nil {

View File

@@ -94,11 +94,11 @@ func (b *baiduProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName,
if err != nil {
log.Errorf("failed to load context file: %v", err)
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
_ = util.SendResponse(500, "ai-proxy.baidu.load_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
}
b.setSystemContent(request, content)
if err := replaceJsonRequestBody(request, log); err != nil {
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
_ = util.SendResponse(500, "ai-proxy.baidu.insert_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
}
}, log)
if err == nil {
@@ -137,12 +137,12 @@ func (b *baiduProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName,
}()
if err != nil {
log.Errorf("failed to load context file: %v", err)
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
_ = util.SendResponse(500, "ai-proxy.baidu.load_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
}
insertContextMessage(request, content)
baiduRequest := b.baiduTextGenRequest(request)
if err := replaceJsonRequestBody(baiduRequest, log); err != nil {
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to replace Request body: %v", err))
_ = util.SendResponse(500, "ai-proxy.baidu.insert_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to replace Request body: %v", err))
}
}, log)
if err == nil {
@@ -298,7 +298,7 @@ func (b *baiduProvider) responseBaidu2OpenAI(ctx wrapper.HttpContext, response *
return &chatCompletionResponse{
Id: response.Id,
Created: time.Now().UnixMilli() / 1000,
Model: ctx.GetContext(ctxKeyFinalRequestModel).(string),
Model: ctx.GetStringContext(ctxKeyFinalRequestModel, ""),
SystemFingerprint: "",
Object: objectChatCompletion,
Choices: []chatCompletionChoice{choice},
@@ -321,7 +321,7 @@ func (b *baiduProvider) streamResponseBaidu2OpenAI(ctx wrapper.HttpContext, resp
return &chatCompletionResponse{
Id: response.Id,
Created: time.Now().UnixMilli() / 1000,
Model: ctx.GetContext(ctxKeyFinalRequestModel).(string),
Model: ctx.GetStringContext(ctxKeyFinalRequestModel, ""),
SystemFingerprint: "",
Object: objectChatCompletion,
Choices: []chatCompletionChoice{choice},

View File

@@ -139,10 +139,10 @@ func (c *claudeProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName,
if err != nil {
log.Errorf("failed to load context file: %v", err)
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
_ = util.SendResponse(500, "ai-proxy.claude.load_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
}
if err := replaceJsonRequestBody(request, log); err != nil {
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
_ = util.SendResponse(500, "ai-proxy.claude.insert_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
}
}, log)
if err == nil {
@@ -185,12 +185,12 @@ func (c *claudeProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName,
}()
if err != nil {
log.Errorf("failed to load context file: %v", err)
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
_ = util.SendResponse(500, "ai-proxy.claude.load_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
}
insertContextMessage(request, content)
claudeRequest := c.buildClaudeTextGenRequest(request)
if err := replaceJsonRequestBody(claudeRequest, log); err != nil {
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
_ = util.SendResponse(500, "ai-proxy.claude.insert_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
}
}, log)
if err == nil {
@@ -292,7 +292,7 @@ func (c *claudeProvider) responseClaude2OpenAI(ctx wrapper.HttpContext, origResp
return &chatCompletionResponse{
Id: origResponse.Id,
Created: time.Now().UnixMilli() / 1000,
Model: ctx.GetContext(ctxKeyFinalRequestModel).(string),
Model: ctx.GetStringContext(ctxKeyFinalRequestModel, ""),
SystemFingerprint: "",
Object: objectChatCompletion,
Choices: []chatCompletionChoice{choice},
@@ -356,7 +356,7 @@ func createChatCompletionResponse(ctx wrapper.HttpContext, response *claudeTextG
return &chatCompletionResponse{
Id: response.Message.Id,
Created: time.Now().UnixMilli() / 1000,
Model: ctx.GetContext(ctxKeyFinalRequestModel).(string),
Model: ctx.GetStringContext(ctxKeyFinalRequestModel, ""),
Object: objectChatCompletionChunk,
Choices: []chatCompletionChoice{choice},
}

View File

@@ -3,11 +3,12 @@ package provider
import (
"errors"
"fmt"
"strings"
"github.com/alibaba/higress/plugins/wasm-go/extensions/ai-proxy/util"
"github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper"
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm"
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm/types"
"strings"
)
const (
@@ -45,11 +46,8 @@ func (c *cloudflareProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName A
}
_ = util.OverwriteRequestPath(strings.Replace(cloudflareChatCompletionPath, "{account_id}", c.config.cloudflareAccountId, 1))
_ = util.OverwriteRequestHost(cloudflareDomain)
_ = proxywasm.ReplaceHttpRequestHeader("Authorization", "Bearer "+c.config.GetRandomToken())
_ = util.OverwriteRequestAuthorization("Bearer " + c.config.GetRandomToken())
if c.config.context == nil && c.config.protocol == protocolOriginal {
ctx.DontReadRequestBody()
}
_ = proxywasm.RemoveHttpRequestHeader("Accept-Encoding")
_ = proxywasm.RemoveHttpRequestHeader("Content-Length")
@@ -84,7 +82,7 @@ func (c *cloudflareProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiN
if c.contextCache == nil {
if err := replaceJsonRequestBody(request, log); err != nil {
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
_ = util.SendResponse(500, "ai-proxy.cloudflare.transform_body_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
}
return types.ActionContinue, nil
}
@@ -94,11 +92,11 @@ func (c *cloudflareProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiN
}()
if err != nil {
log.Errorf("failed to load context file: %v", err)
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
_ = util.SendResponse(500, "ai-proxy.cloudflare.load_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
}
insertContextMessage(request, content)
if err := replaceJsonRequestBody(request, log); err != nil {
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
_ = util.SendResponse(500, "ai-proxy.cloudflare.insert_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
}
}, log)
if err == nil {

View File

@@ -45,14 +45,8 @@ func (m *deepseekProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName Api
}
_ = util.OverwriteRequestPath(deepseekChatCompletionPath)
_ = util.OverwriteRequestHost(deepseekDomain)
_ = proxywasm.ReplaceHttpRequestHeader("Authorization", "Bearer "+m.config.GetRandomToken())
if m.contextCache == nil {
ctx.DontReadRequestBody()
} else {
_ = proxywasm.RemoveHttpRequestHeader("Content-Length")
}
_ = util.OverwriteRequestAuthorization("Bearer " + m.config.GetRandomToken())
_ = proxywasm.RemoveHttpRequestHeader("Content-Length")
return types.ActionContinue, nil
}
@@ -73,11 +67,11 @@ func (m *deepseekProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiNam
}()
if err != nil {
log.Errorf("failed to load context file: %v", err)
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
_ = util.SendResponse(500, "ai-proxy.deepseek.load_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
}
insertContextMessage(request, content)
if err := replaceJsonRequestBody(request, log); err != nil {
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
_ = util.SendResponse(500, "ai-proxy.deepseek.insert_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
}
}, log)
if err == nil {

View File

@@ -43,14 +43,8 @@ func (m *groqProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName
}
_ = util.OverwriteRequestPath(groqChatCompletionPath)
_ = util.OverwriteRequestHost(groqDomain)
_ = proxywasm.ReplaceHttpRequestHeader("Authorization", "Bearer "+m.config.GetRandomToken())
if m.contextCache == nil {
ctx.DontReadRequestBody()
} else {
_ = proxywasm.RemoveHttpRequestHeader("Content-Length")
}
_ = util.OverwriteRequestAuthorization("Bearer " + m.config.GetRandomToken())
_ = proxywasm.RemoveHttpRequestHeader("Content-Length")
return types.ActionContinue, nil
}
@@ -71,11 +65,11 @@ func (m *groqProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName, b
}()
if err != nil {
log.Errorf("failed to load context file: %v", err)
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
_ = util.SendResponse(500, "ai-proxy.groq.load_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
}
insertContextMessage(request, content)
if err := replaceJsonRequestBody(request, log); err != nil {
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
_ = util.SendResponse(500, "ai-proxy.groq.insert_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
}
}, log)
if err == nil {

View File

@@ -155,7 +155,7 @@ func (m *hunyuanProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName
// 根据确定好的payload进行签名
hunyuanBody, _ := json.Marshal(request)
authorizedValueNew := GetTC3Authorizationcode(m.config.hunyuanAuthId, m.config.hunyuanAuthKey, timestamp, hunyuanDomain, hunyuanChatCompletionTCAction, string(hunyuanBody))
_ = proxywasm.ReplaceHttpRequestHeader(authorizationKey, authorizedValueNew)
_ = util.OverwriteRequestAuthorization(authorizedValueNew)
_ = proxywasm.ReplaceHttpRequestHeader("Accept", "*/*")
// log.Debugf("#debug nash5# OnRequestBody call hunyuan api using original api! signature computation done!")
@@ -171,17 +171,17 @@ func (m *hunyuanProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName
if err != nil {
log.Errorf("failed to load context file: %v", err)
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
_ = util.SendResponse(500, "ai-proxy.hunyuan.load_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
}
m.insertContextMessageIntoHunyuanRequest(request, content)
// 因为手动插入了context内容这里需要重新计算签名
hunyuanBody, _ := json.Marshal(request)
authorizedValueNew := GetTC3Authorizationcode(m.config.hunyuanAuthId, m.config.hunyuanAuthKey, timestamp, hunyuanDomain, hunyuanChatCompletionTCAction, string(hunyuanBody))
_ = proxywasm.ReplaceHttpRequestHeader(authorizationKey, authorizedValueNew)
_ = util.OverwriteRequestAuthorization(authorizedValueNew)
if err := replaceJsonRequestBody(request, log); err != nil {
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
_ = util.SendResponse(500, "ai-proxy.hunyuan.insert_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
}
}, log)
if err == nil {
@@ -234,7 +234,7 @@ func (m *hunyuanProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName
hunyuanChatCompletionTCAction,
string(body),
)
_ = proxywasm.ReplaceHttpRequestHeader(authorizationKey, authorizedValueNew)
_ = util.OverwriteRequestAuthorization(authorizedValueNew)
// log.Debugf("#debug nash5# OnRequestBody done, body is: ", string(body))
// // 打印所有的headers
@@ -256,7 +256,7 @@ func (m *hunyuanProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName
}()
if err != nil {
log.Errorf("failed to load context file: %v", err)
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
_ = util.SendResponse(500, "ai-proxy.hunyuan.load_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
return
}
insertContextMessage(request, content)
@@ -265,10 +265,10 @@ func (m *hunyuanProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName
// 因为手动插入了context内容这里需要重新计算签名
hunyuanBody, _ := json.Marshal(hunyuanRequest)
authorizedValueNew := GetTC3Authorizationcode(m.config.hunyuanAuthId, m.config.hunyuanAuthKey, timestamp, hunyuanDomain, hunyuanChatCompletionTCAction, string(hunyuanBody))
_ = proxywasm.ReplaceHttpRequestHeader(authorizationKey, authorizedValueNew)
_ = util.OverwriteRequestAuthorization(authorizedValueNew)
if err := replaceJsonRequestBody(hunyuanRequest, log); err != nil {
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
_ = util.SendResponse(500, "ai-proxy.hunyuan.insert_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
}
}, log)
if err == nil {
@@ -351,7 +351,7 @@ func (m *hunyuanProvider) convertChunkFromHunyuanToOpenAI(ctx wrapper.HttpContex
openAIFormattedChunk := &chatCompletionResponse{
Id: hunyuanFormattedChunk.Id,
Created: time.Now().UnixMilli() / 1000,
Model: ctx.GetContext(ctxKeyFinalRequestModel).(string),
Model: ctx.GetStringContext(ctxKeyFinalRequestModel, ""),
SystemFingerprint: "",
Object: objectChatCompletionChunk,
Usage: usage{
@@ -470,7 +470,7 @@ func (m *hunyuanProvider) buildChatCompletionResponse(ctx wrapper.HttpContext, h
return &chatCompletionResponse{
Id: hunyuanResponse.Response.Id,
Created: time.Now().UnixMilli() / 1000,
Model: ctx.GetContext(ctxKeyFinalRequestModel).(string),
Model: ctx.GetStringContext(ctxKeyFinalRequestModel, ""),
SystemFingerprint: "",
Object: objectChatCompletion,
Choices: choices,

View File

@@ -4,11 +4,12 @@ import (
"encoding/json"
"errors"
"fmt"
"strings"
"github.com/alibaba/higress/plugins/wasm-go/extensions/ai-proxy/util"
"github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper"
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm"
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm/types"
"strings"
)
// minimaxProvider is the provider for minimax service.
@@ -75,7 +76,7 @@ func (m *minimaxProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiN
return types.ActionContinue, errUnsupportedApiName
}
_ = util.OverwriteRequestHost(minimaxDomain)
_ = proxywasm.ReplaceHttpRequestHeader("Authorization", "Bearer "+m.config.GetRandomToken())
_ = util.OverwriteRequestAuthorization("Bearer " + m.config.GetRandomToken())
_ = proxywasm.RemoveHttpRequestHeader("Content-Length")
// Delay the header processing to allow changing streaming mode in OnRequestBody
@@ -135,11 +136,11 @@ func (m *minimaxProvider) handleRequestBodyByChatCompletionPro(body []byte, log
if err != nil {
log.Errorf("failed to load context file: %v", err)
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
_ = util.SendResponse(500, "ai-proxy.minimax.load_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
}
m.setBotSettings(request, content)
if err := replaceJsonRequestBody(request, log); err != nil {
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
_ = util.SendResponse(500, "ai-proxy.minimax.insert_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
}
}, log)
if err == nil {
@@ -168,11 +169,11 @@ func (m *minimaxProvider) handleRequestBodyByChatCompletionPro(body []byte, log
}()
if err != nil {
log.Errorf("failed to load context file: %v", err)
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
_ = util.SendResponse(500, "ai-proxy.minimax.load_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
}
minimaxRequest := m.buildMinimaxChatCompletionV2Request(request, content)
if err := replaceJsonRequestBody(minimaxRequest, log); err != nil {
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to replace Request body: %v", err))
_ = util.SendResponse(500, "ai-proxy.minimax.insert_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to replace Request body: %v", err))
}
}, log)
if err == nil {
@@ -202,11 +203,11 @@ func (m *minimaxProvider) handleRequestBodyByChatCompletionV2(body []byte, log w
}()
if err != nil {
log.Errorf("failed to load context file: %v", err)
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
_ = util.SendResponse(500, "ai-proxy.minimax.load_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
}
insertContextMessage(request, content)
if err := replaceJsonRequestBody(request, log); err != nil {
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
_ = util.SendResponse(500, "ai-proxy.minimax.insert_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
}
}, log)
if err == nil {
@@ -222,9 +223,9 @@ func (m *minimaxProvider) OnResponseHeaders(ctx wrapper.HttpContext, apiName Api
return types.ActionContinue, nil
}
// 模型对应接口为ChatCompletion v2,跳过OnStreamingResponseBody()和OnResponseBody()
model := ctx.GetContext(ctxKeyFinalRequestModel)
if model != nil {
_, ok := chatCompletionProModels[model.(string)]
model := ctx.GetStringContext(ctxKeyFinalRequestModel, "")
if model != "" {
_, ok := chatCompletionProModels[model]
if !ok {
ctx.DontReadResponseBody()
return types.ActionContinue, nil

View File

@@ -57,7 +57,7 @@ func (m *moonshotProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName Api
}
_ = util.OverwriteRequestPath(moonshotChatCompletionPath)
_ = util.OverwriteRequestHost(moonshotDomain)
_ = proxywasm.ReplaceHttpRequestHeader("Authorization", "Bearer "+m.config.GetRandomToken())
_ = util.OverwriteRequestAuthorization("Bearer " + m.config.GetRandomToken())
_ = proxywasm.RemoveHttpRequestHeader("Content-Length")
return types.ActionContinue, nil
}
@@ -92,12 +92,12 @@ func (m *moonshotProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiNam
}()
if err != nil {
log.Errorf("failed to load context file: %v", err)
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
_ = util.SendResponse(500, "ai-proxy.moonshot.load_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
return
}
err = m.performChatCompletion(ctx, content, request, log)
if err != nil {
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to perform chat completion: %v", err))
_ = util.SendResponse(500, "ai-proxy.moonshot.insert_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to perform chat completion: %v", err))
}
}, log)
if err == nil {

View File

@@ -68,7 +68,7 @@ func (m *ollamaProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName,
if m.config.modelMapping == nil && m.contextCache == nil {
return types.ActionContinue, nil
}
request := &chatCompletionRequest{}
if err := decodeChatCompletionRequest(body, request); err != nil {
return types.ActionContinue, err
@@ -83,7 +83,7 @@ func (m *ollamaProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName,
return types.ActionContinue, errors.New("model becomes empty after applying the configured mapping")
}
request.Model = mappedModel
if m.contextCache != nil {
err := m.contextCache.GetContent(func(content string, err error) {
defer func() {
@@ -91,11 +91,11 @@ func (m *ollamaProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName,
}()
if err != nil {
log.Errorf("failed to load context file: %v", err)
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
_ = util.SendResponse(500, "ai-proxy.ollama.load_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
}
insertContextMessage(request, content)
if err := replaceJsonRequestBody(request, log); err != nil {
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
_ = util.SendResponse(500, "ai-proxy.ollama.insert_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
}
}, log)
if err == nil {
@@ -105,7 +105,7 @@ func (m *ollamaProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName,
}
} else {
if err := replaceJsonRequestBody(request, log); err != nil {
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
_ = util.SendResponse(500, "ai-proxy.ollama.transform_body_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
return types.ActionContinue, err
}
_ = proxywasm.ResumeHttpRequest()

View File

@@ -41,24 +41,16 @@ func (m *openaiProvider) GetProviderType() string {
}
func (m *openaiProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, log wrapper.Log) (types.Action, error) {
skipRequestBody := true
switch apiName {
case ApiNameChatCompletion:
_ = util.OverwriteRequestPath(openaiChatCompletionPath)
skipRequestBody = m.contextCache == nil
break
case ApiNameEmbeddings:
_ = util.OverwriteRequestPath(openaiEmbeddingsPath)
break
}
_ = proxywasm.ReplaceHttpRequestHeader("Authorization", "Bearer "+m.config.GetRandomToken())
if skipRequestBody {
ctx.DontReadRequestBody()
} else {
_ = proxywasm.RemoveHttpRequestHeader("Content-Length")
}
_ = util.OverwriteRequestAuthorization("Bearer " + m.config.GetRandomToken())
_ = proxywasm.RemoveHttpRequestHeader("Content-Length")
return types.ActionContinue, nil
}
@@ -67,24 +59,42 @@ func (m *openaiProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName,
// We don't need to process the request body for other APIs.
return types.ActionContinue, nil
}
if m.contextCache == nil {
return types.ActionContinue, nil
}
request := &chatCompletionRequest{}
if err := decodeChatCompletionRequest(body, request); err != nil {
return types.ActionContinue, err
}
bodyAltered := false
if request.Stream {
// For stream requests, we need to include usage in the response.
if request.StreamOptions == nil {
request.StreamOptions = &streamOptions{IncludeUsage: true}
bodyAltered = true
} else if !request.StreamOptions.IncludeUsage {
request.StreamOptions.IncludeUsage = true
bodyAltered = true
}
}
if m.contextCache == nil {
if bodyAltered {
if err := replaceJsonRequestBody(request, log); err != nil {
_ = util.SendResponse(500, "ai-proxy.openai.set_include_usage_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
}
}
return types.ActionContinue, nil
} else {
// If context cache is configured and body has been altered, the new body will be replaced when inserting the context data.
}
err := m.contextCache.GetContent(func(content string, err error) {
defer func() {
_ = proxywasm.ResumeHttpRequest()
}()
if err != nil {
log.Errorf("failed to load context file: %v", err)
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
_ = util.SendResponse(500, "ai-proxy.openai.load_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
}
insertContextMessage(request, content)
if err := replaceJsonRequestBody(request, log); err != nil {
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
_ = util.SendResponse(500, "ai-proxy.openai.insert_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
}
}, log)
if err == nil {

View File

@@ -60,20 +60,17 @@ func (m *qwenProvider) GetProviderType() string {
}
func (m *qwenProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, log wrapper.Log) (types.Action, error) {
needRequestBody := false
if apiName == ApiNameChatCompletion {
_ = util.OverwriteRequestPath(qwenChatCompletionPath)
needRequestBody = m.config.context != nil
} else if apiName == ApiNameEmbeddings {
_ = util.OverwriteRequestPath(qwenTextEmbeddingPath)
} else {
return types.ActionContinue, errUnsupportedApiName
}
_ = util.OverwriteRequestHost(qwenDomain)
_ = proxywasm.ReplaceHttpRequestHeader("Authorization", "Bearer "+m.config.GetRandomToken())
_ = util.OverwriteRequestAuthorization("Bearer " + m.config.GetRandomToken())
if m.config.protocol == protocolOriginal && !needRequestBody {
ctx.DontReadRequestBody()
if m.config.protocol == protocolOriginal {
return types.ActionContinue, nil
}
@@ -112,11 +109,11 @@ func (m *qwenProvider) onChatCompletionRequestBody(ctx wrapper.HttpContext, body
if err != nil {
log.Errorf("failed to load context file: %v", err)
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
_ = util.SendResponse(500, "ai-proxy.qwen.load_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
}
m.insertContextMessage(request, content, false)
if err := replaceJsonRequestBody(request, log); err != nil {
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
_ = util.SendResponse(500, "ai-proxy.qwen.insert_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
}
}, log)
if err == nil {
@@ -165,7 +162,7 @@ func (m *qwenProvider) onChatCompletionRequestBody(ctx wrapper.HttpContext, body
}()
if err != nil {
log.Errorf("failed to load context file: %v", err)
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
_ = util.SendResponse(500, "ai-proxy.qwen.load_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
}
insertContextMessage(request, content)
qwenRequest := m.buildQwenTextGenerationRequest(request, streaming)
@@ -173,7 +170,7 @@ func (m *qwenProvider) onChatCompletionRequestBody(ctx wrapper.HttpContext, body
ctx.SetContext(ctxKeyIncrementalStreaming, qwenRequest.Parameters.IncrementalOutput)
}
if err := replaceJsonRequestBody(qwenRequest, log); err != nil {
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
_ = util.SendResponse(500, "ai-proxy.qwen.insert_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
}
}, log)
if err == nil {
@@ -229,10 +226,7 @@ func (m *qwenProvider) OnStreamingResponseBody(ctx wrapper.HttpContext, name Api
receivedBody = append(bufferedStreamingBody, chunk...)
}
incrementalStreaming, err := ctx.GetContext(ctxKeyIncrementalStreaming).(bool)
if !err {
incrementalStreaming = false
}
incrementalStreaming := ctx.GetBoolContext(ctxKeyIncrementalStreaming, false)
eventStartIndex, lineStartIndex, valueStartIndex := -1, -1, -1
@@ -387,7 +381,7 @@ func (m *qwenProvider) buildChatCompletionResponse(ctx wrapper.HttpContext, qwen
return &chatCompletionResponse{
Id: qwenResponse.RequestId,
Created: time.Now().UnixMilli() / 1000,
Model: ctx.GetContext(ctxKeyFinalRequestModel).(string),
Model: ctx.GetStringContext(ctxKeyFinalRequestModel, ""),
SystemFingerprint: "",
Object: objectChatCompletion,
Choices: choices,
@@ -403,7 +397,7 @@ func (m *qwenProvider) buildChatCompletionStreamingResponse(ctx wrapper.HttpCont
baseMessage := chatCompletionResponse{
Id: qwenResponse.RequestId,
Created: time.Now().UnixMilli() / 1000,
Model: ctx.GetContext(ctxKeyFinalRequestModel).(string),
Model: ctx.GetStringContext(ctxKeyFinalRequestModel, ""),
Choices: make([]chatCompletionChoice, 0),
SystemFingerprint: "",
Object: objectChatCompletionChunk,

View File

@@ -43,14 +43,8 @@ func (m *stepfunProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiN
}
_ = util.OverwriteRequestPath(stepfunChatCompletionPath)
_ = util.OverwriteRequestHost(stepfunDomain)
_ = proxywasm.ReplaceHttpRequestHeader("Authorization", "Bearer "+m.config.GetRandomToken())
if m.contextCache == nil {
ctx.DontReadRequestBody()
} else {
_ = proxywasm.RemoveHttpRequestHeader("Content-Length")
}
_ = util.OverwriteRequestAuthorization("Bearer " + m.config.GetRandomToken())
_ = proxywasm.RemoveHttpRequestHeader("Content-Length")
return types.ActionContinue, nil
}
@@ -71,11 +65,11 @@ func (m *stepfunProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName
}()
if err != nil {
log.Errorf("failed to load context file: %v", err)
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
_ = util.SendResponse(500, "ai-proxy.stepfun.load_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
}
insertContextMessage(request, content)
if err := replaceJsonRequestBody(request, log); err != nil {
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
_ = util.SendResponse(500, "ai-proxy.stepfun.insert_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
}
}, log)
if err == nil {

View File

@@ -43,14 +43,8 @@ func (m *yiProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName,
}
_ = util.OverwriteRequestPath(yiChatCompletionPath)
_ = util.OverwriteRequestHost(yiDomain)
_ = proxywasm.ReplaceHttpRequestHeader("Authorization", "Bearer "+m.config.GetRandomToken())
if m.contextCache == nil {
ctx.DontReadRequestBody()
} else {
_ = proxywasm.RemoveHttpRequestHeader("Content-Length")
}
_ = util.OverwriteRequestAuthorization("Bearer " + m.config.GetRandomToken())
_ = proxywasm.RemoveHttpRequestHeader("Content-Length")
return types.ActionContinue, nil
}
@@ -71,11 +65,11 @@ func (m *yiProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName, bod
}()
if err != nil {
log.Errorf("failed to load context file: %v", err)
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
_ = util.SendResponse(500, "ai-proxy.yi.load_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
}
insertContextMessage(request, content)
if err := replaceJsonRequestBody(request, log); err != nil {
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
_ = util.SendResponse(500, "ai-proxy.yi.insert_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
}
}, log)
if err == nil {

View File

@@ -42,14 +42,8 @@ func (m *zhipuAiProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiN
}
_ = util.OverwriteRequestPath(zhipuAiChatCompletionPath)
_ = util.OverwriteRequestHost(zhipuAiDomain)
_ = proxywasm.ReplaceHttpRequestHeader("Authorization", "Bearer "+m.config.GetRandomToken())
if m.contextCache == nil {
ctx.DontReadRequestBody()
} else {
_ = proxywasm.RemoveHttpRequestHeader("Content-Length")
}
_ = util.OverwriteRequestAuthorization("Bearer " + m.config.GetRandomToken())
_ = proxywasm.RemoveHttpRequestHeader("Content-Length")
return types.ActionContinue, nil
}
@@ -70,11 +64,11 @@ func (m *zhipuAiProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName
}()
if err != nil {
log.Errorf("failed to load context file: %v", err)
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
_ = util.SendResponse(500, "ai-proxy.zhihupai.load_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to load context file: %v", err))
}
insertContextMessage(request, content)
if err := replaceJsonRequestBody(request, log); err != nil {
_ = util.SendResponse(500, util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
_ = util.SendResponse(500, "ai-proxy.zhihupai.insert_ctx_failed", util.MimeTypeTextPlain, fmt.Sprintf("failed to replace request body: %v", err))
}
}, log)
if err == nil {

View File

@@ -9,8 +9,8 @@ const (
MimeTypeApplicationJson = "application/json"
)
func SendResponse(statusCode uint32, contentType, body string) error {
return proxywasm.SendHttpResponse(statusCode, CreateHeaders(HeaderContentType, contentType), []byte(body), -1)
func SendResponse(statusCode uint32, statusCodeDetails string, contentType, body string) error {
return proxywasm.SendHttpResponseWithDetail(statusCode, statusCodeDetails, CreateHeaders(HeaderContentType, contentType), []byte(body), -1)
}
func CreateHeaders(kvs ...string) [][2]string {
@@ -34,3 +34,12 @@ func OverwriteRequestPath(path string) error {
}
return proxywasm.ReplaceHttpRequestHeader(":path", path)
}
func OverwriteRequestAuthorization(credential string) error {
if exist, _ := proxywasm.GetHttpRequestHeader("X-HI-ORIGINAL-AUTH"); exist == "" {
if originAuth, err := proxywasm.GetHttpRequestHeader("Authorization"); err == nil {
_ = proxywasm.AddHttpRequestHeader("X-HI-ORIGINAL-AUTH", originAuth)
}
}
return proxywasm.ReplaceHttpRequestHeader("Authorization", credential)
}

View File

@@ -2,9 +2,11 @@ module ai-rag
go 1.18
replace github.com/alibaba/higress/plugins/wasm-go => ../..
require (
github.com/alibaba/higress/plugins/wasm-go v1.3.5
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f
github.com/tidwall/gjson v1.14.3
)

View File

@@ -7,6 +7,7 @@ github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520 h1:IHDghbG
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520/go.mod h1:Nz8ORLaFiLWotg6GeKlJMhv8cci8mM43uEnLA5t8iew=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a h1:luYRvxLTE1xYxrXYj7nmjd1U0HHh8pUPiKfdZ0MhCGE=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

View File

@@ -0,0 +1 @@
EXTRA_TAGS=proxy_wasm_version_0_2_100

View File

@@ -2,9 +2,11 @@ module myplugin
go 1.18
replace github.com/alibaba/higress/plugins/wasm-go => ../..
require (
github.com/alibaba/higress/plugins/wasm-go v1.3.6-0.20240522012622-fc6a6aad8906
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f
github.com/tidwall/gjson v1.14.3
)

View File

@@ -9,6 +9,7 @@ github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520 h1:IHDghbG
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520/go.mod h1:Nz8ORLaFiLWotg6GeKlJMhv8cci8mM43uEnLA5t8iew=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc h1:t2AT8zb6N/59Y78lyRWedVoVWHNRSCBh0oWCC+bluTQ=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

View File

@@ -145,8 +145,9 @@ func onHttpRequestBody(ctx wrapper.HttpContext, config AISecurityConfig, body []
Message: respAdvice.Array()[0].Get("Answer").String(),
}
jsonData, _ := json.MarshalIndent(sr, "", " ")
proxywasm.SetProperty([]string{"risklabel"}, []byte(respResult.Array()[0].Get("Label").String()))
proxywasm.SendHttpResponse(403, [][2]string{{"content-type", "application/json"}}, jsonData, -1)
label := respResult.Array()[0].Get("Label").String()
proxywasm.SetProperty([]string{"risklabel"}, []byte(label))
proxywasm.SendHttpResponseWithDetail(403, "ai-security-guard.label."+label, [][2]string{{"content-type", "application/json"}}, jsonData, -1)
} else if respResult.Array()[0].Get("Label").String() != "nonLabel" {
sr := StandardResponse{
Code: 403,
@@ -155,7 +156,7 @@ func onHttpRequestBody(ctx wrapper.HttpContext, config AISecurityConfig, body []
}
jsonData, _ := json.MarshalIndent(sr, "", " ")
proxywasm.SetProperty([]string{"risklabel"}, []byte(respResult.Array()[0].Get("Label").String()))
proxywasm.SendHttpResponse(403, [][2]string{{"content-type", "application/json"}}, jsonData, -1)
proxywasm.SendHttpResponseWithDetail(403, "ai-security-guard.risk_detected", [][2]string{{"content-type", "application/json"}}, jsonData, -1)
} else {
proxywasm.ResumeHttpRequest()
}

View File

@@ -2,9 +2,11 @@ module ai-statistics
go 1.18
replace github.com/alibaba/higress/plugins/wasm-go => ../..
require (
github.com/alibaba/higress/plugins/wasm-go v1.3.6-0.20240522012622-fc6a6aad8906
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f
github.com/tidwall/gjson v1.14.3
)

View File

@@ -7,6 +7,7 @@ github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520 h1:IHDghbG
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520/go.mod h1:Nz8ORLaFiLWotg6GeKlJMhv8cci8mM43uEnLA5t8iew=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc h1:t2AT8zb6N/59Y78lyRWedVoVWHNRSCBh0oWCC+bluTQ=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

View File

@@ -2,9 +2,11 @@ module ai-token-ratelimit
go 1.18
replace github.com/alibaba/higress/plugins/wasm-go => ../..
require (
github.com/alibaba/higress/plugins/wasm-go v1.4.1-0.20240617024146-5f150179637c
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f
github.com/tidwall/gjson v1.14.3
github.com/wasilibs/go-re2 v1.5.3
github.com/zmap/go-iptree v0.0.0-20210731043055-d4e632617837

View File

@@ -1,5 +1,3 @@
github.com/alibaba/higress/plugins/wasm-go v1.4.1-0.20240617024146-5f150179637c h1:wKCSg4rYfwkZrMk7tYY7navjgcHCMZjcgFrCsjLQBmg=
github.com/alibaba/higress/plugins/wasm-go v1.4.1-0.20240617024146-5f150179637c/go.mod h1:10jQXKsYFUF7djs+Oy7t82f4dbie9pISfP9FJwpPLuk=
github.com/asergeyev/nradix v0.0.0-20170505151046-3872ab85bb56 h1:Wi5Tgn8K+jDcBYL+dIMS1+qXYH2r7tpRAyBgqrWfQtw=
github.com/asergeyev/nradix v0.0.0-20170505151046-3872ab85bb56/go.mod h1:8BhOLuqtSuT5NZtZMwfvEibi09RO3u79uqfHZzfDTR4=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -7,8 +5,8 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520 h1:IHDghbGQ2DTIXHBHxWfqCYQW1fKjyJ/I7W1pMyUDeEA=
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520/go.mod h1:Nz8ORLaFiLWotg6GeKlJMhv8cci8mM43uEnLA5t8iew=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc h1:t2AT8zb6N/59Y78lyRWedVoVWHNRSCBh0oWCC+bluTQ=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f h1:ZIiIBRvIw62gA5MJhuwp1+2wWbqL9IGElQ499rUsYYg=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

View File

@@ -114,6 +114,7 @@ func onHttpRequestHeaders(ctx wrapper.HttpContext, config ClusterKeyRateLimitCon
resultArray := response.Array()
if len(resultArray) != 3 {
log.Errorf("redis response parse error, response: %v", response)
proxywasm.ResumeHttpRequest()
return
}
context := LimitContext{
@@ -162,12 +163,7 @@ func onHttpStreamingBody(ctx wrapper.HttpContext, config ClusterKeyRateLimitConf
keys := []interface{}{limitRedisContext.key}
args := []interface{}{limitRedisContext.count, limitRedisContext.window, inputToken + outputToken}
err = config.redisClient.Eval(ResponsePhaseFixedWindowScript, 1, keys, args, func(response resp.Value) {
if response.Error() != nil {
log.Errorf("call Eval error: %v", response.Error())
}
proxywasm.ResumeHttpResponse()
})
err = config.redisClient.Eval(ResponsePhaseFixedWindowScript, 1, keys, args, nil)
if err != nil {
log.Errorf("redis call failed: %v", err)
return data
@@ -298,6 +294,6 @@ func getDownStreamIp(rule LimitRuleItem) (net.IP, error) {
func rejected(config ClusterKeyRateLimitConfig, context LimitContext) {
headers := make(map[string][]string)
headers[RateLimitResetHeader] = []string{strconv.Itoa(context.reset)}
_ = proxywasm.SendHttpResponse(
config.rejectedCode, reconvertHeaders(headers), []byte(config.rejectedMsg), -1)
_ = proxywasm.SendHttpResponseWithDetail(
config.rejectedCode, "ai-token-ratelimit.rejected", reconvertHeaders(headers), []byte(config.rejectedMsg), -1)
}

View File

@@ -0,0 +1 @@
EXTRA_TAGS=proxy_wasm_version_0_2_100

View File

@@ -2,9 +2,11 @@ module ai-transformer
go 1.18
replace github.com/alibaba/higress/plugins/wasm-go => ../..
require (
github.com/alibaba/higress/plugins/wasm-go v1.4.0
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f
github.com/tidwall/gjson v1.14.3
)

View File

@@ -11,6 +11,7 @@ github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a h1
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc h1:t2AT8zb6N/59Y78lyRWedVoVWHNRSCBh0oWCC+bluTQ=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

View File

@@ -6,7 +6,7 @@ replace github.com/alibaba/higress/plugins/wasm-go => ../..
require (
github.com/alibaba/higress/plugins/wasm-go v0.0.0
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f
github.com/pkg/errors v0.9.1
github.com/tidwall/gjson v1.14.3
)

View File

@@ -7,6 +7,7 @@ github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a h1
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240318034951-d5306e367c43/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=

View File

@@ -293,19 +293,19 @@ func onHttpRequestHeaders(ctx wrapper.HttpContext, config BasicAuthConfig, log w
}
func deniedNoBasicAuthData() types.Action {
_ = proxywasm.SendHttpResponse(http.StatusUnauthorized, WWWAuthenticateHeader(protectionSpace),
_ = proxywasm.SendHttpResponseWithDetail(http.StatusUnauthorized, "basic-auth.no_auth_data", WWWAuthenticateHeader(protectionSpace),
[]byte("Request denied by Basic Auth check. No Basic Authentication information found."), -1)
return types.ActionContinue
}
func deniedInvalidCredentials() types.Action {
_ = proxywasm.SendHttpResponse(http.StatusUnauthorized, WWWAuthenticateHeader(protectionSpace),
_ = proxywasm.SendHttpResponseWithDetail(http.StatusUnauthorized, "basic-auth.bad_credential", WWWAuthenticateHeader(protectionSpace),
[]byte("Request denied by Basic Auth check. Invalid username and/or password."), -1)
return types.ActionContinue
}
func deniedUnauthorizedConsumer() types.Action {
_ = proxywasm.SendHttpResponse(http.StatusForbidden, WWWAuthenticateHeader(protectionSpace),
_ = proxywasm.SendHttpResponseWithDetail(http.StatusForbidden, "basic-auth.unauthorized", WWWAuthenticateHeader(protectionSpace),
[]byte("Request denied by Basic Auth check. Unauthorized consumer."), -1)
return types.ActionContinue
}

View File

@@ -6,7 +6,7 @@ replace github.com/alibaba/higress/plugins/wasm-go => ../..
require (
github.com/alibaba/higress/plugins/wasm-go v1.3.2
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f
github.com/stretchr/testify v1.8.4
github.com/tidwall/gjson v1.14.3
github.com/wasilibs/go-re2 v1.4.1

View File

@@ -8,6 +8,7 @@ github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a h1
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240318034951-d5306e367c43/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg=
github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

View File

@@ -95,7 +95,7 @@ func onHttpRequestHeaders(ctx wrapper.HttpContext, botDetectConfig config.BotDet
method := ctx.Method()
if ok, rule := botDetectConfig.Process(ua); !ok {
proxywasm.SendHttpResponse(botDetectConfig.BlockedCode, nil, []byte(botDetectConfig.BlockedMessage), -1)
proxywasm.SendHttpResponseWithDetail(botDetectConfig.BlockedCode, "bot-detect.blocked", nil, []byte(botDetectConfig.BlockedMessage), -1)
log.Debugf("scheme:%s, host:%s, method:%s, path:%s user-agent:%s has been blocked by rule:%s", scheme, host, method, path, ua, rule)
return types.ActionPause
}

View File

@@ -6,7 +6,7 @@ replace github.com/alibaba/higress/plugins/wasm-go => ../..
require (
github.com/alibaba/higress/plugins/wasm-go v0.0.0
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f
github.com/tidwall/gjson v1.14.3
)

View File

@@ -2,6 +2,7 @@ github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520/go.mod h1:Nz8ORLaFiLWotg6GeKlJMhv8cci8mM43uEnLA5t8iew=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240318034951-d5306e367c43/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=

View File

@@ -6,7 +6,7 @@ replace github.com/alibaba/higress/plugins/wasm-go => ../..
require (
github.com/alibaba/higress/plugins/wasm-go v0.0.0-20230629030002-81e467b6242d
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f
github.com/tidwall/gjson v1.14.4
)

View File

@@ -7,6 +7,7 @@ github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a h1
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240318034951-d5306e367c43/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

View File

@@ -94,18 +94,18 @@ func onHttpRequestHeaders(ctx wrapper.HttpContext, config MyConfig, log wrapper.
pairs := strings.SplitN(ctx.Path(), "?", 2)
if len(pairs) < 2 {
proxywasm.SendHttpResponse(http.StatusBadRequest, nil, []byte("1-need prompt param"), -1)
proxywasm.SendHttpResponseWithDetail(http.StatusBadRequest, "chatgpt-proxy.empty_query_string", nil, []byte("1-need prompt param"), -1)
return types.ActionContinue
}
querys, err := url.ParseQuery(pairs[1])
if err != nil {
proxywasm.SendHttpResponse(http.StatusBadRequest, nil, []byte("2-need prompt param"), -1)
proxywasm.SendHttpResponseWithDetail(http.StatusBadRequest, "chatgpt-proxy.bad_query_string", nil, []byte("2-need prompt param"), -1)
return types.ActionContinue
}
var prompt []string
var ok bool
if prompt, ok = querys[config.PromptParam]; !ok || len(prompt) == 0 {
proxywasm.SendHttpResponse(http.StatusBadRequest, nil, []byte("3-need prompt param"), -1)
proxywasm.SendHttpResponseWithDetail(http.StatusBadRequest, "chatgpt-proxy.no_prompt", nil, []byte("3-need prompt param"), -1)
return types.ActionContinue
}
body := fmt.Sprintf(bodyTemplate, config.Model, prompt[0], config.HumainId, config.AIId)
@@ -118,10 +118,10 @@ func onHttpRequestHeaders(ctx wrapper.HttpContext, config MyConfig, log wrapper.
for key, value := range responseHeaders {
headers = append(headers, [2]string{key, value[0]})
}
proxywasm.SendHttpResponse(uint32(statusCode), headers, responseBody, -1)
proxywasm.SendHttpResponseWithDetail(uint32(statusCode), "chatgpt-proxy.forward", headers, responseBody, -1)
}, 10000)
if err != nil {
proxywasm.SendHttpResponse(http.StatusInternalServerError, nil, []byte("Internel Error: "+err.Error()), -1)
proxywasm.SendHttpResponseWithDetail(http.StatusInternalServerError, "chatgpt-proxy.request_failed", nil, []byte("Internal Error: "+err.Error()), -1)
return types.ActionContinue
}
return types.ActionPause

View File

@@ -1,36 +1,41 @@
# 功能说明
---
title: 基于 Key 集群限流
keywords: [higress, rate-limit]
description: 基于 Key 集群限流插件配置参考
---
`key-cluster-rate-limit`插件实现了基于特定键值实现集群限流,键值来源可以是 URL 参数、HTTP 请求头、客户端 IP 地址、consumer 名称、cookie中 key 名称
## 功能说明
`cluster-key-rate-limit` 插件基于 Redis 实现集群限流,适用于需要跨多个 Higress Gateway 实例实现全局一致速率限制的场景。
限流所使用的 Key 可以来源于 URL 参数、HTTP 请求头、客户端 IP 地址、消费者名称或 Cookie 中的 Key。
## 配置说明
# 配置说明
| 配置项 | 类型 | 必填 | 默认值 | 说明 |
| ----------------------- | ------ | ---- | ------ |-----------------------------------------------------------------------------|
| rule_name | string | 是 | - | 限流规则名称,根据限流规则名称 + 限流类型 + 限流 key 名称 + 限流 key 对应的实际值来拼装 redis key |
| rule_items | array of object | 是 | - | 限流规则项,按照 rule_items 下的排列顺序,匹配第一个 rule_item 后命中限流规则,后续规则将被忽略 |
| show_limit_quota_header | bool | 否 | false | 响应头中是否显示 `X-RateLimit-Limit`(限制的总请求数)和 `X-RateLimit-Remaining`(剩余还可以发送的请求数) |
| rejected_code | int | 否 | 429 | 请求被限流时,返回的 HTTP 状态码 |
| rejected_msg | string | 否 | Too many requests | 请求被限流时,返回的响应体 |
| redis | object | 是 | - | redis 相关配置 |
| 配置项 | 类型 | 必填 | 默认值 | 说明 |
| ----------------------- | ------ | ---- | ------ |---------------------------------------------------------------------------|
| rule_name | string | 是 | - | 限流规则名称,根据限流规则名称+限流类型+限流key名称+限流key对应的实际值来拼装redis key |
| rule_items | array of object | 是 | - | 限流规则项按照rule_items下的排列顺序匹配第一个rule_item后命中限流规则后续规则将被忽略 |
| show_limit_quota_header | bool | 否 | false | 响应头中是否显示`X-RateLimit-Limit`(限制的总请求数)和`X-RateLimit-Remaining`(剩余还可以发送的请求数) |
| rejected_code | int | 否 | 429 | 请求被限流时返回的HTTP状态码 |
| rejected_msg | string | 否 | Too many requests | 请求被限流时,返回的响应体 |
| redis | object | 是 | - | redis相关配置 |
`rule_items` 中每一项的配置字段说明。
`rule_items`中每一项的配置字段说明
| 配置项 | 类型 | 必填 | 默认值 | 说明 |
| --------------------- | --------------- |----------------------| ------ |----------------------------------------------------------------------------------------------------------------------------------------------------------|
| limit_by_header | string | 否,`limit_by_*` 中选填一项 | - | 配置获取限流键值的来源 HTTP 请求头名称 |
| limit_by_param | string | 否,`limit_by_*` 中选填一项 | - | 配置获取限流键值的来源 URL 参数名称 |
| limit_by_consumer | string | 否,`limit_by_*` 中选填一项 | - | 根据 consumer 名称进行限流,无需添加实际值 |
| limit_by_cookie | string | 否,`limit_by_*` 中选填一项 | - | 配置获取限流键值的来源 Cookie中 key 名称 |
| limit_by_per_header | string | 否,`limit_by_*` 中选填一项 | - | 按规则匹配特定 HTTP 请求头,并对每个请求头分别计算限流,配置获取限流键值的来源 HTTP 请求头名称,配置 `limit_keys` 时支持正则表达式或 `*` |
| limit_by_per_param | string | 否,`limit_by_*` 中选填一项 | - | 按规则匹配特定 URL 参数,并对每个参数分别计算限流,配置获取限流键值的来源 URL 参数名称,配置 `limit_keys` 时支持正则表达式或 `*` |
| limit_by_per_consumer | string | 否,`limit_by_*` 中选填一项 | - | 按规则匹配特定 consumer并对每个 consumer 分别计算限流,根据 consumer 名称进行限流,无需添加实际值,配置 `limit_keys` 时支持正则表达式或 `*` |
| limit_by_per_cookie | string | 否,`limit_by_*` 中选填一项 | - | 按规则匹配特定 Cookie并对每个 Cookie 分别计算限流,配置获取限流键值的来源 Cookie中 key 名称,配置 `limit_keys` 时支持正则表达式或 `*` |
| limit_by_per_ip | string | 否,`limit_by_*` 中选填一项 | - | 按规则匹配特定 IP并对每个 IP 分别计算限流,配置获取限流键值的来源 IP 参数名称,从请求头获取,以 `from-header-对应的header名`,示例:`from-header-x-forwarded-for`,直接获取对端 socket ip配置为 `from-remote-addr` |
| limit_keys | array of object | 是 | - | 配置匹配键值后的限流次数 |
| 配置项 | 类型 | 必填 | 默认值 | 说明 |
| --------------------- | --------------- | -------------------------- | ------ | ------------------------------------------------------------ |
| limit_by_header | string | 否,`limit_by_*`中选填一项 | - | 配置获取限流键值的来源 HTTP 请求头名称 |
| limit_by_param | string | 否,`limit_by_*`中选填一项 | - | 配置获取限流键值的来源 URL 参数名称 |
| limit_by_consumer | string | 否,`limit_by_*`中选填一项 | - | 根据 consumer 名称进行限流,无需添加实际值 |
| limit_by_cookie | string | 否,`limit_by_*`中选填一项 | - | 配置获取限流键值的来源 Cookie中 key 名称 |
| limit_by_per_header | string | 否,`limit_by_*`中选填一项 | - | 按规则匹配特定 HTTP 请求头,并对每个请求头分别计算限流,配置获取限流键值的来源 HTTP 请求头名称,配置`limit_keys`时支持正则表达式或`*` |
| limit_by_per_param | string | 否,`limit_by_*`中选填一项 | - | 按规则匹配特定 URL 参数,并对每个参数分别计算限流,配置获取限流键值的来源 URL 参数名称,配置`limit_keys`时支持正则表达式或`*` |
| limit_by_per_consumer | string | 否,`limit_by_*`中选填一项 | - | 按规则匹配特定 consumer并对每个 consumer 分别计算限流,根据 consumer 名称进行限流,无需添加实际值,配置`limit_keys`时支持正则表达式或`*` |
| limit_by_per_cookie | string | 否,`limit_by_*`中选填一项 | - | 按规则匹配特定 Cookie并对每个 Cookie 分别计算限流,配置获取限流键值的来源 Cookie中 key 名称,配置`limit_keys`时支持正则表达式或`*` |
| limit_by_per_ip | string | 否,`limit_by_*`中选填一项 | - | 按规则匹配特定 IP并对每个 IP 分别计算限流,配置获取限流键值的来源 IP 参数名称,从请求头获取,以`from-header-对应的header名`,示例:`from-header-x-forwarded-for`直接获取对端socket ip配置为`from-remote-addr` |
| limit_keys | array of object | 是 | - | 配置匹配键值后的限流次数 |
`limit_keys`中每一项的配置字段说明
`limit_keys` 中每一项的配置字段说明。
| 配置项 | 类型 | 必填 | 默认值 | 说明 |
| ---------------- | ------ | ------------------------------------------------------------ | ------ | ------------------------------------------------------------ |
@@ -40,131 +45,121 @@
| query_per_hour | int | 否,`query_per_second`,`query_per_minute`,`query_per_hour`,`query_per_day` 中选填一项 | - | 允许每小时请求次数 |
| query_per_day | int | 否,`query_per_second`,`query_per_minute`,`query_per_hour`,`query_per_day` 中选填一项 | - | 允许每天请求次数 |
`redis`中每一项的配置字段说明
`redis` 中每一项的配置字段说明
| 配置项 | 类型 | 必填 | 默认值 | 说明 |
| ------------ | ------ | ---- | ---------------------------------------------------------- | --------------------------- |
| service_name | string | 必填 | - | redis 服务名称,带服务类型的完整 FQDN 名称,例如 my-redis.dns、redis.my-ns.svc.cluster.local |
| service_port | int | 否 | 服务类型为固定地址static service默认值为80其他为6379 | 输入redis服务的服务端口 |
| username | string | 否 | - | redis用户名 |
| password | string | 否 | - | redis密码 |
| timeout | int | 否 | 1000 | redis连接超时时间单位毫秒 |
| 配置项 | 类型 | 必填 | 默认值 | 说明 |
| ------------ | ------ | ---- | ---------------------------------------------------------- |---------------------------------------------------------------------------|
| service_name | string | 必填 | - | redis 服务名称,带服务类型的完整 FQDN 名称,例如 my-redis.dns、redis.my-ns.svc.cluster.local |
| service_port | int | 否 | 服务类型为固定地址static service默认值为80其他为6379 | 输入redis服务的服务端口 |
| username | string | 否 | - | redis 用户名 |
| password | string | 否 | - | redis 密码 |
| timeout | int | 否 | 1000 | redis 连接超时时间,单位毫秒 |
## 配置示例
# 配置示例
## 识别请求参数 apikey进行区别限流
### 识别请求参数 apikey进行区别限流
```yaml
rule_name: default_rule
rule_items:
- limit_by_param: apikey
limit_keys:
- key: 9a342114-ba8a-11ec-b1bf-00163e1250b5
query_per_minute: 10
- key: a6a6d7f2-ba8a-11ec-bec2-00163e1250b5
query_per_hour: 100
- limit_by_per_param: apikey
limit_keys:
# 正则表达式,匹配以a开头的所有字符串每个apikey对应的请求10qds
- key: "regexp:^a.*"
query_per_second: 10
# 正则表达式,匹配以b开头的所有字符串每个apikey对应的请求100qd
- key: "regexp:^b.*"
query_per_minute: 100
# 兜底用匹配所有请求每个apikey对应的请求1000qdh
- key: "*"
query_per_hour: 1000
- limit_by_param: apikey
limit_keys:
- key: 9a342114-ba8a-11ec-b1bf-00163e1250b5
query_per_minute: 10
- key: a6a6d7f2-ba8a-11ec-bec2-00163e1250b5
query_per_hour: 100
- limit_by_per_param: apikey
limit_keys:
# 正则表达式,匹配以 a 开头的所有字符串,每个 apikey 对应的请求 10qds
- key: "regexp:^a.*"
query_per_second: 10
# 正则表达式,匹配以 b 开头的所有字符串,每个 apikey 对应的请求 100qd
- key: "regexp:^b.*"
query_per_minute: 100
# 兜底用,匹配所有请求,每个 apikey 对应的请求 1000qdh
- key: "*"
query_per_hour: 1000
redis:
service_name: redis.static
show_limit_quota_header: true
```
## 识别请求头 x-ca-key进行区别限流
### 识别请求头 x-ca-key进行区别限流
```yaml
rule_name: default_rule
rule_items:
- limit_by_header: x-ca-key
limit_keys:
- key: 102234
query_per_minute: 10
- key: 308239
query_per_hour: 10
- limit_by_per_header: x-ca-key
limit_keys:
# 正则表达式,匹配以a开头的所有字符串每个apikey对应的请求10qds
- key: "regexp:^a.*"
query_per_second: 10
# 正则表达式匹配以b开头的所有字符串每个apikey对应的请求100qd
- key: "regexp:^b.*"
query_per_minute: 100
# 兜底用匹配所有请求每个apikey对应的请求1000qdh
- key: "*"
query_per_hour: 1000
- limit_by_header: x-ca-key
limit_keys:
- key: 102234
query_per_minute: 10
- key: 308239
query_per_hour: 10
- limit_by_per_header: x-ca-key
limit_keys:
# 正则表达式,匹配以 a 开头的所有字符串,每个 apikey 对应的请求 10qds
- key: "regexp:^a.*"
query_per_second: 10
# 正则表达式匹配以b开头的所有字符串每个 apikey 对应的请求 100qd
- key: "regexp:^b.*"
query_per_minute: 100
# 兜底用,匹配所有请求,每个 apikey 对应的请求 1000qdh
- key: "*"
query_per_hour: 1000
redis:
service_name: redis.static
show_limit_quota_header: true
```
## 根据请求头 x-forwarded-for 获取对端IP进行区别限流
### 根据请求头 x-forwarded-for 获取对端 IP进行区别限流
```yaml
rule_name: default_rule
rule_items:
- limit_by_per_ip: from-header-x-forwarded-for
limit_keys:
# 精确ip
- key: 1.1.1.1
query_per_day: 10
# ip段,符合这个ip段的ip每个ip 100qpd
- key: 1.1.1.0/24
query_per_day: 100
# 兜底用,即默认每个ip 1000qpd
- key: 0.0.0.0/0
query_per_day: 1000
- limit_by_per_ip: from-header-x-forwarded-for
limit_keys:
# 精确 IP
- key: 1.1.1.1
query_per_day: 10
# IP 段,符合这个 IP 段的 IP每个 IP 100qpd
- key: 1.1.1.0/24
query_per_day: 100
# 兜底用,即默认每个 IP 1000 qpd
- key: 0.0.0.0/0
query_per_day: 1000
redis:
service_name: redis.static
show_limit_quota_header: true
```
## 识别consumer进行区别限流
### 识别 consumer进行区别限流
```yaml
rule_name: default_rule
rule_items:
- limit_by_consumer: ''
limit_keys:
- key: consumer1
query_per_second: 10
- key: consumer2
query_per_hour: 100
- limit_by_per_consumer: ''
limit_keys:
# 正则表达式,匹配以a开头的所有字符串每个consumer对应的请求10qds
- key: "regexp:^a.*"
query_per_second: 10
# 正则表达式,匹配以b开头的所有字符串每个consumer对应的请求100qd
- key: "regexp:^b.*"
query_per_minute: 100
# 兜底用匹配所有请求每个consumer对应的请求1000qdh
- key: "*"
query_per_hour: 1000
- limit_by_consumer: ''
limit_keys:
- key: consumer1
query_per_second: 10
- key: consumer2
query_per_hour: 100
- limit_by_per_consumer: ''
limit_keys:
# 正则表达式,匹配以 a 开头的所有字符串,每个 consumer 对应的请求 10qds
- key: "regexp:^a.*"
query_per_second: 10
# 正则表达式,匹配以 b 开头的所有字符串,每个 consumer 对应的请求 100qd
- key: "regexp:^b.*"
query_per_minute: 100
# 兜底用,匹配所有请求,每个 consumer 对应的请求 1000qdh
- key: "*"
query_per_hour: 1000
redis:
service_name: redis.static
show_limit_quota_header: true
```
## 识别cookie中的键值对进行区别限流
### 识别 Cookie 中的键值对,进行区别限流
```yaml
rule_name: default_rule
@@ -177,15 +172,15 @@ rule_items:
query_per_hour: 100
- limit_by_per_cookie: key1
limit_keys:
# 正则表达式,匹配以a开头的所有字符串每个cookie中的value对应的请求10qds
# 正则表达式,匹配以 a 开头的所有字符串,每个 cookie 中的 value 对应的请求 10qds
- key: "regexp:^a.*"
query_per_second: 10
# 正则表达式,匹配以b开头的所有字符串每个cookie中的value对应的请求100qd
# 正则表达式,匹配以 b 开头的所有字符串,每个 cookie 中的 value 对应的请求 100qd
- key: "regexp:^b.*"
query_per_minute: 100
# 兜底用匹配所有请求每个cookie中的value对应的请求1000qdh
# 兜底用,匹配所有请求,每个 cookie 中的 value 对应的请求 1000qdh
- key: "*"
query_per_hour: 1000
query_per_hour: 1000
rejected_code: 200
rejected_msg: '{"code":-1,"msg":"Too many requests"}'
redis:

View File

@@ -1,4 +1,4 @@
module github.com/alibaba/higress/plugins/wasm-go/extensions/key-cluster-rate-limit
module cluster-key-rate-limit
go 1.19
@@ -6,7 +6,7 @@ replace github.com/alibaba/higress/plugins/wasm-go => ../..
require (
github.com/alibaba/higress/plugins/wasm-go v0.0.0
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f
github.com/tidwall/gjson v1.14.3
github.com/tidwall/resp v0.1.1
github.com/wasilibs/go-re2 v1.5.3

View File

@@ -7,6 +7,7 @@ github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520 h1:IHDghbG
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520/go.mod h1:Nz8ORLaFiLWotg6GeKlJMhv8cci8mM43uEnLA5t8iew=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc h1:t2AT8zb6N/59Y78lyRWedVoVWHNRSCBh0oWCC+bluTQ=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -23,6 +24,7 @@ github.com/tidwall/resp v0.1.1 h1:Ly20wkhqKTmDUPlyM1S7pWo5kk0tDu8OoC/vFArXmwE=
github.com/tidwall/resp v0.1.1/go.mod h1:3/FrruOBAxPTPtundW0VXgmsQ4ZBA0Aw714lVYgwFa0=
github.com/wasilibs/go-re2 v1.5.3 h1:wiuTcgDZdLhu8NG8oqF5sF5Q3yIU14lPAvXqeYzDK3g=
github.com/wasilibs/go-re2 v1.5.3/go.mod h1:PzpVPsBdFC7vM8QJbbEnOeTmwA0DGE783d/Gex8eCV8=
github.com/wasilibs/nottinygc v0.4.0 h1:h1TJMihMC4neN6Zq+WKpLxgd9xCFMw7O9ETLwY2exJQ=
github.com/zmap/go-iptree v0.0.0-20210731043055-d4e632617837 h1:DjHnADS2r2zynZ3WkCFAQ+PNYngMSNceRROi0pO6c3M=
github.com/zmap/go-iptree v0.0.0-20210731043055-d4e632617837/go.mod h1:9vp0bxqozzQwcjBwenEXfKVq8+mYbwHkQ1NF9Ap0DMw=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

View File

@@ -253,6 +253,6 @@ func rejected(config ClusterKeyRateLimitConfig, context LimitContext) {
headers[RateLimitLimitHeader] = []string{strconv.Itoa(context.count)}
headers[RateLimitRemainingHeader] = []string{strconv.Itoa(0)}
}
_ = proxywasm.SendHttpResponse(
config.rejectedCode, reconvertHeaders(headers), []byte(config.rejectedMsg), -1)
_ = proxywasm.SendHttpResponseWithDetail(
config.rejectedCode, "cluster-key-rate-limit.rejected", reconvertHeaders(headers), []byte(config.rejectedMsg), -1)
}

View File

@@ -6,7 +6,7 @@ replace github.com/alibaba/higress/plugins/wasm-go => ../..
require (
github.com/alibaba/higress/plugins/wasm-go v0.0.0-20230519024024-625c06e58f91
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f
github.com/stretchr/testify v1.8.4
github.com/tidwall/gjson v1.14.4
)

View File

@@ -8,6 +8,7 @@ github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a h1
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240318034951-d5306e367c43/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

View File

@@ -94,7 +94,7 @@ func onHttpRequestHeaders(ctx wrapper.HttpContext, corsConfig config.CorsConfig,
if !httpCorsContext.IsValid {
headers := make([][2]string, 0)
headers = append(headers, [2]string{config.HeaderPluginTrace, "trace"})
proxywasm.SendHttpResponse(http.StatusForbidden, headers, []byte("Invalid CORS request"), -1)
proxywasm.SendHttpResponseWithDetail(http.StatusForbidden, "cors.forbidden", headers, []byte("Invalid CORS request"), -1)
return types.ActionPause
}
@@ -102,7 +102,7 @@ func onHttpRequestHeaders(ctx wrapper.HttpContext, corsConfig config.CorsConfig,
if httpCorsContext.IsPreFlight {
headers := make([][2]string, 0)
headers = append(headers, [2]string{config.HeaderPluginTrace, "trace"})
proxywasm.SendHttpResponse(http.StatusOK, headers, nil, -1)
proxywasm.SendHttpResponseWithDetail(http.StatusOK, "cores.preflight", headers, nil, -1)
return types.ActionPause
}

View File

@@ -6,7 +6,7 @@ replace github.com/alibaba/higress/plugins/wasm-go => ../..
require (
github.com/alibaba/higress/plugins/wasm-go v0.0.0
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f
github.com/tidwall/gjson v1.14.3
)

View File

@@ -7,6 +7,7 @@ github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a h1
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240318034951-d5306e367c43/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

View File

@@ -100,7 +100,7 @@ func onHttpRequestHeaders(ctx wrapper.HttpContext, config CustomResponseConfig,
if len(config.enableOnStatus) != 0 {
return types.ActionContinue
}
err := proxywasm.SendHttpResponse(config.statusCode, config.headers, []byte(config.body), -1)
err := proxywasm.SendHttpResponseWithDetail(config.statusCode, "custom-response", config.headers, []byte(config.body), -1)
if err != nil {
log.Errorf("send http response failed: %v", err)
}
@@ -124,7 +124,7 @@ func onHttpResponseHeaders(ctx wrapper.HttpContext, config CustomResponseConfig,
for _, v := range config.enableOnStatus {
if uint32(statusCode) == v {
err = proxywasm.SendHttpResponse(config.statusCode, config.headers, []byte(config.body), -1)
err = proxywasm.SendHttpResponseWithDetail(config.statusCode, "custom-response", config.headers, []byte(config.body), -1)
if err != nil {
log.Errorf("send http response failed: %v", err)
}

View File

@@ -6,7 +6,7 @@ replace github.com/alibaba/higress/plugins/wasm-go => ../..
require (
github.com/alibaba/higress/plugins/wasm-go v0.0.0-20230410091208-df60dd43079c
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f
github.com/stretchr/testify v1.8.4
github.com/tidwall/gjson v1.14.4
)

View File

@@ -8,6 +8,7 @@ github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a h1
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240318034951-d5306e367c43/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

View File

@@ -95,7 +95,7 @@ func onHttpRequestHeaders(ctx wrapper.HttpContext, config config.DeGraphQLConfig
headers = append(headers, [2]string{"x-degraphql-endpoint", config.GetEndpoint()})
headers = append(headers, [2]string{"x-degraphql-timeout", fmt.Sprintf("%d", config.GetTimeout())})
headers = append(headers, [2]string{"x-degraphql-version", config.GetVersion()})
proxywasm.SendHttpResponse(uint32(statusCode), headers, responseBody, -1)
proxywasm.SendHttpResponseWithDetail(uint32(statusCode), "de-graphql", headers, responseBody, -1)
return
}, config.GetTimeout())

Some files were not shown because too many files have changed in this diff Show More